@compiled/react 0.11.4 → 0.13.0

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 (132) hide show
  1. package/dist/browser/css/index.js +1 -5
  2. package/dist/browser/css/index.js.map +1 -1
  3. package/dist/browser/index.js +1 -1
  4. package/dist/browser/index.js.map +1 -1
  5. package/dist/browser/keyframes/__fixtures__/index.js +2 -2
  6. package/dist/browser/keyframes/__fixtures__/index.js.map +1 -1
  7. package/dist/browser/keyframes/index.js +1 -5
  8. package/dist/browser/keyframes/index.js.map +1 -1
  9. package/dist/browser/runtime/ac.d.ts +47 -0
  10. package/dist/browser/runtime/ac.js +118 -0
  11. package/dist/browser/runtime/ac.js.flow +56 -0
  12. package/dist/browser/runtime/ac.js.map +1 -0
  13. package/dist/browser/runtime/ax.js +12 -12
  14. package/dist/browser/runtime/ax.js.map +1 -1
  15. package/dist/browser/runtime/cache.js +1 -1
  16. package/dist/browser/runtime/cache.js.map +1 -1
  17. package/dist/browser/runtime/dev-warnings.js +19 -21
  18. package/dist/browser/runtime/dev-warnings.js.map +1 -1
  19. package/dist/browser/runtime/index.d.ts +1 -0
  20. package/dist/browser/runtime/index.js +9 -0
  21. package/dist/browser/runtime/index.js.flow +1 -0
  22. package/dist/browser/runtime/index.js.map +1 -1
  23. package/dist/browser/runtime/is-server-environment.js +4 -6
  24. package/dist/browser/runtime/is-server-environment.js.map +1 -1
  25. package/dist/browser/runtime/sheet.js +11 -11
  26. package/dist/browser/runtime/sheet.js.map +1 -1
  27. package/dist/browser/runtime/style-cache.js +6 -6
  28. package/dist/browser/runtime/style-cache.js.map +1 -1
  29. package/dist/browser/runtime/style.js +10 -10
  30. package/dist/browser/runtime/style.js.map +1 -1
  31. package/dist/browser/runtime.d.ts +1 -1
  32. package/dist/browser/runtime.js +1 -1
  33. package/dist/browser/runtime.js.flow +1 -1
  34. package/dist/browser/runtime.js.map +1 -1
  35. package/dist/browser/styled/index.js +3 -3
  36. package/dist/browser/styled/index.js.map +1 -1
  37. package/dist/browser/utils/error.js +18 -2
  38. package/dist/browser/utils/error.js.map +1 -1
  39. package/dist/cjs/class-names/index.js +1 -1
  40. package/dist/cjs/class-names/index.js.map +1 -1
  41. package/dist/cjs/css/index.js +2 -6
  42. package/dist/cjs/css/index.js.map +1 -1
  43. package/dist/cjs/index.js +1 -1
  44. package/dist/cjs/index.js.map +1 -1
  45. package/dist/cjs/keyframes/__fixtures__/index.js +1 -1
  46. package/dist/cjs/keyframes/__fixtures__/index.js.map +1 -1
  47. package/dist/cjs/keyframes/index.js +2 -6
  48. package/dist/cjs/keyframes/index.js.map +1 -1
  49. package/dist/cjs/runtime/ac.d.ts +47 -0
  50. package/dist/cjs/runtime/ac.js +125 -0
  51. package/dist/cjs/runtime/ac.js.flow +56 -0
  52. package/dist/cjs/runtime/ac.js.map +1 -0
  53. package/dist/cjs/runtime/ax.js +12 -12
  54. package/dist/cjs/runtime/ax.js.map +1 -1
  55. package/dist/cjs/runtime/cache.js +1 -1
  56. package/dist/cjs/runtime/cache.js.map +1 -1
  57. package/dist/cjs/runtime/dev-warnings.js +19 -21
  58. package/dist/cjs/runtime/dev-warnings.js.map +1 -1
  59. package/dist/cjs/runtime/index.d.ts +1 -0
  60. package/dist/cjs/runtime/index.js +12 -1
  61. package/dist/cjs/runtime/index.js.flow +1 -0
  62. package/dist/cjs/runtime/index.js.map +1 -1
  63. package/dist/cjs/runtime/is-server-environment.js +4 -6
  64. package/dist/cjs/runtime/is-server-environment.js.map +1 -1
  65. package/dist/cjs/runtime/sheet.js +11 -11
  66. package/dist/cjs/runtime/sheet.js.map +1 -1
  67. package/dist/cjs/runtime/style-cache.js +10 -10
  68. package/dist/cjs/runtime/style-cache.js.map +1 -1
  69. package/dist/cjs/runtime/style.js +15 -15
  70. package/dist/cjs/runtime/style.js.map +1 -1
  71. package/dist/cjs/runtime.d.ts +1 -1
  72. package/dist/cjs/runtime.js +3 -1
  73. package/dist/cjs/runtime.js.flow +1 -1
  74. package/dist/cjs/runtime.js.map +1 -1
  75. package/dist/cjs/styled/index.js +3 -3
  76. package/dist/cjs/styled/index.js.map +1 -1
  77. package/dist/cjs/utils/error.js +18 -2
  78. package/dist/cjs/utils/error.js.map +1 -1
  79. package/dist/esm/css/index.js +1 -5
  80. package/dist/esm/css/index.js.map +1 -1
  81. package/dist/esm/index.js +1 -1
  82. package/dist/esm/index.js.map +1 -1
  83. package/dist/esm/keyframes/__fixtures__/index.js +2 -2
  84. package/dist/esm/keyframes/__fixtures__/index.js.map +1 -1
  85. package/dist/esm/keyframes/index.js +1 -5
  86. package/dist/esm/keyframes/index.js.map +1 -1
  87. package/dist/esm/runtime/ac.d.ts +47 -0
  88. package/dist/esm/runtime/ac.js +118 -0
  89. package/dist/esm/runtime/ac.js.flow +56 -0
  90. package/dist/esm/runtime/ac.js.map +1 -0
  91. package/dist/esm/runtime/ax.js +12 -12
  92. package/dist/esm/runtime/ax.js.map +1 -1
  93. package/dist/esm/runtime/cache.js +1 -1
  94. package/dist/esm/runtime/cache.js.map +1 -1
  95. package/dist/esm/runtime/dev-warnings.js +19 -21
  96. package/dist/esm/runtime/dev-warnings.js.map +1 -1
  97. package/dist/esm/runtime/index.d.ts +1 -0
  98. package/dist/esm/runtime/index.js +9 -0
  99. package/dist/esm/runtime/index.js.flow +1 -0
  100. package/dist/esm/runtime/index.js.map +1 -1
  101. package/dist/esm/runtime/is-server-environment.js +4 -6
  102. package/dist/esm/runtime/is-server-environment.js.map +1 -1
  103. package/dist/esm/runtime/sheet.js +11 -11
  104. package/dist/esm/runtime/sheet.js.map +1 -1
  105. package/dist/esm/runtime/style-cache.js +6 -6
  106. package/dist/esm/runtime/style-cache.js.map +1 -1
  107. package/dist/esm/runtime/style.js +10 -10
  108. package/dist/esm/runtime/style.js.map +1 -1
  109. package/dist/esm/runtime.d.ts +1 -1
  110. package/dist/esm/runtime.js +1 -1
  111. package/dist/esm/runtime.js.flow +1 -1
  112. package/dist/esm/runtime.js.map +1 -1
  113. package/dist/esm/styled/index.js +3 -3
  114. package/dist/esm/styled/index.js.map +1 -1
  115. package/dist/esm/utils/error.js +18 -2
  116. package/dist/esm/utils/error.js.map +1 -1
  117. package/package.json +8 -4
  118. package/src/__tests__/browser.test.tsx +9 -9
  119. package/src/__tests__/server-side-hydrate.test.tsx +1 -1
  120. package/src/__tests__/ssr.test.tsx +7 -7
  121. package/src/global.d.ts +7 -0
  122. package/src/runtime/__perf__/ac.test.ts +97 -0
  123. package/src/runtime/__perf__/ax.test.ts +19 -17
  124. package/src/runtime/__tests__/ac.test.ts +112 -0
  125. package/src/runtime/__tests__/ax.test.ts +51 -65
  126. package/src/runtime/__tests__/style-ssr.test.tsx +1 -1
  127. package/src/runtime/ac.js.flow +56 -0
  128. package/src/runtime/ac.ts +143 -0
  129. package/src/runtime/index.js.flow +1 -0
  130. package/src/runtime/index.ts +12 -0
  131. package/src/runtime.js.flow +1 -1
  132. package/src/runtime.ts +1 -1
