typestyle
typestyle copied to clipboard
Using typestyle-generated classes in $nest selectors
Hi everyone! First off, I'd like to say that I've been using TypeStyle in a few libraries and apps (in production!) and I think it is fantastic. Please, keep up the good work 👍
That being said, naturally, I do have a question / suggestion about the ability to use top-level generated TypeStyle classNames in $nest
selectors. Sometimes, due to library updates or integration issues, relying on a component to always generate the same nested HTML is spotty (though, in an ideal world, this would not be the case). As such, I've created a simple TypeStyle Extensions library which allows an engineer to use their top-level classnames in a manner similar to jss
: https://github.com/benduran/typestyle-extensions
The idea behind this library was to have a single function call that would cover ~90% of all CSS-in-JS styling solutions an engineer would need for common paradigms. Here's the example demonstrated in the typestyle-extensions
readme:
import { createStyles } from 'typestyle-extensions';
const styles = createStyles({
icon: {
fontSize: '1em',
height: '1em',
width: '1em',
},
myButton: {
$nest: {
'&:hover': {
$nest: {
'& > $icon': { // Use the generated classname for "icon" here in a nested selector
color: 'pink',
},
},
backgroundColor: 'blue',
color: 'white',
},
},
backgroundColor: 'transparent',
border: '1px solid blue',
color: 'blue',
},
});
// Your React component
const MyComponent = () => (
<button className={styles.myButton}>
<svg className={styles.icon}>{ /*...*/ }</svg>
</button>
);
export default MyComponent;
I'd love to get your feedback on this idea and whether or not the core TypeStyle library could benefit from having such things included in it, or if it would be better off keeping this as a separate extensions library. Thanks!
Thanks for the kind words! :rose: :heart: 💯
I don't like the type unsafety of $icon
. My current solution consists of known classes
. Here is an example from our internal library, that we are sadly unable to open source as a whole 😢
// styles.ts
export namespace KnownClasses {
// some styling class names
export const onErrorGoRed = 'ap-on-error-go-red';
export const inTooltipBeWhite = 'ap-in-tooltip-be-white';
// some action class names
export const onErrorFocusHere = 'ap-error-focus-here';
export const onSectionEnterFocusHere = 'ap-section-enter-focus-here';
}
// Something that applies styles to its children
export const errorClass = typestyle.style({
color: Colors.errorColor,
$nest: {
['& .' + KnownClasses.onErrorGoRed]: {
color: Colors.errorColor
}
}
});
// Something that listens to changes requested by parent e.g. paragraphs
export const pClass = typestyle.style(
wrapStyle,
{
color: Colors.normalColor,
fontFamily: FontFamilies.normal,
fontSize: FontSizes.paragraph,
lineHeight: FontSizes.paragraphLineHeight,
margin: '0px',
}
) + ' ' + KnownClasses.onErrorGoRed;
Thanks for sharing. Your proposal feels similar in some ways, but obviously differs a little on that it requires managing the class names manually in an app integrated with TypeStyle.
With regards to your comment on using the $icon
syntax for marking that a parent class selector should be used, would you have any recommendations to improve upon this?
We have been dealing with the same challenge, and made an enriched variant of stylesheet()
that can make $nest
selectors refer to other classes in a typesafe manner.
I've created a gist to demonstrate the idea here: https://gist.github.com/mntnoe/7c26f39e44223e3741ae4307a9d52b8b
Any feedback is greatly appreciated.
I think perhaps something like this might be workable:
const styles = stylesheet({
card: {},
button: (parent) => ({
color: 'red',
parent.card({
'&:hover' {
color: 'blue'
}
})
}),
});
The parameter for each function could have a function for each top level class that is in the stylesheet that would act as a parent selector. With the output effectively being something like this (with automatic $debugName as is typical)
.card {}
.button {
color: red;
}
.card .button:hover {
color: blue;
}
I think this would be backward compatible, but might require rethinking the order in which the stylesheet is evaluated. If we assume all top level classes should be unique, it might be a lot simpler.
I did some prototyping in TypeStyle and found something that could work.
See prototype test here with usage: https://github.com/typestyle/typestyle/blob/prototype-nested/src/tests/basic.tsx#L142
See prototype implementation here: https://github.com/typestyle/typestyle/blob/prototype-nested/src/internal/typestyle.ts#L210
There is certainly some API niceness to work out, but this feature seems possible to add without adding too much more code. It would change stylesheet to not deduplicate styles though.