@griffel/react 1.7.1 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/.storybook/main.js +20 -0
  2. package/.storybook/preview.js +1 -0
  3. package/CHANGELOG.json +1281 -0
  4. package/CHANGELOG.md +501 -0
  5. package/README.md +4 -0
  6. package/bundle-size/__css.fixture.js +7 -0
  7. package/bundle-size/__styles.fixture.js +7 -0
  8. package/bundle-size/makeResetStyles.fixture.js +7 -0
  9. package/bundle-size/makeStaticStyles.fixture.js +7 -0
  10. package/bundle-size/makeStyles.fixture.js +7 -0
  11. package/eslint.config.mjs +31 -0
  12. package/package.json +3 -3
  13. package/project.json +96 -0
  14. package/src/RendererContext.tsx +52 -0
  15. package/src/TextDirectionContext.tsx +34 -0
  16. package/src/__css.ts +21 -0
  17. package/src/__resetCSS.ts +19 -0
  18. package/src/__resetStyles.ts +28 -0
  19. package/src/{__staticCSS.js → __staticCSS.ts} +7 -6
  20. package/src/__staticStyles.ts +22 -0
  21. package/src/__styles.ts +27 -0
  22. package/src/createDOMRenderer.test.tsx +133 -0
  23. package/src/{index.d.ts → index.ts} +6 -0
  24. package/src/insertionFactory-node.test.ts +31 -0
  25. package/src/insertionFactory.test.ts +29 -0
  26. package/src/insertionFactory.ts +27 -0
  27. package/src/makeResetStyles.test.tsx +27 -0
  28. package/src/makeResetStyles.ts +31 -0
  29. package/src/makeStaticStyles.ts +23 -0
  30. package/src/makeStyles.test.tsx +27 -0
  31. package/src/makeStyles.ts +31 -0
  32. package/src/renderToStyleElements-node.test.tsx +418 -0
  33. package/src/renderToStyleElements.test.tsx +103 -0
  34. package/src/renderToStyleElements.ts +61 -0
  35. package/src/stories/ComponentStyles.stories.tsx +55 -0
  36. package/src/stories/DOMRendererFilter.stories.tsx +76 -0
  37. package/src/stories/FallbackValues.stories.tsx +50 -0
  38. package/src/stories/makeStyles.stories.tsx +17 -0
  39. package/src/useInsertionEffect.ts +11 -0
  40. package/src/utils/canUseDOM-node.test.ts +14 -0
  41. package/src/utils/canUseDOM.test.tsx +8 -0
  42. package/src/utils/canUseDOM.ts +8 -0
  43. package/src/utils/isInsideComponent.ts +41 -0
  44. package/tsconfig.json +20 -0
  45. package/tsconfig.lib.json +28 -0
  46. package/tsconfig.spec.json +21 -0
  47. package/tsconfig.storybook.json +12 -0
  48. package/vitest.config.ts +21 -0
  49. package/LICENSE.md +0 -21
  50. package/lib/RendererContext.cjs +0 -45
  51. package/lib/TextDirectionContext.cjs +0 -33
  52. package/lib/__css.cjs +0 -22
  53. package/lib/__resetCSS.cjs +0 -22
  54. package/lib/__resetStyles.cjs +0 -26
  55. package/lib/__staticCSS.cjs +0 -18
  56. package/lib/__staticStyles.cjs +0 -23
  57. package/lib/__styles.cjs +0 -26
  58. package/lib/index.cjs +0 -78
  59. package/lib/insertionFactory.cjs +0 -33
  60. package/lib/makeResetStyles.cjs +0 -35
  61. package/lib/makeStaticStyles.cjs +0 -28
  62. package/lib/makeStyles.cjs +0 -35
  63. package/lib/renderToStyleElements.cjs +0 -50
  64. package/lib/useInsertionEffect.cjs +0 -20
  65. package/lib/utils/canUseDOM.cjs +0 -17
  66. package/lib/utils/isInsideComponent.cjs +0 -46
  67. package/src/RendererContext.d.ts +0 -24
  68. package/src/RendererContext.js +0 -31
  69. package/src/RendererContext.js.map +0 -1
  70. package/src/TextDirectionContext.d.ts +0 -19
  71. package/src/TextDirectionContext.js +0 -22
  72. package/src/TextDirectionContext.js.map +0 -1
  73. package/src/__css.d.ts +0 -7
  74. package/src/__css.js +0 -17
  75. package/src/__css.js.map +0 -1
  76. package/src/__resetCSS.d.ts +0 -6
  77. package/src/__resetCSS.js +0 -17
  78. package/src/__resetCSS.js.map +0 -1
  79. package/src/__resetStyles.d.ts +0 -7
  80. package/src/__resetStyles.js +0 -20
  81. package/src/__resetStyles.js.map +0 -1
  82. package/src/__staticCSS.d.ts +0 -6
  83. package/src/__staticCSS.js.map +0 -1
  84. package/src/__staticStyles.d.ts +0 -7
  85. package/src/__staticStyles.js +0 -18
  86. package/src/__staticStyles.js.map +0 -1
  87. package/src/__styles.d.ts +0 -7
  88. package/src/__styles.js +0 -20
  89. package/src/__styles.js.map +0 -1
  90. package/src/index.js +0 -16
  91. package/src/index.js.map +0 -1
  92. package/src/insertionFactory.d.ts +0 -2
  93. package/src/insertionFactory.js +0 -21
  94. package/src/insertionFactory.js.map +0 -1
  95. package/src/makeResetStyles.d.ts +0 -2
  96. package/src/makeResetStyles.js +0 -23
  97. package/src/makeResetStyles.js.map +0 -1
  98. package/src/makeStaticStyles.d.ts +0 -2
  99. package/src/makeStaticStyles.js +0 -17
  100. package/src/makeStaticStyles.js.map +0 -1
  101. package/src/makeStyles.d.ts +0 -2
  102. package/src/makeStyles.js +0 -23
  103. package/src/makeStyles.js.map +0 -1
  104. package/src/renderToStyleElements.d.ts +0 -8
  105. package/src/renderToStyleElements.js +0 -51
  106. package/src/renderToStyleElements.js.map +0 -1
  107. package/src/useInsertionEffect.d.ts +0 -1
  108. package/src/useInsertionEffect.js +0 -10
  109. package/src/useInsertionEffect.js.map +0 -1
  110. package/src/utils/canUseDOM.d.ts +0 -1
  111. package/src/utils/canUseDOM.js +0 -9
  112. package/src/utils/canUseDOM.js.map +0 -1
  113. package/src/utils/isInsideComponent.d.ts +0 -1
  114. package/src/utils/isInsideComponent.js +0 -39
  115. package/src/utils/isInsideComponent.js.map +0 -1