@@ -16,7 +16,7 @@ describe('server side hydrate', () => {
16
16
  jest.resetModules();
17
17
  // We need to force this module to re-instantiate because on the client
18
18
  // when it does it will move all found SSRd style elements to the head.
19
- require('../runtime');
19
+ require('../runtime/style-cache');
20
20
  };
21
21
 
22
22
  const appendHTML = (markup: string) => {
@@ -17,7 +17,7 @@ describe('SSR', () => {
17
17
  const result = renderToStaticMarkup(<StyledDiv>hello world</StyledDiv>);
18
18
 
19
19
  expect(result).toMatchInlineSnapshot(
20
- `"<style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1wyb1fwx{font-size:12px}</style><div class=\\"_1wyb1fwx\\">hello world</div>"`
20
+ `"<style data-cmpld="true" nonce="k0Mp1lEd">._1wyb1fwx{font-size:12px}</style><div class="_1wyb1fwx">hello world</div>"`
21
21
  );
22
22
  });
23
23
 
@@ -44,7 +44,7 @@ describe('SSR', () => {
44
44
  );
45
45
 
46
46
  expect(result).toMatchInlineSnapshot(
47
- `"<style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1wyb1fwx{font-size:12px}</style><div class=\\"_1wyb1fwx\\">hello world</div><div class=\\"_1wyb1fwx\\">hello world</div>"`
47
+ `"<style data-cmpld="true" nonce="k0Mp1lEd">._1wyb1fwx{font-size:12px}</style><div class="_1wyb1fwx">hello world</div><div class="_1wyb1fwx">hello world</div>"`
48
48
  );
49
49
  });
50
50
 
@@ -68,7 +68,7 @@ describe('SSR', () => {
68
68
  );
69
69
 
70
70
  expect(result).toMatchInlineSnapshot(
71
- `"<div><div><div><style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1wyb1fwx{font-size:12px}</style><div class=\\"_1wyb1fwx\\">hello world</div></div></div><div class=\\"_1wyb1fwx\\">hello world</div></div>"`
71
+ `"<div><div><div><style data-cmpld="true" nonce="k0Mp1lEd">._1wyb1fwx{font-size:12px}</style><div class="_1wyb1fwx">hello world</div></div></div><div class="_1wyb1fwx">hello world</div></div>"`
72
72
  );
73
73
  });
