Reputation: 9205
I have a Spinner component that's basically a loading icon. I'm trying to pass props to the JSS styles so that it can be customized. But the animations don't seem to work if I pass props to the keyframes.
Below is the component. When I use the animation $spinnertest
it works fine. If I use $spinners
, it doesn't load the animation (when inspecting the elements, animation-name
doesn't even show up in the class, leading me to believe it doesn't get generated. ).
**Example CodeSandBox of issue (just change animation to spinners
): https://codesandbox.io/s/exciting-shirley-pqt1o?fontsize=14&hidenavigation=1&theme=dark
const useStyles = makeStyles(theme => ({
root: props => ({
width: props.size,
height: props.size,
position: 'relative',
contain: 'paint',
display: 'inline-block',
}),
spinner: props => ({
width: props.size*0.3125,
height: props.size*0.3125,
background: props.color,
position: 'absolute',
animationDuration: props.duration,
animationIterationCount: 'infinite',
animationTimingFunction: 'ease-in-out',
}),
spinnerAnimation: {
animationName: '$spinners',
},
square2: props => ({
animationDelay: -props.duration/2,
}),
'@keyframes spinnertest': {
'25%': {
transform: 'translateX(22px) rotate(-90deg) scale(.5)',
},
'50%': {
transform: 'translateX(22px) translateY(22px) rotate(-180deg)',
},
'75%': {
transform: 'translateX(0) translateY(22px) rotate(-270deg) scale(.5)',
},
'to': {
transform: 'rotate(-1turn)',
},
},
'@keyframes spinners': props => ({
'25%': {
transform: `translateX(${props.translate}px) rotate(-90deg) scale(.5)`,
},
'50%': {
transform: `translateX(${props.translate}px) translateY(${props.translate}px) rotate(-180deg)`,
},
'75%': {
transform: `translateX(0) translateY(${props.translate}px) rotate(-270deg) scale(.5)`,
},
'to': {
transform: `rotate(-1turn)`,
},
}),
}));
export default function Spinner(props) {
const {duration, size, color} = props;
const classes = useStyles({
duration: duration,
size: size,
color: color,
translate: size*(1-0.3125),
});
return (
<Box className={classes.root}>
<Box className={clsx(classes.spinner, classes.spinnerAnimation)} />
<Box className={clsx(classes.spinner, classes.square2, classes.spinnerAnimation)} />
</Box>
)
}
Spinner.defaultProps = {
duration: 1800,
size: 32,
color: #fff,
}
Upvotes: 2
Views: 1001
Reputation: 2341
It sounds that MUI has a bug around props in makeStyles @keyframes
#16673
as Olivier Tassinari stated, this bug will be fixed in v5 where MUI gonna use a new styling solution styled-components
RCF #22342.
The problem is even more general:
The arrow functions (with or without props) do not work within makeStyles
#21011
Passing the props to rules in your defined keyframes will fix it (after v5 has been available, hopefully)
"@keyframes spinners": {
"25%": {
transform: (props) =>
// console.log(props) and template generation will be created correctly.
`translateX(${props.translate}px) rotate(-90deg) scale(.5)`
},
// ...
}
Until then you can use higher-order useStyle creator for embedding your keyframes, as @buzatto suggested.
Or define your animation presets in your theme object and uses them globally around your project.
const theme = createMuiTheme({
animation: {
presets: {
duration: 180,
// or even function
rotateDeg: (angle) => `{angle}deg`
//...
}
}
});
// usage
const useStyles = makeStyles(theme => ({
"@keyframes spinners": {
"25%": {
transform: `translateX(${
theme.animation.presets.duration * 10
}px) rotate(${theme.animation.presets.rotateDeg(-90)}) scale(.5)`,
},
},
}
Upvotes: 1
Reputation: 10382
I have a turnaround solution, which works (not that pretty). You would turn your withStyles
into a currying function, that takes keyframesProps
, and at your key frame definition you would use an IIFE that returns the object with its properties:
const useStyles = keyframesProps => makeStyles((theme) => ({
... all other styles,
// you need to call an IIFE because keyframes doesn't receive a function
"@keyframes spinners": ((props) => ({
"25%": {
transform: `translateX(${props.translate}px) rotate(-90deg) scale(.5)`
},
"50%": {
transform: `translateX(${props.translate}px) translateY(${props.translate}px) rotate(-180deg)`
},
"75%": {
transform: `translateX(0) translateY(${props.translate}px) rotate(-270deg) scale(.5)`
},
to: {
transform: `rotate(-1turn)`
}
}))(keyframesProps)
}));
at your component you would define your classes
like:
const styleProps = {
duration: duration,
size: size,
color: color
}
const framesProps = {
translate: size * (1 - 0.3125)
}
const classes = useStyles(framesProps)(styleProps);
Upvotes: 2