Material UI modifier class styles using props not working - reactjs

Trying to set the colors based on props for an inner selector ('&$selected' and '&:hover'). But the colors are not applied, though I can see the class related to selected being applied.
const getColor = (color, theme) => {
return color === 'primary'
? theme.palette.primary.contrastText
: color === 'secondary'
? theme.palette.secondary.contrastText
: theme.palette.action.active;
};
const getBgColor = (color, theme) => {
return color === 'primary'
? theme.palette.primary.main
: color === 'secondary'
? theme.palette.secondary.main
: theme.palette.action.active;
};
const useStyles = makeStyles(theme => ({
root: {
textTransform: 'none',
// This does not apply the set colors
'&$selected': {
color: ({ color }) => getColor(color, theme),
backgroundColor: ({ color }) =>
getBgColor(color, theme),
// This is not applied as well
'&:hover': {
backgroundColor: ({ color }) =>
getBgColor(color, theme),
},
},
},
selected: {},
}))

Related

react-select, AsyncSelect only able to select one option even i added isMulti after that it display no options

I can select first option successfully, but after that it doesn't display any option, can't add second option and I even added isMulti.
import React from "react";
import AsyncSelect from "react-select/async";
import makeAnimated from "react-select/animated";
import { options } from "../colorOptions";
import chroma from "chroma-js";
const animatedComponents = makeAnimated();
export const SelectBox = () => {
const loadOptions = (searchValue, callback) => {
console.log(searchValue);
setTimeout(() => {
const filteredOptions = options.filter((option) =>
option.name.toLowerCase().includes(searchValue.toLowerCase())
);
console.log(filteredOptions);
callback(filteredOptions);
}, 1000);
};
const colorStyles = {
control: (styles) => ({ ...styles, backgroundColor: "white" }),
option: (styles, { data, isDesable, isFocused, isSelected }) => {
return { ...styles, color: data.colorCode };
},
multiValue: (styles, { data }) => {
const color = chroma(data.colorCode);
return {
...styles,
backgroundColor: color.alpha(0.1).css(),
color: data.colorCode
};
},
multiValueLabel: (styles, { data }) => ({
...styles,
color: data.colorCode
})
};
return (
<AsyncSelect
key={options.length}
loadOptions={loadOptions}
option={options}
closeMenuOnSelect={false}
components={animatedComponents}
isMulti
defaultOptions
styles={colorStyles}
/>
);
};
code sandbox link:
https://codesandbox.io/s/dreamy-water-j2m55v?file=/src/components/SelectBox.jsx:0-1401
code sandbox link:
https://codesandbox.io/s/dreamy-water-j2m55v?file=/src/components/SelectBox.jsx:0-1401
my mistake
i should provide my collection of option in this format
export const options = [ { id: 1, value: "Red", colorCode: "#FF0000", label: "Red" }, ];
when i change to this format the code works

React-Select with Formik Reset/Clear button