74
74
 
@@ -88,7 +88,7 @@ describe('SSR', () => {
88
88
  );
89
89
 
90
90
  expect(result).toMatchInlineSnapshot(
91
- `"<style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1e0c1txw{display:flex}</style><div class=\\"_1e0c1txw\\"><style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1wyb1fwx{font-size:12px}</style><div class=\\"_1wyb1fwx\\">hello world</div><div class=\\"_1wyb1fwx\\">hello world</div></div>"`
91
+ `"<style data-cmpld="true" nonce="k0Mp1lEd">._1e0c1txw{display:flex}</style><div class="_1e0c1txw"><style data-cmpld="true" nonce="k0Mp1lEd">._1wyb1fwx{font-size:12px}</style><div class="_1wyb1fwx">hello world</div><div class="_1wyb1fwx">hello world</div></div>"`
92
92
  );
93
93
  });
94
94
 
@@ -135,8 +135,8 @@ describe('SSR', () => {
135
135
  );
136
136
 
137
137
  expect(result.split('</style>').join('</style>\n')).toMatchInlineSnapshot(`
138
- "<style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1e0c1txw{display:flex}._1wyb12am{font-size:50px}._syaz1cnh{color:purple}._ysv75scu:link{color:red}._105332ev:visited{color:pink}._f8pjbf54:focus{color:green}._30l31gy6:hover{color:yellow}._9h8h13q2:active{color:blue}@supports (display:grid){._1df61gy6:focus{color:yellow}._7okp11x8:active{color:black}}@media (max-width:800px){._1o8z1gy6:focus{color:yellow}._1cld11x8:active{color:black}}</style>
139
- <a href=\\"https://atlassian.design\\" class=\\"_1e0c1txw _1wyb12am _syaz1cnh _30l31gy6 _9h8h13q2 _ysv75scu _1df61gy6 _7okp11x8 _f8pjbf54 _105332ev _1o8z1gy6 _1cld11x8\\">Atlassian Design System</a>"
138
+ "<style data-cmpld="true" nonce="k0Mp1lEd">._1e0c1txw{display:flex}._1wyb12am{font-size:50px}._syaz1cnh{color:purple}._ysv75scu:link{color:red}._105332ev:visited{color:pink}._f8pjbf54:focus{color:green}._30l31gy6:hover{color:yellow}._9h8h13q2:active{color:blue}@supports (display:grid){._1df61gy6:focus{color:yellow}._7okp11x8:active{color:black}}@media (max-width:800px){._1o8z1gy6:focus{color:yellow}._1cld11x8:active{color:black}}</style>
139
+ <a href="https://atlassian.design" class="_1e0c1txw _1wyb12am _syaz1cnh _30l31gy6 _9h8h13q2 _ysv75scu _1df61gy6 _7okp11x8 _f8pjbf54 _105332ev _1o8z1gy6 _1cld11x8">Atlassian Design System</a>"
140
140
  `);
141
141
  });
142
142
 
@@ -154,7 +154,7 @@ describe('SSR', () => {
154
154
  );
155
155
 
156
156
  expect(result).toMatchInlineSnapshot(
157
- `"<style data-cmpld=\\"true\\" nonce=\\"k0Mp1lEd\\">._1m9k13q2>span{color:blue}</style><div class=\\"_1m9k13q2\\"><span>hello world</span></div>"`
157
+ `"<style data-cmpld="true" nonce="k0Mp1lEd">._1m9k13q2>span{color:blue}</style><div class="_1m9k13q2"><span>hello world</span></div>"`
158
158
  );
159
159
  });
160
160
  });
