@acusti/styling 0.7.0 → 0.7.2

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.
@@ -9,5 +9,5 @@ import * as React from "react";
9
9
  declare type Props = {|
10
10
  children: string,
11
11
  |};
12
- declare var Style: (x: Props) => React.JSX.Element | null;
12
+ declare var Style: (x: Props) => React.Node | null;
13
13
  declare export default typeof Style;
@@ -14,4 +14,6 @@ type UpdatePayload = {
14
14
  styles: string;
15
15
  };
16
16
  export declare const updateStyles: ({ ownerDocument, previousStyles, styles, }: UpdatePayload) => void;
17
+ export declare const getStyleRegistryKeys: () => IterableIterator<string>;
18
+ export declare const clearRegistry: () => void;
17
19
  export {};
@@ -8,6 +8,8 @@ export const getRegisteredStyles = ({ ownerDocument, styles }) => {
8
8
  return null;
9
9
  return (_a = stylesMap.get(ownerDocument)) !== null && _a !== void 0 ? _a : null;
10
10
  };
11
+ // NOTE a more idiomatic API than (register|unregister)Styles would be
12
+ // to make registerStyles a thunk that returns a cleanup function
11
13
  export const registerStyles = ({ ownerDocument, styles }) => {
12
14
  if (!styles)
13
15
  return;
@@ -17,7 +19,15 @@ export const registerStyles = ({ ownerDocument, styles }) => {
17
19
  return;
18
20
  }
19
21
  if (ownerDocument === 'global') {
20
- styleRegistry.set(styles, new Map([[ownerDocument, { element: null, referenceCount: 1 }]]));
22
+ const stylesItem = { element: null, referenceCount: 1 };
23
+ let stylesMap = styleRegistry.get(styles);
24
+ if (stylesMap) {
25
+ stylesMap.set(ownerDocument, stylesItem);
26
+ }
27
+ else {
28
+ stylesMap = new Map([[ownerDocument, stylesItem]]);
29
+ }
30
+ styleRegistry.set(styles, stylesMap);
21
31
  return;
22
32
  }
23
33
  const element = ownerDocument.createElement('style');
@@ -77,4 +87,8 @@ export const updateStyles = ({ ownerDocument, previousStyles, styles, }) => {
77
87
  }
78
88
  registerStyles({ ownerDocument, styles });
79
89
  };
90
+ export const getStyleRegistryKeys = () => styleRegistry.keys();
91
+ export const clearRegistry = () => {
92
+ styleRegistry.clear();
93
+ };
80
94
  //# sourceMappingURL=style-registry.js.map
@@ -21,3 +21,5 @@ declare type UpdatePayload = {|
21
21
  styles: string,
22
22
  |};
23
23
  declare export var updateStyles: (x: UpdatePayload) => void;