@@ -0,0 +1,418 @@
1
+ /*
2
+ * @vitest-environment node
3
+ */
4
+
5
+ // 👆 this is intentionally to test in SSR like environment
6
+
7
+ import { describe, it, expect } from 'vitest';
8
+ import { createDOMRenderer } from '@griffel/core';
9
+ import * as prettier from 'prettier';
10
+ import type * as React from 'react';
11
+ import * as ReactDOM from 'react-dom/server';
12
+
13
+ import { makeStyles } from './makeStyles.js';
14
+ import { makeResetStyles } from './makeResetStyles.js';
15
+ import { RendererProvider } from './RendererContext.js';
16
+ import { renderToStyleElements } from './renderToStyleElements.js';
17
+
18
+ async function formatHtml(value: string) {
19
+ return (await prettier.format(value, { parser: 'html' })).trim();
20
+ }
21
+
22
+ describe('renderToStyleElements (node)', () => {
23
+ describe('makeStyles', () => {
24
+ it('supports overrides', async () => {
25
+ const useExampleStyles = makeStyles({
26
+ root: {
27
+ color: 'red',
28
+ ':hover': { color: 'pink' },
29
+ },
30
+ });
31
+ const ExampleComponent: React.FC = () => {
32
+ const classes = useExampleStyles();
33
+
34
+ return <div className={classes.root} />;
35
+ };
36
+
37
+ const renderer = createDOMRenderer();
38
+
39
+ ReactDOM.renderToStaticMarkup(
40
+ <RendererProvider renderer={renderer}>
41
+ <ExampleComponent />
42
+ </RendererProvider>,
43
+ );
44
+
45
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
46
+ .toMatchInlineSnapshot(`
47
+ "<style
48
+ data-make-styles-bucket="d"
49
+ data-priority="0"
50
+ data-make-styles-rehydration="true"
51
+ >
52
+ .fe3e8s9 {
53
+ color: red;
54
+ }</style
55
+ ><style
56
+ data-make-styles-bucket="h"
57
+ data-priority="0"
58
+ data-make-styles-rehydration="true"
59
+ >
60
+ .f14hep94:hover {
61
+ color: pink;
62
+ }
63
+ </style>"
64
+ `);
65
+ });
66
+
67
+ it('supports overrides', async () => {
68
+ const useExampleStylesA = makeStyles({
69
+ root: {
70
+ paddingLeft: '10px',
71
+ margin: '10px',
72
+ ':hover': { paddingRight: '20px' },
73
+ },
74
+ });
75
+ const useExampleStylesB = makeStyles({
76
+ root: { padding: '10px', ':hover': { padding: '20px' } },
77
+ });
78
+ const useExampleStylesC = makeStyles({
79
+ root: { marginLeft: '10px' },
80
+ });
81
+ const ExampleComponent: React.FC = () => {
82
+ useExampleStylesA();
83
+ useExampleStylesB();
84
+ useExampleStylesC();
85
+
86
+ return null;
87
+ };
88
+
89
+ const renderer = createDOMRenderer();
90
+
91
+ ReactDOM.renderToStaticMarkup(
92
+ <RendererProvider renderer={renderer}>
93
+ <ExampleComponent />
94
+ </RendererProvider>,
95
+ );
96
+
97
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
98
+ .toMatchInlineSnapshot(`
99
+ "<style
100
+ data-make-styles-bucket="d"
101
+ data-priority="-1"
102
+ data-make-styles-rehydration="true"
103
+ >
104
+ .femlv54 {
105
+ margin: 10px;
106
+ }
107
+ .fbhmu18 {
108
+ padding: 10px;
109
+ }</style
110
+ ><style
111
+ data-make-styles-bucket="d"
112
+ data-priority="0"
113
+ data-make-styles-rehydration="true"
114
+ >
115
+ .frdkuqy {
116
+ padding-left: 10px;
117
+ }
118
+ .f81rol6 {
119
+ padding-right: 10px;
120
+ }
121
+ .f1oou7ox {
122
+ margin-left: 10px;
123
+ }
124
+ .f1pxv85q {
125
+ margin-right: 10px;
126
+ }</style
127
+ ><style
128
+ data-make-styles-bucket="h"
129
+ data-priority="-1"
130
+ data-make-styles-rehydration="true"
131
+ >
132
+ .fp9hkdp:hover {
133
+ padding: 20px;
134
+ }</style
135
+ ><style
136
+ data-make-styles-bucket="h"
137
+ data-priority="0"
138
+ data-make-styles-rehydration="true"
139
+ >
140
+ .f19vcps:hover {
141
+ padding-right: 20px;
142
+ }
143
+ .f1mr755h:hover {
144
+ padding-left: 20px;
145
+ }
146
+ </style>"
147
+ `);
148
+ });
149
+
150
+ it('handles @at rules', async () => {
151
+ const useExampleStyles = makeStyles({
152
+ media: {
153
+ '@media screen and (max-width: 992px)': {
154
+ ':hover': { color: 'blue' },
155
+ },
156
+ },
157
+
158
+ support: {
159
+ '@supports (display: grid)': {
160
+ color: 'red',
161
+ },
162
+ },
163
+ });
164
+ const ExampleComponent: React.FC = () => {
165
+ const classes = useExampleStyles();
166
+
167
+ return (
168
+ <>
169
+ <div className={classes.media} />
170
+ <div className={classes.support} />
171
+ </>
172
+ );
173
+ };
174
+
175
+ const renderer = createDOMRenderer();
176
+
177
+ ReactDOM.renderToStaticMarkup(
178
+ <RendererProvider renderer={renderer}>
179
+ <ExampleComponent />
180
+ </RendererProvider>,
181
+ );
182
+
183
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
184
+ .toMatchInlineSnapshot(`
185
+ "<style
186
+ data-make-styles-bucket="t"
187
+ data-priority="0"
188
+ data-make-styles-rehydration="true"
189
+ >
190
+ @supports (display: grid) {
191
+ .fo1gfrc {
192
+ color: red;
193
+ }
194
+ }</style
195
+ ><style
196
+ media="screen and (max-width: 992px)"
197
+ data-make-styles-bucket="m"
198
+ data-priority="0"
199
+ data-make-styles-rehydration="true"
200
+ >
201
+ @media screen and (max-width: 992px) {
202
+ .fzd6x39:hover {
203
+ color: blue;
204
+ }
205
+ }
206
+ </style>"
207
+ `);
208
+ });
209
+
210
+ it('handles media query order', async () => {
211
+ const useExampleStyles = makeStyles({
212
+ media: {
213
+ color: 'red',
214
+ '@media (max-width: 4px)': {
215
+ ':hover': { color: 'blue' },
216
+ },
217
+ '@media (max-width: 2px)': {
218
+ ':hover': { color: 'blue' },
219
+ },
220
+ '@supports (display: grid)': {
221
+ color: 'green',
222
+ },
223
+ '@media (max-width: 3px)': {
224
+ ':hover': { color: 'blue' },
225
+ },
226
+ '@media (max-width: 1px)': {
227
+ ':hover': { color: 'blue' },
228
+ },
229
+ },
230
+ });
231
+ const ExampleComponent: React.FC = () => {
232
+ const classes = useExampleStyles();
233
+
234
+ return <div className={classes.media} />;
235
+ };
236
+
237
+ const mediaQueryOrder = ['(max-width: 1px)', '(max-width: 2px)', '(max-width: 3px)', '(max-width: 4px)'];
238
+ const renderer = createDOMRenderer(undefined, {
239
+ compareMediaQueries(a, b) {
240
+ return mediaQueryOrder.indexOf(a) - mediaQueryOrder.indexOf(b);
241
+ },
242
+ });
243
+
244
+ ReactDOM.renderToStaticMarkup(
245
+ <RendererProvider renderer={renderer}>
246
+ <ExampleComponent />
247
+ </RendererProvider>,
248
+ );
249
+
250
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
251
+ .toMatchInlineSnapshot(`
252
+ "<style
253
+ data-make-styles-bucket="d"
254
+ data-priority="0"
255
+ data-make-styles-rehydration="true"
256
+ >
257
+ .fe3e8s9 {
258
+ color: red;
259
+ }</style
260
+ ><style
261
+ data-make-styles-bucket="t"
262
+ data-priority="0"
263
+ data-make-styles-rehydration="true"
264
+ >
265
+ @supports (display: grid) {
266
+ .fui0tgz {
267
+ color: green;
268
+ }
269
+ }</style
270
+ ><style
271
+ media="(max-width: 1px)"
272
+ data-make-styles-bucket="m"
273
+ data-priority="0"
274
+ data-make-styles-rehydration="true"
275
+ >
276
+ @media (max-width: 1px) {
277
+ .f13d6lhy:hover {
278
+ color: blue;
279
+ }
280
+ }</style
281
+ ><style
282
+ media="(max-width: 2px)"
283
+ data-make-styles-bucket="m"
284
+ data-priority="0"
285
+ data-make-styles-rehydration="true"
286
+ >
287
+ @media (max-width: 2px) {
288
+ .f1b07yzi:hover {
289
+ color: blue;
290
+ }
291
+ }</style
292
+ ><style
293
+ media="(max-width: 3px)"
294
+ data-make-styles-bucket="m"
295
+ data-priority="0"
296
+ data-make-styles-rehydration="true"
297
+ >
298
+ @media (max-width: 3px) {
299
+ .f1cy3850:hover {
300
+ color: blue;
301
+ }
302
+ }</style
303
+ ><style
304
+ media="(max-width: 4px)"
305
+ data-make-styles-bucket="m"
306
+ data-priority="0"
307
+ data-make-styles-rehydration="true"
308
+ >
309
+ @media (max-width: 4px) {
310
+ .fyvg8w:hover {
311
+ color: blue;
312
+ }
313
+ }
314
+ </style>"
315
+ `);
316
+ });
317
+
318
+ it('handles keyframes', async () => {
319
+ const useExampleStyles = makeStyles({
320
+ keyframe: {
321
+ animationName: {
322
+ from: {
323
+ transform: 'rotate(0deg)',
324
+ },
325
+ to: {
326
+ transform: 'rotate(360deg)',
327
+ },
328
+ },
329
+ },
330
+ });
331
+ const ExampleComponent: React.FC = () => {
332
+ const classes = useExampleStyles();
333
+
334
+ return <div className={classes.keyframe} />;
335
+ };
336
+
337
+ const renderer = createDOMRenderer();
338
+
339
+ ReactDOM.renderToStaticMarkup(
340
+ <RendererProvider renderer={renderer}>
341
+ <ExampleComponent />
342
+ </RendererProvider>,
343
+ );
344
+
345
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
346
+ .toMatchInlineSnapshot(`
347
+ "<style
348
+ data-make-styles-bucket="d"
349
+ data-priority="0"
350
+ data-make-styles-rehydration="true"
351
+ >
352
+ .f1g6ul6r {
353
+ animation-name: f1q8eu9e;
354
+ }
355
+ .f1fp4ujf {
356
+ animation-name: f55c0se;
357
+ }</style
358
+ ><style
359
+ data-make-styles-bucket="k"
360
+ data-priority="0"
361
+ data-make-styles-rehydration="true"
362
+ >
363
+ @keyframes f1q8eu9e {
364
+ from {
365
+ transform: rotate(0deg);
366
+ }
367
+ to {
368
+ transform: rotate(360deg);
369
+ }
370
+ }
371
+ @keyframes f55c0se {
372
+ from {
373
+ transform: rotate(0deg);
374
+ }
375
+ to {
376
+ transform: rotate(-360deg);
377
+ }
378
+ }
379
+ </style>"
380
+ `);
381
+ });
382
+ });
383
+
384
+ describe('makeResetStyles', () => {
385
+ it('renders styles', async () => {
386
+ const useClassName = makeResetStyles({
387
+ color: 'red',
388
+ ':hover': { color: 'pink' },
389
+ });
390
+ const ExampleComponent: React.FC = () => {
391
+ return <div className={useClassName()} />;
392
+ };
393
+ const renderer = createDOMRenderer();
394
+
395
+ ReactDOM.renderToStaticMarkup(
396
+ <RendererProvider renderer={renderer}>
397
+ <ExampleComponent />
398
+ </RendererProvider>,
399
+ );
400
+
401
+ expect(await formatHtml(ReactDOM.renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>)))
402
+ .toMatchInlineSnapshot(`
403
+ "<style
404
+ data-make-styles-bucket="r"
405
+ data-priority="0"
406
+ data-make-styles-rehydration="true"
407
+ >
408
+ .r1tsu58y {
409
+ color: red;
410
+ }
411
+ .r1tsu58y:hover {
412
+ color: pink;
413
+ }
414
+ </style>"
415
+ `);
416
+ });
417
+ });
418
+ });
@@ -0,0 +1,103 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import type { GriffelRenderer } from '@griffel/core';
3
+ import { createDOMRenderer } from '@griffel/core';
4
+ import * as prettier from 'prettier';
5
+ import * as React from 'react';
6
+ import { createRoot } from 'react-dom/client';
7
+ import { renderToStaticMarkup } from 'react-dom/server';
8
+
9
+ import { makeStyles } from './makeStyles.js';
10
+ import { makeResetStyles } from './makeResetStyles.js';
11
+ import { RendererProvider } from './RendererContext.js';
12
+ import { renderToStyleElements } from './renderToStyleElements.js';
13
+
14
+ async function formatHtml(value: string) {
15
+ return (await prettier.format(value, { parser: 'html' })).trim();
16
+ }
17
+
18
+ describe('renderToStyleElements (DOM)', () => {
19
+ let renderer: GriffelRenderer;
20
+
21
+ beforeEach(() => {
22
+ process.env.NODE_ENV = 'production';
23
+ renderer = createDOMRenderer(document);
24
+ });
25
+
26
+ afterEach(() => {
27
+ document.head.innerHTML = '';
28
+ });
29
+
30
+ it('makeStyles', async () => {
31
+ const useExampleStyles = makeStyles({
32
+ root: { color: 'red', ':hover': { color: 'green' } },
33
+ });
34
+ const ExampleComponent: React.FC = () => {
35
+ const classes = useExampleStyles();
36
+
37
+ return <div className={classes.root} />;
38
+ };
39
+ const root = createRoot(document.createElement('div'));
40
+
41
+ React.act(() => {
42
+ root.render(
43
+ <RendererProvider renderer={renderer}>
44
+ <ExampleComponent />
45
+ </RendererProvider>,
46
+ );
47
+ });
48
+
49
+ expect(await formatHtml(renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>))).toMatchInlineSnapshot(`
50
+ "<style
51
+ data-make-styles-bucket="d"
52
+ data-priority="0"
53
+ data-make-styles-rehydration="true"
54
+ >
55
+ .fe3e8s9 {
56
+ color: red;
57
+ }</style
58
+ ><style
59
+ data-make-styles-bucket="h"
60
+ data-priority="0"
61
+ data-make-styles-rehydration="true"
62
+ >
63
+ .f1ej289o:hover {
64
+ color: green;
65
+ }
66
+ </style>"
67
+ `);
68
+ });
69
+
70
+ it('makeResetStyles', async () => {
71
+ const useClassName = makeResetStyles({
72
+ color: 'red',
73
+ ':hover': { color: 'pink' },
74
+ });
75
+ const ExampleComponent: React.FC = () => {
76
+ return <div className={useClassName()} />;
77
+ };
78
+ const root = createRoot(document.createElement('div'));
79
+
80
+ React.act(() => {
81
+ root.render(
82
+ <RendererProvider renderer={renderer}>
83
+ <ExampleComponent />
84
+ </RendererProvider>,
85
+ );
86
+ });
87
+
88
+ expect(await formatHtml(renderToStaticMarkup(<>{renderToStyleElements(renderer)}</>))).toMatchInlineSnapshot(`
89
+ "<style
90
+ data-make-styles-bucket="r"
91
+ data-priority="0"
92
+ data-make-styles-rehydration="true"
93
+ >
94
+ .r1tsu58y {
95
+ color: red;
96
+ }
97
+ .r1tsu58y:hover {
98
+ color: pink;
99
+ }
100
+ </style>"
101
+ `);
102
+ });
103
+ });
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+
3
+ import { styleBucketOrdering } from '@griffel/core';
4
+ import { createElement } from 'react';
5
+ import type { ReactElement } from 'react';
6
+ import type { GriffelRenderer } from '@griffel/core';
7
+
8
+ /**
9
+ * This method returns a list of <style> React elements with the rendered CSS. This is useful for Server-Side rendering.
10
+ *
11
+ * @public
12
+ */
13
+ export function renderToStyleElements(renderer: GriffelRenderer): ReactElement[] {
14
+ const stylesheets = Object.values(renderer.stylesheets)
15
+ // first sort: bucket by order [data-priority]
16
+ .sort((a, b) => {
17
+ return Number(a.elementAttributes['data-priority']) - Number(b.elementAttributes['data-priority']);
18
+ })
19
+ // second sort: bucket by bucket name
20
+ .sort((a, b) => {
21
+ return styleBucketOrdering.indexOf(a.bucketName) - styleBucketOrdering.indexOf(b.bucketName);
22
+ })
23
+ // third sort: media queries
24
+ .sort((a, b) => {
25
+ const mediaA = a.elementAttributes['media'];
26
+ const mediaB = b.elementAttributes['media'];
27
+
28
+ if (mediaA && mediaB) {
29
+ return renderer.compareMediaQueries(mediaA, mediaB);
30
+ }
31
+
32
+ if (mediaA || mediaB) {
33
+ return mediaA ? 1 : -1;
34
+ }
35
+
36
+ return 0;
37
+ });
38
+
39
+ return stylesheets
40
+ .map(stylesheet => {
41
+ const cssRules = stylesheet.cssRules();
42
+ // don't want to create any empty style elements
43
+ if (!cssRules.length) {
44
+ return null;
45
+ }
46
+
47
+ return createElement('style', {
48
+ key: stylesheet.bucketName,
49
+
50
+ // TODO: support "nonce"
51
+ // ...renderer.styleNodeAttributes,
52
+ ...stylesheet.elementAttributes,
53
+ 'data-make-styles-rehydration': 'true',
54
+
55
+ dangerouslySetInnerHTML: {
56
+ __html: cssRules.join(''),
57
+ },
58
+ });
59
+ })
60
+ .filter(Boolean) as ReactElement[];
61
+ }
@@ -0,0 +1,55 @@
1
+ import type * as React from 'react';
2
+ import type { StoryObj } from '@storybook/react-vite';
3
+
4
+ import { makeStyles, mergeClasses, shorthands } from '../';
5
+
6
+ const tokens = {
7
+ brandBackground: '#106ebe',
8
+ brandBackgroundHover: '#2899f5',
9
+ };
10
+
11
+ const useButtonStyles = makeStyles({
12
+ root: {
13
+ backgroundColor: 'transparent',
14
+ outlineStyle: 'none',
15
+ ...shorthands.borderRadius('.3em'),
16
+ ...shorthands.border('1px', 'solid', '#333'),
17
+ ...shorthands.padding('.3em', '1em'),
18
+ ':hover': {
19
+ cursor: 'pointer',
20
+ backgroundColor: '#ddd',
21
+ },
22
+ },
23
+
24
+ primary: {
25
+ backgroundColor: tokens.brandBackground,
26
+ color: '#eff6fc',
27
+ ':hover': {
28
+ backgroundColor: tokens.brandBackgroundHover,
29
+ },
30
+ },
31
+ });
32
+
33
+ const Button: React.FunctionComponent<{ className?: string; primary?: boolean }> = ({
34
+ className,
35
+ primary = false,
36
+ ...props
37
+ }) => {
38
+ const classes = useButtonStyles();
39
+ const mergedClasses = mergeClasses(classes.root, primary && classes.primary, className);
40
+ return <button {...props} className={mergedClasses} />;
41
+ };
42
+
43
+ export const ComponentStyles: StoryObj<{ primary: boolean }> = {
44
+ render: args => {
45
+ return <Button {...args}>button</Button>;
46
+ },
47
+
48
+ args: {
49
+ primary: false,
50
+ },
51
+ };
52
+
53
+ export default {
54
+ title: 'Component styles',
55
+ };
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import type { StoryObj } from '@storybook/react-vite';
3
+
4
+ import { createDOMRenderer } from '@griffel/core';
5
+ import { makeStyles, RendererProvider, shorthands } from '../';
6
+
7
+ const useStyles = makeStyles({
8
+ root: {
9
+ width: '200px',
10
+ height: '100px',
11
+ display: 'flex',
12
+ justifyContent: 'center',
13
+ alignItems: 'center',
14
+ ...shorthands.border('1px', 'solid', '#333'),
15
+ backgroundColor: 'cornflowerblue',
16
+ },
17
+ });
18
+
19
+ const ColorBox: React.FC = () => {
20
+ const classes = useStyles();
21
+
22
+ return <div className={classes.root}>blue box</div>;
23
+ };
24
+
25
+ const CustomRendererProvider: React.FC<{ children: React.ReactNode; filterEnabled: boolean }> = ({
26
+ children,
27
+ filterEnabled,
28
+ }) => {
29
+ const customDOMRenderer = React.useMemo(() => {
30
+ return createDOMRenderer(undefined, {
31
+ // eslint-disable-next-line @typescript-eslint/naming-convention
32
+ unstable_filterCSSRule: cssRule => {
33
+ // Filter out background-color
34
+ return !filterEnabled || cssRule.indexOf('{background-color:') === -1;
35
+ },
36
+ });
37
+ }, [filterEnabled]);
38
+
39
+ return <RendererProvider renderer={customDOMRenderer}>{children}</RendererProvider>;
40
+ };
41
+
42
+ export const DOMRendererFilter: StoryObj<{ filterEnabled: boolean }> = {
43
+ render: ({ filterEnabled }) => {
44
+ return (
45
+ <CustomRendererProvider filterEnabled={filterEnabled}>
46
+ <p>
47
+ It is possible to define a filter function in <code>DOMRenderer</code> to filter out CSS rules before adding
48
+ them to DOM. The classes are still applied to an element.
49
+ </p>
50
+ <p>Once the CSS rule is added, there is no way to remove it.</p>
51
+ <ol>
52
+ <li>Render this story with filter enabled &rarr; it renders the box without a background.</li>
53
+ <li>Disable the filter &rarr; story is re-rendered, blue background is added to the box.</li>
54
+ <li>
55
+ Enable the filter again &rarr; there is still the blue background, you need to refresh the page to get rid
56
+ of the background
57
+ </li>
58
+ </ol>
59
+ <p style={{ color: 'red' }}>
60
+ Filter is currently marked as unstable. This functionality can be changed or removed without considering it a
61
+ breaking change!
62
+ </p>
63
+
64
+ <ColorBox />
65
+ </CustomRendererProvider>
66
+ );
67
+ },
68
+
69
+ args: {
70
+ filterEnabled: true,
71
+ },
72
+ };
73
+
74
+ export default {
75
+ title: 'unstable_filterCSSRule',
76
+ };