@@ -0,0 +1,7 @@
1
+ export {};
2
+
3
+ declare global {
4
+ interface Window {
5
+ __COMPILED_IMPORTED__: undefined | true;
6
+ }
7
+ }
@@ -0,0 +1,97 @@
1
+ import { runBenchmark } from '@compiled/benchmark';
2
+
3
+ import { ac } from '../ac';
4
+ import ax from '../ax';
5
+
6
+ describe('ac vs ax benchmark', () => {
7
+ const arr = [
8
+ '_19itglyw',
9
+ '_2rko1l7b',
10
+ '_ca0qftgi',
11
+ '_u5f319bv',
12
+ '_n3tdftgi',
13
+ '_19bv19bv',
14
+ '_bfhk1mzw',
15
+ '_syazu67f',
16
+ '_k48p1nn1',
17
+ '_ect41kw7',
18
+ '_1wybdlk8',
19
+ '_irr3mlcl',
20
+ '_1di6vctu',
21
+ // `undefined` is an acceptable parameter so we want to include it in the test case.
22
+ // Example: ax(['aaaabbbb', foo() && "aaaacccc"])
23
+ undefined,
24
+ ];
25
+
26
+ // Remove undefined and join the strings
27
+ const str = arr.slice(0, -1).join(' ');
28
+
29
+ const arrWithCompressedClassNames = arr.map((item) =>
30
+ item ? `${item.slice(0, 4)}_${item.slice(8)}` : item
31
+ );
32
+
33
+ const strWithCompressedClassNames = arr
34
+ .map((item) => (item ? `${item.slice(0, 4)}_${item.slice(8)}` : item))
35
+ .slice(0, -1)
36
+ .join(' ');
37
+
38
+ it('compares ax array with ac array', async () => {
39
+ // Remove undefined and join the strings
40
+ const benchmark = await runBenchmark('ax', [
41
+ {
42
+ name: 'ax() array',
43
+ fn: () => ax(arr),
44
+ },
45
+ {
46
+ name: 'ac() array with compressed class names',
47
+ fn: () => {
48
+ ac(arrWithCompressedClassNames)?.toString();
49
+ },
50
+ },
51
+ ]);
52
+
53
+ expect(benchmark).toMatchObject({
54
+ fastest: ['ax() array'],
55
+ });
56
+ }, 30000);
57
+
58
+ it('compares ax string with ac string', async () => {
59
+ // Remove undefined and join the strings
60
+ const benchmark = await runBenchmark('ax', [
61
+ {
62
+ name: 'ax() string',
63
+ fn: () => ax([str, undefined]),
64
+ },
65
+ {
66
+ name: 'ac() string with compressed class names',
67
+ fn: () => {
68
+ ac([strWithCompressedClassNames, undefined])?.toString();
69
+ },
70
+ },
71
+ ]);
72
+
73
+ expect(benchmark).toMatchObject({
74
+ fastest: ['ax() string'],
75
+ });
76
+ }, 30000);
77
+
78
+ it('compares chaining ax with chaining ac', async () => {
79
+ // Remove undefined and join the strings
80
+ const benchmark = await runBenchmark('ax', [
81
+ {
82
+ name: 'chain ax() string',
83
+ fn: () => ax([ax([str, undefined]), '_aaaabbbb']),
84
+ },
85
+ {
86
+ name: 'chain ac() string with compressed class names',
87
+ fn: () => {
88
+ ac([ac([strWithCompressedClassNames, undefined]), '_aaaa_a'])?.toString();
89
+ },
90
+ },
91
+ ]);
92
+
93
+ expect(benchmark).toMatchObject({
94
+ fastest: ['chain ac() string with compressed class names'],
95
+ });
96
+ }, 30000);
97
+ });
@@ -3,24 +3,26 @@ import { runBenchmark } from '@compiled/benchmark';
3
3
  import { ax } from '../index';
4
4
 