What i want, a "reset/clear" button on the first page to refresh the searchable drop down list of react-select with Formik.This is the first page,the one after is the second,the problem iam facing is to refresh the code from a clear button in the first page,i tried everything i can to change,i added some props that are not needed.
<SearchableDropDownList
onChange={(value) =>
formik.setFieldValue('formDay', value || null)}
resetValue={resetValue}
value={formik.values.formDay}
options={dayOptions}
formik={formik}
/>
import React from 'react';
import Select from 'react-select';
import CreatableSelect from 'react-select/creatable';
import chroma from 'chroma-js';
import { StylesConfig } from 'react-select';
// https://codesandbox.io/s/1j4zxl8bq
export default ({ inputRef, onChange, options, value, className, resetValue, onBlur, formik }) => {
// -----------Creating design for react-select----------------------------For Creatable--umust
// --u must set this line as well : const color = chroma(data.color ?? 'black'); because there is no data on creatable
// so i must handle the empty created by the user input
const dot = (color = 'white') => ({
alignItems: 'center',
display: 'flex',
':before': {
backgroundColor: color,
borderRadius: 10,
content: '" "',
display: 'block',
marginRight: 8,
height: 10,
width: 10,
},
});
const colourStyles = {
control: (styles) => ({
...styles,
backgroundColor: '#212529',
borderRadius: 10,
borderColor: '#323232',
}),
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
const randomColor = 'black';
const color = chroma(data.color ?? 'black');
return {
...styles,
backgroundColor: isDisabled
? undefined
: isSelected
? randomColor
: isFocused
? color.alpha(0.1).css()
: undefined,
color: isDisabled
? '#ccc'
: isSelected
? chroma.contrast(color, 'white') > 2
? 'white'
: 'blue'
: randomColor,
cursor: isDisabled ? 'not-allowed' : 'default',
':active': {
...styles[':active'],
backgroundColor: !isDisabled
? isSelected
? randomColor
: color.alpha(0.3).css()
: undefined,
},
};
},
input: (styles) => ({
...styles,
...dot(),
color: 'grey',
borderColor: '#6c5dd3',
text: 'john#domain.com',
}),
placeholder: (styles) => ({
...styles,
...dot('#ccc'),
borderColor: '#6c5dd3',
text: 'john#domain.com',
}),
singleValue: (styles, { data }) => ({
...styles,
...dot('white'),
color: 'grey',
borderColor: '#6c5dd3',
text: 'john#domain.com',
}),
};
if (resetValue === true) {
value = null;
// formik.setFieldValue('formDay', null)
resetValue = false;
}
const handleChange = (event) => {
// Overwrite the event with your own object if it doesn't exist
if (!event || value === null) {
event = {
target: inputRef,
value: '',
};
}
onChange(event);
};
const defaultValue = (options, value) => {
return options ? options.find((option) => option.value === value) : null;
// return {value:'developer',label:'Software Developer'};
};
// const randomColor = `#`.concat( Math.floor(Math.random()*16777215).toString(16))
// const color = chroma.random();
// const color = chroma(data.color ?? 'black');
// https://nibes.cn/blog/22525
return (
<div className={className}>
<CreatableSelect
value={defaultValue(options, value)}
styles={colourStyles}
onChange={handleChange}
isClearable
ref={inputRef}
options={options}
/>
</div>
);
};

MUI makeStyles Props and logic to set multiple styles

This is a really simple on im sure, but i just cannot find an answer that works.
I am passing props to makeStyles like below.
const classes = useStyles({ isActive });
And then having to set up the properties like so.
const useStyles = makeStyles((theme) => ({
root: {
color: ({ isActive }) => isActive && "red,
position: ({ isActive }) => isActive && "fixed",
top: ({ genClaimsOpen, mileClaimsOpen }) => isActive && "20px",
},
}));
What i would like to do (i have done similar in styled components), is group logic so that it is a lot cleaner to achieve more complex stylings)
Something like:
const useStyles = makeStyles((theme) => ({
root: {
({ isActive }) => isActive && (
color: "red,
position: "fixed",
top: "20px"
)
},
}));
I didnt find an answer, but I did a workaround using clsx package that allows me to do the logic in the className prop, and target specific classes depending on outcome.
https://www.npmjs.com/package/clsx

Styled components + Storybook: SVG Icon is not re-rendering when I pass new styles