24
+ declare export var getStyleRegistryKeys: () => IterableIterator<string>;
25
+ declare export var clearRegistry: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"style-registry.js","sourceRoot":"","sources":["../src/style-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"style-registry.js","sourceRoot":"","sources":["../src/style-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,114 @@
1
+ // @vitest-environment happy-dom
2
+ import { beforeEach, describe, expect, it } from 'vitest';
3
+ import { clearRegistry, getRegisteredStyles, getStyleRegistryKeys, registerStyles, unregisterStyles, updateStyles, } from './style-registry.js';
4
+ describe('@acusti/styling', () => {
5
+ describe('style-registry.ts', () => {
6
+ const mockStyles = '.test { color: red; }';
7
+ // reset styleRegistry before each test
8
+ beforeEach(clearRegistry);
9
+ describe('registerStyles', () => {
10
+ it('should add styles to the registry keyed by the style string', () => {
11
+ const payload = { ownerDocument: document, styles: mockStyles };
12
+ registerStyles(payload);
13
+ const styleRegistryKeys = getStyleRegistryKeys();
14
+ const keysArray = [...styleRegistryKeys];
15
+ expect(keysArray.length).toBe(1);
16
+ expect(keysArray[0]).toBe(mockStyles);
17
+ const result = getRegisteredStyles(payload);
18
+ expect(result.element).toBeDefined();
19
+ expect(result.referenceCount).toBe(1);
20
+ });
21
+ it('should allow registering styles without a DOM via ownerDocument: "global"', () => {
22
+ const payload = Object.freeze({
23
+ ownerDocument: 'global',
24
+ styles: mockStyles,
25
+ });
26
+ registerStyles(payload);
27
+ const registryKeys = [...getStyleRegistryKeys()];
28
+ expect(registryKeys.length).toBe(1);
29
+ expect(registryKeys[0]).toBe(mockStyles);
30
+ const result = getRegisteredStyles(payload);
31
+ expect(result.element).toBeNull();
32
+ expect(result.referenceCount).toBe(1);
33
+ });
34
+ });
35
+ describe('getRegisteredStyles', () => {
36
+ it('should retrieve registered styles', () => {
37
+ const payload = { ownerDocument: document, styles: mockStyles };
38
+ registerStyles(payload);
39
+ const result = getRegisteredStyles(payload);
40
+ expect(result.element.tagName).toBe('STYLE');
41
+ expect(result.referenceCount).toBe(1);
42
+ });
43
+ });
44
+ describe('unregisterStyles', () => {
45
+ it('should remove styles from the registry if no other references to same styles exist', () => {
46
+ const payload = { ownerDocument: document, styles: mockStyles };
47
+ const otherPayload = Object.freeze({
48
+ ownerDocument: 'global',
49
+ styles: mockStyles,
50
+ });
51
+ registerStyles(payload);
52
+ registerStyles(otherPayload);
53
+ expect(getStyleRegistryKeys().next().value).toBe(mockStyles);
54
+ expect(getRegisteredStyles(payload).referenceCount).toBe(1);
55
+ expect(getRegisteredStyles(otherPayload).referenceCount).toBe(1);
56
+ unregisterStyles(payload);
57
+ // style registry for this style should still exist
58
+ expect(getStyleRegistryKeys().next().value).toBe(mockStyles);
59
+ // but this document’s styles item should be cleared
60
+ expect(getRegisteredStyles(payload)).toBeNull();
61
+ unregisterStyles(otherPayload);
62
+ // now the style registry should be empty
63
+ expect([...getStyleRegistryKeys()].length).toBe(0);
64
+ });
65
+ });
66
+ describe('updateStyles', () => {
67
+ it('should update styles in the registry, reusing the existing DOM element if no other reference', () => {
68
+ const previousStyles = '.previous { color: blue; }';
69
+ const payload = {
70
+ ownerDocument: document,
71
+ styles: previousStyles,
72
+ };
73
+ registerStyles(payload);
74
+ const previousStylesItem = getRegisteredStyles(payload);
75
+ expect(previousStylesItem.element.innerText).toBe(previousStyles);
76
+ updateStyles({
77
+ ownerDocument: document,
78
+ previousStyles,
79
+ styles: mockStyles,
80
+ });
81
+ const stylesItem = getRegisteredStyles({
82
+ ownerDocument: document,
83
+ styles: mockStyles,
84
+ });
85
+ expect(previousStylesItem.element).toBe(stylesItem.element);
86
+ expect(stylesItem.element.innerText).toBe(mockStyles);
87
+ expect(getRegisteredStyles(payload)).toBeNull();
88
+ });
89
+ it('should update styles in the registry, creating a new DOM element if there are other references', () => {
90
+ const previousStyles = '.previous { color: blue; }';
91
+ const payload = { ownerDocument: document, styles: previousStyles };
92
+ registerStyles(payload);
93
+ // create multiple references to the same styles and document
94
+ registerStyles(payload);
95
+ const previousStylesItem = getRegisteredStyles(payload);
96
+ expect(previousStylesItem.referenceCount).toBe(2);
97
+ expect(previousStylesItem.element.innerText).toBe(previousStyles);
98
+ updateStyles({
99
+ ownerDocument: document,
100
+ previousStyles,
101
+ styles: mockStyles,
102
+ });
103
+ const stylesItem = getRegisteredStyles({
104
+ ownerDocument: document,
105
+ styles: mockStyles,
106
+ });
107
+ expect(previousStylesItem.element).not.toBe(stylesItem.element);
108
+ expect(stylesItem.element.innerText).toBe(mockStyles);
109
+ expect(getRegisteredStyles(payload).referenceCount).toBe(1);
110
+ });
111
+ });
112
+ });
113
+ });
114
+ //# sourceMappingURL=style-registry.test.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Flowtype definitions for style-registry.test
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.20.1
5
+ * @flow
6
+ */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-registry.test.js","sourceRoot":"","sources":["../src/style-registry.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,15 @@
1
1
  {
2
2
  "name": "@acusti/styling",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "exports": "./dist/index.js",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "src"
12
+ ],
4
13
  "description": "React component that renders a CSS style string as a <style> element in the <head> of the document (with global style de-duplication)",
5
14
  "keywords": [
6
15
  "react",
@@ -13,15 +22,9 @@
13
22
  "ts",
14
23
  "flow"
15
24
  ],
16
- "type": "module",
17
- "sideEffects": false,
18
- "exports": "./dist/index.js",
19
- "main": "./dist/index.js",
20
- "types": "./dist/index.d.ts",
21
- "files": [
22
- "dist",
23
- "src"
24
- ],
25
+ "scripts": {
26
+ "test": "vitest"
27
+ },
25
28
  "repository": {
26
29
  "type": "git",
27
30
  "url": "https://github.com/acusti/uikit.git",
@@ -34,7 +37,13 @@
34
37
  },
35
38
  "homepage": "https://github.com/acusti/uikit/tree/main/packages/styling#readme",
36
39
  "devDependencies": {
40
+ "@testing-library/dom": "^9.3.1",
41
+ "@testing-library/react": "^14.0.0",
42
+ "@testing-library/user-event": "^14.4.3",
37
43
  "@types/react": "^18.2.45",
44
+ "happy-dom": "^12.10.3",
45
+ "react": "^18",
46
+ "react-dom": "^18",
38
47
  "typescript": "^5.3.3",
39
48
  "vitest": "^1.1.0"
40
49
  },
@@ -0,0 +1,129 @@
1
+ // @vitest-environment happy-dom
2
+ import { beforeEach, describe, expect, it } from 'vitest';
3
+
4
+ import {
5
+ clearRegistry,
6
+ getRegisteredStyles,
7
+ getStyleRegistryKeys,
8
+ registerStyles,
9
+ unregisterStyles,
10
+ updateStyles,
11
+ } from './style-registry.js';
12
+
13
+ describe('@acusti/styling', () => {
14
+ describe('style-registry.ts', () => {
15
+ const mockStyles = '.test { color: red; }';
16
+
17
+ // reset styleRegistry before each test
18
+ beforeEach(clearRegistry);
19
+
20
+ describe('registerStyles', () => {
21
+ it('should add styles to the registry keyed by the style string', () => {
22
+ const payload = { ownerDocument: document, styles: mockStyles };
23
+ registerStyles(payload);
24
+ const styleRegistryKeys = getStyleRegistryKeys();
25
+ const keysArray = [...styleRegistryKeys];
26
+ expect(keysArray.length).toBe(1);
27
+ expect(keysArray[0]).toBe(mockStyles);
28
+ const result = getRegisteredStyles(payload);
29
+ expect(result!.element).toBeDefined();
30
+ expect(result!.referenceCount).toBe(1);
31
+ });
32
+
33
+ it('should allow registering styles without a DOM via ownerDocument: "global"', () => {
34
+ const payload = Object.freeze({
35
+ ownerDocument: 'global',
36
+ styles: mockStyles,
37
+ });
38
+ registerStyles(payload);
39
+ const registryKeys = [...getStyleRegistryKeys()];
40
+ expect(registryKeys.length).toBe(1);
41
+ expect(registryKeys[0]).toBe(mockStyles);
42
+ const result = getRegisteredStyles(payload);
43
+ expect(result!.element).toBeNull();
44
+ expect(result!.referenceCount).toBe(1);
45
+ });
46
+ });
47
+
48
+ describe('getRegisteredStyles', () => {
49
+ it('should retrieve registered styles', () => {
50
+ const payload = { ownerDocument: document, styles: mockStyles };
51
+ registerStyles(payload);
52
+ const result = getRegisteredStyles(payload);
53
+ expect(result!.element!.tagName).toBe('STYLE');
54
+ expect(result!.referenceCount).toBe(1);
55
+ });
56
+ });
57
+
58
+ describe('unregisterStyles', () => {
59
+ it('should remove styles from the registry if no other references to same styles exist', () => {
60
+ const payload = { ownerDocument: document, styles: mockStyles };
61
+ const otherPayload = Object.freeze({
62
+ ownerDocument: 'global',
63
+ styles: mockStyles,
64
+ });
65
+ registerStyles(payload);
66
+ registerStyles(otherPayload);
67
+ expect(getStyleRegistryKeys().next().value).toBe(mockStyles);
68
+ expect(getRegisteredStyles(payload)!.referenceCount).toBe(1);
69
+ expect(getRegisteredStyles(otherPayload)!.referenceCount).toBe(1);
70
+ unregisterStyles(payload);
71
+ // style registry for this style should still exist
72
+ expect(getStyleRegistryKeys().next().value).toBe(mockStyles);
73
+ // but this document’s styles item should be cleared
74
+ expect(getRegisteredStyles(payload)).toBeNull();
75
+ unregisterStyles(otherPayload);
76
+ // now the style registry should be empty
77
+ expect([...getStyleRegistryKeys()].length).toBe(0);
78
+ });
79
+ });
80
+
81
+ describe('updateStyles', () => {
82
+ it('should update styles in the registry, reusing the existing DOM element if no other reference', () => {
83
+ const previousStyles = '.previous { color: blue; }';
84
+ const payload = {
85
+ ownerDocument: document,
86
+ styles: previousStyles,
87
+ };
88
+ registerStyles(payload);
89
+ const previousStylesItem = getRegisteredStyles(payload)!;
90
+ expect(previousStylesItem.element!.innerText).toBe(previousStyles);
91
+ updateStyles({
92
+ ownerDocument: document,
93
+ previousStyles,
94
+ styles: mockStyles,
95
+ });
96
+ const stylesItem = getRegisteredStyles({
97
+ ownerDocument: document,
98
+ styles: mockStyles,
99
+ })!;
100
+ expect(previousStylesItem.element).toBe(stylesItem.element);
101
+ expect(stylesItem.element!.innerText).toBe(mockStyles);
102
+ expect(getRegisteredStyles(payload)).toBeNull();
103
+ });
104
+
105
+ it('should update styles in the registry, creating a new DOM element if there are other references', () => {
106
+ const previousStyles = '.previous { color: blue; }';
107
+ const payload = { ownerDocument: document, styles: previousStyles };
108
+ registerStyles(payload);
109
+ // create multiple references to the same styles and document
110
+ registerStyles(payload);
111
+ const previousStylesItem = getRegisteredStyles(payload)!;
112
+ expect(previousStylesItem.referenceCount).toBe(2);
113
+ expect(previousStylesItem.element!.innerText).toBe(previousStyles);
114
+ updateStyles({
115
+ ownerDocument: document,
116
+ previousStyles,
117
+ styles: mockStyles,
118
+ });
119
+ const stylesItem = getRegisteredStyles({
120
+ ownerDocument: document,
121
+ styles: mockStyles,
122
+ })!;
123
+ expect(previousStylesItem.element).not.toBe(stylesItem.element);
124
+ expect(stylesItem.element!.innerText).toBe(mockStyles);
125
+ expect(getRegisteredStyles(payload)!.referenceCount).toBe(1);
126
+ });
127
+ });
128
+ });
129
+ });
@@ -14,6 +14,8 @@ export const getRegisteredStyles = ({ ownerDocument, styles }: Payload) => {
14
14
  return stylesMap.get(ownerDocument) ?? null;
15
15
  };
16
16
 
17
+ // NOTE a more idiomatic API than (register|unregister)Styles would be
18
+ // to make registerStyles a thunk that returns a cleanup function
17
19
  export const registerStyles = ({ ownerDocument, styles }: Payload) => {
18
20
  if (!styles) return;
19
21
 
@@ -24,10 +26,14 @@ export const registerStyles = ({ ownerDocument, styles }: Payload) => {
24
26
  }
25
27
 
26
28
  if (ownerDocument === 'global') {
27
- styleRegistry.set(
28
- styles,
29
- new Map([[ownerDocument, { element: null, referenceCount: 1 }]]),
30
- );
29
+ const stylesItem = { element: null, referenceCount: 1 };
30
+ let stylesMap = styleRegistry.get(styles);
31
+ if (stylesMap) {
32
+ stylesMap.set(ownerDocument, stylesItem);
33
+ } else {
34
+ stylesMap = new Map([[ownerDocument, stylesItem]]);
35
+ }
36
+ styleRegistry.set(styles, stylesMap);
31
37
  return;
32
38
  }
33
39
 
@@ -101,3 +107,9 @@ export const updateStyles = ({
101
107
 
102
108
  registerStyles({ ownerDocument, styles });
103
109
  };
110
+
111
+ export const getStyleRegistryKeys = () => styleRegistry.keys();
112
+
113
+ export const clearRegistry = () => {
114
+ styleRegistry.clear();
115
+ };