Comments (6)
Hey, there is no plans to do this currently or near future. It's our intentional decision. Let me explain it a bit.
makeStyles({
root: { fontColor: "red" }
});
// => .hash { font-color: red }
- Result there is stable
- Does not depend on user's input
- Can be safely executed in any environment (browsers, servers, Node)
// ⚠️ not real code
makeStyles(color => {
fontColor: color;
});
// => .??hash?? { font-color: ??? }
- Result there is not stable and may vary based on users input
- Option 1: precompute all input combinations (no go)
- Option 2: use CSS variables:
color => { fontColor: color; }; // => .hash-var { font-color: var(--hash) }
- The open question is how to apply that CSS variable then 💥
Another issue with dynamic params that nothing prevents following:
// ⚠️ not real code, not something that we want to support
const useClasses = makeStyles(isFoo => ({
color: "red",
...(isFoo & { color: "blue" })
}));
In this case static evaluation will be impossible at all.
Our current solution for these cases is to use inline styles or combination with CSS variables:
function App(props) {
return <div style={{ color: props.color }} />;
}
const useClasses = makeStyles({
root: { color: 'var(--color)',
})
function App(props) {
const classes = useClasses()
return <div className={classes.root} style={{ '--color': props.color }} />
}
P.S. We can reconsider this later based on consumers feedback, but currently we don't have enough data to turn it into usable API.
from griffel.
@layershifter I do not think that this is a solution that is maintainable in the long run. I tested this on a small scale project and it was wonky at best. On one hand, it requires a lot of additional work from the user which can be faulty and can lead to mixing style with logic. On the other hand it is not possible to typecheck which makes early detection of mistakes during development even harder.
If I could choose an API, it would probably look something like this:
const useClasses = makeStyles((props) => {
root: { color: props.color }
}, { color: "#aabbcc" }) // type of props is the same as the second parameter
function App(props) {
const classes = useClasses({}, { color: "red" }) // same second argument types as props
return <div className={classes.root} />
}
Then the makeStyles function injects some hashes into the parameters and the useClasses function handles provision of the variables via those hashes. This effectively reduces the amount of work needed to be done for an update while still allowing for changing props to influence the style. However, the work for the creation and injection of the hashes could be a bit more involved, since it would be useful to be able to pass deep objects. But since this work can be done on load it might not be as bad.
There is also the possibility to encourage the current API whilst providing an additional API like the one mentioned for the cases where it is needed.
from griffel.
Then the makeStyles function injects some hashes into the parameters and the useClasses function handles provision of the variables via those hashes. This effectively reduces the amount of work needed to be done for an update while still allowing for changing props to influence the style. However, the work for the creation and injection of the hashes could be a bit more involved, since it would be useful to be able to pass deep objects. But since this work can be done on load it might not be as bad.
There is also the possibility to encourage the current API whilst providing an additional API like the one mentioned for the cases where it is needed.
There are two problems with that, read below.
CSS variables generation
To support SSR and build time optimisations we need a deterministic way to generate CSS variables in Browser & Node environments to avoid collisions:
const useClasses = makeStyles((props) => ({
root: { color: variables.color }
}))
- if it will be just
--color
i.e..rule { color: var(--color) }
it can unpredictably collide with other variables/scopes - it will be a random hash i.e.
(Math.random() + 1).toString(36).substring(7)
it will cause problems for SSR/build time processing as these hashes will be different from build to build - I was trying to prototype a solution around stack traces to get filename into hash, but there are no good results
To summarise: currently I don't know a predictable way to generate CSS variables that would scale.
API changes
Well, let's assume that we can generate CSS variables, but how they will be passed?
const useClasses = makeStyles((props) => ({
root: { color: variables.color }
}))
function Foo() {
// Where to pass variables?
const classes = useClasses({ color: 'foo' })
}
Something like that could work:
function Foo() {
// Where to pass variables?
const [classes, styles] = useClasses({ color: 'foo' })
return <div className={classes.root} style={styles} />
}
But I don't see this intuitive and scaling to other JS frameworks/libraries rather than React.
I prototyped a solution that should be typesafe: https://codesandbox.io/s/clever-sunset-5ju2bq?file=/src/App.tsx
But until CSS variables generation will be solved I don't think that it something that could go to the core.
from griffel.
Looking at the simpler Problem first, does anything speak against injecting in into a style bucket sheet with sheet.insertRule(":root{--<hash>: <value>}");
then obtaining a reference to that style rule and modifying the rule.style.cssText
on prop change? Then you would not need to pass any styles around by hand.
It seems to me that the hash could be generated from the encoded style object by injecting placeholder into the variables. However, in corner cases this would create collisions.
from griffel.
Looking at the simpler Problem first, does anything speak against injecting in into a style bucket sheet with
sheet.insertRule(":root{--<hash>: <value>}");
then obtaining a reference to that style rule and modifying therule.style.cssText
on prop change? Then you would not need to pass any styles around by hand.
Well, if it's global then it brings few more interesting questions:
-
how to do CSS extraction later (it's impossible, this feature is only runtime thing)
-
I still should be able to do:
function Foo() { const classes1 = useClasses({ color: 'red' }) const classes2 = useClasses({ color: 'blue }) return ( <> <div className={classes1.root} /> <div className={classes2.root} /> </> ) }
Then it's really questionable what will "hash" in this case 🤯
👆 It's also show that this API does not scale well as I may have 10 divs. Do I need to call
useClasses()
for each of them?
from griffel.
sorry for coming back to you so late. Corona got me.
Now assuming there is a good solution for creating a hash one could create a helper class with each call of useClasses that is passed around with the classes. This helper class then gets all the variables for the instance of useClasses.
function Foo() {
const classes1 = useClasses({ color: 'red' }) // produces something like { root: ["abc123", "h3lp3r"], helpers: ["h3lp3r"] }
const classes2 = useClasses({ color: 'blue }) // produces something like { root: ["abc123", "r3pl3h"], helpers: ["r3pl3h"] }
return (
<>
<div className={classes1.root} />
<div className={classes2.root} />
</>
)
}
where the previous still holds true that the helper classes get updated when the props object is updated. However this looks like it would make the problem of finding hashes even worse.
from griffel.
Related Issues (20)
- core: shorthands.gridArea() does not expand custom idents properly HOT 7
- core: Support object literal with multiline keys HOT 2
- Can we cache the `makeStyles` internal HOT 2
- Failed to override styles when selectors are grouped
- lint: add lint rule which warn unused makeStyles classes HOT 2
- vite: add support for CSS extraction
- core: add support for fallback properties in `makeStaticStyles` HOT 3
- lint: forbid comma separated selectors in selectors HOT 1
- `shorthands.flex(1)` should produce `flex: 1 1 0%` instead of `flex: 1 1 0px` HOT 3
- Vite plugin: TypeError: griffel is not a function HOT 5
- eslint-plugin: Is not compatible with eslint 8.x HOT 2
- eslint-plugin: add no-unnecesary-shorthands rule HOT 1
- `csstype` bump to 3.1.3 causing BREAKING CHANGEs on type-level
- babel-preset: transforms don't work with native ESM packages that use `.mjs` HOT 2
- babel-preset: transforms dont work with `swc` commonjs output HOT 1
- makeResetStyles should not override makeStyles HOT 2
- core: add support for CSS shorthands
- docs: add mergeClasses() to playground
- babel-preset: huge perf slowdown on first babel transform invoction
- core: `makeStaticStyles` to support @at-rules HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from griffel.