@furystack/shades 11.1.0 → 12.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/CHANGELOG.md +291 -0
- package/README.md +13 -13
- package/esm/component-factory.spec.js +13 -5
- package/esm/component-factory.spec.js.map +1 -1
- package/esm/components/index.d.ts +4 -1
- package/esm/components/index.d.ts.map +1 -1
- package/esm/components/index.js +4 -1
- package/esm/components/index.js.map +1 -1
- package/esm/components/lazy-load.d.ts +2 -4
- package/esm/components/lazy-load.d.ts.map +1 -1
- package/esm/components/lazy-load.js +40 -24
- package/esm/components/lazy-load.js.map +1 -1
- package/esm/components/lazy-load.spec.js +57 -50
- package/esm/components/lazy-load.spec.js.map +1 -1
- package/esm/components/link-to-route.d.ts +2 -0
- package/esm/components/link-to-route.d.ts.map +1 -1
- package/esm/components/link-to-route.js +3 -2
- package/esm/components/link-to-route.js.map +1 -1
- package/esm/components/link-to-route.spec.js +13 -9
- package/esm/components/link-to-route.spec.js.map +1 -1
- package/esm/components/nested-route-link.d.ts +62 -0
- package/esm/components/nested-route-link.d.ts.map +1 -0
- package/esm/components/nested-route-link.js +66 -0
- package/esm/components/nested-route-link.js.map +1 -0
- package/esm/components/nested-route-link.spec.d.ts +2 -0
- package/esm/components/nested-route-link.spec.d.ts.map +1 -0
- package/esm/components/nested-route-link.spec.js +179 -0
- package/esm/components/nested-route-link.spec.js.map +1 -0
- package/esm/components/nested-route-types.d.ts +37 -0
- package/esm/components/nested-route-types.d.ts.map +1 -0
- package/esm/components/nested-route-types.js +2 -0
- package/esm/components/nested-route-types.js.map +1 -0
- package/esm/components/nested-router.d.ts +103 -0
- package/esm/components/nested-router.d.ts.map +1 -0
- package/esm/components/nested-router.js +178 -0
- package/esm/components/nested-router.js.map +1 -0
- package/esm/components/nested-router.spec.d.ts +2 -0
- package/esm/components/nested-router.spec.d.ts.map +1 -0
- package/esm/components/nested-router.spec.js +659 -0
- package/esm/components/nested-router.spec.js.map +1 -0
- package/esm/components/route-link.d.ts +4 -0
- package/esm/components/route-link.d.ts.map +1 -1
- package/esm/components/route-link.js +5 -5
- package/esm/components/route-link.js.map +1 -1
- package/esm/components/route-link.spec.js +16 -12
- package/esm/components/route-link.spec.js.map +1 -1
- package/esm/components/router.d.ts +20 -2
- package/esm/components/router.d.ts.map +1 -1
- package/esm/components/router.js +3 -0
- package/esm/components/router.js.map +1 -1
- package/esm/components/router.spec.js +75 -74
- package/esm/components/router.spec.js.map +1 -1
- package/esm/initialize.d.ts +11 -0
- package/esm/initialize.d.ts.map +1 -1
- package/esm/initialize.js +5 -0
- package/esm/initialize.js.map +1 -1
- package/esm/jsx.d.ts +83 -2
- package/esm/jsx.d.ts.map +1 -1
- package/esm/models/children-list.d.ts +5 -1
- package/esm/models/children-list.d.ts.map +1 -1
- package/esm/models/partial-element.d.ts +12 -2
- package/esm/models/partial-element.d.ts.map +1 -1
- package/esm/models/render-options.d.ts +89 -3
- package/esm/models/render-options.d.ts.map +1 -1
- package/esm/models/selection-state.d.ts +4 -0
- package/esm/models/selection-state.d.ts.map +1 -1
- package/esm/services/location-service.d.ts +11 -0
- package/esm/services/location-service.d.ts.map +1 -1
- package/esm/services/location-service.js +11 -0
- package/esm/services/location-service.js.map +1 -1
- package/esm/services/resource-manager.d.ts +24 -0
- package/esm/services/resource-manager.d.ts.map +1 -1
- package/esm/services/resource-manager.js +30 -0
- package/esm/services/resource-manager.js.map +1 -1
- package/esm/services/resource-manager.spec.js +93 -0
- package/esm/services/resource-manager.spec.js.map +1 -1
- package/esm/services/screen-service.d.ts +81 -4
- package/esm/services/screen-service.d.ts.map +1 -1
- package/esm/services/screen-service.js +75 -4
- package/esm/services/screen-service.js.map +1 -1
- package/esm/services/screen-service.spec.js +91 -7
- package/esm/services/screen-service.spec.js.map +1 -1
- package/esm/shade-component.d.ts +17 -4
- package/esm/shade-component.d.ts.map +1 -1
- package/esm/shade-component.js +67 -5
- package/esm/shade-component.js.map +1 -1
- package/esm/shade-host-props-ref.integration.spec.d.ts +2 -0
- package/esm/shade-host-props-ref.integration.spec.d.ts.map +1 -0
- package/esm/shade-host-props-ref.integration.spec.js +381 -0
- package/esm/shade-host-props-ref.integration.spec.js.map +1 -0
- package/esm/shade-resources.integration.spec.js +208 -39
- package/esm/shade-resources.integration.spec.js.map +1 -1
- package/esm/shade.d.ts +20 -17
- package/esm/shade.d.ts.map +1 -1
- package/esm/shade.js +172 -33
- package/esm/shade.js.map +1 -1
- package/esm/shade.spec.js +31 -30
- package/esm/shade.spec.js.map +1 -1
- package/esm/shades.integration.spec.js +135 -72
- package/esm/shades.integration.spec.js.map +1 -1
- package/esm/style-manager.d.ts +2 -2
- package/esm/style-manager.js +2 -2
- package/esm/svg-types.d.ts +389 -0
- package/esm/svg-types.d.ts.map +1 -0
- package/esm/svg-types.js +9 -0
- package/esm/svg-types.js.map +1 -0
- package/esm/svg.d.ts +15 -0
- package/esm/svg.d.ts.map +1 -0
- package/esm/svg.js +76 -0
- package/esm/svg.js.map +1 -0
- package/esm/svg.spec.d.ts +2 -0
- package/esm/svg.spec.d.ts.map +1 -0
- package/esm/svg.spec.js +80 -0
- package/esm/svg.spec.js.map +1 -0
- package/esm/vnode.d.ts +103 -0
- package/esm/vnode.d.ts.map +1 -0
- package/esm/vnode.integration.spec.d.ts +2 -0
- package/esm/vnode.integration.spec.d.ts.map +1 -0
- package/esm/vnode.integration.spec.js +494 -0
- package/esm/vnode.integration.spec.js.map +1 -0
- package/esm/vnode.js +453 -0
- package/esm/vnode.js.map +1 -0
- package/esm/vnode.spec.d.ts +2 -0
- package/esm/vnode.spec.d.ts.map +1 -0
- package/esm/vnode.spec.js +473 -0
- package/esm/vnode.spec.js.map +1 -0
- package/package.json +3 -3
- package/src/component-factory.spec.tsx +18 -5
- package/src/components/index.ts +4 -1
- package/src/components/lazy-load.spec.tsx +82 -75
- package/src/components/lazy-load.tsx +49 -27
- package/src/components/link-to-route.spec.tsx +25 -21
- package/src/components/link-to-route.tsx +4 -2
- package/src/components/nested-route-link.spec.tsx +303 -0
- package/src/components/nested-route-link.tsx +100 -0
- package/src/components/nested-route-types.ts +42 -0
- package/src/components/nested-router.spec.tsx +817 -0
- package/src/components/nested-router.tsx +256 -0
- package/src/components/route-link.spec.tsx +22 -18
- package/src/components/route-link.tsx +6 -5
- package/src/components/router.spec.tsx +109 -108
- package/src/components/router.tsx +15 -2
- package/src/initialize.ts +12 -0
- package/src/jsx.ts +129 -2
- package/src/models/children-list.ts +7 -1
- package/src/models/partial-element.ts +13 -2
- package/src/models/render-options.ts +90 -3
- package/src/models/selection-state.ts +4 -0
- package/src/services/location-service.tsx +11 -0
- package/src/services/resource-manager.spec.ts +116 -0
- package/src/services/resource-manager.ts +30 -0
- package/src/services/screen-service.spec.ts +109 -7
- package/src/services/screen-service.ts +81 -4
- package/src/shade-component.ts +72 -6
- package/src/shade-host-props-ref.integration.spec.tsx +460 -0
- package/src/shade-resources.integration.spec.tsx +276 -52
- package/src/shade.spec.tsx +40 -39
- package/src/shade.ts +186 -58
- package/src/shades.integration.spec.tsx +154 -80
- package/src/style-manager.ts +2 -2
- package/src/svg-types.ts +437 -0
- package/src/svg.spec.ts +89 -0
- package/src/svg.ts +78 -0
- package/src/vnode.integration.spec.tsx +657 -0
- package/src/vnode.spec.ts +579 -0
- package/src/vnode.ts +508 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject';
|
|
2
|
-
import { ObservableValue, sleepAsync } from '@furystack/utils';
|
|
2
|
+
import { ObservableValue, sleepAsync, usingAsync } from '@furystack/utils';
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import { initializeShadeRoot } from './initialize.js';
|
|
5
5
|
import { createComponent } from './shade-component.js';
|
|
6
|
-
import { Shade } from './shade.js';
|
|
6
|
+
import { flushUpdates, Shade } from './shade.js';
|
|
7
7
|
describe('Shade Resources integration tests', () => {
|
|
8
8
|
beforeEach(() => {
|
|
9
9
|
document.body.innerHTML = '<div id="root"></div>';
|
|
@@ -12,45 +12,214 @@ describe('Shade Resources integration tests', () => {
|
|
|
12
12
|
document.body.innerHTML = '';
|
|
13
13
|
});
|
|
14
14
|
it('Should update the component based on a custom observable value change', async () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
16
|
+
const rootElement = document.getElementById('root');
|
|
17
|
+
const renderCounter = vi.fn();
|
|
18
|
+
const obs1 = new ObservableValue(0);
|
|
19
|
+
const obs2 = new ObservableValue('a');
|
|
20
|
+
const ExampleComponent = Shade({
|
|
21
|
+
render: ({ useObservable }) => {
|
|
22
|
+
const [value1] = useObservable('obs1', obs1);
|
|
23
|
+
const [value2] = useObservable('obs2', obs2);
|
|
24
|
+
renderCounter();
|
|
25
|
+
return (createComponent("div", null,
|
|
26
|
+
createComponent("div", { id: "val1" }, value1),
|
|
27
|
+
createComponent("div", { id: "val2" }, value2)));
|
|
28
|
+
},
|
|
29
|
+
shadowDomName: 'shades-example-resource',
|
|
30
|
+
});
|
|
31
|
+
expect(obs1.getObservers().length).toBe(0);
|
|
32
|
+
expect(obs2.getObservers().length).toBe(0);
|
|
33
|
+
initializeShadeRoot({
|
|
34
|
+
injector,
|
|
35
|
+
rootElement,
|
|
36
|
+
jsxElement: createComponent(ExampleComponent, null),
|
|
37
|
+
});
|
|
38
|
+
await flushUpdates();
|
|
39
|
+
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">0</div><div id="val2">a</div></div></shades-example-resource></div>');
|
|
40
|
+
expect(obs1.getObservers().length).toBe(1);
|
|
41
|
+
expect(obs2.getObservers().length).toBe(1);
|
|
42
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
43
|
+
obs1.setValue(1);
|
|
44
|
+
await flushUpdates();
|
|
45
|
+
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">1</div><div id="val2">a</div></div></shades-example-resource></div>');
|
|
46
|
+
expect(renderCounter).toBeCalledTimes(2);
|
|
47
|
+
obs2.setValue('b');
|
|
48
|
+
await flushUpdates();
|
|
49
|
+
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">1</div><div id="val2">b</div></div></shades-example-resource></div>');
|
|
50
|
+
const element = document.querySelector('shades-example-resource');
|
|
51
|
+
expect(element.getRenderCount()).toBe(3);
|
|
52
|
+
document.body.innerHTML = '';
|
|
53
|
+
await sleepAsync(10); // Cleanup can be async
|
|
54
|
+
expect(obs1.getObservers().length).toBe(0);
|
|
55
|
+
expect(obs2.getObservers().length).toBe(0);
|
|
56
|
+
expect(renderCounter).toBeCalledTimes(3);
|
|
30
57
|
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
});
|
|
59
|
+
it('Should NOT re-render the component when a custom onChange callback is provided', async () => {
|
|
60
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
61
|
+
const rootElement = document.getElementById('root');
|
|
62
|
+
const renderCounter = vi.fn();
|
|
63
|
+
const customOnChange = vi.fn();
|
|
64
|
+
const obs = new ObservableValue(0);
|
|
65
|
+
const ExampleComponent = Shade({
|
|
66
|
+
render: ({ useObservable }) => {
|
|
67
|
+
const [value] = useObservable('obs', obs, { onChange: customOnChange });
|
|
68
|
+
renderCounter();
|
|
69
|
+
return createComponent("div", { id: "val" }, value);
|
|
70
|
+
},
|
|
71
|
+
shadowDomName: 'shades-example-custom-onchange',
|
|
72
|
+
});
|
|
73
|
+
initializeShadeRoot({
|
|
74
|
+
injector,
|
|
75
|
+
rootElement,
|
|
76
|
+
jsxElement: createComponent(ExampleComponent, null),
|
|
77
|
+
});
|
|
78
|
+
await flushUpdates();
|
|
79
|
+
const element = document.querySelector('shades-example-custom-onchange');
|
|
80
|
+
// Initial render
|
|
81
|
+
expect(element.getRenderCount()).toBe(1);
|
|
82
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
83
|
+
expect(customOnChange).toBeCalledTimes(0); // Not called until value changes
|
|
84
|
+
expect(document.getElementById('val')?.textContent).toBe('0');
|
|
85
|
+
// Change the observable value
|
|
86
|
+
obs.setValue(1);
|
|
87
|
+
// Custom onChange should be called
|
|
88
|
+
expect(customOnChange).toBeCalledTimes(1);
|
|
89
|
+
expect(customOnChange).toHaveBeenLastCalledWith(1);
|
|
90
|
+
// But component should NOT re-render
|
|
91
|
+
expect(element.getRenderCount()).toBe(1);
|
|
92
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
93
|
+
// DOM should still show old value since no re-render occurred
|
|
94
|
+
expect(document.getElementById('val')?.textContent).toBe('0');
|
|
95
|
+
// Change again to verify consistent behavior
|
|
96
|
+
obs.setValue(2);
|
|
97
|
+
expect(customOnChange).toBeCalledTimes(2);
|
|
98
|
+
expect(customOnChange).toHaveBeenLastCalledWith(2);
|
|
99
|
+
expect(element.getRenderCount()).toBe(1);
|
|
100
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
it('Should allow manual DOM updates in custom onChange callback without re-render', async () => {
|
|
104
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
105
|
+
const rootElement = document.getElementById('root');
|
|
106
|
+
const renderCounter = vi.fn();
|
|
107
|
+
const obs = new ObservableValue(0);
|
|
108
|
+
const ExampleComponent = Shade({
|
|
109
|
+
render: ({ useObservable, useRef }) => {
|
|
110
|
+
const valRef = useRef('manualVal');
|
|
111
|
+
useObservable('obs', obs, {
|
|
112
|
+
onChange: (newValue) => {
|
|
113
|
+
if (valRef.current) {
|
|
114
|
+
valRef.current.textContent = String(newValue);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
renderCounter();
|
|
119
|
+
return (createComponent("div", { ref: valRef, id: "manual-val" }, obs.getValue()));
|
|
120
|
+
},
|
|
121
|
+
shadowDomName: 'shades-example-manual-dom-update',
|
|
122
|
+
});
|
|
123
|
+
initializeShadeRoot({
|
|
124
|
+
injector,
|
|
125
|
+
rootElement,
|
|
126
|
+
jsxElement: createComponent(ExampleComponent, null),
|
|
127
|
+
});
|
|
128
|
+
await flushUpdates();
|
|
129
|
+
const element = document.querySelector('shades-example-manual-dom-update');
|
|
130
|
+
// Initial render
|
|
131
|
+
expect(element.getRenderCount()).toBe(1);
|
|
132
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
133
|
+
expect(document.getElementById('manual-val')?.textContent).toBe('0');
|
|
134
|
+
// Change the observable value
|
|
135
|
+
obs.setValue(42);
|
|
136
|
+
// Component should NOT re-render
|
|
137
|
+
expect(element.getRenderCount()).toBe(1);
|
|
138
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
139
|
+
// But DOM should be updated via the manual onChange callback
|
|
140
|
+
expect(document.getElementById('manual-val')?.textContent).toBe('42');
|
|
141
|
+
// Change again
|
|
142
|
+
obs.setValue(100);
|
|
143
|
+
expect(element.getRenderCount()).toBe(1);
|
|
144
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
145
|
+
expect(document.getElementById('manual-val')?.textContent).toBe('100');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
it('Should batch multiple synchronous observable changes into a single render', async () => {
|
|
149
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
150
|
+
const rootElement = document.getElementById('root');
|
|
151
|
+
const renderCounter = vi.fn();
|
|
152
|
+
const obs1 = new ObservableValue(0);
|
|
153
|
+
const obs2 = new ObservableValue('a');
|
|
154
|
+
const obs3 = new ObservableValue(false);
|
|
155
|
+
const ExampleComponent = Shade({
|
|
156
|
+
render: ({ useObservable }) => {
|
|
157
|
+
const [value1] = useObservable('obs1', obs1);
|
|
158
|
+
const [value2] = useObservable('obs2', obs2);
|
|
159
|
+
const [value3] = useObservable('obs3', obs3);
|
|
160
|
+
renderCounter();
|
|
161
|
+
return (createComponent("div", null,
|
|
162
|
+
createComponent("span", { id: "v1" }, value1),
|
|
163
|
+
createComponent("span", { id: "v2" }, value2),
|
|
164
|
+
createComponent("span", { id: "v3" }, String(value3))));
|
|
165
|
+
},
|
|
166
|
+
shadowDomName: 'shades-example-batching',
|
|
167
|
+
});
|
|
168
|
+
initializeShadeRoot({
|
|
169
|
+
injector,
|
|
170
|
+
rootElement,
|
|
171
|
+
jsxElement: createComponent(ExampleComponent, null),
|
|
172
|
+
});
|
|
173
|
+
await flushUpdates();
|
|
174
|
+
const element = document.querySelector('shades-example-batching');
|
|
175
|
+
expect(element.getRenderCount()).toBe(1);
|
|
176
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
177
|
+
// Change all three observables synchronously without awaiting in between
|
|
178
|
+
obs1.setValue(42);
|
|
179
|
+
obs2.setValue('z');
|
|
180
|
+
obs3.setValue(true);
|
|
181
|
+
// Before flushing, the DOM should still reflect the old values
|
|
182
|
+
expect(element.getRenderCount()).toBe(1);
|
|
183
|
+
await flushUpdates();
|
|
184
|
+
// After flushing, all changes should be reflected in a single render
|
|
185
|
+
expect(element.getRenderCount()).toBe(2);
|
|
186
|
+
expect(renderCounter).toBeCalledTimes(2);
|
|
187
|
+
expect(document.getElementById('v1')?.textContent).toBe('42');
|
|
188
|
+
expect(document.getElementById('v2')?.textContent).toBe('z');
|
|
189
|
+
expect(document.getElementById('v3')?.textContent).toBe('true');
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
it('Should batch multiple updateComponent() calls into a single render', async () => {
|
|
193
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
194
|
+
const rootElement = document.getElementById('root');
|
|
195
|
+
const renderCounter = vi.fn();
|
|
196
|
+
const ExampleComponent = Shade({
|
|
197
|
+
render: () => {
|
|
198
|
+
renderCounter();
|
|
199
|
+
return createComponent("div", null, "content");
|
|
200
|
+
},
|
|
201
|
+
shadowDomName: 'shades-example-update-batching',
|
|
202
|
+
});
|
|
203
|
+
initializeShadeRoot({
|
|
204
|
+
injector,
|
|
205
|
+
rootElement,
|
|
206
|
+
jsxElement: createComponent(ExampleComponent, null),
|
|
207
|
+
});
|
|
208
|
+
await flushUpdates();
|
|
209
|
+
const element = document.querySelector('shades-example-update-batching');
|
|
210
|
+
expect(element.getRenderCount()).toBe(1);
|
|
211
|
+
expect(renderCounter).toBeCalledTimes(1);
|
|
212
|
+
// Call updateComponent multiple times synchronously
|
|
213
|
+
element.updateComponent();
|
|
214
|
+
element.updateComponent();
|
|
215
|
+
element.updateComponent();
|
|
216
|
+
// Before flushing, render count should still be 1
|
|
217
|
+
expect(element.getRenderCount()).toBe(1);
|
|
218
|
+
await flushUpdates();
|
|
219
|
+
// After flushing, only a single additional render should have occurred
|
|
220
|
+
expect(element.getRenderCount()).toBe(2);
|
|
221
|
+
expect(renderCounter).toBeCalledTimes(2);
|
|
37
222
|
});
|
|
38
|
-
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">0</div><div id="val2">a</div></div></shades-example-resource></div>');
|
|
39
|
-
expect(obs1.getObservers().length).toBe(1);
|
|
40
|
-
expect(obs2.getObservers().length).toBe(1);
|
|
41
|
-
expect(renderCounter).toBeCalledTimes(1);
|
|
42
|
-
obs1.setValue(1);
|
|
43
|
-
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">1</div><div id="val2">a</div></div></shades-example-resource></div>');
|
|
44
|
-
expect(renderCounter).toBeCalledTimes(2);
|
|
45
|
-
obs2.setValue('b');
|
|
46
|
-
expect(document.body.innerHTML).toBe('<div id="root"><shades-example-resource><div><div id="val1">1</div><div id="val2">b</div></div></shades-example-resource></div>');
|
|
47
|
-
const element = document.querySelector('shades-example-resource');
|
|
48
|
-
expect(element.getRenderCount()).toBe(3);
|
|
49
|
-
document.body.innerHTML = '';
|
|
50
|
-
await sleepAsync(10); // Cleanup can be async
|
|
51
|
-
expect(obs1.getObservers().length).toBe(0);
|
|
52
|
-
expect(obs2.getObservers().length).toBe(0);
|
|
53
|
-
expect(renderCounter).toBeCalledTimes(3);
|
|
54
223
|
});
|
|
55
224
|
});
|
|
56
225
|
//# sourceMappingURL=shade-resources.integration.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shade-resources.integration.spec.js","sourceRoot":"","sources":["../src/shade-resources.integration.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"shade-resources.integration.spec.js","sourceRoot":"","sources":["../src/shade-resources.integration.spec.tsx"],"names":[],"mappings":"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"}
|
package/esm/shade.d.ts
CHANGED
|
@@ -2,25 +2,16 @@ import type { Constructable } from '@furystack/inject';
|
|
|
2
2
|
import type { ChildrenList, CSSObject, PartialElement, RenderOptions } from './models/index.js';
|
|
3
3
|
export type ShadeOptions<TProps, TElementBase extends HTMLElement> = {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* The custom element tag name used to register the component.
|
|
6
|
+
* Must follow the Custom Elements naming convention (lowercase, must contain a hyphen).
|
|
7
|
+
*
|
|
8
|
+
* @example 'my-button', 'shade-dialog', 'app-header'
|
|
6
9
|
*/
|
|
7
10
|
shadowDomName: string;
|
|
8
11
|
/**
|
|
9
12
|
* Render hook, this method will be executed on each and every render.
|
|
10
13
|
*/
|
|
11
14
|
render: (options: RenderOptions<TProps, TElementBase>) => JSX.Element | string | null;
|
|
12
|
-
/**
|
|
13
|
-
* Construct hook. Will be executed once when the element has been constructed and initialized
|
|
14
|
-
*/
|
|
15
|
-
constructed?: (options: RenderOptions<TProps, TElementBase>) => void | undefined | (() => void) | Promise<void | undefined | (() => void)>;
|
|
16
|
-
/**
|
|
17
|
-
* Will be executed when the element is attached to the DOM.
|
|
18
|
-
*/
|
|
19
|
-
onAttach?: (options: RenderOptions<TProps, TElementBase>) => void;
|
|
20
|
-
/**
|
|
21
|
-
* Will be executed when the element is detached from the DOM.
|
|
22
|
-
*/
|
|
23
|
-
onDetach?: (options: RenderOptions<TProps, TElementBase>) => void;
|
|
24
15
|
/**
|
|
25
16
|
* Name of the HTML Element's base class. Needs to be defined if the elementBase is set. E.g.: 'div', 'button', 'input'
|
|
26
17
|
*/
|
|
@@ -30,18 +21,21 @@ export type ShadeOptions<TProps, TElementBase extends HTMLElement> = {
|
|
|
30
21
|
*/
|
|
31
22
|
elementBase?: Constructable<TElementBase>;
|
|
32
23
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
24
|
+
* Inline styles applied to each component instance.
|
|
25
|
+
* Use for per-instance dynamic overrides. Prefer `css` for component-level defaults.
|
|
35
26
|
*/
|
|
36
27
|
style?: Partial<CSSStyleDeclaration>;
|
|
37
28
|
/**
|
|
38
29
|
* CSS styles injected as a stylesheet during component registration.
|
|
39
|
-
* Supports pseudo-selectors (
|
|
40
|
-
*
|
|
30
|
+
* Supports pseudo-selectors (`&:hover`, `&:active`) and nested selectors (`& .class`).
|
|
31
|
+
*
|
|
32
|
+
* **Best practice:** Prefer `css` over `style` for component defaults -- styles are injected
|
|
33
|
+
* once per component type (better performance), and support pseudo-selectors and nesting.
|
|
41
34
|
*
|
|
42
35
|
* @example
|
|
43
36
|
* ```typescript
|
|
44
37
|
* css: {
|
|
38
|
+
* display: 'flex',
|
|
45
39
|
* padding: '16px',
|
|
46
40
|
* '&:hover': { backgroundColor: '#f0f0f0' },
|
|
47
41
|
* '& .title': { fontWeight: 'bold' }
|
|
@@ -56,4 +50,13 @@ export type ShadeOptions<TProps, TElementBase extends HTMLElement> = {
|
|
|
56
50
|
* @returns the JSX element
|
|
57
51
|
*/
|
|
58
52
|
export declare const Shade: <TProps, TElementBase extends HTMLElement = HTMLElement>(o: ShadeOptions<TProps, TElementBase>) => (props: TProps & PartialElement<TElementBase>, children?: ChildrenList) => JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* Flushes any pending microtask-based component updates.
|
|
55
|
+
* Useful in tests to wait for batched renders to complete before asserting DOM state.
|
|
56
|
+
*
|
|
57
|
+
* Note: this flushes one level of pending updates. If a render itself triggers new
|
|
58
|
+
* `updateComponent()` calls, an additional `await flushUpdates()` may be needed.
|
|
59
|
+
* @returns a promise that resolves after the current microtask queue has been processed
|
|
60
|
+
*/
|
|
61
|
+
export declare const flushUpdates: () => Promise<void>;
|
|
59
62
|
//# sourceMappingURL=shade.d.ts.map
|
package/esm/shade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shade.d.ts","sourceRoot":"","sources":["../src/shade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAGtD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"shade.d.ts","sourceRoot":"","sources":["../src/shade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAGtD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAS/F,MAAM,MAAM,YAAY,CAAC,MAAM,EAAE,YAAY,SAAS,WAAW,IAAI;IACnE;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,MAAM,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAErF;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IAEzC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAEpC;;;;;;;;;;;;;;;;OAgBG;IACH,GAAG,CAAC,EAAE,SAAS,CAAA;CAChB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,MAAM,EAAE,YAAY,SAAS,WAAW,GAAG,WAAW,EAC1E,GAAG,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,MA+V7B,OAAO,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,EAAE,WAAW,YAAY,KAgB9D,GAAG,CAAC,OAEpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,QAAO,OAAO,CAAC,IAAI,CAA4D,CAAA"}
|
package/esm/shade.js
CHANGED
|
@@ -2,15 +2,16 @@ import { hasInjectorReference, Injector } from '@furystack/inject';
|
|
|
2
2
|
import { ObservableValue } from '@furystack/utils';
|
|
3
3
|
import { LocationService } from './services/location-service.js';
|
|
4
4
|
import { ResourceManager } from './services/resource-manager.js';
|
|
5
|
-
import { attachProps, attachStyles } from './shade-component.js';
|
|
5
|
+
import { attachProps, attachStyles, setRenderMode } from './shade-component.js';
|
|
6
6
|
import { StyleManager } from './style-manager.js';
|
|
7
|
+
import { patchChildren, toVChildArray } from './vnode.js';
|
|
7
8
|
/**
|
|
8
9
|
* Factory method for creating Shade components
|
|
9
10
|
* @param o The options object for component creation
|
|
10
11
|
* @returns the JSX element
|
|
11
12
|
*/
|
|
12
13
|
export const Shade = (o) => {
|
|
13
|
-
//
|
|
14
|
+
// Register custom element
|
|
14
15
|
const customElementName = o.shadowDomName;
|
|
15
16
|
const existing = customElements.get(customElementName);
|
|
16
17
|
if (!existing) {
|
|
@@ -28,14 +29,27 @@ export const Shade = (o) => {
|
|
|
28
29
|
return this._renderCount;
|
|
29
30
|
}
|
|
30
31
|
resourceManager = new ResourceManager();
|
|
32
|
+
/**
|
|
33
|
+
* Host props collected during the current render pass via `useHostProps`.
|
|
34
|
+
* Applied to the host element after each render.
|
|
35
|
+
*/
|
|
36
|
+
_pendingHostProps = [];
|
|
37
|
+
/**
|
|
38
|
+
* The host props that were applied in the previous render, used for diffing.
|
|
39
|
+
*/
|
|
40
|
+
_prevHostProps = null;
|
|
41
|
+
/**
|
|
42
|
+
* Cached ref objects keyed by the user-provided key string.
|
|
43
|
+
*/
|
|
44
|
+
_refs = new Map();
|
|
31
45
|
connectedCallback() {
|
|
32
|
-
|
|
33
|
-
this.callConstructed();
|
|
46
|
+
this.updateComponent();
|
|
34
47
|
}
|
|
35
48
|
async disconnectedCallback() {
|
|
36
|
-
|
|
49
|
+
this._refs.clear();
|
|
50
|
+
this._prevVTree = null;
|
|
51
|
+
this._prevHostProps = null;
|
|
37
52
|
await this.resourceManager[Symbol.asyncDispose]();
|
|
38
|
-
this.cleanup?.();
|
|
39
53
|
}
|
|
40
54
|
/**
|
|
41
55
|
* Will be triggered when updating the external props object
|
|
@@ -61,8 +75,18 @@ export const Shade = (o) => {
|
|
|
61
75
|
props: this.props,
|
|
62
76
|
injector: this.injector,
|
|
63
77
|
children: this.shadeChildren,
|
|
64
|
-
element: this,
|
|
65
78
|
renderCount: this._renderCount,
|
|
79
|
+
useHostProps: (hostProps) => {
|
|
80
|
+
this._pendingHostProps.push(hostProps);
|
|
81
|
+
},
|
|
82
|
+
useRef: (key) => {
|
|
83
|
+
const existingRef = this._refs.get(key);
|
|
84
|
+
if (existingRef)
|
|
85
|
+
return existingRef;
|
|
86
|
+
const refObject = { current: null };
|
|
87
|
+
this._refs.set(key, refObject);
|
|
88
|
+
return refObject;
|
|
89
|
+
},
|
|
66
90
|
useObservable: (key, obesrvable, options) => {
|
|
67
91
|
const onChange = options?.onChange || (() => this.updateComponent());
|
|
68
92
|
return this.resourceManager.useObservable(key, obesrvable, onChange, options);
|
|
@@ -116,43 +140,149 @@ export const Shade = (o) => {
|
|
|
116
140
|
};
|
|
117
141
|
return renderOptions;
|
|
118
142
|
};
|
|
143
|
+
_updateScheduled = false;
|
|
119
144
|
/**
|
|
120
|
-
*
|
|
145
|
+
* The VChild array from the previous render, with `_el` references
|
|
146
|
+
* pointing to the real DOM nodes. Used to diff against the next render.
|
|
147
|
+
*/
|
|
148
|
+
_prevVTree = null;
|
|
149
|
+
/**
|
|
150
|
+
* Schedules a component update via microtask. Multiple calls before the microtask
|
|
151
|
+
* runs are coalesced into a single render pass.
|
|
121
152
|
*/
|
|
122
153
|
updateComponent() {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
154
|
+
if (!this._updateScheduled) {
|
|
155
|
+
this._updateScheduled = true;
|
|
156
|
+
queueMicrotask(() => {
|
|
157
|
+
this._updateScheduled = false;
|
|
158
|
+
this._performUpdate();
|
|
159
|
+
});
|
|
129
160
|
}
|
|
130
|
-
|
|
131
|
-
|
|
161
|
+
}
|
|
162
|
+
_performUpdate() {
|
|
163
|
+
this._pendingHostProps = [];
|
|
164
|
+
let renderResult;
|
|
165
|
+
setRenderMode(true);
|
|
166
|
+
try {
|
|
167
|
+
renderResult = this.render(this.getRenderOptions());
|
|
132
168
|
}
|
|
133
|
-
|
|
134
|
-
|
|
169
|
+
finally {
|
|
170
|
+
setRenderMode(false);
|
|
135
171
|
}
|
|
172
|
+
const newVTree = toVChildArray(renderResult);
|
|
173
|
+
patchChildren(this, this._prevVTree || [], newVTree);
|
|
174
|
+
this._prevVTree = newVTree;
|
|
175
|
+
this._applyHostProps();
|
|
136
176
|
}
|
|
137
177
|
/**
|
|
138
|
-
*
|
|
178
|
+
* Merges all pending host props from the render pass and applies them
|
|
179
|
+
* to the host element, diffing against the previously applied host props.
|
|
139
180
|
*/
|
|
140
|
-
|
|
141
|
-
this.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
181
|
+
_applyHostProps() {
|
|
182
|
+
if (this._pendingHostProps.length === 0) {
|
|
183
|
+
if (this._prevHostProps) {
|
|
184
|
+
// All host props were removed — clean up
|
|
185
|
+
for (const key of Object.keys(this._prevHostProps)) {
|
|
186
|
+
if (key === 'style')
|
|
187
|
+
continue;
|
|
188
|
+
this.removeAttribute(key);
|
|
189
|
+
}
|
|
190
|
+
if (this._prevHostProps.style) {
|
|
191
|
+
for (const sk of Object.keys(this._prevHostProps.style)) {
|
|
192
|
+
if (sk.startsWith('--')) {
|
|
193
|
+
this.style.removeProperty(sk);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
;
|
|
197
|
+
this.style[sk] = '';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
this._prevHostProps = null;
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Merge all pending host prop calls into a single object
|
|
206
|
+
const merged = {};
|
|
207
|
+
let mergedStyle;
|
|
208
|
+
for (const hp of this._pendingHostProps) {
|
|
209
|
+
for (const [key, value] of Object.entries(hp)) {
|
|
210
|
+
if (key === 'style' && typeof value === 'object' && value !== null) {
|
|
211
|
+
mergedStyle = { ...mergedStyle, ...value };
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
merged[key] = value;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (mergedStyle) {
|
|
219
|
+
merged.style = mergedStyle;
|
|
220
|
+
}
|
|
221
|
+
const oldHP = this._prevHostProps || {};
|
|
222
|
+
const newHP = merged;
|
|
223
|
+
// Remove attributes no longer present
|
|
224
|
+
for (const key of Object.keys(oldHP)) {
|
|
225
|
+
if (key === 'style')
|
|
226
|
+
continue;
|
|
227
|
+
if (!(key in newHP)) {
|
|
228
|
+
if (key.startsWith('on') && typeof oldHP[key] === 'function') {
|
|
229
|
+
;
|
|
230
|
+
this[key] = null;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
this.removeAttribute(key);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
149
236
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
237
|
+
// Apply new/changed attributes
|
|
238
|
+
for (const [key, value] of Object.entries(newHP)) {
|
|
239
|
+
if (key === 'style')
|
|
240
|
+
continue;
|
|
241
|
+
if (oldHP[key] !== value) {
|
|
242
|
+
if (typeof value === 'function' || (typeof value === 'object' && value !== null)) {
|
|
243
|
+
;
|
|
244
|
+
this[key] = value;
|
|
245
|
+
}
|
|
246
|
+
else if (value === null || value === undefined || value === false) {
|
|
247
|
+
if (key in this) {
|
|
248
|
+
;
|
|
249
|
+
this[key] = undefined;
|
|
250
|
+
}
|
|
251
|
+
this.removeAttribute(key);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
255
|
+
this.setAttribute(key, String(value));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Diff styles
|
|
260
|
+
const oldStyle = oldHP.style || {};
|
|
261
|
+
const newStyle = mergedStyle || {};
|
|
262
|
+
for (const sk of Object.keys(oldStyle)) {
|
|
263
|
+
if (!(sk in newStyle)) {
|
|
264
|
+
if (sk.startsWith('--')) {
|
|
265
|
+
this.style.removeProperty(sk);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
;
|
|
269
|
+
this.style[sk] = '';
|
|
270
|
+
}
|
|
271
|
+
}
|
|
153
272
|
}
|
|
273
|
+
for (const [sk, sv] of Object.entries(newStyle)) {
|
|
274
|
+
if (oldStyle[sk] !== sv) {
|
|
275
|
+
if (sk.startsWith('--')) {
|
|
276
|
+
this.style.setProperty(sk, sv);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
;
|
|
280
|
+
this.style[sk] = sv;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this._prevHostProps = merged;
|
|
154
285
|
}
|
|
155
|
-
cleanup = undefined;
|
|
156
286
|
_injector;
|
|
157
287
|
getInjectorFromParent() {
|
|
158
288
|
let parent = this.parentElement;
|
|
@@ -185,7 +315,7 @@ export const Shade = (o) => {
|
|
|
185
315
|
}, o.elementBaseName ? { extends: o.elementBaseName } : undefined);
|
|
186
316
|
}
|
|
187
317
|
else {
|
|
188
|
-
throw Error(`A custom shade with
|
|
318
|
+
throw Error(`A custom shade with name '${o.shadowDomName}' has already been registered!`);
|
|
189
319
|
}
|
|
190
320
|
return (props, children) => {
|
|
191
321
|
const ElementType = customElements.get(customElementName);
|
|
@@ -202,4 +332,13 @@ export const Shade = (o) => {
|
|
|
202
332
|
return el;
|
|
203
333
|
};
|
|
204
334
|
};
|
|
335
|
+
/**
|
|
336
|
+
* Flushes any pending microtask-based component updates.
|
|
337
|
+
* Useful in tests to wait for batched renders to complete before asserting DOM state.
|
|
338
|
+
*
|
|
339
|
+
* Note: this flushes one level of pending updates. If a render itself triggers new
|
|
340
|
+
* `updateComponent()` calls, an additional `await flushUpdates()` may be needed.
|
|
341
|
+
* @returns a promise that resolves after the current microtask queue has been processed
|
|
342
|
+
*/
|
|
343
|
+
export const flushUpdates = () => new Promise((resolve) => queueMicrotask(resolve));
|
|
205
344
|
//# sourceMappingURL=shade.js.map
|