microsoft / griffel Goto Github PK
View Code? Open in Web Editor NEWCSS-in-JS with ahead-of-time compilation ⚡️
Home Page: https://griffel.js.org
License: MIT License
CSS-in-JS with ahead-of-time compilation ⚡️
Home Page: https://griffel.js.org
License: MIT License
yarn
webpack
dist/main.*.js
The problem is in module evaluation and missing special handling around it to keep imports in place.
RC for React 18 is already published:
NOTE: Make sure you read the section "When to Insert <style> on The Client". If you currently inject style rules "during render", it could make your library VERY slow in concurrent rendering.
reactwg/react-18#110
In short we should use useInsertionEffect
to apply our styles to DOM.
For reference:
changes in Emotion emotion-js/emotion#2600
issue with bundling emotion-js/emotion#2651
Types in React 18 does not allow children
by default in React.FC
, check components and update (#214)
DEFINITION_LOOKUP_TABLE
is a singleton used by mergeClasses()
to merge classes sequences deterministically. The problem comes when there are multiple versions of @griffel/core
that use different by reference DEFINITION_LOOKUP_TABLE
constants.
It's more or less the same problem that React has with .createContext()
calls (see facebook/react#13346).
Repro on Stackblitz: https://stackblitz.com/edit/node-zerdgf?file=index.js
#141 added a feature to allows media queries to be sorted. However, the default sort implementation is string comparison which breaks down for common breakpoint media queries that depend on insertion order like:
"@media (min-width: 488px)": {
width: "816px"
},
"@media (min-width: 1024px)": {
width: "816px"
},
"@media (min-width: 1366px)": {
width: "1164px"
},
"@media (min-width: 1920px)": {
width: "1564px"
}
Because the default sort function is a string comparison these media queries are inserted in the following order:
Which leads to incorrect behavior based on the order in which the styles was authored.
This can be worked around by using a min-max range in the media queries but I think a better approach is for the default sort implementation to respect the order in which the media queries are authored.
Example workaround:
"@media (min-width: 488px) and (max-width: 1024px)": {
width: "816px"
},
"@media (min-width: 1024px) and (max-width: 1366px)": {
width: "816px"
},
"@media (min-width: 1366px) and (max-width: 1920px)": {
width: "1164px"
},
"@media (min-width: 1920px)": {
width: "1564px"
}
I've made a Codesandbox to demonstrate this behavior: https://codesandbox.io/s/griffel-media-query-sort-order-gkt1n9
As far as I understand the react bindings expose the makeStyle function from core in a way that does will cause reevaluation of the resolveStyleRulesForSlots function on rerender. This does not seem sensible to me as it could be evaluated earlier as it does not depend on anything from inside the function and seems to be somewhat expensive.
Hi team, how to set the nonce for CSPpolicy with griffel?
Expect a global window configuration and an API configuration.
Reference to the mergeStyles https://github.com/microsoft/fluentui/blob/master/packages/merge-styles/README.md#working-with-content-security-policy-csp
Thanks for making a very good library.
I tried using "@griffel/webpack-extraction-plugin" in "Nextjs".
almost everything works perfectly, but "makeStyles" using "shorthands" is not bundled in css
getElementReference()
function does not handle comments, this causes errors and failing builds:
HookWebpackError: getElementReference(): An unhandled case, please report if it happens and provide debug information about an element:
ERR! {
ERR! "value": "/*!***************************************************************************************************************************************************************************************************************************!*\\\n !*** css ../../node_modules/css-loader/dist/cjs.js!../../node_modules/@griffel/webpack-extraction-plugin/virtual-loader/index.js!../../node_modules/@griffel/webpack-extraction-plugin/virtual-loader/griffel.css?style= ***!\n \\***************************************************************************************************************************************************************************************************************************/",
ERR! "type": "comm",
ERR! "props": "/",
ERR! "children": "!***************************************************************************************************************************************************************************************************************************!*\\\n !*** css ../../node_modules/css-loader/dist/cjs.js!../../node_modules/@griffel/webpack-extraction-plugin/virtual-loader/index.js!../../node_modules/@griffel/webpack-extraction-plugin/virtual-loader/griffel.css?style= ***!\n \\**************************************************************************************************************************************************************************************************************************",
ERR! "line": 3,
ERR! "column": 224,
ERR! "length": 0,
ERR! "return": ""
ERR! }
Webpack generates a concatenated source for griffel
asset (as we use the same griffel.css
file):
When Webpack emits assets it can add a comment to source if output.pathinfo
is enabled. Instances of RawSource
there are comments:
@griffel/react with version 1.0.0 has a dependency on @griffel/core with version 1.0.7
But @griffel/react with version 1.0.3 has a dependency on @griffel/core with version 1.2.0 which caused issues with using mergeClasses().
The console gave the following error:
mergeClasses(): a passed string contains an identifier (___1pqbv0t) that does not match any entry in cache.
Please make sure that minor bumps in versioning, do not create this level of breaking change.
I have fixed the issue currently by using "@griffel/core": "1.0.7"
and "@griffel/react": "1.0.0"
.
We got a report that builds on Windows are failing:
Generated code for node_modules\css-loader\dist\cjs.js!node_modules\@griffel\webpack-extraction-plugin\virtual-loader\index.js!node_modules\@griffel\webpack-extraction-plugin\virtual-loader\griffel.css?style=.fe317vm%7Bcursor%3Aurl(..%5C..%5C..%5C..%5Cpackages%5Capp-ux%5Clib%5Cimages%5Craw%5CCursor.svg)%2Cauto%3B%7D
1 | throw new Error("Module build failed (from ../../node_modules/css-loader/dist/cjs.js):\nError: Can't resolve '........packagesapp-uxlibimagesraw\fursor.svg'
Hi! Great project!
I'm trying to understand how this project differs from existing solutions, like https://github.com/callstack/linaria for example?
If a browser doesn’t recognize a property or its corresponding value, the browser will ignore the property altogether. When this happens, the browser uses (or falls back) to the previous value it finds.
This is the easiest way to provide a fallback. Here’s an example:
.layout { display: block; display: grid; }In this example, browsers that support CSS Grid will use
display: grid
. Browser doesn’t support CSS Grid will fall back todisplay: block
.
https://zellwk.com/blog/older-browsers-css/
As we use objects to declare styles we can't simply do:
// ⚠️ this is not real code, this does not work
makeStyles({
root: {
color: "red",
color: "rgba(0, 0, 0, 0.5)"
}
});
We can use the similar approach as fela-plugin-fallback-value
with arrays or something else.
The approach to fallback values should be tested and documented.
See: #105
I'm following the directions provided on the following README, but it doesn't do anything: https://github.com/microsoft/griffel/tree/main/packages/jest-serializer
We're using jest "^27.5.1" and ts-jest "^27.1.3".
The output still has all the generated class names.
transition: ".3s cubic-bezier(.33,0,0,1) all" can't be used with griffel atm
import { makeStyles } from "@griffel/react";
import "./styles.css";
const useClasses = makeStyles({
rootA: {
".foo .bar .baz": {
opacity: 1
}
},
rootB: {
".foo .bar .baz": {
zIndex: 1
}
}
});
The following code should not produce TypeScript errors, but it does:
Type '{ opacity: number; }' is not assignable to type 'GriffelStylesCSSValue | GriffelStylesCSSObjectCustomL2 | undefined'.
Type '{ opacity: number; }' is not assignable to type 'GriffelStylesCSSObjectCustomL2'.
Type '{ opacity: number; }' is not assignable to type '{ [Property: string]: GriffelStylesCSSValue | GriffelStylesCSSObjectCustomL3 | undefined; }'.
Property 'opacity' is incompatible with index signature.
Type 'number' is not assignable to type 'GriffelStylesCSSValue | GriffelStylesCSSObjectCustomL3 | undefined'.ts(2322)
https://codesandbox.io/s/gifted-newton-e6lmvo?file=/src/App.tsx
Styles like padding
and margin
which need the use of a shorthand to be expanded into their left
, right
, top
, bottom
equivalents error when you try to use them in a makeStyles
call. However, if they are used inside of a selector that's not part of CSS.Pseudos
then they do not error out and the styles are ultimately ignored.
We should fix the types so that these styles always error out to indicate the user that they need to change them to shorthands.
Example:
const useStyles = makeStyles({
base: {
':hover': {
// will error out
padding: "1px"
},
[`& .${testClassName}`]': {
// will not error out
padding: "1px"
}
}
});
Right now there's no shorthand in @griffer/core
for outline
Although this isn't the main focus border styling method we use in Fluent UI itself, having a shorthand available would be helpful in cases where it's necessary to use outline
.
outline
is CSS shorthand that is expanded to three properties outline-color
, outline-style
, outline-width
.
CSS has variadic handlers for parameters:
/* style */
outline: solid;
/* color | style */
outline: #f66 dashed;
/* style | width */
outline: inset thick;
/* color | style | width */
outline: green solid 3px;
But we can't do the same smart thing, proposed API that follows the same CSS order:
outline('color') // { outlineColor: 'color' }
outline('color', 'style') // { outlineColor: 'color', outlineStyle: 'style' }
outline('color', 'style', 'width') // { outlineColor: 'color', outlineStyle: 'style', outlineWidth: 'width' }
For reference use an existing shorthand function for borderLeft
:
griffel/packages/core/src/shorthands/borderLeft.ts
Lines 6 to 15 in 345719a
Devtools extension not work as expected when pass style renderer on SSR.
Sandbox: https://codesandbox.io/s/jovial-elion-ngvj2f
Page with the exception: https://ngvj2f.sse.codesandbox.io/
README
file for @griffel/react
should contain limitations section.
It should include explainer why CSS shorthands are forbidden and reference shorthand functions.
Hi,
@griffel/babel-preset
is missing a dependency to @griffel/core
.
@griffel/core
is used in packages/babel-preset/src/transformPlugin.ts but not defined in packages/babel-preset/package.json.
This causes missing dependencies issues in some use cases.
#103 fixed handling of multiple exports of the same module, but there is an edge case with multiple modules:
import { makeStyles as makeStylesA } from 'module-a'
import { makeStyles as makeStylesB } from 'module-b'
// ⬇️⬇️⬇️
import { __styles } from 'module-a'
import { __styles } from 'module-b' // 💥 duplicate import for "__styles"
This will explode as __styles
is duplicated identifier. We should use local imports for this case, i.e. result should be:
import { __styles } from 'module-a'
import { __styles as __stylesB } from 'module-b'
If there are slots that produce large amounts of classes, for example when using @rules and several selectors, debugging can get quite tiresome since the DOM is cluttered with classes and when looking at one Node one sometimes has to work through quite a lot of classes to find what they are looking for. I have no real feasable solution at this point for this. Maybe allowing disabling the atomic aspect for development builds could work.
It would be useful to have type safe helper functions for merging Record<Slots, string>
or selecting several of those slots, I also found being able to rename slots quite helpful. Something along the lines of:
type ClassRecord = Record<Slots, string>
function mergeClassesDeep
<C1 extends ClassRecord, C2 extends ClassRecord>
(cf1: (() => C1) | undefined, cf2: ((() => C2)) | undefined): () => C1 & C2
function mergeClassesDeep
<C1 extends ClassRecord, C2 extends ClassRecord, C3 extends ClassRecord>
(cf1: (() => C1) | undefined, cf2: (() => C2) | undefined, cf3: (() => C3) | undefined): () => C1 & C2 & C3
//...
export function selectSlots
<T extends ClassRecord, K1 extends keyof T>
(record: T, key1: K1): Pick<T, K1>
export function selectSlots
<T extends ClassRecord, K1 extends keyof T, K2 extends keyof T>
(record: T, key1: K1, key2: K2): Pick<T, K1 | K2>
//...
export function renameSlots
<T extends ClassRecord, K1 extends keyof T, R1 extends SlotType>
(styleFunction: T, mapping1: [K1, R1]): Omit<T, K1> & ClassRecord<R1>
export function renameSlots
<T extends ClassRecord, K1 extends keyof T, R1 extends SlotType, K2 extends keyof T, R2 extends SlotType>
(record: T, mapping1: [K1, R1], mapping2: [K2, R2]): Omit<T, K1 | K2> & ClassRecord<R1 | R2>
I would much prefer if mapping was a Record, but I am not sure if it is possible to make that type safe.
Hi, I was trying to use this package with nextJS using the mini-css-extract-plugin built-in but in its construction I get the following error:
Global CSS cannot be imported from files other than your Custom . Due to the Global natureof stylesheets, and to avoid conflicts, Please move all first-party global CSS imports to pages/_app.js. Or convert the import to Component-Level CSS (CSS Modules).
Sandbox: https://codesandbox.io/s/withered-firefly-2ff6m8
I have to add the plugin with certain parameters to the pipeline so it’ll work properly:
new MiniCssExtractPlugin({ // without these Next.js will look for the generated stylesheets from the wrong place filename: "static/chunks/[chunkhash].css", chunkFilename: "static/chunks/[chunkhash].css", ignoreOrder: true, })
Sandbox: https://codesandbox.io/s/hardcore-mendel-9xywyx
Maybe you have an idea how can I use a built-in plugin?
Now this might be a strange kind of issue, but given that you are using a German word as a name and German is my mother tongue, I feel qualified to comment. Whilst Griffel definitely means "stylus" this meaning is out of style. The kind of stylus called Griffel has not been in use for several decades, and so next to no one uses that word in that sense. It is however still a used word, but mainly in a derogatory sense, to describe the fingers of a person. Usually when that Person touches something they should not be touching, in the worst case another Person.
I can't quite figure out how to use grid-template-areas
with Griffel (using "@griffel/react": "^1.2.3",
). I have looked through the documentation and shorthands with no avail.
I am trying to make the equivalent of something like this css:
.layout {
display: grid;
grid-template-areas:
"header header"
"nav main "
"footer footer";
}
.header {
grid-area: header;
}
Any help on how to do this will be greatly appreciated.
The problem itself is similar to microsoft/fluentui#17607, behavior of @media
queries is not deterministic: it depends on order of insertion.
The closest competitor is Fela, there is mediaQueryOrder
in a config for render to solve such cases.
@fluentui/react-make-styles@9
shorthands
support for flex
propertyExpand ...shorthands.flex(0, 0, 'auto')
into:
{
flexGrow: 0,
flexShrink: 0,
flexBasis: 'auto'
}
If the r
SVG CSS prop is specified with no units, griffel will generate a className + style for Chromium browsers, but will create a className with no style for Firefox. You can see the difference in this codesandbox on each browser:
https://codesandbox.io/s/musing-roentgen-r9i7g5?file=/src/App.js
Firefox has these classNames/styles:
.f1uzb8hk { width: 45px; }
.fvfw249 { height: 45px; }
.f4a1i41 { cx: 50%; }
.f15az5lx { cy: 50%; }
.f10o6nd5 { }
Chromium has these:
.f1uzb8hk { width: 45px; }
.fvfw249 { height: 45px; }
.f4a1i41 { cx: 50%; }
.f15az5lx { cy: 50%; }
.f10o6nd5 { r: 10; }
It seems like it would be more predictable and much easier to debug if griffel were to output the r
style regardless of browser support for units/unitless values.
👆 see title.
grid-area
is a shorthand for 4 different values, engineers perhaps use just the grid-area
shorthand and even don't know what that should be expanded to.
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area
Add shorthands.gridArea()
.
The current global selector creates a style that is a parent selector
':global(.parent)': {
color: 'red',
},
.parent .fztiaq5 {
color: red;
}
The above will work with
<div class="parent">
<div class=" .fztiaq5" />
</div>
How can one created a chained class selector with Griffel ?
.same-element.fztiaq5 {
color: red;
}
<div class=".same-element .fztiaq5" />
Hello.
When configuring styles in SSR in Next.js, I encountered a problem.
After hydrating the styles - the client also inserts its own <style>
tags. This results in duplication of styles.
As there is no SSR documentation yet, I implemented using the source code.
static async getInitialProps(ctx) {
const originalRenderPage = ctx.renderPage;
const renderer = createDOMRenderer();
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => {
return function EnhancedApp(props) {
return (
<RendererProvider renderer={renderer}>
<App {...props} />
</RendererProvider>
);
};
}
});
const documentProps = await NextDocument.getInitialProps(ctx);
documentProps.styles = (
<>
{documentProps.styles}
{renderToStyleElements(renderer)}
</>
);
return documentProps;
}
Reproduced the problem in CodeSandbox.
Maybe this is not a bug and there is a way to disable client initialisation of already hydrated elements
After updating from @fluentui/[email protected] to @fluentui/[email protected], we discovered that the newer Griffel version bundled with the package removes child selectors after webpack compilation.
In dev mode, where we do not compile styles ahead of time, child selectors still work. It seems to be related to storing some of the styles in a separate object.
Example of failing code:
const menuListStyles = {
/** Loop app style overrides for Fluent UI `<MenuDivider />` component. */
[`& .${menuDividerClassNames.root}`]: {
...shorthands.margin('4px', '-8px')
},
}
/** Loop app style overrides for @fluentui/react-menu. */
const useMenuStyles = makeStyles({
/** Loop app style overrides for Fluent UI `<MenuPopover />` component. */
popover: {
boxShadow: tokens.shadow28,
...menuListStyles
},
list: menuListStyles,
/**
* Style overrides for Fluent UI `<MenuPopover />` component that apply acrylic background.
*/
popoverAcrylicColorized: {
[`& .${menuItemClassNames.root}`]: {
backgroundColor: 'transparent' // this still works
}
},
});
Creating styles that are more real-time can feel incongruous! It is not known if Griffel has any plans to support dynamic parameters. Similar to:
`
const useClasses= makeStyles((color)=>({fontColor:{color}}))
const classes = useClasses('red')
`
Right now there's no shorthand in @griffer/core
for inset
Setting top
, bottom
, left
, and right
for an absolute positioned element is a fairly common pattern. It would be great to expose a shorthand equivalent for this newer CSS rule.
inset
is CSS shorthand that is expanded to the top
, bottom
, left
, and right
properties. It follows the same format as margin
and padding
, so the logic from those shorthand functions can be reused.
The shape of GriffelStyle
is currently guarded only by TS typings. Does are sometimes difficult to understand and not always 100% accurate.
It would be great to add lint rules to improve strictness and readability of the error messages.
In the playground, I tried adding this:
import { makeStyles, shorthands } from '@griffel/core';
export default makeStyles({
root: {
backgroundColor: 'red',
},
foo: {
background: 'green'
}
});
Expected:
green
shows up in the output.
Resulted:
.f3xbvq9 {
background-color: red;
}
Changing background
to backgroundColor
fixes it. But this was the first thing I tried, and it failed to update or even show an error message. Would be good to expand shorthand.
... which would benefit the entire CSS-in-JS community!
I've been creating PRs toward inline-style-expand-shorthand, which is currently the only shorthand expander the entire CSS-in-JS community has, but none of them has been merged.
I'd like to ask are you going to add support for extracting CSS?
It does not seem like style rules are ever removed. Once they are rendered they seem to persist until the page is reloaded.
Add source maps to the production files bundled in the npm packages to improve debugging experience.
Based on #43.
makeStyles()
supports hydration process, but makeStaticStyles
does not (while it should!). Missing hydration process results in doubled styles definitions:
rehydrateRendererCache()
should support styles from makeStaticStyles
and rehydrate them properly:
Static styles might go to a separate style bucket to avoid collisions with classes generated by makeStyles
.
We have few issues with Nx where bugs are present or something work as not expected. Temporary this is solved with patches via yarn
, but it's not a long term solution.
griffel/.yarn/patches/@nrwl-web-npm-13.10.6-0fda8b81ed.patch
Lines 3 to 13 in eb86759
NX issue: nrwl/nx#8505
griffel/.yarn/patches/@nrwl-js-npm-13.10.6-08130e9fbb.patch
Lines 3 to 13 in eb86759
NX issue: nrwl/nx#9371
@nrwl/web:rollup
Hello 👋
This project seems very promising! Do you have plan to support Vite with a custom plugin?
Documentation: https://vitejs.dev/guide/api-plugin.html
vanilla-extract
plugin (for reference): https://github.com/seek-oss/vanilla-extract/tree/master/packages/vite-plugin
We don't allow to use CSS shorthands:
griffel/packages/core/src/types.ts
Lines 5 to 49 in b4c7acc
We should implement something in runtime to prevent adding rules with shorthands. Currently shorthands usage produces TS errors, but rules are still inserted to DOM. That creates confusion and feeling that something is wrong with typings.
import { makeStyles } from "@griffel/react";
const useClasses = makeStyles({
root: {
// ⏭ "background" is not inserted to DOM & a warning is produced (currently inserted)
// 💥 produces TS error (already done)
background: "red"
}
});
When writing multiple selectors separated by commas only the first selector is properly scoped with a class name.
Here's a link to an annotated repro case in CodeSandbox.
A Griffel styles like
makeStyles({
root: {
":active,:focus-within": {
...shorthands.borderColor("red")
}
}
});
Produces a selector like this in DevTools:
.f1mk9nzz:active, :focus-within {
border-right-color: red;
}
Currently only the :active
selector is scoped with a generated class name.
Both the :active
and :focus-within
selectors should be scoped with the same generated class name. So we should see something like this in DevTools:
.f1mk9nzz:active, .f1mk9nzz:focus-within {
border-right-color: red;
}
Alternatively, if this syntax is not supported I should get an error in VSCode explaining to me that I cannot write styles in this way.
In Codesandbox I get an error (red squiggle under the selectors) when writing ":active,:focus-within"
indicating to me that perhaps this way of writing styles is not supported by Griffel. However, I don't get this error when writing styles like this in VS Code so I'm not certain. I'm using [email protected]
in both Codesandbox and VSCode.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.