I am trying to create a SvgIcon component that I pass an SVG to through the props.
Because of the way React handles SVGs, when they're imported as ReactComponents (e.g. import { ReactComponent as ArrowIcon } from "icons/arrow.svg") I have to define my component in a dynamic way.
This is what I have so far:
const styleSvgIcon = ({ theme, stroke, fill, size, icon: Icon }) => styled(
Icon
).attrs({
viewBox: `0 0 24 24`,
})`
path {
${stroke && `stroke: ${calculateColor({ color: stroke, theme })};`}
${fill && `fill: ${calculateColor({ color: fill, theme })};`}
}
height: ${calculateSize(size)};
width: ${calculateSize(size)};
`;
const SvgIcon = ({ stroke, fill, size, icon }) => {
const theme = useTheme();
const StyledIcon = styleSvgIcon({ theme, stroke, fill, size, icon });
console.log('styledddddddddd', StyledIcon); // prints the styled component with the new styles, but on the page nothing changes
return <StyledIcon />;
};
SvgIcon.propTypes = {
stroke: PropTypes.oneOf(Object.values(SVG_ICON_COLORS)),
fill: PropTypes.oneOf(Object.values(SVG_ICON_COLORS)),
size: PropTypes.oneOf(Object.values(SVG_ICON_SIZES)),
icon: PropTypes.elementType.isRequired,
};
export default SvgIcon;
Here's my story definition:
import React from 'react';
import SvgIcon from './SvgIcon';
import * as all_icons from '../icons';
import { SVG_ICON_SIZES, SVG_ICON_COLORS } from '../constants/variants';
export default {
title: 'media/SvgIcon',
component: SvgIcon,
argTypes: {
size: {
type: 'select',
options: Object.values(SVG_ICON_SIZES),
defaultValue: SVG_ICON_SIZES.SMALL,
},
stroke: {
type: 'select',
options: Object.values(SVG_ICON_COLORS),
defaultValue: SVG_ICON_COLORS.PRIMARY,
},
fill: {
type: 'select',
options: Object.values(SVG_ICON_COLORS),
defaultValue: SVG_ICON_COLORS.PRIMARY,
},
},
};
const Template = (args) => {
const icons = Object.values(all_icons);
// return icons.map((SvgComponent, i) => (
return icons
.slice(0, 2)
.map((SvgComponent, i) => (
<SvgIcon key={i} {...args} icon={SvgComponent} />
));
};
export const Small = Template.bind({});
Small.args = {
size: SVG_ICON_SIZES.SMALL,
};
export const Medium = Template.bind({});
Medium.args = {
size: SVG_ICON_SIZES.MEDIUM,
};
export const Large = Template.bind({});
Large.args = {
size: SVG_ICON_SIZES.LARGE,
};
export const XL = Template.bind({});
XL.args = {
size: SVG_ICON_SIZES.XL,
};
This works fine locally, but when I deploy my app and try to change the props through Storybook, nothing gets updated.
However, in production, the controls do nothing.
I FIGURED IT OUT!!!
So because I was just setting the styles without using the props like this:
size: ${calculate(size)};
styled-components somehow knows and therefore doesn't add listeners to updated props. So my StyledIcon just becomes a static component that does not update when new styles are passed in since they are just set in stone.
Instead, passing them as props and accessing them through props adds those listeners
const SvgIcon = ({ stroke, fill, size, icon: Icon }) => {
const StyledIcon = styled(Icon).attrs({
viewBox: `0 0 24 24`,
})`
path {
stroke: ${({ stroke, theme }) =>
calculateColor({ color: stroke, theme })};
fill: ${({ fill, theme }) => calculateColor({ color: fill, theme })};
}
height: ${({ size }) => calculateSize(size)};
width: ${({ size }) => calculateSize(size)};
`;
return (
<div>
<StyledIcon size={size} fill={fill} stroke={stroke} />,{size},{fill},
{stroke}
<StyledArrowUpIcon stroke={stroke} size={size} fill={fill} />
</div>
);
};

How to style TabNavigator's Tabs?

I have such an ugly looking default Tabs for TabNavigator. How can I add styles on it like Instagram?
I want to set the Tabs Navigator's background as white (not grey) and set the border's top with line. Plus, I want to set the active icon color as black. (JUST LIKE THE INSTAGRAM..!)
I'm not sure where I can put these styles on my TabNavigator.
export default TabNavigator(
{
Feed: {
screen: FeedStackNavigator,
},
...
},
{
navigationOptions: ({ navigation }) => ({
header: null,
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
let iconName;
switch (routeName) {
case 'Feed':
iconName = Platform.OS === 'ios'
? `ios-information-circle${focused ? '' : '-outline'}`
: 'md-list-box';
break;
}
Thanks! :)
react-navigation has lots of different properties for styling TabNavigator. You can use them to style your icons and TabBar itself.
Example
tabBarOptions: {
activeTintColor: '#e91e63',
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'blue',
},
}

Resources