Nested SVG
In our best practices article we discussed how nested components are generally best avoided. In fact, other samples (Value and ValueLabel) show how you can keep your components atomic, working around Styletron's inability to create descendant style selectors. (Which we consider a feature, not a bug.)
Well, here is a counter-example. The following component renders a small amount of SVG. It doesn't really make sense to extract each SVG element into its own component. Instead, we use the classify
function to manually run styles through the Styletron system. This allows us to keep multiple elements coordinated inside a single component.
The first version of the component does not allow the user to override the styles on the sub-elements (such as stroke color), which are hard-coded. That will be done in the second sample below.
import {Styled} from 'styletron-themer';
const wrapperStyle = {
width: '100px',
height: '100px'
};
class CircularMeter extends Component {
render() {
const
// prep some style objects for styletron. these are inserted into
// the DOM below
//
mainSvgStyles = {position: 'absolute'},
circle1Styles = {fill: 'none', stroke: 'red'}, // TODO: remove hard-coded color
circle2Styles = {fill: 'none', stroke: 'blue'};
return (
<Styled
themeName = 'CircularMeter'
staticStyle = {wrapperStyle}
>
{(className, props, {classify}) => {
const {componentProps, ...otherProps} = this.props,
return (
<div {...otherProps} className={className}>
{/* the SVG wrapper has its own classes */}
<svg className = {classify(mainSvgStyles)}>
{/* as do each of the circle objects */}
<circle className = {classify(circle1Styles)} />
<circle className = {classify(circle2Styles)} />
</svg>
</div>
);
}}
</Styled>
);
}
}
Overriding styles in sub-components
The following snippet extends the above sample. It allows the user to override styles on internal components. Here we remove the hard-coded stroke colors, moving them to the component meta.
Notice that we're loading componentTheme
from the third parameter to the render callback. This is documented in the API.
const wrapperStyle = {
width: '100px',
height: '100px',
// the end user can override these styles now
meta: {
strokeColors: {
outer: 'red',
inner: 'blue'
}
}
};
class CircularMeter extends Component {
render() {
return (
<Styled
themeName = 'CircularMeter'
staticStyle = {wrapperStyle}
>
{(className, props, {componentTheme, classify}) => {
const {componentProps, ...otherProps} = props;
// the render callback is given a third parameter, which
// includes the component theme. we peek into its meta to
// get the colors, which allows the user to override them
// in theme. (that's why we're not looking into the original
// "wrapperStyle" object, which does not include user
// overrides)
//
const {strokeColors} = componentTheme.meta,
mainSvgStyles = {position: 'absolute'},
circle1Styles = {fill: 'none', stroke: strokeColors.outer},
circle2Styles = {fill: 'none', stroke: strokeColors.outer};
return (
{/* ... same as above ... */}
);
}}
</Styled>
);
}
}