How to get Stripe Elements to dynamically change styles with Next-themes - css

I am using stripe elements and dynamically changing the input styles depending on the theme. It works, but my only problem is if I change the theme whilst being on the page containing the stripe elements input I have to hard refresh the page in order to see the CSS changes.
What I am trying to achieve is to get the styles to change when the theme changes. Please note, I am trying to change the backgroundColor.
Here's what I currently have:
import { useTheme } from "next-themes";
const { resolvedTheme, setTheme } = useTheme();
const CARD_OPTIONS = {
iconStyle: "solid",
style: {
base: {
backgroundColor: `${resolvedTheme === "dark" ? "black" : "white"}`,
iconColor: "#6D28D9",
color: `${resolvedTheme === "dark" ? "white" : "#9CA3AF"}`,
fontWeight: "500",
fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
fontSize: "16px",
fontSmoothing: "antialiased",
":-webkit-autofill": {
color: "#fce883",
},
"::placeholder": {
color: "#D1D5DB",
},
},
invalid: {
iconColor: "#ef2961",
color: "#ef2961",
},
},
};
<CardElement options={CARD_OPTIONS} />
Another option I have tried is using mount and then passing DARK_CARD_OPTIONS to the Card Element.
Like so:
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
const DARK_CARD_OPTIONS = {
iconStyle: "solid",
style: {
base: {
backgroundColor: "red",
iconColor: "#6D28D9",
color: "white,
fontWeight: "500",
fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
fontSize: "16px",
fontSmoothing: "antialiased",
":-webkit-autofill": {
color: "#fce883",
},
"::placeholder": {
color: "#D1D5DB",
},
},
invalid: {
iconColor: "#ef2961",
color: "#ef2961",
},
},
};
{mounted && (
<div className="p-4 rounded-lg border border-gray-800 dark:border-gray-600 focus:border-purple-700">
{resolvedTheme === "dark" ? (
<CardElement options={DARK_CARD_OPTIONS} />
) : (
<CardElement options={CARD_OPTIONS} />
)}
</div>
)}
For some reason this only makes some areas of the CardElements input change dynamically.
Please see screenshot below (please note I've used red to make it stand out):

You have to forcefully re-mounting the CardElement when the theme changes to get it to work:
<CardElement key={resolvedTheme} options={CARD_OPTIONS} />

Related

How to override nested child component styling in MaterialUI v5?

I have a ToggleButton component that has custom styling. I want to make that Toggle Button component look differently only when it's used as a child (inside) a ToggleButtonGroup. Here is how I'd call the ToggleButtonGroup component:
<ToggleButtonGroup onChange={()=>{}} ariaLabel='platform'>
<ToggleButton label='Japan' value='1' selected={true}/>
<ToggleButton label='China' value='2' selected={false}/>
<ToggleButton label='Brazil' value='3' selected={false}/>
</ToggleButtonGroup>
Here is the code for my ToggleButtonGroup component:
const StyledToggleGroup = styled(ToggleOptionsGroup)(
({ theme: { palette, spacing } }) => ({
height: spacing(10),
borderRadius: '6px',
boxShadow: 'none',
'&:hover': {
boxShadow: 'none',
},
'&.MuiToggleButtonGroup-root':{
gap: '0px'
},
'&.MuiToggleButton-standard':{
backgroundColor:'red',
},
'&.MuiToggleButtonGroup-grouped.Mui-selected': {
backgroundColor:'green',
}
})
);
const ToggleButtonGroup:React.FC<ToggleButtonGroupProps> = ({children, onChange, ariaLabel}) =>{
return(
<StyledToggleGroup
exclusive
onChange={onChange}
aria-label={ariaLabel}>
{children}
</StyledToggleGroup>
)
}
However, the last two classes:
'&.MuiToggleButton-standard':{
backgroundColor:'red',
},
'&.MuiToggleButtonGroup-grouped.Mui-selected': {
backgroundColor:'green',
}
don't really change anything.
How can I change the styling of my ToggleButton component only when it's passed as a child to the ToggleButtonGroup component?
It seems that class names are correct according to MUI document, the posted code should just need to specify these as children of StyledToggleGroup with a descendant combinator after & for the styles to work:
Tested in a simple demo here: stackblitz
"& .MuiToggleButton-standard": {
backgroundColor: "hotpink",
},
"& .MuiToggleButtonGroup-grouped.Mui-selected": {
backgroundColor: "lightblue",
},

MUI KeyboardDatePicker change styles of date input box

Currently, I am trying to modify KeyboardDatePicker board color, size, font, padding, but unfortunately, all approaches don’t work. I tried so far:
1 . useStyles :
const useStyles = (params: any) =>
makeStyles(() =>
createStyles({
componentStyle: {
width: params.width ? params.width : 'auto',
color: params.color ? params.color : 'inherit',
verticalAlign: 'middle',
fontSize: '12px',
border: 'solid 2px #0070D8',
},
})
);
Doesn’t override and a border appears on current KeyboardDatePicker border, size doesn’t change as well.
2 . Theme provide, it overrides calendar theme, but not KeyboardDatePicker date box.
<ThemeProvider theme={theme}>
3 . Add styles into KeyboardDatePicker, it is the only working approach
style={{width:"246px",height:"44px"}}
How would you suggest modifying styles of KeyboardDatePicker, and yes style={} approach it's not the correct way to changes styles. p.s I am using Material-UI 4
My KeyboardDatesPicker:
<KeyboardDatePicker
format="MM/dd/yyyy"
margin="normal"
id="date-picker-inline"
defaultValue={props.value}
value={selectedDate}
required={props.required}
showTodayButton={true}
disableToolbar
inputVariant="outlined"
variant="inline"
onChange={(selectedDate) => setSelectedDate(selectedDate)}
KeyboardButtonProps={{
"aria-label": "change date",
}}
keyboardIcon={<Icon icon={ICONS.Cool_icon} />}
className={classes.componentStyle} // do not overide , but puts on top
/>
makeStyles is a hook factory that returns a style hook (usually called useStyles), this is how it's used:
const useStyles = makeStyles(...);
In your code, you define useStyles as a function that return makeStyles instead of telling makeStyles to create a new hook which doesn't make sense here, so change your code to the above. I also fixed the styles for you. The text color styles should be placed in InputBase component:
const useStyles = makeStyles(() =>
createStyles({
componentStyle: {
verticalAlign: "middle",
fontSize: "12px",
width: (params) => (params.width ? params.width : "auto"),
"& fieldset": {
border: "solid 2px #0070D8"
},
"& .MuiInputBase-root": {
height: (params) => (params.height ? params.height : "auto"),
color: (params) => (params.color ? params.color : "inherit")
}
}
})
);
const classes = useStyles({
color: "red",
width: 400,
height: 80,
});
<KeyboardDatePicker
onChange={() => {}}
inputVariant="outlined"
InputProps={{
className: classes.componentStyle
}}
/>
If you want to style via createMuiTheme, here is the equivalent code. Note that you can't pass the component props to create dynamic styles unlike the useStyles approach above:
const theme = createMuiTheme({
overrides: {
MuiTextField: {
root: {
verticalAlign: "middle",
fontSize: "12px",
width: 150,
"& fieldset": {
border: "solid 2px #0070D8"
}
}
}
}
});
And it should work again. For reference, see this section to know how you can use makeStyles with component props.
It seems you don't need to write a custom hook like this useStyles = (params: any) => ..., the hook returned by makeStyles already accepts a props param.
When styling MUI components you need to check the API for each component to define the object you pass to makeStyles, in this case, the date picker component is a group of other MUI components, if you go to the API you'll see different props to pass to each individual component. To style the input you pass the classes returned by the useStyle hook in InputProps, with root rule as it is in the Input API, apply other rules if you need more specific styles.
const useInputStyles = makeStyles({
root: {
width: (props) => (props.width ? props.width : "auto"),
color: (props) => (props.color ? props.color : "inherit"),
verticalAlign: "middle",
fontSize: "12px",
border: "solid 2px #0070D8"
}
});
...
const inputClasses = useInputStyles()
...
<KeyboardDatePicker
...
InputProps={{ classes: inputClasses }}
/>
and to style the "board", not sure if you mean the popover, since you use the inline variant, you pass the styles in the PopoverProps, defining the styles in the paper rule as described in the Popover API
const usePopoverStyles = makeStyles({
paper: {
backgroundColor: "green"
}
});
...
const popoverClasses = usePopoverStyles();
...
<KeyboardDatePicker
...
PopoverProps={{ classes: popoverClasses }}
/>
you can see it working here https://codesandbox.io/s/mui-keyboarddatepicker-styles-sueqd?file=/src/App.tsx
I have implemented it like this in TS, not a finished component, but I hope that this assists people. I am about to add MuiFormLabel-root etc to add more specific styling to the label.
const useDatePickerStyles = makeStyles<ITheme, ITextFieldStyleProps>((theme) =>
createStyles({
datePickerContainer: ({ isValid, isError }) => ({
border: 'solid',
borderRadius: 4,
borderWidth: theme.mvf.border.width.thin,
borderColor: theme.mvf.palette.border,
...(!isError && {
'&:hover': {
boxShadow: theme.mvf.boxShadow.primary,
borderColor: theme.mvf.palette.primary.main,
},
...(isValid && {
color: theme.mvf.palette.primary.main,
boxShadow: theme.mvf.boxShadow.primary,
borderColor: theme.mvf.palette.primary.main,
}),
}),
...(isError && {
color: theme.mvf.palette.error,
boxShadow: theme.mvf.boxShadow.error,
borderColor: theme.mvf.palette.error,
}),
}),
datePicker: () => ({
margin: theme.mvf.spacing.small,
}),
}),
);
export default useDatePickerStyles;
And get access to classes like so
const DatePicker: DatePickerType = ({
id,
onChange,
format,
value,
label,
errorMessage,
placeholder,
isVerticallyCentered,
...props
}: IDatePickerProps) => {
const isValid = !errorMessage && !!value;
const classes = useDatePickerStyles({
isError: !!errorMessage,
isVerticallyCentered,
isValid,
});
return (
<div className={classes.datePickerContainer}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
id={id}
fullWidth
maxDateMessage={''}
minDateMessage={''}
invalidDateMessage={''}
className={classes.datePicker}
label={isVerticallyCentered ? undefined : label} // don't show as label will be outside
placeholder={placeholder}
format={format} // of the displayed date
emptyLabel={placeholder} // displayed value if empty
name="datePicker"
InputLabelProps={{
className: classes.inputLabel,
}}
margin="normal"
value={value}
onChange={onChange}
InputProps={{
className: classes.inputPropsClasses,
inputProps: { className: classes.textInput },
disableUnderline: true,
}}
inputVariant="standard"
KeyboardButtonProps={{
className: classes.calendarButton,
}}
{...props}
/>
</MuiPickersUtilsProvider>
</div>
);
};

Customize colors of withAuthenticator HOC component

I am trying to customize the colors in withAuthenticator HOC aws-amplifier login screen.
I followed:
https://aws-amplify.github.io/docs/js/authentication#using-components-in-react
and also read:
https://medium.com/#coryschimmoeller/customizing-the-authentication-experience-of-amplifys-withauthenticator-e6f2089ff469
import { AmplifyTheme } from 'aws-amplify-react';
const myTheme = {
...AmplifyTheme,
BackgroundColor: { color: 'blue',backgroundColor: 'blue' },
button: { color: 'blue',backgroundColor: 'blue' },
amazonSignInButton: { color: 'blue',backgroundColor: 'blue' },
signInButton: { backgroundColor: 'blue' , color: 'blue'}
};
...
//export default App;
export default withAuthenticator(App, myTheme );
amplify still renders the AWS default look and feel. I doesn't make any difference what I put in myTheme, looks like as if it is ignored completely.
Thanks for any feedback in advance.
You need to adress the different elements like so:
import { AmplifyTheme } from "aws-amplify-react";
const authTheme = {
...AmplifyTheme,
sectionHeader:{
...AmplifyTheme.sectionHeader,
color:"red",
},
formSection: {
...AmplifyTheme.formSection,
backgroundColor: "green",
},
sectionFooter: {
...AmplifyTheme.sectionFooter,
backgroundColor: "purple"
},
button: {
...AmplifyTheme.button,
backgroundColor: "blue"
}
}
export default withAuthenticator(App, { theme: authTheme });
If you are not sure about the names of the different elements you can look them up in the developer console of your browser. It´s a bit tedious but i haven´t found a documentation so far
Taken from the documentation:
Web
const MyTheme = {
signInButtonIcon: { 'display': 'none' },
googleSignInButton: { 'backgroundColor': 'red', 'borderColor': 'red' }
}
<Authenticator theme={MyTheme} />
Web components reference
React Native
import { AmplifyTheme } from 'aws-amplify-react-native';
const MySectionHeader = Object.assign({}, AmplifyTheme.sectionHeader, { background: 'orange' });
const MyTheme = Object.assign({}, AmplifyTheme, { sectionHeader: MySectionHeader });
<Authenticator theme={MyTheme} />
React Native components reference
Since the question is about withAuthenticator specifically, the previous examples apply to that too:
export default withAuthenticator(App, false, [], null, MyTheme);

How to change the text color of the selected row in material ui table

I am trying to change the color of the row text and the background color of row on selection.
I am able to change the background color successfully but I am not able to change the text color.
<TableRow
className={classes.tableBody}
>
tableBody: {
"&:focus": {
color: "yellow !important",
backgroundColor: "#3D85D2 !important",
},
},
The background color is controlled in TableRow. In order to get the correct specificity (you shouldn't ever need to leverage "!important" when overriding Material-UI styles), you need to leverage the "hover" class similar to what is done within TableRow.
The color is controlled in TableCell, so that is the level where you need to control it.
For a working solution, in the styles you would have something like:
const styles = theme => ({
tableRow: {
"&$hover:hover": {
backgroundColor: "blue"
}
},
tableCell: {
"$hover:hover &": {
color: "pink"
}
},
hover: {}
});
then in the rendering:
<TableRow
hover
key={row.id}
classes={{ hover: classes.hover }}
className={classes.tableRow}
>
<TableCell
className={classes.tableCell}
component="th"
scope="row"
>
{row.name}
</TableCell>
Here's a working version based on your sandbox:
Here's a similar example, but using "selected" instead of "hover":
https://codesandbox.io/s/llyqqwmr79
This uses the following styles:
const styles = theme => ({
tableRow: {
"&$selected, &$selected:hover": {
backgroundColor: "purple"
}
},
tableCell: {
"$selected &": {
color: "yellow"
}
},
selected: {}
});
and some state:
const [selectedID, setSelectedID] = useState(null);
and changing the TableRow rendering to be:
<TableRow
hover
key={row.id}
onClick={() => {
setSelectedID(row.id);
}}
selected={selectedID === row.id}
classes={{ selected: classes.selected }}
className={classes.tableRow}
>
v4 of Material-UI will include some changes that should make overriding styles considerably easier (and easier to figure out how to do successfully without looking at the source code).
In v4 of Material-UI, we can use the global class names for the selected state ("Mui-selected") and for TableCell ("MuiTableCell-root") and then we only need to apply a single class to TableRow:
const styles = (theme) => ({
tableRow: {
"&.Mui-selected, &.Mui-selected:hover": {
backgroundColor: "purple",
"& > .MuiTableCell-root": {
color: "yellow"
}
}
}
});
This is the only solution that worked for me
const styles = theme => ({
tableRow: {
'&&:hover': {
backgroundColor: '#0CB5F3',
},
},
});
<TableRow
hover
className={classes.tableRow}
>
const useStyles = makeStyles((theme) => ({
selected: {
backgroundColor: "green !important",
"&:hover": {
backgroundColor: "green !important",
},
},
}));
const classes = useStyles();
<TableRow selected classes={{selected: classes.selected,}}/>

Dynamically swap css in react

Im generating two css files from my sass files with defined color variables
Lets call them dark.css and light.css
Now what i want to do is dynamically swap these two css to change themes
So far I have something like this
...
componentDidUpdate() {
if (this.props.colorScheme === 'dark') {
require('../../../static/css/style-dark.css');
} else {
require('../../../static/css/style-light.css');
}
}
}
...
Above doesnt really work.Well it wroks ..partially
The problem is that theme is switched only once e.g default one is light then it can be changed to dark but after that no matter what i cant change it back to light
Had somebady similar problem? maybe this isnt a right way at all so any ideas are apprecited
I think you can do something like that...
Create a js styles file instead of css styles file.
example file1.js
export default = ({
backgroundColor: 'red',
color: 'blue',
paddingTop: 20,
paddingBottom: 20,
});
// file 1
//export default({ <-- replace this line in your file
const file1 = {
backgroundColor: 'red',
color: 'blue',
paddingTop: 20,
paddingBottom: 20,
};
// file 2
//export default({ <-- replace this line in your file
const file2 = {
backgroundColor: 'yellow',
color: 'black',
paddingTop: 40,
paddingBottom: 40,
};
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: 1,
styles: {...file1},
};
}
changeTheme = () => {
this.setState({
styles: this.state.theme === 1 ? {...file2} : {...file1},
theme: this.state.theme === 1 ? 2 : 1,
});
};
render() {
return (
<div style={this.state.styles}>
Hello
<button onClick={this.changeTheme}>
Change Theme
</button>
</div>
);
}
}
ReactDOM.render(
<Dashboard />,
document.querySelector('#app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Resources