5
5
  describe('ax benchmark', () => {
6
- it('completes with ax() string as the fastest', async () => {
7
- const arr = [
8
- '_19itglyw',
9
- '_2rko1l7b',
10
- '_ca0qftgi',
11
- '_u5f319bv',
12
- '_n3tdftgi',
13
- '_19bv19bv',
14
- '_bfhk1mzw',
15
- '_syazu67f',
16
- '_k48p1nn1',
17
- '_ect41kw7',
18
- '_1wybdlk8',
19
- '_irr3mlcl',
20
- '_1di6vctu',
21
- undefined,
22
- ];
6
+ const arr = [
7
+ '_19itglyw',
8
+ '_2rko1l7b',
9
+ '_ca0qftgi',
10
+ '_u5f319bv',
11
+ '_n3tdftgi',
12
+ '_19bv19bv',
13
+ '_bfhk1mzw',
14
+ '_syazu67f',
15
+ '_k48p1nn1',
16
+ '_ect41kw7',
17
+ '_1wybdlk8',
18
+ '_irr3mlcl',
19
+ '_1di6vctu',
20
+ // `undefined` is an acceptable parameter so we want to include it in the test case.
21
+ // Example: ax(['aaaabbbb', foo() && "aaaacccc"])
22
+ undefined,
23
+ ];
23
24
 
25
+ it('completes with ax() string as the fastest', async () => {
24
26
  // Remove undefined and join the strings
25
27
  const str = arr.slice(0, -1).join(' ');
26
28
 
@@ -0,0 +1,112 @@
1
+ import { ac, memoizedAc, getCache } from '../ac';
2
+
3
+ describe('ac', () => {
4
+ const isEnabled: boolean = (() => false)();
5
+
6
+ it.each([
7
+ ['should handle empty array', [], undefined],
8
+ ['should handle array with undefined', [undefined], undefined],
9
+ ['should join single classes together', ['foo', 'bar'], 'foo bar'],
10
+ ['should join multi classes together', ['foo baz', 'bar'], 'foo baz bar'],
11
+ ['should remove undefined', ['foo', 'bar', undefined], 'foo bar'],
12
+ [
13
+ 'should ensure the last atomic declaration of a single group wins',
14
+ ['_aaaabbbb', '_aaaacccc'],
15
+ '_aaaacccc',
16
+ ],
17
+ [
18
+ 'should ensure the last atomic declaration of a single group with short class name wins',
19
+ ['_aaaabbbb', '_aaaacccc', '_aaaa_a'],
20
+ 'a',
21
+ ],
22
+ [
23
+ 'should ensure the last atomic declaration of many single groups wins',
24
+ ['_aaaabbbb', '_aaaacccc', '_aaaadddd', '_aaaaeeee'],
25
+ '_aaaaeeee',
26
+ ],
27
+ [
28
+ 'should ensure the last atomic declaration of many single groups with short class name wins',
29
+ ['_aaaabbbb', '_aaaacccc', '_aaaa_a', '_aaaa_b'],
30
+ 'b',
31
+ ],
32
+ [
33
+ 'should ensure the last atomic declaration of a multi group wins',
34
+ ['_aaaabbbb _aaaacccc'],
35
+ '_aaaacccc',
36
+ ],
37
+ [
38
+ 'should ensure the last atomic declaration of a multi group with short class name wins',
39
+ ['_aaaa_e', '_aaaabbbb _aaaacccc'],
40
+ '_aaaacccc',
41
+ ],
42
+ [
43
+ 'should ensure the last atomic declaration of many multi groups wins',
44
+ ['_aaaabbbb _aaaacccc _aaaadddd _aaaaeeee'],
45
+ '_aaaaeeee',
46
+ ],
47
+ [
48
+ 'should ensure the last atomic declaration of many multi groups with short class name wins',
49
+ ['_aaaabbbb', '_aaaa_a', '_bbbb_b', '_ddddcccc'],
50
+ 'a b _ddddcccc',
51
+ ],
52
+ [
53
+ 'should not remove any atomic declarations if there are no duplicate groups',
54
+ ['_aaaabbbb', '_bbbbcccc'],
55
+ '_aaaabbbb _bbbbcccc',
56
+ ],
57
+ [
58
+ 'should not remove any atomic declarations if there are short class name and no duplicate groups',
59
+ ['_eeee_e', '_aaaabbbb', '_bbbbcccc'],
60
+ 'e _aaaabbbb _bbbbcccc',
61
+ ],
62
+ ['should not apply conditional class', [isEnabled && 'foo', 'bar'], 'bar'],
63
+ [
64
+ 'should ignore non atomic declarations',
65
+ ['hello_there', 'hello_world'],
66
+ 'hello_there hello_world',
67
+ ],
68
+ [
69
+ 'should ignore non atomic declarations when atomic declarations exist',
70
+ ['hello_there', 'hello_world', '_aaaabbbb'],
71
+ 'hello_there hello_world _aaaabbbb',
72
+ ],
73
+ [
74
+ 'should ignore non atomic declarations when atomic declarations with short class name exist',
75
+ ['hello_there', 'hello_world', '_aaaa_a'],
76
+ 'hello_there hello_world a',
77
+ ],
78
+ ])('%s', (_, params, result) => {
79
+ expect(result).toEqual(ac(params)?.toString());
80
+ });
81
+
82
+ it('should ensure the last atomic declaration wins if calling ax multiple times with short class names', () => {
83
+ expect(ac([ac(['_aaaa_b']), '_aaaa_c'])?.toString()).toEqual('c');
84
+ });
85
+ });
86
+
87
+ describe('memoizedAc', () => {
88
+ it('should cache correctly', () => {
89
+ memoizedAc([memoizedAc(['_aaaa_b', '_aaaabbbb', 'hello_world']), '_bbbb_d', '_aaaa_e']);
90
+
91
+ expect(getCache()).toMatchInlineSnapshot(`
92
+ Map {
93
+ "_aaaa_b _aaaabbbb hello_world" => AtomicGroups {
94
+ "values": Map {
95
+ "_aaaa" => "_aaaabbbb",
96
+ "hello_world" => "hello_world",
97
+ },
98
+ },
99
+ "_aaaabbbb hello_world _bbbb_d _aaaa_e" => AtomicGroups {
100
+ "values": Map {
101
+ "_aaaa" => "e",
102
+ "hello_world" => "hello_world",
103
+ "_bbbb" => "d",
104
+ },
105
+ },
106
+ }
107
+ `);
108
+ });
109
+ it('should not create a new ref', () => {
110
+ expect(memoizedAc(['a'])).toBe(memoizedAc(['a']));
111
+ });
112
+ });
@@ -1,70 +1,56 @@
1
1
  import ax from '../ax';
2
2
 
3
3
  describe('ax', () => {
4
- it('should join single classes together', () => {
5
- const result = ax(['foo', 'bar']);
6
-
7
- expect(result).toEqual('foo bar');
8
- });
9
-
10
- it('should join multi classes together', () => {
11
- const result = ax(['foo baz', 'bar']);
12
-
13
- expect(result).toEqual('foo baz bar');
14
- });
15
-
16
- it('should remove undefined', () => {
17
- const result = ax(['foo', 'bar', undefined]);
18
-
19
- expect(result).toEqual('foo bar');
20
- });
21
-
22
- it('should ensure the last atomic declaration of a single group wins', () => {
23
- const result = ax(['_aaaabbbb', '_aaaacccc']);
24
-
25
- expect(result).toEqual('_aaaacccc');
26
- });
27
-
28
- it('should ensure the last atomic declaration of many single groups wins', () => {
29
- const result = ax(['_aaaabbbb', '_aaaacccc', '_aaaadddd', '_aaaaeeee']);
30
-
31
- expect(result).toEqual('_aaaaeeee');
32
- });
33
-
34
- it('should ensure the last atomic declaration of a multi group wins', () => {
35
- const result = ax(['_aaaabbbb _aaaacccc']);
36
-
37
- expect(result).toEqual('_aaaacccc');
38
- });
39
-
40
- it('should ensure the last atomic declaration of many multi groups wins', () => {
41
- const result = ax(['_aaaabbbb _aaaacccc _aaaadddd _aaaaeeee']);
42
-
43
- expect(result).toEqual('_aaaaeeee');
44
- });
45
-
46
- it('should not remove any atomic declarations if there are no duplicate groups', () => {
47
- const result = ax(['_aaaabbbb', '_bbbbcccc']);
48
-
49
- expect(result).toEqual('_aaaabbbb _bbbbcccc');
50
- });
51
-
52
- it('should not apply conditional class', () => {
53
- const isEnabled: boolean = (() => false)();
54
- const result = ax([isEnabled && 'foo', 'bar']);
55
-
56
- expect(result).toEqual('bar');
57
- });
58
-
59
- it('should ignore non atomic declarations', () => {
60
- const result = ax(['hello_there', 'hello_world']);
61
-
62
- expect(result).toEqual('hello_there hello_world');
63
- });
64
-
65
- it('should ignore non atomic declarations when atomic declarations exist', () => {
66
- const result = ax(['hello_there', 'hello_world', '_aaaabbbb']);
67
-
68
- expect(result).toEqual('hello_there hello_world _aaaabbbb');
4
+ const isEnabled: boolean = (() => false)();
5
+
6
+ it.each([
7
+ ['should handle empty array', [], undefined],
8
+ ['should handle array with undefined', [undefined], undefined],
9
+ ['should join single classes together', ['foo', 'bar'], 'foo bar'],
10
+ ['should join multi classes together', ['foo baz', 'bar'], 'foo baz bar'],
11
+ ['should remove undefined', ['foo', 'bar', undefined], 'foo bar'],
12
+ [
13
+ 'should ensure the last atomic declaration of a single group wins',
14
+ ['_aaaabbbb', '_aaaacccc'],
15
+ '_aaaacccc',
16
+ ],
17
+ [
18
+ 'should ensure the last atomic declaration of many single groups wins',
19
+ ['_aaaabbbb', '_aaaacccc', '_aaaadddd', '_aaaaeeee'],
20
+ '_aaaaeeee',
21
+ ],
22
+ [
23
+ 'should ensure the last atomic declaration of a multi group wins',
24
+ ['_aaaabbbb _aaaacccc'],
25
+ '_aaaacccc',
26
+ ],
27
+ [
28
+ 'should ensure the last atomic declaration of many multi groups wins',
29
+ ['_aaaabbbb _aaaacccc _aaaadddd _aaaaeeee'],
30
+ '_aaaaeeee',
31
+ ],
32
+ [
33
+ 'should ensure the last atomic declaration of many multi groups with short class name wins',
34
+ ['_aaaabbbb', '_aaaaaaa', '_ddddbbb', '_ddddcccc'],
35
+ '_aaaaaaa _ddddcccc',
36
+ ],
37
+ [
38
+ 'should not remove any atomic declarations if there are no duplicate groups',
39
+ ['_aaaabbbb', '_bbbbcccc'],
40
+ '_aaaabbbb _bbbbcccc',
41
+ ],
42
+ ['should not apply conditional class', [isEnabled && 'foo', 'bar'], 'bar'],
43
+ [
44
+ 'should ignore non atomic declarations',
45
+ ['hello_there', 'hello_world'],
46
+ 'hello_there hello_world',
47
+ ],
48
+ [
49
+ 'should ignore non atomic declarations when atomic declarations exist',
50
+ ['hello_there', 'hello_world', '_aaaabbbb'],
51
+ 'hello_there hello_world _aaaabbbb',
52
+ ],
53
+ ])('%s', (_, params, result) => {
54
+ expect(result).toEqual(ax(params));
69
55
  });
70
56
  });
@@ -48,7 +48,7 @@ describe('<Style />', () => {
48
48
  );
49
49
 
50
50
  expect(result.split('</style>').join('</style>\n')).toMatchInlineSnapshot(`
51
- "<style data-cmpld=\\"true\\">._c1234567{ display: block; }._d1234567:link{ color: green; }._g1234567:visited{ color: grey; }._i1234567:focus-within{ color: black; }._f1234567:focus{ color: pink; }._h1234567:focus-visible{ color: white; }._a1234567:hover{ color: red; }._b1234567:active{ color: blue; }@media (max-width: 800px){ ._e1234567{ color: yellow; } }</style>
51
+ "<style data-cmpld="true">._c1234567{ display: block; }._d1234567:link{ color: green; }._g1234567:visited{ color: grey; }._i1234567:focus-within{ color: black; }._f1234567:focus{ color: pink; }._h1234567:focus-visible{ color: white; }._a1234567:hover{ color: red; }._b1234567:active{ color: blue; }@media (max-width: 800px){ ._e1234567{ color: yellow; } }</style>
52
52
  "
53
53
  `);
54
54
  });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Flowtype definitions for ac
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.20.1
5
+ * @flow
6
+ */
7
+ /**
8
+ * Memoize the result of ac so if it is called with the same args, it returns immediately.
9
+ * Also, to prevent useless React rerenders
10
+ */
11
+ declare var cache: Map<any, any>;
12
+ /**
13
+ * `ac` returns an instance of AtomicGroups. The instance holds the knowledge of Atomic Group so we can chain `ac`.
14
+ * e.g. <div className={ax([ax(['_aaaa_b']), '_aaaa_c'])} />
15
+ */
16
+ declare class AtomicGroups {
17
+ values: Map<string, string>;
18
+ constructor(values: Map<string, string>): this;
19
+ toString(): string;
20
+ }
21
+ /**
22
+ * Joins classes together and ensures atomic declarations of a single group exist.
23
+ * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
24
+ * where both `group` and `value` are hashes **four characters long**.
25
+ * Class names can be of any length,
26
+ * this function can take both atomic declarations and class names.
27
+ *
28
+ * Input:
29
+ *
30
+ * ```
31
+ * ax(['_aaaabbbb', '_aaaacccc'])
32
+ * ```
33
+ *
34
+ * Output:
35
+ *
36
+ * ```
37
+ * '_aaaacccc'
38
+ * ```
39
+ * @param classes
40
+ */
41
+ declare export function ac(
42
+ classNames: (AtomicGroups | string | void | false)[]
43
+ ): AtomicGroups | void;
44
+ declare export function memoizedAc(
45
+ classNames: (AtomicGroups | string | void | false)[]
46
+ ): AtomicGroups | void;
47
+ declare var _default: typeof ac;
48
+ declare export default typeof _default;
49
+ /**
50
+ * Provide an opportunity to clear the cache to prevent memory leak.
51
+ */
52
+ declare export function clearCache(): void;
53
+ /**
54
+ * Expose cache
55
+ */
56
+ declare export function getCache(): typeof cache;
@@ -0,0 +1,143 @@
1
+ import { isServerEnvironment } from './is-server-environment';
2
+
3
+ const UNDERSCORE_UNICODE = 95;
4
+
5
+ /**
6
+ * This length includes the underscore,
7
+ * e.g. `"_1s4A"` would be a valid atomic group hash.
8
+ */
9
+ const ATOMIC_GROUP_LENGTH = 5;
10
+
11
+ /**
12
+ * Memoize the result of ac so if it is called with the same args, it returns immediately.
13
+ * Also, to prevent useless React rerenders
14
+ */
15
+ const cache = new Map();
16
+
17
+ /**
18
+ * `ac` returns an instance of AtomicGroups. The instance holds the knowledge of Atomic Group so we can chain `ac`.
19
+ * e.g. <div className={ax([ax(['_aaaa_b']), '_aaaa_c'])} />
20
+ */
21
+ class AtomicGroups {
22
+ values: Map<string, string>;
23
+ constructor(values: Map<string, string>) {
24
+ // An object stores the relation between Atomic group and actual class name
25
+ // e.g. { "aaaa": "a" } `aaaa` is the Atomic group and `a` is the actual class name
26
+ this.values = values;
27
+ }
28
+ toString() {
29
+ let str = '';
30
+
31
+ for (const [, value] of this.values) {
32
+ str += value + ' ';
33
+ }
34
+
35
+ return str.slice(0, -1);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Joins classes together and ensures atomic declarations of a single group exist.
41
+ * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
42
+ * where both `group` and `value` are hashes **four characters long**.
43
+ * Class names can be of any length,
44
+ * this function can take both atomic declarations and class names.
45
+ *
46
+ * Input:
47
+ *
48
+ * ```
49
+ * ax(['_aaaabbbb', '_aaaacccc'])
50
+ * ```
51
+ *
52
+ * Output:
53
+ *
54
+ * ```
55
+ * '_aaaacccc'
56
+ * ```
57
+ *
58
+ * @param classes
59
+ */
60
+ export function ac(
61
+ classNames: (AtomicGroups | string | undefined | false)[]
62
+ ): AtomicGroups | undefined {
63
+ // short circuit if there's no class names.
64
+ if (classNames.length <= 1 && !classNames[0]) return undefined;
65
+
66
+ const atomicGroups: Map<string, string> = new Map();
67
+
68
+ for (let i = 0; i < classNames.length; i++) {
69
+ const cls = classNames[i];
70
+ if (!cls) {
71
+ continue;
72
+ }
73
+
74
+ if (typeof cls === 'string') {
75
+ const groups = cls.split(' ');
76
+
77
+ for (let x = 0; x < groups.length; x++) {
78
+ const atomic = groups[x];
79
+ const isAtomic = atomic.charCodeAt(0) === UNDERSCORE_UNICODE;
80
+ const isCompressed = isAtomic && atomic.charCodeAt(5) === UNDERSCORE_UNICODE;
81
+
82
+ const atomicGroupName = isAtomic ? atomic.slice(0, ATOMIC_GROUP_LENGTH) : atomic;
83
+ atomicGroups.set(
84
+ atomicGroupName,
85
+ isCompressed ? atomic.slice(ATOMIC_GROUP_LENGTH + 1) : atomic
86
+ );
87
+ }
88
+ } else {
89
+ // if cls is an instance of AtomicGroups, transfer its values to `atomicGroups`
90
+ for (const [key, value] of cls.values) {
91
+ atomicGroups.set(key, value);
92
+ }
93
+ }
94
+ }
95
+
96
+ return new AtomicGroups(atomicGroups);
97
+ }
98
+
99
+ export function memoizedAc(
100
+ classNames: (AtomicGroups | string | undefined | false)[]
101
+ ): AtomicGroups | undefined {
102
+ // short circuit if there's no class names.
103
+ if (classNames.length <= 1 && !classNames[0]) return undefined;
104
+
105
+ // build the cacheKey based on the function argument
106
+ // e.g. if the argument is ["_aaaabbbb", "_aaaa_a", "some-class-name"],
107
+ // then the cacheKey is "_aaaabbbb _aaaa_a some-class-name"
108
+ let cacheKey = '';
109
+ for (let i = 0; i < classNames.length; i += 1) {
110
+ const current = classNames[i];
111
+ // continue if current is undefined, false, or ""
112
+ if (!current) continue;
113
+ cacheKey += current + ' ';
114
+ }
115
+
116
+ cacheKey = cacheKey.slice(0, -1);
117
+
118
+ if (cache.has(cacheKey)) return cache.get(cacheKey);
119
+
120
+ const result = ac(classNames);
121
+
122
+ cache.set(cacheKey, result);
123
+
124
+ return result;
125
+ }
126
+
127
+ // Memoization is primarily used to prevent React from unncessary re-rendering.
128
+ // Use unmemoizedAc on server-side because We don't need to worry about re-rendering on server-side.
129
+ export default isServerEnvironment() ? ac : memoizedAc;
130
+
131
+ /**
132
+ * Provide an opportunity to clear the cache to prevent memory leak.
133
+ */
134
+ export function clearCache(): void {
135
+ cache.clear();
136
+ }
137
+
138
+ /**
139
+ * Expose cache
140
+ */
141
+ export function getCache(): typeof cache {
142
+ return cache;
143
+ }
@@ -7,4 +7,5 @@
7
7
  declare export { default as CS } from './style';
8
8
  declare export { default as CC } from './style-cache';
9
9
  declare export { default as ax } from './ax';
10
+ declare export { default as ac, clearCache as clearAcCache } from './ac';
10
11
  declare export { default as ix } from './css-custom-property';