I find myself writing a few generic components in material ui, where the styling is actually defined in a parent or grandparent component. For example:
const GenericDescendant = (props: DescendantProps) => {
const { classesFromAncestor, ...other } = props
return <Button className={classesFromAncestor} {...props}>Text here</Button>
}
Where from the Ancestor, I create a useStyles and classes object and pass it down:
const useDescendantStyles = makeStyles({
selector: {
border: '1px solid green',
// more customized styles
}
})
const Ancestor = () => {
const descendantClasses = useDescendantStyles()
return <GenericDescendant classesFromAncestor={descendantClasses} />
}
Or another way, I can use withStyles to wrap a component used in the descendant:
const GenericDescendant = (props: DescendantProps) => {
const { tooltipClassesFromAncestor, buttonClassesFromAncestor, ...other } = props
const CustmoizedTooltip = withStyles(tooltipClassesFromAncestor)(Tooltip);
const CustomButton = withStyles(buttonClassesFromAncestor)(Button)
return (
<CustmoizedTooltip>
<CustomButton>Text here</CustomButton>
</CustmoizedTooltip>
)
}
In this case, I wouldn't call useStyles in the Ancestor, I would just pass the object like this:
const Ancestor = () => {
return <GenericDescendant classesFromAncestor={{
selector: {
border: '1px solid green',
// more customized styles
}
}} />
}
I don't want to just wrap the whole GenericDescendant in a withStyles, because then I can't target which component is taking the custom styles being passed from the ancestor.
The cases are slightly different, but I can go either route to allow customization of a generic descendant from the ancestor. However, when passing the customized styles as a prop, I don't know how to properly type the classesFromAncestor prop in DescendantProps. It could really take any form, and that form won't be known until runtime. I don't want to type it as any. What's the best way to define the type of classes that are passed as a prop?