@acusti/styling 1.0.0-rc.0 → 1.0.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.
package/README.md CHANGED
@@ -5,13 +5,26 @@
5
5
  [![bundle size](https://img.shields.io/bundlephobia/minzip/@acusti/styling?style=for-the-badge)](https://bundlephobia.com/package/@acusti/styling)
6
6
  [![downloads per month](https://img.shields.io/npm/dm/@acusti/styling?style=for-the-badge)](https://www.npmjs.com/package/@acusti/styling)
7
7
 
8
- Exports `Style`, which is a React component that renders a CSS style string
9
- as a `<style>` element in the `<head>` of the document optionally specified
10
- by `props.ownerDocument`. Keeps a per-document global registry of styles
11
- being rendered so that the same string of CSS will only be rendered as a
12
- single `<style>` element, no matter how many times the `<Style>` element
13
- with that string appears in the React component tree.
8
+ This package exports `Style`, which is a React component that takes a CSS
9
+ string as its children, minifies it, and renders it using the react v19+
10
+ `<style>` element’s
11
+ [special rendering behavior](https://react.dev/reference/react-dom/components/style#special-rendering-behavior):
14
12
 
15
- Also exports useful CSS string literals, such as `SYSTEM_UI_FONT` which can
16
- be used as `font-family: ${SYSTEM_UI_FONT};` to specify the appropriate UI
17
- font for the current OS and browser.
13
+ > React will move `<style>` components to the document’s `<head>`,
14
+ > de-duplicate identical stylesheets, and suspend while the stylesheet is
15
+ > loading.
16
+
17
+ This behavior is SSR-friendly (no server hydration errors), and the
18
+ suspense behavior ensures any assets used by the CSS styles that must be
19
+ fetched and parsed (e.g. fonts or images) can do so with a loading behavior
20
+ as-good or better than the way regular CSS stylesheets or inline styles are
21
+ handled by the browser.
22
+
23
+ The CSS minification means that insignifant differences between styles
24
+ (e.g. varying whitespace or empty declarations) won’t result in sthyle
25
+ duplication. Also, the component maintains an internal global cache of the
26
+ minified styles to avoid unnecessary re-calculations.
27
+
28
+ Lastly, this package exports useful CSS string literals, such as
29
+ `SYSTEM_UI_FONT` which can be used as `font-family: ${SYSTEM_UI_FONT};` to
30
+ specify the appropriate UI font for the current OS and browser.
package/dist/Style.js CHANGED
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
1
  import React from 'react';
3
2
  import { useStyles } from './useStyles.js';
4
3
  const Style = ({ children, href: _href, precedence = 'medium' }) => {
@@ -6,11 +5,7 @@ const Style = ({ children, href: _href, precedence = 'medium' }) => {
6
5
  const { href, styles } = useStyles(children, _href);
7
6
  // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/canary.d.ts
8
7
  // https://react.dev/reference/react-dom/components/style#props
9
- return (
10
- // @ts-expect-error @types/react is missing new <style> props
11
- // eslint-disable-next-line react/no-unknown-property
12
- React.createElement('style', { href: href, precedence: precedence }, styles)
13
- );
8
+ return (React.createElement("style", { href: href, precedence: precedence }, styles));
14
9
  };
15
10
  export default Style;
16
- //# sourceMappingURL=Style.js.map
11
+ //# sourceMappingURL=Style.js.map
package/dist/Style.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Style.js","sourceRoot":"","sources":["../src/Style.tsx"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQ3C,MAAM,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAS,EAAE,EAAE;IACtE,gFAAgF;IAChF,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACpD,yFAAyF;IACzF,+DAA+D;IAC/D,OAAO;IACH,6DAA6D;IAC7D,qDAAqD;IACrD,+BAAO,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,IACpC,MAAM,CACH,CACX,CAAC;AACN,CAAC,CAAC;AAEF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Style.js","sourceRoot":"","sources":["../src/Style.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQ3C,MAAM,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAS,EAAE,EAAE;IACtE,gFAAgF;IAChF,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACpD,yFAAyF;IACzF,+DAA+D;IAC/D,OAAO,CACH,+BAAO,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,IACpC,MAAM,CACH,CACX,CAAC;AACN,CAAC,CAAC;AAEF,eAAe,KAAK,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export { default as Style } from './Style.js';
2
- export declare const SYSTEM_UI_FONT =
3
- '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif';
2
+ export declare const SYSTEM_UI_FONT = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif";
package/dist/index.js CHANGED
@@ -1,5 +1,3 @@
1
- /// <reference types="react/canary" />
2
1
  export { default as Style } from './Style.js';
3
- export const SYSTEM_UI_FONT =
4
- '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif';
5
- //# sourceMappingURL=index.js.map
2
+ export const SYSTEM_UI_FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif';
3
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,CAAC,MAAM,cAAc,GACvB,qHAAqH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,CAAC,MAAM,cAAc,GACvB,qHAAqH,CAAC"}
@@ -26,12 +26,7 @@ export function minifyStyles(css) {
26
26
  const preservedTokens = [];
27
27
  const comments = [];
28
28
  const totalLength = css.length;
29
- let startIndex = 0,
30
- endIndex = 0,
31
- i = 0,
32
- max = 0,
33
- token = '',
34
- placeholder = '';
29
+ let startIndex = 0, endIndex = 0, token = '', placeholder = '';
35
30
  // collect all comment blocks...
36
31
  while ((startIndex = css.indexOf('/*', startIndex)) >= 0) {
37
32
  endIndex = css.indexOf('*/', startIndex + 2);
@@ -42,44 +37,35 @@ export function minifyStyles(css) {
42
37
  comments.push(token);
43
38
  css =
44
39
  css.slice(0, startIndex + 2) +
45
- '___PRESERVE_CANDIDATE_COMMENT_' +
46
- (comments.length - 1) +
47
- '___' +
48
- css.slice(endIndex);
40
+ '___PRESERVE_CANDIDATE_COMMENT_' +
41
+ (comments.length - 1) +
42
+ '___' +
43
+ css.slice(endIndex);
49
44
  startIndex += 2;
50
45
  }
51
46
  // preserve strings so their content doesn't get accidentally minified
52
47
  css = css.replace(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/g, function (match) {
53
48
  const quote = match.substring(0, 1);
54
- let i, max;
55
49
  match = match.slice(1, -1);
56
50
  // maybe the string contains a comment-like substring?
57
51
  // one, maybe more? put'em back then
58
52
  if (match.indexOf('___PRESERVE_CANDIDATE_COMMENT_') >= 0) {
59
- for (i = 0, max = comments.length; i < max; i = i + 1) {
60
- match = match.replace(
61
- '___PRESERVE_CANDIDATE_COMMENT_' + i + '___',
62
- comments[i],
63
- );
53
+ for (let i = 0, max = comments.length; i < max; i++) {
54
+ match = match.replace('___PRESERVE_CANDIDATE_COMMENT_' + i + '___', comments[i]);
64
55
  }
65
56
  }
66
57
  preservedTokens.push(match);
67
- return (
68
- quote + '___PRESERVED_TOKEN_' + (preservedTokens.length - 1) + '___' + quote
69
- );
58
+ return (quote + '___PRESERVED_TOKEN_' + (preservedTokens.length - 1) + '___' + quote);
70
59
  });
71
60
  // strings are safe, now wrestle the comments
72
- for (i = 0, max = comments.length; i < max; i = i + 1) {
61
+ for (let i = 0, max = comments.length; i < max; i = i + 1) {
73
62
  token = comments[i];
74
63
  placeholder = '___PRESERVE_CANDIDATE_COMMENT_' + i + '___';
75
64
  // ! in the first position of the comment means preserve
76
65
  // so push to the preserved tokens keeping the !
77
66
  if (token.charAt(0) === '!') {
78
67
  preservedTokens.push(token);
79
- css = css.replace(
80
- placeholder,
81
- '___PRESERVED_TOKEN_' + (preservedTokens.length - 1) + '___',
82
- );
68
+ css = css.replace(placeholder, '___PRESERVED_TOKEN_' + (preservedTokens.length - 1) + '___');
83
69
  continue;
84
70
  }
85
71
  // otherwise, kill the comment
@@ -121,31 +107,25 @@ export function minifyStyles(css) {
121
107
  css = css.replace(/:0 0(;|\})/g, ':0$1');
122
108
  // Replace background-position:0; with background-position:0 0;
123
109
  // same for transform-origin
124
- css = css.replace(
125
- /(background-position|transform-origin):0(;|\})/gi,
126
- function (_all, prop, tail) {
127
- return prop.toLowerCase() + ':0 0' + tail;
128
- },
129
- );
110
+ css = css.replace(/(background-position|transform-origin):0(;|\})/gi, function (_all, prop, tail) {
111
+ return prop.toLowerCase() + ':0 0' + tail;
112
+ });
130
113
  // Replace 0.6 to .6, but only when preceded by : or a white-space
131
114
  css = css.replace(/(:|\s)0+\.(\d+)/g, '$1.$2');
132
115
  // border: none -> border:0
133
- css = css.replace(
134
- /(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|\})/gi,
135
- function (_all, prop, tail) {
136
- return prop.toLowerCase() + ':0' + tail;
137
- },
138
- );
116
+ css = css.replace(/(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|\})/gi, function (_all, prop, tail) {
117
+ return prop.toLowerCase() + ':0' + tail;
118
+ });
139
119
  // Remove empty rules.
140
120
  css = css.replace(/[^};{/]+\{\}/g, '');
141
121
  // Replace multiple semi-colons in a row by a single one
142
122
  // See SF bug #1980989
143
123
  css = css.replace(/;;+/g, ';');
144
124
  // restore preserved comments and strings
145
- for (i = 0, max = preservedTokens.length; i < max; i = i + 1) {
125
+ for (let i = 0, max = preservedTokens.length; i < max; i = i + 1) {
146
126
  css = css.replace('___PRESERVED_TOKEN_' + i + '___', preservedTokens[i]);
147
127
  }
148
128
  return css.trim();
149
129
  }
150
130
  export default minifyStyles;
151
- //# sourceMappingURL=minifyStyles.js.map
131
+ //# sourceMappingURL=minifyStyles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"minifyStyles.js","sourceRoot":"","sources":["../src/minifyStyles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"minifyStyles.js","sourceRoot":"","sources":["../src/minifyStyles.ts"],"names":[],"mappings":"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"}
@@ -3,30 +3,30 @@ import { minifyStyles } from './minifyStyles.js';
3
3
  describe('@acusti/styling', () => {
4
4
  describe('minifyStyles.ts', () => {
5
5
  it('minifies basic CSS declarations', () => {
6
- expect(
7
- minifyStyles(`
6
+ expect(minifyStyles(`
8
7
  .foo {
9
8
  padding: 10px;
10
9
  color: red;
11
- }`),
12
- ).toBe('.foo{padding:10px;color:red}');
10
+ }`)).toBe('.foo{padding:10px;color:red}');
13
11
  });
14
12
  it('preserves whitespace where needed in selectors', () => {
15
- expect(
16
- minifyStyles(`
13
+ expect(minifyStyles(`
17
14
  .foo > .bar :hover {
18
15
  background-color: cyan;
19
- }`),
20
- ).toBe('.foo>.bar :hover{background-color:cyan}');
16
+ }`)).toBe('.foo>.bar :hover{background-color:cyan}');
21
17
  });
22
18
  it('minifies 0.6 to .6, but only when preceded by : or a whitespace', () => {
23
- expect(
24
- minifyStyles(`
19
+ expect(minifyStyles(`
25
20
  .foo {
26
21
  opacity: 0.6;
27
- }`),
28
- ).toBe('.foo{opacity:.6}');
22
+ }`)).toBe('.foo{opacity:.6}');
23
+ });
24
+ it('strips out comments', () => {
25
+ expect(minifyStyles(`
26
+ .bar {
27
+ font-weight: 900;/*.bar is so *strong**/
28
+ }`)).toBe('.bar{font-weight:900}');
29
29
  });
30
30
  });
31
31
  });
32
- //# sourceMappingURL=minifyStyles.test.js.map
32
+ //# sourceMappingURL=minifyStyles.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"minifyStyles.test.js","sourceRoot":"","sources":["../src/minifyStyles.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACvC,MAAM,CACF,YAAY,CAAC;;;;EAI3B,CAAC,CACU,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACtD,MAAM,CACF,YAAY,CAAC;;;EAG3B,CAAC,CACU,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACvE,MAAM,CACF,YAAY,CAAC;;;EAG3B,CAAC,CACU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"minifyStyles.test.js","sourceRoot":"","sources":["../src/minifyStyles.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACvC,MAAM,CACF,YAAY,CAAC;;;;EAI3B,CAAC,CACU,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACtD,MAAM,CACF,YAAY,CAAC;;;EAG3B,CAAC,CACU,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACvE,MAAM,CACF,YAAY,CAAC;;;EAG3B,CAAC,CACU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC3B,MAAM,CACF,YAAY,CAAC;;;EAG3B,CAAC,CACU,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -1,19 +1,12 @@
1
- type StyleRegistry = Map<
2
- string,
3
- {
4
- href: string;
5
- referenceCount: number;
6
- styles: string;
7
- }
8
- >;
9
- export declare const getStyleRegistry: () => StyleRegistry;
10
- export declare function useStyles(
11
- styles: string,
12
- initialHref?: string,
13
- ): {
1
+ type StyleCache = Map<string, {
2
+ href: string;
3
+ referenceCount: number;
4
+ styles: string;
5
+ }>;
6
+ export declare function useStyles(styles: string, initialHref?: string): {
14
7
  href: string;
15
8
  referenceCount: number;
16
9
  styles: string;
17
10
  };
18
11
  export default useStyles;
19
- export declare const clearRegistry: () => void;
12
+ export declare const getStyleCache: () => StyleCache;
package/dist/useStyles.js CHANGED
@@ -1,48 +1,43 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { minifyStyles } from './minifyStyles.js';
3
- const styleRegistry = new Map();
4
- export const getStyleRegistry = () => styleRegistry;
3
+ const styleCache = new Map();
4
+ const EMPTY_STYLES_ITEM = { href: '', referenceCount: 0, styles: '' };
5
5
  export function useStyles(styles, initialHref) {
6
6
  const [stylesItem, setStylesItem] = useState(() => {
7
- if (!styles) return { href: '', referenceCount: 0, styles: '' };
7
+ if (!styles)
8
+ return EMPTY_STYLES_ITEM;
8
9
  const key = initialHref !== null && initialHref !== void 0 ? initialHref : styles;
9
- let item = styleRegistry.get(key);
10
+ let item = styleCache.get(key);
10
11
  if (item) {
11
12
  item.referenceCount++;
12
- } else {
13
+ }
14
+ else {
13
15
  const minified = minifyStyles(styles);
14
16
  item = {
15
- href: sanitizeHref(
16
- initialHref !== null && initialHref !== void 0
17
- ? initialHref
18
- : minified,
19
- ),
17
+ href: sanitizeHref(initialHref !== null && initialHref !== void 0 ? initialHref : minified),
20
18
  referenceCount: 1,
21
19
  styles: minified,
22
20
  };
23
- styleRegistry.set(key, item);
21
+ styleCache.set(key, item);
24
22
  }
25
23
  return item;
26
24
  });
27
25
  useEffect(() => {
28
- if (!styles) return;
26
+ if (!styles)
27
+ return;
29
28
  const key = initialHref !== null && initialHref !== void 0 ? initialHref : styles;
30
- if (!styleRegistry.get(key)) {
29
+ if (!styleCache.get(key)) {
31
30
  const minified = minifyStyles(styles);
32
31
  const item = {
33
- href: sanitizeHref(
34
- initialHref !== null && initialHref !== void 0
35
- ? initialHref
36
- : minified,
37
- ),
32
+ href: sanitizeHref(initialHref !== null && initialHref !== void 0 ? initialHref : minified),
38
33
  referenceCount: 1,
39
34
  styles: minified,
40
35
  };
41
- styleRegistry.set(key, item);
36
+ styleCache.set(key, item);
42
37
  setStylesItem(item);
43
38
  }
44
39
  return () => {
45
- const existingItem = styleRegistry.get(styles);
40
+ const existingItem = styleCache.get(styles);
46
41
  if (existingItem) {
47
42
  existingItem.referenceCount--;
48
43
  if (!existingItem.referenceCount) {
@@ -50,7 +45,7 @@ export function useStyles(styles, initialHref) {
50
45
  // and add another referenceCount check
51
46
  // to deal with instance where existing <Style>
52
47
  // component is moved in the tree or re-keyed
53
- styleRegistry.delete(styles);
48
+ styleCache.delete(styles);
54
49
  }
55
50
  }
56
51
  };
@@ -58,12 +53,11 @@ export function useStyles(styles, initialHref) {
58
53
  return stylesItem;
59
54
  }
60
55
  export default useStyles;
61
- export const clearRegistry = () => {
62
- styleRegistry.clear();
63
- };
64
56
  // Dashes in selectors in href prop create happy-dom / jsdom test errors:
65
57
  // Invalid regular expression (“Range out of order in character class”)
66
58
  function sanitizeHref(text) {
67
59
  return text.replace(/-/g, '');
68
60
  }
69
- //# sourceMappingURL=useStyles.js.map
61
+ // The following export is for test usage only
62
+ export const getStyleCache = () => styleCache;
63
+ //# sourceMappingURL=useStyles.js.map
@@ -5,7 +5,7 @@
5
5
  * @flow
6
6
  */
7
7
 
8
- declare type StyleRegistry = Map<
8
+ declare type StyleCache = Map<
9
9
  string,
10
10
  {|
11
11
  href: string,
@@ -13,7 +13,6 @@ declare type StyleRegistry = Map<
13
13
  styles: string,
14
14
  |}
15
15
  >;
16
- declare export var getStyleRegistry: () => StyleRegistry;
17
16
  declare export function useStyles(
18
17
  styles: string,
19
18
  initialHref?: string
@@ -23,4 +22,4 @@ declare export function useStyles(
23
22
  styles: string,
24
23
  |};
25
24
  declare export default typeof useStyles;
26
- declare export var clearRegistry: () => void;
25
+ declare export var getStyleCache: () => StyleCache;
@@ -1 +1 @@
1
- {"version":3,"file":"useStyles.js","sourceRoot":"","sources":["../src/useStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOjD,MAAM,aAAa,GAAkB,IAAI,GAAG,EAAE,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC;AAEpD,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,WAAoB;IAC1D,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAEhE,MAAM,GAAG,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,MAAM,CAAC;QAClC,IAAI,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,GAAG;gBACH,IAAI,EAAE,YAAY,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,QAAQ,CAAC;gBAC3C,cAAc,EAAE,CAAC;gBACjB,MAAM,EAAE,QAAQ;aACnB,CAAC;YACF,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,GAAG,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,MAAM,CAAC;QAElC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG;gBACT,IAAI,EAAE,YAAY,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,QAAQ,CAAC;gBAC3C,cAAc,EAAE,CAAC;gBACjB,MAAM,EAAE,QAAQ;aACnB,CAAC;YACF,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,aAAa,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,GAAG,EAAE;YACR,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAI,YAAY,EAAE,CAAC;gBACf,YAAY,CAAC,cAAc,EAAE,CAAC;gBAC9B,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;oBAC/B,0CAA0C;oBAC1C,uCAAuC;oBACvC,+CAA+C;oBAC/C,6CAA6C;oBAC7C,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACjC,CAAC;YACL,CAAC;QACL,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAE1B,OAAO,UAAU,CAAC;AACtB,CAAC;AAED,eAAe,SAAS,CAAC;AAEzB,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAC9B,aAAa,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC,CAAC;AAEF,yEAAyE;AACzE,uEAAuE;AACvE,SAAS,YAAY,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"useStyles.js","sourceRoot":"","sources":["../src/useStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIjD,MAAM,UAAU,GAAe,IAAI,GAAG,EAAE,CAAC;AAEzC,MAAM,iBAAiB,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAEtE,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,WAAoB;IAC1D,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,iBAAiB,CAAC;QAEtC,MAAM,GAAG,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,MAAM,CAAC;QAClC,IAAI,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE/B,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,GAAG;gBACH,IAAI,EAAE,YAAY,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,QAAQ,CAAC;gBAC3C,cAAc,EAAE,CAAC;gBACjB,MAAM,EAAE,QAAQ;aACnB,CAAC;YACF,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,GAAG,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,MAAM,CAAC;QAElC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG;gBACT,IAAI,EAAE,YAAY,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,QAAQ,CAAC;gBAC3C,cAAc,EAAE,CAAC;gBACjB,MAAM,EAAE,QAAQ;aACnB,CAAC;YACF,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC1B,aAAa,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,GAAG,EAAE;YACR,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,YAAY,EAAE,CAAC;gBACf,YAAY,CAAC,cAAc,EAAE,CAAC;gBAC9B,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;oBAC/B,0CAA0C;oBAC1C,uCAAuC;oBACvC,+CAA+C;oBAC/C,6CAA6C;oBAC7C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC;YACL,CAAC;QACL,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAE1B,OAAO,UAAU,CAAC;AACtB,CAAC;AAED,eAAe,SAAS,CAAC;AAEzB,yEAAyE;AACzE,uEAAuE;AACvE,SAAS,YAAY,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,8CAA8C;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC"}
@@ -3,86 +3,77 @@ import { render } from '@testing-library/react';
3
3
  import React from 'react';
4
4
  import { beforeEach, describe, expect, it } from 'vitest';
5
5
  import Style from './Style.js';
6
- import { getStyleRegistry } from './useStyles.js';
6
+ import { getStyleCache } from './useStyles.js';
7
7
  describe('@acusti/styling', () => {
8
8
  describe('useStyles.ts', () => {
9
9
  const mockStylesA = '.test-a {\n color: cyan;\n}';
10
10
  const mockStylesB = '.test-b {\n padding: 10px;\n}';
11
- // reset styleRegistry before each test
11
+ // reset styleCache before each test
12
12
  beforeEach(() => {
13
- getStyleRegistry().clear();
13
+ getStyleCache().clear();
14
14
  });
15
15
  it('should cache minified styles in the registry keyed by the style string', () => {
16
- const styleRegistry = getStyleRegistry();
17
- const { rerender } = render(
18
- React.createElement(
19
- React.Fragment,
20
- null,
21
- React.createElement(Style, null, mockStylesA),
22
- React.createElement(Style, null, mockStylesA),
23
- ),
24
- );
25
- let stylesItemA = styleRegistry.get(mockStylesA);
26
- expect(
27
- stylesItemA === null || stylesItemA === void 0
28
- ? void 0
29
- : stylesItemA.referenceCount,
30
- ).toBe(2);
31
- expect(
32
- stylesItemA === null || stylesItemA === void 0
33
- ? void 0
34
- : stylesItemA.styles,
35
- ).toBe('.test-a{color:cyan}');
36
- expect(styleRegistry.size).toBe(1);
16
+ const styleCache = getStyleCache();
17
+ const { rerender } = render(React.createElement(React.Fragment, null,
18
+ React.createElement(Style, null, mockStylesA),
19
+ React.createElement(Style, null, mockStylesA)));
20
+ let stylesItemA = styleCache.get(mockStylesA);
21
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(2);
22
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.styles).toBe('.test-a{color:cyan}');
23
+ expect(styleCache.size).toBe(1);
37
24
  rerender(React.createElement(Style, null, mockStylesA));
38
- expect(
39
- stylesItemA === null || stylesItemA === void 0
40
- ? void 0
41
- : stylesItemA.referenceCount,
42
- ).toBe(1);
43
- expect(stylesItemA).toBe(styleRegistry.get(mockStylesA));
44
- expect(styleRegistry.size).toBe(1);
25
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(1);
26
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
27
+ expect(styleCache.size).toBe(1);
45
28
  rerender(React.createElement(Style, null, mockStylesB));
46
- stylesItemA = styleRegistry.get(mockStylesA);
29
+ stylesItemA = styleCache.get(mockStylesA);
47
30
  expect(stylesItemA).toBe(undefined);
48
- let stylesItemB = styleRegistry.get(mockStylesB);
49
- expect(
50
- stylesItemB === null || stylesItemB === void 0
51
- ? void 0
52
- : stylesItemB.referenceCount,
53
- ).toBe(1);
54
- expect(styleRegistry.size).toBe(1);
55
- rerender(
56
- React.createElement(
57
- React.Fragment,
58
- null,
59
- React.createElement(Style, null, mockStylesA),
60
- React.createElement(Style, null, mockStylesB),
61
- ),
62
- );
63
- stylesItemA = styleRegistry.get(mockStylesA);
64
- expect(
65
- stylesItemA === null || stylesItemA === void 0
66
- ? void 0
67
- : stylesItemA.referenceCount,
68
- ).toBe(1);
69
- expect(stylesItemA).toBe(styleRegistry.get(mockStylesA));
70
- stylesItemB = styleRegistry.get(mockStylesB);
71
- expect(
72
- stylesItemB === null || stylesItemB === void 0
73
- ? void 0
74
- : stylesItemB.referenceCount,
75
- ).toBe(1);
76
- expect(styleRegistry.size).toBe(2);
77
- rerender(React.createElement('div', null));
78
- expect(styleRegistry.size).toBe(0);
31
+ let stylesItemB = styleCache.get(mockStylesB);
32
+ expect(stylesItemB === null || stylesItemB === void 0 ? void 0 : stylesItemB.referenceCount).toBe(1);
33
+ expect(styleCache.size).toBe(1);
34
+ rerender(React.createElement(React.Fragment, null,
35
+ React.createElement(Style, null, mockStylesA),
36
+ React.createElement(Style, null, mockStylesB)));
37
+ stylesItemA = styleCache.get(mockStylesA);
38
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(1);
39
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
40
+ stylesItemB = styleCache.get(mockStylesB);
41
+ expect(stylesItemB === null || stylesItemB === void 0 ? void 0 : stylesItemB.referenceCount).toBe(1);
42
+ expect(styleCache.size).toBe(2);
43
+ rerender(React.createElement("div", null));
44
+ expect(styleCache.size).toBe(0);
45
+ });
46
+ it('should preserve style cache across component position changes and re-keying', () => {
47
+ const styleCache = getStyleCache();
48
+ const { rerender } = render(React.createElement(React.Fragment, null,
49
+ React.createElement(Style, null, mockStylesA)));
50
+ const stylesItemA = styleCache.get(mockStylesA);
51
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(1);
52
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.styles).toBe('.test-a{color:cyan}');
53
+ expect(styleCache.size).toBe(1);
54
+ rerender(React.createElement(React.Fragment, null,
55
+ React.createElement(Style, null, mockStylesB),
56
+ React.createElement(Style, null, mockStylesA)));
57
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(1);
58
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
59
+ rerender(React.createElement(Style, { key: "new-a" }, mockStylesA));
60
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(1);
61
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
62
+ rerender(React.createElement(React.Fragment, null,
63
+ React.createElement(Style, null, mockStylesA),
64
+ React.createElement(Style, { key: "new-a" }, mockStylesA)));
65
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(2);
66
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
67
+ rerender(React.createElement("div", null));
68
+ expect(stylesItemA === null || stylesItemA === void 0 ? void 0 : stylesItemA.referenceCount).toBe(0);
69
+ expect(styleCache.size).toBe(0);
70
+ });
71
+ it('should sanitize styles used as href prop if no href prop provided', () => {
72
+ render(React.createElement(Style, null, `div[data-foo-bar] { color: cyan; }`));
73
+ // the two-dash attribute selector results in “Range out of order in character class”
74
+ // and render() fails with SyntaxError: Invalid regular expression if not sanitized
75
+ expect(true).toBeTruthy();
79
76
  });
80
- });
81
- it('should sanitize styles used as href prop if no href prop provided', () => {
82
- render(React.createElement(Style, null, `div[data-foo-bar] { color: cyan; }`));
83
- // the two-dash attribute selector results in “Range out of order in character class”
84
- // and render() fails with SyntaxError: Invalid regular expression if not sanitized
85
- expect(true).toBeTruthy();
86
77
  });
87
78
  });
88
- //# sourceMappingURL=useStyles.test.js.map
79
+ //# sourceMappingURL=useStyles.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStyles.test.js","sourceRoot":"","sources":["../src/useStyles.test.tsx"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1B,MAAM,WAAW,GAAG,8BAA8B,CAAC;QACnD,MAAM,WAAW,GAAG,gCAAgC,CAAC;QAErD,uCAAuC;QACvC,UAAU,CAAC,GAAG,EAAE;YACZ,gBAAgB,EAAE,CAAC,KAAK,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;YAC9E,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;YAEzC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CACvB,oBAAC,KAAK,CAAC,QAAQ;gBACX,oBAAC,KAAK,QAAE,WAAW,CAAS;gBAC5B,oBAAC,KAAK,QAAE,WAAW,CAAS,CACf,CACpB,CAAC;YAEF,IAAI,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACxD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnC,QAAQ,CAAC,oBAAC,KAAK,QAAE,WAAW,CAAS,CAAC,CAAC;YACvC,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnC,QAAQ,CAAC,oBAAC,KAAK,QAAE,WAAW,CAAS,CAAC,CAAC;YACvC,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnC,QAAQ,CACJ,oBAAC,KAAK,CAAC,QAAQ;gBACX,oBAAC,KAAK,QAAE,WAAW,CAAS;gBAC5B,oBAAC,KAAK,QAAE,WAAW,CAAS,CACf,CACpB,CAAC;YACF,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;YACzD,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAM,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnC,QAAQ,CAAC,gCAAO,CAAC,CAAC;YAClB,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,oBAAC,KAAK,QAAE,oCAAoC,CAAS,CAAC,CAAC;QAC9D,qFAAqF;QACrF,mFAAmF;QACnF,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"useStyles.test.js","sourceRoot":"","sources":["../src/useStyles.test.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acusti/styling",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": "./dist/index.js",
@@ -38,17 +38,17 @@
38
38
  "homepage": "https://github.com/acusti/uikit/tree/main/packages/styling#readme",
39
39
  "devDependencies": {
40
40
  "@testing-library/dom": "^10.4.0",
41
- "@testing-library/react": "^16.0.1",
41
+ "@testing-library/react": "^16.1.0",
42
42
  "@testing-library/user-event": "^14.5.2",
43
- "@types/react": "^18.3.3",
44
- "happy-dom": "^15.7.3",
45
- "react": "^19.0.0-0",
46
- "react-dom": "^19.0.0-0",
43
+ "@types/react": "^19.0.2",
44
+ "happy-dom": "^15.11.7",
45
+ "react": "^19.0.0",
46
+ "react-dom": "^19.0.0",
47
47
  "typescript": "5.3.3",
48
- "vitest": "^1.1.0"
48
+ "vitest": "^2.1.8"
49
49
  },
50
50
  "peerDependencies": {
51
- "react": "^19.0.0-0",
52
- "react-dom": "^19.0.0-0"
51
+ "react": "^19.0.0",
52
+ "react-dom": "^19.0.0"
53
53
  }
54
54
  }
package/src/Style.tsx CHANGED
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
1
  import React from 'react';
3
2
 
4
3
  import { useStyles } from './useStyles.js';
@@ -15,8 +14,6 @@ const Style = ({ children, href: _href, precedence = 'medium' }: Props) => {
15
14
  // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/canary.d.ts
16
15
  // https://react.dev/reference/react-dom/components/style#props
17
16
  return (
18
- // @ts-expect-error @types/react is missing new <style> props
19
- // eslint-disable-next-line react/no-unknown-property
20
17
  <style href={href} precedence={precedence}>
21
18
  {styles}
22
19
  </style>
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="react/canary" />
2
1
  export { default as Style } from './Style.js';
3
2
 
4
3
  export const SYSTEM_UI_FONT =
@@ -31,5 +31,14 @@ describe('@acusti/styling', () => {
31
31
  }`),
32
32
  ).toBe('.foo{opacity:.6}');
33
33
  });
34
+
35
+ it('strips out comments', () => {
36
+ expect(
37
+ minifyStyles(`
38
+ .bar {
39
+ font-weight: 900;/*.bar is so *strong**/
40
+ }`),
41
+ ).toBe('.bar{font-weight:900}');
42
+ });
34
43
  });
35
44
  });
@@ -31,8 +31,6 @@ export function minifyStyles(css: string) {
31
31
  const totalLength = css.length;
32
32
  let startIndex = 0,
33
33
  endIndex = 0,
34
- i = 0,
35
- max = 0,
36
34
  token = '',
37
35
  placeholder = '';
38
36
 
@@ -56,14 +54,13 @@ export function minifyStyles(css: string) {
56
54
  // preserve strings so their content doesn't get accidentally minified
57
55
  css = css.replace(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/g, function (match) {
58
56
  const quote = match.substring(0, 1);
59
- let i, max;
60
57
 
61
58
  match = match.slice(1, -1);
62
59
 
63
60
  // maybe the string contains a comment-like substring?
64
61
  // one, maybe more? put'em back then
65
62
  if (match.indexOf('___PRESERVE_CANDIDATE_COMMENT_') >= 0) {
66
- for (i = 0, max = comments.length; i < max; i = i + 1) {
63
+ for (let i = 0, max = comments.length; i < max; i++) {
67
64
  match = match.replace(
68
65
  '___PRESERVE_CANDIDATE_COMMENT_' + i + '___',
69
66
  comments[i],
@@ -78,7 +75,7 @@ export function minifyStyles(css: string) {
78
75
  });
79
76
 
80
77
  // strings are safe, now wrestle the comments
81
- for (i = 0, max = comments.length; i < max; i = i + 1) {
78
+ for (let i = 0, max = comments.length; i < max; i = i + 1) {
82
79
  token = comments[i];
83
80
  placeholder = '___PRESERVE_CANDIDATE_COMMENT_' + i + '___';
84
81
 
@@ -171,7 +168,7 @@ export function minifyStyles(css: string) {
171
168
  css = css.replace(/;;+/g, ';');
172
169
 
173
170
  // restore preserved comments and strings
174
- for (i = 0, max = preservedTokens.length; i < max; i = i + 1) {
171
+ for (let i = 0, max = preservedTokens.length; i < max; i = i + 1) {
175
172
  css = css.replace('___PRESERVED_TOKEN_' + i + '___', preservedTokens[i]);
176
173
  }
177
174
 
@@ -4,20 +4,20 @@ import React from 'react';
4
4
  import { beforeEach, describe, expect, it } from 'vitest';
5
5
 
6
6
  import Style from './Style.js';
7
- import { getStyleRegistry } from './useStyles.js';
7
+ import { getStyleCache } from './useStyles.js';
8
8
 
9
9
  describe('@acusti/styling', () => {
10
10
  describe('useStyles.ts', () => {
11
11
  const mockStylesA = '.test-a {\n color: cyan;\n}';
12
12
  const mockStylesB = '.test-b {\n padding: 10px;\n}';
13
13
 
14
- // reset styleRegistry before each test
14
+ // reset styleCache before each test
15
15
  beforeEach(() => {
16
- getStyleRegistry().clear();
16
+ getStyleCache().clear();
17
17
  });
18
18
 
19
19
  it('should cache minified styles in the registry keyed by the style string', () => {
20
- const styleRegistry = getStyleRegistry();
20
+ const styleCache = getStyleCache();
21
21
 
22
22
  const { rerender } = render(
23
23
  <React.Fragment>
@@ -26,22 +26,22 @@ describe('@acusti/styling', () => {
26
26
  </React.Fragment>,
27
27
  );
28
28
 
29
- let stylesItemA = styleRegistry.get(mockStylesA);
29
+ let stylesItemA = styleCache.get(mockStylesA);
30
30
  expect(stylesItemA?.referenceCount).toBe(2);
31
31
  expect(stylesItemA?.styles).toBe('.test-a{color:cyan}');
32
- expect(styleRegistry.size).toBe(1);
32
+ expect(styleCache.size).toBe(1);
33
33
 
34
34
  rerender(<Style>{mockStylesA}</Style>);
35
35
  expect(stylesItemA?.referenceCount).toBe(1);
36
- expect(stylesItemA).toBe(styleRegistry.get(mockStylesA));
37
- expect(styleRegistry.size).toBe(1);
36
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
37
+ expect(styleCache.size).toBe(1);
38
38
 
39
39
  rerender(<Style>{mockStylesB}</Style>);
40
- stylesItemA = styleRegistry.get(mockStylesA);
40
+ stylesItemA = styleCache.get(mockStylesA);
41
41
  expect(stylesItemA).toBe(undefined);
42
- let stylesItemB = styleRegistry.get(mockStylesB);
42
+ let stylesItemB = styleCache.get(mockStylesB);
43
43
  expect(stylesItemB?.referenceCount).toBe(1);
44
- expect(styleRegistry.size).toBe(1);
44
+ expect(styleCache.size).toBe(1);
45
45
 
46
46
  rerender(
47
47
  <React.Fragment>
@@ -49,22 +49,63 @@ describe('@acusti/styling', () => {
49
49
  <Style>{mockStylesB}</Style>
50
50
  </React.Fragment>,
51
51
  );
52
- stylesItemA = styleRegistry.get(mockStylesA);
52
+ stylesItemA = styleCache.get(mockStylesA);
53
53
  expect(stylesItemA?.referenceCount).toBe(1);
54
- expect(stylesItemA).toBe(styleRegistry.get(mockStylesA));
55
- stylesItemB = styleRegistry.get(mockStylesB);
54
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
55
+ stylesItemB = styleCache.get(mockStylesB);
56
56
  expect(stylesItemB?.referenceCount).toBe(1);
57
- expect(styleRegistry.size).toBe(2);
57
+ expect(styleCache.size).toBe(2);
58
58
 
59
59
  rerender(<div />);
60
- expect(styleRegistry.size).toBe(0);
60
+ expect(styleCache.size).toBe(0);
61
61
  });
62
- });
63
62
 
64
- it('should sanitize styles used as href prop if no href prop provided', () => {
65
- render(<Style>{`div[data-foo-bar] { color: cyan; }`}</Style>);
66
- // the two-dash attribute selector results in “Range out of order in character class”
67
- // and render() fails with SyntaxError: Invalid regular expression if not sanitized
68
- expect(true).toBeTruthy();
63
+ it('should preserve style cache across component position changes and re-keying', () => {
64
+ const styleCache = getStyleCache();
65
+
66
+ const { rerender } = render(
67
+ <React.Fragment>
68
+ <Style>{mockStylesA}</Style>
69
+ </React.Fragment>,
70
+ );
71
+
72
+ const stylesItemA = styleCache.get(mockStylesA);
73
+ expect(stylesItemA?.referenceCount).toBe(1);
74
+ expect(stylesItemA?.styles).toBe('.test-a{color:cyan}');
75
+ expect(styleCache.size).toBe(1);
76
+
77
+ rerender(
78
+ <React.Fragment>
79
+ <Style>{mockStylesB}</Style>
80
+ <Style>{mockStylesA}</Style>
81
+ </React.Fragment>,
82
+ );
83
+ expect(stylesItemA?.referenceCount).toBe(1);
84
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
85
+
86
+ rerender(<Style key="new-a">{mockStylesA}</Style>);
87
+ expect(stylesItemA?.referenceCount).toBe(1);
88
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
89
+
90
+ rerender(
91
+ <React.Fragment>
92
+ <Style>{mockStylesA}</Style>
93
+ <Style key="new-a">{mockStylesA}</Style>
94
+ </React.Fragment>,
95
+ );
96
+ expect(stylesItemA?.referenceCount).toBe(2);
97
+ expect(stylesItemA).toBe(styleCache.get(mockStylesA));
98
+
99
+ rerender(<div />);
100
+ expect(stylesItemA?.referenceCount).toBe(0);
101
+ expect(styleCache.size).toBe(0);
102
+ });
103
+
104
+ it('should sanitize styles used as href prop if no href prop provided', () => {
105
+ render(<Style>{`div[data-foo-bar] { color: cyan; }`}</Style>);
106
+ // the two-dash attribute selector results in “Range out of order in character class”
107
+ // and render() fails with SyntaxError: Invalid regular expression if not sanitized
108
+ expect(true).toBeTruthy();
109
+ });
69
110
  });
70
111
  });
package/src/useStyles.ts CHANGED
@@ -2,21 +2,18 @@ import { useEffect, useState } from 'react';
2
2
 
3
3
  import { minifyStyles } from './minifyStyles.js';
4
4
 
5
- type StyleRegistry = Map<
6
- string,
7
- { href: string; referenceCount: number; styles: string }
8
- >;
5
+ type StyleCache = Map<string, { href: string; referenceCount: number; styles: string }>;
9
6
 
10
- const styleRegistry: StyleRegistry = new Map();
7
+ const styleCache: StyleCache = new Map();
11
8
 
12
- export const getStyleRegistry = () => styleRegistry;
9
+ const EMPTY_STYLES_ITEM = { href: '', referenceCount: 0, styles: '' };
13
10
 
14
11
  export function useStyles(styles: string, initialHref?: string) {
15
12
  const [stylesItem, setStylesItem] = useState(() => {
16
- if (!styles) return { href: '', referenceCount: 0, styles: '' };
13
+ if (!styles) return EMPTY_STYLES_ITEM;
17
14
 
18
15
  const key = initialHref ?? styles;
19
- let item = styleRegistry.get(key);
16
+ let item = styleCache.get(key);
20
17
 
21
18
  if (item) {
22
19
  item.referenceCount++;
@@ -27,7 +24,7 @@ export function useStyles(styles: string, initialHref?: string) {
27
24
  referenceCount: 1,
28
25
  styles: minified,
29
26
  };
30
- styleRegistry.set(key, item);
27
+ styleCache.set(key, item);
31
28
  }
32
29
 
33
30
  return item;
@@ -38,19 +35,19 @@ export function useStyles(styles: string, initialHref?: string) {
38
35
 
39
36
  const key = initialHref ?? styles;
40
37
 
41
- if (!styleRegistry.get(key)) {
38
+ if (!styleCache.get(key)) {
42
39
  const minified = minifyStyles(styles);
43
40
  const item = {
44
41
  href: sanitizeHref(initialHref ?? minified),
45
42
  referenceCount: 1,
46
43
  styles: minified,
47
44
  };
48
- styleRegistry.set(key, item);
45
+ styleCache.set(key, item);
49
46
  setStylesItem(item);
50
47
  }
51
48
 
52
49
  return () => {
53
- const existingItem = styleRegistry.get(styles);
50
+ const existingItem = styleCache.get(styles);
54
51
  if (existingItem) {
55
52
  existingItem.referenceCount--;
56
53
  if (!existingItem.referenceCount) {
@@ -58,7 +55,7 @@ export function useStyles(styles: string, initialHref?: string) {
58
55
  // and add another referenceCount check
59
56
  // to deal with instance where existing <Style>
60
57
  // component is moved in the tree or re-keyed
61
- styleRegistry.delete(styles);
58
+ styleCache.delete(styles);
62
59
  }
63
60
  }
64
61
  };
@@ -69,12 +66,11 @@ export function useStyles(styles: string, initialHref?: string) {
69
66
 
70
67
  export default useStyles;
71
68
 
72
- export const clearRegistry = () => {
73
- styleRegistry.clear();
74
- };
75
-
76
69
  // Dashes in selectors in href prop create happy-dom / jsdom test errors:
77
70
  // Invalid regular expression (“Range out of order in character class”)
78
71
  function sanitizeHref(text: string) {
79
72
  return text.replace(/-/g, '');
80
73
  }
74
+
75
+ // The following export is for test usage only
76
+ export const getStyleCache = () => styleCache;