Color each selected Dropdown item in react semantic-ui - javascript

I have the following jsx code (react-semantic-ui) in render method:
{!this.props.loading &&
<ControlRow>
<Grid.Column width={5}>
<Dropdown
multiple
fluid
selection
options={myOptions}
onChange={this.navigateToMyFunc}
/>
...
...
And I am using styled-components to style my elements:
https://github.com/styled-components/styled-components
Unfortunately the only working styling for the Dropdown due to some weird specifics of the environment is indirect from ControlRow:
const ControlsRow = styled(Grid.Row)`
.ui.multiple.dropdown > .label {
color: white !important;
background-color: #2185d0;
}
`
See also the following thread: Dropdown in semantic ui can't be made of multiple selection type when wrapped with styled-components
Now the Dropdown as you can see is of type multiple. Each selected item should be colored according to the specified in the myOptions options. I can pass myOptions to the ControlRow which will make the array to be accessible in it, but I am not sure how to write the styled-components part of it:
.ui.multiple.dropdown > .label {
color: white !important;
background-color: ${props => props.myOptions..??};
}
I need to also know which item it is to select correct myOptions color. Here is how it looks:
Right now it is just always blue, but I need it to be colored according to each option.
Update
Seems like it is an absent feature in semantic-ui-react - coloring by hex - codes (only a few regular color names allowed) - so I posted this feature to their github:
https://github.com/Semantic-Org/Semantic-UI-React/issues/3889

by default semantic-ui supports selected list of colors. If you need custom label color, you can add your custom css classes and apply the class name to the label.
const getOptions = (myOptions : string[]) => {
return myOptions.map((myValue : string) =>({
key: myValue,
text: myValue,
value: myValue,
label: { className: setColorClass(myValue), empty: true, circular: true }
}))
}
function setColorClass(optValue) {
if (optValue === '1') return 'light-green';
else if (optValue === '2') return 'sandy-brown';
else return 'light-coral';
}
in your css class you can have the following classes
.ui.label.light-green {
background-color: lightgreen !important;
}
.ui.label.sandy-brown {
background-color: lightgreen !important;
}
.ui.label.light-coral {
background-color: lightgreen !important;
}
Also if you want to apply label circular color when the value is selected, you can do the following, write a renderLabel function in your react class and apply it in the compnent
function renderLabel(label:any){
return {
content: `${label.text}`,
className: setColorClass(label.text)
}
}
Sample component
<Dropdown
search
selection
closeOnChange
value={myValue}
options={getOptions(myOptions)}
placeholder='Choose from here'
onChange={handleDropdownChange}
renderLabel={renderLabel}
/>

You don't need to use CSS styling for this. And nothing related to Styled Components needs to be done.
SemanticUI lets you use a custom render function for labels.
You would use it like this:
const renderLabel = (option) => ({
color: option.color,
content: option.text,
})
const myOptions = [
{ text: "option one", color: "blue" },
{ text: "option two", color: "red" },
// more options...
]
// ...
<Dropdown
multiple
fluid
selection
options={myOptions}
onChange={this.navigateToMyFunc}
renderLabel={renderLabel} // here
/>
This assumes that your option objects have a color property and a text property. You'll need to adjust to the shape of your option objects.
Also, the color property will need to be one of the available label colors in SemanticUI:
const colors = [
'red',
'orange',
'yellow',
'olive',
'green',
'teal',
'blue',
'violet',
'purple',
'pink',
'brown',
'grey',
'black',
]

Related

How can a component be rendered conditionally dependent upon the value in a defaultprops array?

I have a ReactJS static defaultProps array, which is used to render a number of buttons. I'm looking to conditionally generate a text-component dependent upon which specific button is clicked.
Here is an example depicting a Car component:
...
static defaultProps = {
cars: [
{ type: 'hatchback', color: 'red', info: '...' },
{ type: 'sedan', color: 'blue', info: '...' },
{ type: '4x4', color: 'green', info: '...' },
]
}
...
Let us say that each 'type' field generates a button labelled with type. Let's imagine that I want to create a swatch div that depicts the color onClick. So if I click the 'hatchback' button, then the swatch div will turn 'green' or 'red' or 'blue', dependent upon the car type selected.
What is the easiest way to do this?
Here is an example of the button mapping function:
{this.props.cars.map((car) => (
<button>
{car.type}
</button>
And here would be an example of the colorSwatch div:
<div className={styles.colorSwatch}>{car.info}</div>
To be as specific as possible, the problem is to do with the text content and not conditional CSS issues.
I want to know how to conditionally set info.
You can store the clicked button object in state and use it to render your colorSwatch div
{this.props.cars.map((car) => (
<button onClick={() => this.setState({clickedBtn: car})}>
{car.type}
</button>
const { clickedBtn } = this.state;
...
{clickedBtn && <div className={styles.colorSwatch}>{clickedBtn.info}</div>}

Propagate style props to React children and apply them to a CSS file

I am rendering component Dropdown which acts like html dropdown component, but is a collection of divs ordered and unordered lists. I am trying to pass styles to the className elements , which have dropdown.css file rendering the styles, but I am not sure how to target those specific elements all the way from the parent component.
How to target
div className="select-box-current"
with style={{ border: "1px solid #D4D4D4" }}
and
div className="select-box-list"
with
style={{
opacity: 1,
display: "inherit",
animationName: "none",
cursor: "pointer"
}}
The CodeSandblox is here -> https://codesandbox.io/s/weathered-wood-cf8u8?file=/src/App.js:481-614
So with React if you pass props that are the same name, it only select the one that was passed last. So with your two style props, it only would pass the last one. However, it probably isn't the best idea to use the name style anyway, since it isn't descriptive and also mirrors the actual HTML style attribute.
Give the two different styles unique names, in the App.js file:
<div className="App">
<Dropdown
inputName="viola"
list={[
{ yard_id: "1", yard_name: "Yard 1" },
{ yard_id: "2", yard_name: "Yard 2" }
]}
// this style is for className="select-box-current"
currentStyles={{ border: "1px solid #D4D4D4" }}
// this style is for className="select-box-list"
listStyles={{
opacity: 1,
display: "inherit",
animationName: "none",
cursor: "pointer"
}}
/>
</div>
Now we need to pass those two props through your component tree, the next file is the Dropdown.js file.
Before I get to passing the props, I want to comment about something that is wrong, that isn't entirely related.
export const Dropdown = ({ list, ...others }) => {
const copiedProps = {};
Object.keys(others).forEach((key) => {
// these are the props that need to get thru:
if ("style" === key || "className" === key) {
copiedProps[key] = others[key];
}
});
...
The copying of props, isn't necessary and the way that it is done is actually detrimental. If you want to specifically target a value in the incoming props, you can access it directly (ex props.myProp or in this case other.style) or destructuring assignment.
Since you are wanting to only pass the style (now listStyles and currentStyles) and the className I chose to assign them to a variable using the destructuring assignment.
export const Dropdown = ({
list,
currentStyles,
listStyles,
className,
...others
}) => { ... }
Now that we have those props, we want to pass it into your DropdownView which contains the actual elements you're wanting to target.
<DropdownView
dropdownItems={dropdownItems}
activeItem={activeItem}
hover={hover}
setActiveItem={(activeItem) => {
setActiveItem(activeItem);
}}
onMouseOver={(hover) => onMouseOver(hover)}
toggleList={() => toggleList(!hideList)}
hideList={hideList}
className={className}
currentStyles={currentStyles}
listStyles={listStyles}
/>
Okay, now we have the styles and classname where we want them. All you have to do is get the props like we did above, and then set them on the elements.
<div
className="select-box-current"
tabIndex="0"
autoFocus={true}
onClick={() => toggleList()}
style={currentStyles}
>...</div>
I forked the sandbox to include a working example. But node that I didn't set the use the className prop in the DropdowView since it wasn't clear what element would have that.
https://codesandbox.io/s/hardcore-sun-yyx0g?file=/src/DropdownView.jsx
I think instead of using them from the parent div you can directly use those styles to those elements like this. https://codesandbox.io/s/eloquent-lamport-3spzr?file=/src/App.js
But if you want to use those styles from the parent. Then you can pass them using specific name. Like this
<Dropdown
inputName="viola"
list={[
{ yard_id: "1", yard_name: "Yard 1" },
{ yard_id: "2", yard_name: "Yard 2" }
]}
// this style is for className="select-box-current"
selectBoxCurrentStyle={{ border: "1px solid #D4D4D4" }}
// this style is for className="select-box-list"
selectBoxListStyle={{
opacity: 1,
display: "inherit",
animationName: "none",
cursor: "pointer"
}}
/>
Here is the link https://codesandbox.io/s/damp-rain-cyhxb?file=/src/App.js:133-643

How to override global border color styles for disabled Material UI TextField?

I'm trying to override the global style for the Mui TextField components that are disabled, but I can't get the border color to change.
I've managed to change the label color if the field is disabled, but not the border color. Here is what I have so far:
export const theme = createMuiTheme({
overrides: {
// For label
MuiInputLabel: {
root: {
'&$disabled': {
color: '#000000',
},
},
},
// For border color of field (doesn't work)
MuiTextField: {
root: {
'&$disabled': {
borderColor: '#FFFFFF'
},
},
},
},
});
I've tried all kinds of variations, including,
MuiOutlinedInput: {
root: {
fieldset: {
borderColor: '#FFFFFF',
},
}
}
But this only changes the border color of non-disabled fields. What am I doing wrong here?
Here is how it looks:
The border is getting from the fieldset element. You can style if based on your needs:
MuiInputBase: {
root: {
"&$disabled": {
'& fieldset.MuiOutlinedInput-notchedOutline': {
borderColor: "blue",
background: "grey"
}
}
}
}
You can find a working example here: https://codesandbox.io/s/material-styling-disabled-textfield-ckp14?file=/demo.js
Here is a "walkthrough" for how to do it yourself:
Check the html output:
Open the image in new tab to check the marks.
As you can see - the label is actually not a parent of the fieldset tag, which is the one that draws the border.
The fieldset is inside the div.MuiInputBase, which is also disabled, so I had to add the &$disabled on the root of the MuiInputBase.
As for the & fieldset - the fieldset element is a child-element fo the MuiInputBase - so the space between the & and the tag-name means this is a child-element.
The fieldset element has the MuiOutlinedInput-notchedOutline so I used it as the relevant selector. You could probably just use .MuiOutlinedInput-root.Mui-disabled fieldset without the last-selector. Try it :-).

How to custom color text and icon in TableSortText component of Material-ui?

What I'm trying to do:
I am trying to provide the user the option to provide custom styling to my EnhancedTable component by passing in a styles object containing properties such as headCellColor, headCellBackgroundColor, bodyCellColor, bodyCellBackgroundColor etc which can be used to color the cells in TableHead and TableBody.
In the TableHead component, I use a TableSortLabel in a way similar to what they've done in this material-ui docs example: https://material-ui.com/components/tables/#sorting-amp-selecting
I wish to custom color the text and the arrow icons on hover and when active based on the props provided by the user.
Let's see the colors of TableSortLabel in different situations:
The color of the text is grey initially and there is no arrow. When mouse is hovered over it, a grey arrow appears and the text turns black. On clicking it, active state is set, the grey arrow turns black and the text turns black permanently until active state is removed.
What I've tried so far:
const useStyles = makeStyles({
tableSortLabel: props => ({
backgroundColor: "blue",
color: props.headCellColor,
fill: props.headCellColor,
"&:hover": {
backgroundColor: "blue"
}
})
});
function EnhancedTableHeadCell(props) {
const { isActive, onHoverSortState, clickHandler, ...otherProps } = props;
const classes = useStyles(props.styles);
return (
<FancyTableCell styles={props.styles} {...otherProps}>
<TableSortLabel
active={isActive}
classes={{
icon: classes.tableSortLabel,
active: classes.tableSortLabel
}}
direction={onHoverSortState}
onClick={clickHandler}
>
{props.children}
</TableSortLabel>
</FancyTableCell>
);
}
This is what it looks like in the browser:
https://i.postimg.cc/fW7W2MRB/c1.jpg
The first one is a normal header, the second is on hover and the third is when clicked (active state).
From what we can observe, the text color is totally unaffected by the color css property in all the three cases (normal, hover, active). On hover, backgroundColor only affects the icon and not the text. However, we can see that backgroundColor affects the text when it is active. Everything is going as expected with the icon. The only issue is with the text.
What could I be possible doing wrong? How can I solve my problem?
What worked for me is:
const StyledTableSortLabel = withStyles((theme: Theme) =>
createStyles({
root: {
color: 'white',
"&:hover": {
color: 'white',
},
'&$active': {
color: 'white',
},
},
active: {},
icon: {
color: 'inherit !important'
},
})
)(TableSortLabel);
You can reference the following for increasing css specificity:
https://material-ui.com/customization/components/#pseudo-classes
Solution for your problem is following:
MuiTableSortLabel: {
root: {
color: textPrimary,
// if you want to have icons visible permanently
// '& $icon': {
// opacity: 1,
// color: primaryMain
// },
"&:hover": {
color: primaryMain,
'&& $icon': {
opacity: 1,
color: primaryMain
},
},
"&$active": {
color: primaryMain,
// && instead of & is a workaround for https://github.com/cssinjs/jss/issues/1045
'&& $icon': {
opacity: 1,
color: primaryMain
},
},
},
}
This restyling I use globally via my ThemeProvider, but you can of course use it individually in your single component by using "withStyles" HOC (see "BootstrapButton" in example)
I could'nt find a proper way to do it so I came up with a temporary solution overriding the material ui css.
I added this to my global css:
.MuiTableSortLabel-root.MuiTableSortLabel-active,
.MuiTableSortLabel-root:hover,
.MuiTableSortLabel-icon {
color: inherit !important;
}
Worked for me with Mui5:
sx = {
{
'&.MuiTableSortLabel-root': {
color: 'white',
},
'&.MuiTableSortLabel-root:hover': {
color: 'blue',
},
'&.Mui-active': {
color: 'blue',
},
'& .MuiTableSortLabel-icon': {
color: 'blue !important',
},
}
}
'&.MuiTableSortLabel-root' <-- no space &.
'&.Mui-active' <-- no space &.
'& .MuiTableSortLabel-icon' <-- space

Overriding CSS styles in Material UI Stepper with CSS API

I would like to change text color (which is actually a SVG Icon) in Material UI StepIcon only for active and completed steps. At the moment, I successfully changed color of an icon for those steps. That's how my MuiTheme looks like now.
export default createMuiTheme({
overrides: {
MuiStepIcon: {
root: {
'&$active': {
color: styles.myGreen,
},
'&$completed': {
color: styles.myGreen,
},
},
}
},
});
And whole stepper looks like:
Assumings, I would like to change color of tick to gray (which represents completed steps) and color of number two to gray as well (which represents currently active step), while keeping inactive step not changed (white fill).
Changing fill property for text like in official documentation does not give any results, in developer inspector still shows fill equal white.
I want to apply that styling for whole app.
Any tips or solution for this one?
you need to override the text class too
export default createMuiTheme({
overrides: {
MuiStepIcon: {
root: {
'&$active': {
color: styles.myGreen,
},
'&$completed': {
color: styles.myGreen,
},
},
text: {
fill: <YOUR_DESIRED_COLOR>
},
},
}
},
});

Categories

Resources