thunderous 2.4.1 → 2.4.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.
- package/dist/index.cjs +19 -22
- package/dist/index.d.cts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +19 -22
- package/package.json +54 -69
- package/dist/__test__/custom-element.test.js +0 -48
- package/dist/__test__/registry.test.js +0 -60
- package/dist/__test__/render.test.js +0 -48
- package/dist/__test__/server-side.test.js +0 -196
- package/dist/__test__/signals.test.js +0 -247
- package/dist/__test__/utilities.test.js +0 -8
- package/dist/constants.js +0 -13
- package/dist/custom-element.js +0 -391
- package/dist/registry.js +0 -95
- package/dist/render.js +0 -350
- package/dist/server-side.js +0 -136
- package/dist/signals.js +0 -115
- package/dist/utilities.js +0 -9
package/dist/index.cjs
CHANGED
|
@@ -49,14 +49,14 @@ var DEFAULT_RENDER_OPTIONS = {
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
// src/signals.ts
|
|
52
|
-
var
|
|
52
|
+
var ident = null;
|
|
53
53
|
var effects = /* @__PURE__ */ new WeakMap();
|
|
54
54
|
var createSignal = (initVal, options) => {
|
|
55
55
|
const subscribers = /* @__PURE__ */ new Set();
|
|
56
56
|
let value = initVal;
|
|
57
57
|
const getter = (getterOptions) => {
|
|
58
|
-
if (
|
|
59
|
-
subscribers.add(
|
|
58
|
+
if (ident !== null) {
|
|
59
|
+
subscribers.add(ident);
|
|
60
60
|
}
|
|
61
61
|
if (options?.debugMode === true || getterOptions?.debugMode === true) {
|
|
62
62
|
let label = "anonymous signal";
|
|
@@ -70,7 +70,7 @@ var createSignal = (initVal, options) => {
|
|
|
70
70
|
}
|
|
71
71
|
console.log("Signal retrieved:", {
|
|
72
72
|
value,
|
|
73
|
-
subscribers: Array.from(subscribers).map((
|
|
73
|
+
subscribers: Array.from(subscribers).map((sym) => effects.get(sym)),
|
|
74
74
|
label
|
|
75
75
|
});
|
|
76
76
|
}
|
|
@@ -96,22 +96,22 @@ var createSignal = (initVal, options) => {
|
|
|
96
96
|
}
|
|
97
97
|
const oldValue = value;
|
|
98
98
|
value = newValue;
|
|
99
|
-
for (const
|
|
100
|
-
const effectRef = effects.get(
|
|
99
|
+
for (const sym of subscribers) {
|
|
100
|
+
const effectRef = effects.get(sym);
|
|
101
101
|
if (effectRef !== void 0) {
|
|
102
102
|
try {
|
|
103
103
|
effectRef.fn({
|
|
104
104
|
lastValue: effectRef.value,
|
|
105
105
|
destroy: () => {
|
|
106
|
-
effects.delete(
|
|
107
|
-
queueMicrotask(() => subscribers.delete(
|
|
106
|
+
effects.delete(sym);
|
|
107
|
+
queueMicrotask(() => subscribers.delete(sym));
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
} catch (error) {
|
|
111
111
|
console.error("Error in subscriber:", { error, oldValue, newValue, fn: effectRef.fn });
|
|
112
112
|
}
|
|
113
113
|
} else {
|
|
114
|
-
queueMicrotask(() => subscribers.delete(
|
|
114
|
+
queueMicrotask(() => subscribers.delete(sym));
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
if (options?.debugMode === true || setterOptions?.debugMode === true) {
|
|
@@ -127,7 +127,7 @@ var createSignal = (initVal, options) => {
|
|
|
127
127
|
console.log("Signal set:", {
|
|
128
128
|
oldValue,
|
|
129
129
|
newValue,
|
|
130
|
-
subscribers: Array.from(subscribers).map((
|
|
130
|
+
subscribers: Array.from(subscribers).map((sym) => effects.get(sym)),
|
|
131
131
|
label
|
|
132
132
|
});
|
|
133
133
|
}
|
|
@@ -146,19 +146,19 @@ var derived = (fn, options) => {
|
|
|
146
146
|
return getter;
|
|
147
147
|
};
|
|
148
148
|
var createEffect = (fn, value) => {
|
|
149
|
-
const
|
|
150
|
-
effects.set(
|
|
149
|
+
const privateIdent = ident = {};
|
|
150
|
+
effects.set(ident, { fn, value });
|
|
151
151
|
try {
|
|
152
152
|
fn({
|
|
153
153
|
lastValue: value,
|
|
154
154
|
destroy: () => {
|
|
155
|
-
effects.delete(
|
|
155
|
+
effects.delete(privateIdent);
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
158
|
} catch (error) {
|
|
159
159
|
console.error("Error in effect:", { error, fn });
|
|
160
160
|
}
|
|
161
|
-
|
|
161
|
+
ident = null;
|
|
162
162
|
};
|
|
163
163
|
|
|
164
164
|
// src/utilities.ts
|
|
@@ -459,10 +459,6 @@ var evaluateBindings = (element, fragment) => {
|
|
|
459
459
|
createEffect(
|
|
460
460
|
({ lastValue: oldChildren, destroy }) => {
|
|
461
461
|
const result = signal2();
|
|
462
|
-
console.trace("Binding array:", {
|
|
463
|
-
result: result.map((node) => node.cloneNode(true)),
|
|
464
|
-
oldChildren
|
|
465
|
-
});
|
|
466
462
|
const newChildren = asNodeList(result, element);
|
|
467
463
|
const firstChild = newChildren[0];
|
|
468
464
|
if (!Array.isArray(result) && newChildren.length === 1 && firstChild instanceof DocumentFragment) {
|
|
@@ -712,7 +708,7 @@ var css = (strings, ...values) => {
|
|
|
712
708
|
}
|
|
713
709
|
const newCSSText = newCSSTextList.join("");
|
|
714
710
|
if (isCSSStyleSheet(stylesheet)) {
|
|
715
|
-
stylesheet.
|
|
711
|
+
stylesheet.replaceSync(newCSSText);
|
|
716
712
|
} else {
|
|
717
713
|
stylesheet.textContent = newCSSText;
|
|
718
714
|
}
|
|
@@ -741,6 +737,7 @@ var customElement = (render, options) => {
|
|
|
741
737
|
if (shadowRootOptions.registry !== void 0 && "scoped" in shadowRootOptions.registry && shadowRootOptions.registry.scoped) {
|
|
742
738
|
return shadowRootOptions.registry;
|
|
743
739
|
}
|
|
740
|
+
return void 0;
|
|
744
741
|
})();
|
|
745
742
|
return {
|
|
746
743
|
define(tagName) {
|
|
@@ -800,8 +797,8 @@ var customElement = (render, options) => {
|
|
|
800
797
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
|
801
798
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
|
802
799
|
#clientOnlyCallbackFns = /* @__PURE__ */ new Set();
|
|
803
|
-
#shadowRoot = attachShadow ? this.attachShadow(shadowRootOptions) : null;
|
|
804
800
|
#internals = this.attachInternals();
|
|
801
|
+
#shadowRoot = attachShadow ? this.#internals.shadowRoot ?? this.attachShadow(shadowRootOptions) : null;
|
|
805
802
|
#observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
|
|
806
803
|
for (const mutation of mutations) {
|
|
807
804
|
const attrName = mutation.attributeName;
|
|
@@ -854,7 +851,7 @@ Element: <${this.tagName.toLowerCase()}>
|
|
|
854
851
|
this[prop] = newValue;
|
|
855
852
|
_setter(newValue, options2);
|
|
856
853
|
};
|
|
857
|
-
const getter = (options2) => {
|
|
854
|
+
const getter = ((options2) => {
|
|
858
855
|
const value = _getter(options2);
|
|
859
856
|
if (value === void 0 && !allowUndefined) {
|
|
860
857
|
const error = new Error(
|
|
@@ -866,7 +863,7 @@ You must set an initial value before calling a property signal's getter.
|
|
|
866
863
|
throw error;
|
|
867
864
|
}
|
|
868
865
|
return value;
|
|
869
|
-
};
|
|
866
|
+
});
|
|
870
867
|
getter.getter = true;
|
|
871
868
|
const publicSignal = [getter, setter];
|
|
872
869
|
publicSignal.init = (value) => {
|
package/dist/index.d.cts
CHANGED
|
@@ -107,13 +107,11 @@ type Signal<T = unknown> = [SignalGetter<T>, SignalSetter<T>];
|
|
|
107
107
|
type SignalWithInit<T = unknown> = Signal<T> & { init: (value: T) => Signal<T> };
|
|
108
108
|
|
|
109
109
|
// Flexible typing is necessary to support generic functions
|
|
110
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
110
|
type AnyFn = (...args: any[]) => any;
|
|
112
111
|
|
|
113
112
|
type HTMLCustomElement<T extends Record<PropertyKey, unknown>> = Omit<HTMLElement, keyof T> & T;
|
|
114
113
|
|
|
115
114
|
// Again, flexible typing is necessary to support these generics
|
|
116
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
115
|
type Effect<T = any> = (args: { lastValue: T; destroy: () => void }) => T | void;
|
|
118
116
|
|
|
119
117
|
/**
|
|
@@ -186,4 +184,4 @@ declare const createEffect: <T = unknown>(fn: Effect<T>, value?: T) => void;
|
|
|
186
184
|
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
|
187
185
|
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => Styles;
|
|
188
186
|
|
|
189
|
-
export { type HTMLCustomElement, type RenderArgs, type RenderFunction, type Signal, type SignalGetter, type SignalSetter, clientOnlyCallback, createEffect, createRegistry, createSignal, css, customElement, derived, html, insertTemplates, onServerDefine };
|
|
187
|
+
export { type ElementResult, type HTMLCustomElement, type RegistryResult, type RenderArgs, type RenderFunction, type Signal, type SignalGetter, type SignalSetter, clientOnlyCallback, createEffect, createRegistry, createSignal, css, customElement, derived, html, insertTemplates, onServerDefine };
|
package/dist/index.d.ts
CHANGED
|
@@ -107,13 +107,11 @@ type Signal<T = unknown> = [SignalGetter<T>, SignalSetter<T>];
|
|
|
107
107
|
type SignalWithInit<T = unknown> = Signal<T> & { init: (value: T) => Signal<T> };
|
|
108
108
|
|
|
109
109
|
// Flexible typing is necessary to support generic functions
|
|
110
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
110
|
type AnyFn = (...args: any[]) => any;
|
|
112
111
|
|
|
113
112
|
type HTMLCustomElement<T extends Record<PropertyKey, unknown>> = Omit<HTMLElement, keyof T> & T;
|
|
114
113
|
|
|
115
114
|
// Again, flexible typing is necessary to support these generics
|
|
116
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
115
|
type Effect<T = any> = (args: { lastValue: T; destroy: () => void }) => T | void;
|
|
118
116
|
|
|
119
117
|
/**
|
|
@@ -186,4 +184,4 @@ declare const createEffect: <T = unknown>(fn: Effect<T>, value?: T) => void;
|
|
|
186
184
|
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
|
187
185
|
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => Styles;
|
|
188
186
|
|
|
189
|
-
export { type HTMLCustomElement, type RenderArgs, type RenderFunction, type Signal, type SignalGetter, type SignalSetter, clientOnlyCallback, createEffect, createRegistry, createSignal, css, customElement, derived, html, insertTemplates, onServerDefine };
|
|
187
|
+
export { type ElementResult, type HTMLCustomElement, type RegistryResult, type RenderArgs, type RenderFunction, type Signal, type SignalGetter, type SignalSetter, clientOnlyCallback, createEffect, createRegistry, createSignal, css, customElement, derived, html, insertTemplates, onServerDefine };
|
package/dist/index.js
CHANGED
|
@@ -14,14 +14,14 @@ var DEFAULT_RENDER_OPTIONS = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/signals.ts
|
|
17
|
-
var
|
|
17
|
+
var ident = null;
|
|
18
18
|
var effects = /* @__PURE__ */ new WeakMap();
|
|
19
19
|
var createSignal = (initVal, options) => {
|
|
20
20
|
const subscribers = /* @__PURE__ */ new Set();
|
|
21
21
|
let value = initVal;
|
|
22
22
|
const getter = (getterOptions) => {
|
|
23
|
-
if (
|
|
24
|
-
subscribers.add(
|
|
23
|
+
if (ident !== null) {
|
|
24
|
+
subscribers.add(ident);
|
|
25
25
|
}
|
|
26
26
|
if (options?.debugMode === true || getterOptions?.debugMode === true) {
|
|
27
27
|
let label = "anonymous signal";
|
|
@@ -35,7 +35,7 @@ var createSignal = (initVal, options) => {
|
|
|
35
35
|
}
|
|
36
36
|
console.log("Signal retrieved:", {
|
|
37
37
|
value,
|
|
38
|
-
subscribers: Array.from(subscribers).map((
|
|
38
|
+
subscribers: Array.from(subscribers).map((sym) => effects.get(sym)),
|
|
39
39
|
label
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -61,22 +61,22 @@ var createSignal = (initVal, options) => {
|
|
|
61
61
|
}
|
|
62
62
|
const oldValue = value;
|
|
63
63
|
value = newValue;
|
|
64
|
-
for (const
|
|
65
|
-
const effectRef = effects.get(
|
|
64
|
+
for (const sym of subscribers) {
|
|
65
|
+
const effectRef = effects.get(sym);
|
|
66
66
|
if (effectRef !== void 0) {
|
|
67
67
|
try {
|
|
68
68
|
effectRef.fn({
|
|
69
69
|
lastValue: effectRef.value,
|
|
70
70
|
destroy: () => {
|
|
71
|
-
effects.delete(
|
|
72
|
-
queueMicrotask(() => subscribers.delete(
|
|
71
|
+
effects.delete(sym);
|
|
72
|
+
queueMicrotask(() => subscribers.delete(sym));
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
} catch (error) {
|
|
76
76
|
console.error("Error in subscriber:", { error, oldValue, newValue, fn: effectRef.fn });
|
|
77
77
|
}
|
|
78
78
|
} else {
|
|
79
|
-
queueMicrotask(() => subscribers.delete(
|
|
79
|
+
queueMicrotask(() => subscribers.delete(sym));
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
if (options?.debugMode === true || setterOptions?.debugMode === true) {
|
|
@@ -92,7 +92,7 @@ var createSignal = (initVal, options) => {
|
|
|
92
92
|
console.log("Signal set:", {
|
|
93
93
|
oldValue,
|
|
94
94
|
newValue,
|
|
95
|
-
subscribers: Array.from(subscribers).map((
|
|
95
|
+
subscribers: Array.from(subscribers).map((sym) => effects.get(sym)),
|
|
96
96
|
label
|
|
97
97
|
});
|
|
98
98
|
}
|
|
@@ -111,19 +111,19 @@ var derived = (fn, options) => {
|
|
|
111
111
|
return getter;
|
|
112
112
|
};
|
|
113
113
|
var createEffect = (fn, value) => {
|
|
114
|
-
const
|
|
115
|
-
effects.set(
|
|
114
|
+
const privateIdent = ident = {};
|
|
115
|
+
effects.set(ident, { fn, value });
|
|
116
116
|
try {
|
|
117
117
|
fn({
|
|
118
118
|
lastValue: value,
|
|
119
119
|
destroy: () => {
|
|
120
|
-
effects.delete(
|
|
120
|
+
effects.delete(privateIdent);
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
} catch (error) {
|
|
124
124
|
console.error("Error in effect:", { error, fn });
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
ident = null;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
// src/utilities.ts
|
|
@@ -424,10 +424,6 @@ var evaluateBindings = (element, fragment) => {
|
|
|
424
424
|
createEffect(
|
|
425
425
|
({ lastValue: oldChildren, destroy }) => {
|
|
426
426
|
const result = signal2();
|
|
427
|
-
console.trace("Binding array:", {
|
|
428
|
-
result: result.map((node) => node.cloneNode(true)),
|
|
429
|
-
oldChildren
|
|
430
|
-
});
|
|
431
427
|
const newChildren = asNodeList(result, element);
|
|
432
428
|
const firstChild = newChildren[0];
|
|
433
429
|
if (!Array.isArray(result) && newChildren.length === 1 && firstChild instanceof DocumentFragment) {
|
|
@@ -677,7 +673,7 @@ var css = (strings, ...values) => {
|
|
|
677
673
|
}
|
|
678
674
|
const newCSSText = newCSSTextList.join("");
|
|
679
675
|
if (isCSSStyleSheet(stylesheet)) {
|
|
680
|
-
stylesheet.
|
|
676
|
+
stylesheet.replaceSync(newCSSText);
|
|
681
677
|
} else {
|
|
682
678
|
stylesheet.textContent = newCSSText;
|
|
683
679
|
}
|
|
@@ -706,6 +702,7 @@ var customElement = (render, options) => {
|
|
|
706
702
|
if (shadowRootOptions.registry !== void 0 && "scoped" in shadowRootOptions.registry && shadowRootOptions.registry.scoped) {
|
|
707
703
|
return shadowRootOptions.registry;
|
|
708
704
|
}
|
|
705
|
+
return void 0;
|
|
709
706
|
})();
|
|
710
707
|
return {
|
|
711
708
|
define(tagName) {
|
|
@@ -765,8 +762,8 @@ var customElement = (render, options) => {
|
|
|
765
762
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
|
766
763
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
|
767
764
|
#clientOnlyCallbackFns = /* @__PURE__ */ new Set();
|
|
768
|
-
#shadowRoot = attachShadow ? this.attachShadow(shadowRootOptions) : null;
|
|
769
765
|
#internals = this.attachInternals();
|
|
766
|
+
#shadowRoot = attachShadow ? this.#internals.shadowRoot ?? this.attachShadow(shadowRootOptions) : null;
|
|
770
767
|
#observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
|
|
771
768
|
for (const mutation of mutations) {
|
|
772
769
|
const attrName = mutation.attributeName;
|
|
@@ -819,7 +816,7 @@ Element: <${this.tagName.toLowerCase()}>
|
|
|
819
816
|
this[prop] = newValue;
|
|
820
817
|
_setter(newValue, options2);
|
|
821
818
|
};
|
|
822
|
-
const getter = (options2) => {
|
|
819
|
+
const getter = ((options2) => {
|
|
823
820
|
const value = _getter(options2);
|
|
824
821
|
if (value === void 0 && !allowUndefined) {
|
|
825
822
|
const error = new Error(
|
|
@@ -831,7 +828,7 @@ You must set an initial value before calling a property signal's getter.
|
|
|
831
828
|
throw error;
|
|
832
829
|
}
|
|
833
830
|
return value;
|
|
834
|
-
};
|
|
831
|
+
});
|
|
835
832
|
getter.getter = true;
|
|
836
833
|
const publicSignal = [getter, setter];
|
|
837
834
|
publicSignal.init = (value) => {
|
package/package.json
CHANGED
|
@@ -1,70 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"express": "^4.17.1",
|
|
57
|
-
"prettier": "^3.3.3",
|
|
58
|
-
"tsup": "^8.3.0",
|
|
59
|
-
"tsx": "^4.19.2",
|
|
60
|
-
"typescript": "^5.7.2"
|
|
61
|
-
},
|
|
62
|
-
"peerDependencies": {
|
|
63
|
-
"@webcomponents/scoped-custom-element-registry": "^0.0.10"
|
|
64
|
-
},
|
|
65
|
-
"peerDependenciesMeta": {
|
|
66
|
-
"@webcomponents/scoped-custom-element-registry": {
|
|
67
|
-
"optional": true
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
2
|
+
"name": "thunderous",
|
|
3
|
+
"version": "2.4.2",
|
|
4
|
+
"description": "A lightweight, functional web components library that brings the power of signals to your UI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"/dist",
|
|
11
|
+
"/package.json",
|
|
12
|
+
"/README.md",
|
|
13
|
+
"/LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"author": "Jonathan DeWitt <jon.dewitt@thunder.solutions>",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/Thunder-Solutions/Thunderous"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"thunderous",
|
|
22
|
+
"web components",
|
|
23
|
+
"functional",
|
|
24
|
+
"signals",
|
|
25
|
+
"custom elements"
|
|
26
|
+
],
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/Thunder-Solutions/Thunderous/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/Thunder-Solutions/Thunderous#readme",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@webcomponents/scoped-custom-element-registry": "^0.0.10"
|
|
34
|
+
},
|
|
35
|
+
"peerDependenciesMeta": {
|
|
36
|
+
"@webcomponents/scoped-custom-element-registry": {
|
|
37
|
+
"optional": true
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"demo": "cd demo && npm start",
|
|
42
|
+
"demo:ssr": "cd demo && npm run ssr",
|
|
43
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --no-clean",
|
|
44
|
+
"test": "npm run test:server && npm run test:client",
|
|
45
|
+
"test:server": "find src/__test__/server -name '*.test.ts' | xargs c8 tsx --test",
|
|
46
|
+
"test:client": "PLAYWRIGHT_BROWSERS_PATH=../../.browsers playwright test",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"lint": "eslint .",
|
|
49
|
+
"lint:fix": "eslint . --fix",
|
|
50
|
+
"format": "prettier --check . --ignore-path ../../.gitignore",
|
|
51
|
+
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
|
52
|
+
"preversion": "npm run typecheck && npm run lint && npm test && npm run build",
|
|
53
|
+
"version": "node postversion.js"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
import { customElement } from '../custom-element';
|
|
4
|
-
import { html } from '../render';
|
|
5
|
-
import { createRegistry } from '../registry';
|
|
6
|
-
import { NOOP } from '../utilities';
|
|
7
|
-
await describe('customElement', async () => {
|
|
8
|
-
await it('does not throw on the server', () => {
|
|
9
|
-
assert.doesNotThrow(() => customElement(() => html `<div></div>`));
|
|
10
|
-
});
|
|
11
|
-
await it('returns an element result class', () => {
|
|
12
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
13
|
-
assert.ok(MyElement);
|
|
14
|
-
const keys = Object.keys(MyElement);
|
|
15
|
-
assert(keys.every((key) => ['define', 'register', 'eject'].includes(key)));
|
|
16
|
-
});
|
|
17
|
-
await it('supports scoped registries', () => {
|
|
18
|
-
const registry = createRegistry({ scoped: true });
|
|
19
|
-
assert.doesNotThrow(() => customElement(() => html `<div></div>`, { shadowRootOptions: { registry } }));
|
|
20
|
-
});
|
|
21
|
-
await it('returns self for chaining', () => {
|
|
22
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
23
|
-
const registry = createRegistry();
|
|
24
|
-
assert.strictEqual(MyElement.define('my-element'), MyElement);
|
|
25
|
-
assert.strictEqual(MyElement.register(registry), MyElement);
|
|
26
|
-
});
|
|
27
|
-
await it('registers the element with a registry', () => {
|
|
28
|
-
const registry = createRegistry();
|
|
29
|
-
const MyElement = customElement(() => html `<div></div>`)
|
|
30
|
-
.register(registry)
|
|
31
|
-
.define('my-element');
|
|
32
|
-
assert.strictEqual(registry.getTagName(MyElement), 'MY-ELEMENT');
|
|
33
|
-
});
|
|
34
|
-
await it('logs an error when registering after defining in a scoped registry', (testContext) => {
|
|
35
|
-
testContext.mock.method(console, 'error', NOOP);
|
|
36
|
-
const errorMock = console.error.mock;
|
|
37
|
-
const registry = createRegistry({ scoped: true });
|
|
38
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
39
|
-
MyElement.define('my-element');
|
|
40
|
-
MyElement.register(registry);
|
|
41
|
-
assert.strictEqual(errorMock.callCount(), 1);
|
|
42
|
-
assert.strictEqual(errorMock.calls[0].arguments[0], 'Must call `register()` before `define()` for scoped registries.');
|
|
43
|
-
});
|
|
44
|
-
await it('throws an error when ejecting on the server', () => {
|
|
45
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
46
|
-
assert.throws(() => MyElement.eject());
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
import { createRegistry } from '../registry';
|
|
4
|
-
import { customElement } from '../custom-element';
|
|
5
|
-
import { html } from '../render';
|
|
6
|
-
import { NOOP } from '../utilities';
|
|
7
|
-
await describe('createRegistry', async () => {
|
|
8
|
-
await it('creates a global registry', () => {
|
|
9
|
-
const registry = createRegistry();
|
|
10
|
-
assert.ok(registry);
|
|
11
|
-
assert.strictEqual(registry.scoped, false);
|
|
12
|
-
});
|
|
13
|
-
await it('creates a scoped registry', () => {
|
|
14
|
-
const registry = createRegistry({ scoped: true });
|
|
15
|
-
assert.ok(registry);
|
|
16
|
-
assert.strictEqual(registry.scoped, true);
|
|
17
|
-
});
|
|
18
|
-
await it('defines a custom element', () => {
|
|
19
|
-
const registry = createRegistry();
|
|
20
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
21
|
-
assert.doesNotThrow(() => registry.define('my-element', MyElement));
|
|
22
|
-
});
|
|
23
|
-
await it('warns about duplicate custom elements', (testContext) => {
|
|
24
|
-
testContext.mock.method(console, 'warn', NOOP);
|
|
25
|
-
const warnMock = console.warn.mock;
|
|
26
|
-
const registry = createRegistry();
|
|
27
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
28
|
-
const MyElement2 = customElement(() => html `<div></div>`);
|
|
29
|
-
registry.define('my-element', MyElement);
|
|
30
|
-
registry.define('my-element', MyElement2);
|
|
31
|
-
assert.strictEqual(warnMock.callCount(), 1);
|
|
32
|
-
assert.strictEqual(warnMock.calls[0].arguments[0], 'Custom element tag name "MY-ELEMENT" was already defined. Skipping...');
|
|
33
|
-
registry.define('my-element-2', MyElement);
|
|
34
|
-
assert.strictEqual(warnMock.callCount(), 2);
|
|
35
|
-
assert.strictEqual(warnMock.calls[1].arguments[0], 'MY-ELEMENT-2 was already defined. Skipping...');
|
|
36
|
-
});
|
|
37
|
-
await it('gets the tag name of a custom element', () => {
|
|
38
|
-
const registry = createRegistry();
|
|
39
|
-
const tagName = 'my-element';
|
|
40
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
41
|
-
registry.define(tagName, MyElement);
|
|
42
|
-
const result = registry.getTagName(MyElement);
|
|
43
|
-
assert.strictEqual(result, tagName.toUpperCase());
|
|
44
|
-
});
|
|
45
|
-
await it('gets all tag names defined in the registry', () => {
|
|
46
|
-
const registry = createRegistry();
|
|
47
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
48
|
-
const MyElement2 = customElement(() => html `<div></div>`);
|
|
49
|
-
registry.define('my-element', MyElement);
|
|
50
|
-
registry.define('my-element-2', MyElement2);
|
|
51
|
-
const result = registry.getAllTagNames();
|
|
52
|
-
assert.deepStrictEqual(result, ['MY-ELEMENT', 'MY-ELEMENT-2']);
|
|
53
|
-
});
|
|
54
|
-
await it('throws an error if ejected on the server', () => {
|
|
55
|
-
const registry = createRegistry();
|
|
56
|
-
const MyElement = customElement(() => html `<div></div>`);
|
|
57
|
-
registry.define('my-element', MyElement);
|
|
58
|
-
assert.throws(() => registry.eject(), { message: 'Cannot eject a registry on the server.' });
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
import { html, css } from '../render';
|
|
4
|
-
import { NOOP } from '../utilities';
|
|
5
|
-
await describe('html', async () => {
|
|
6
|
-
await it('renders a simple string', () => {
|
|
7
|
-
const result = html `<div></div>`;
|
|
8
|
-
assert.strictEqual(result, '<div></div>');
|
|
9
|
-
});
|
|
10
|
-
await it('renders a string with interpolated values', () => {
|
|
11
|
-
const result = html `<div>${'Hello, world!'} ${1} ${true}</div>`;
|
|
12
|
-
assert.strictEqual(result, '<div>Hello, world! 1 true</div>');
|
|
13
|
-
});
|
|
14
|
-
await it('renders a string with signals', () => {
|
|
15
|
-
const mockGetter = () => 'Hello, world!';
|
|
16
|
-
const result = html `<div>${mockGetter}</div>`;
|
|
17
|
-
assert.strictEqual(result, '<div>Hello, world!</div>');
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
await describe('css', async () => {
|
|
21
|
-
await it('renders a simple string', () => {
|
|
22
|
-
// prettier-ignore
|
|
23
|
-
const result = css `div { color: red; }`;
|
|
24
|
-
assert.strictEqual(result, 'div { color: red; }');
|
|
25
|
-
});
|
|
26
|
-
await it('renders a string with interpolated values', () => {
|
|
27
|
-
// prettier-ignore
|
|
28
|
-
const result = css `div { --str: ${'str'}; --num: ${1}; --bool: ${true}; }`;
|
|
29
|
-
assert.strictEqual(result, 'div { --str: str; --num: 1; --bool: true; }');
|
|
30
|
-
});
|
|
31
|
-
await it('logs an error if a non-primitive value is interpolated', (testContext) => {
|
|
32
|
-
testContext.mock.method(console, 'error', NOOP);
|
|
33
|
-
const errorMock = console.error.mock;
|
|
34
|
-
const obj = {};
|
|
35
|
-
// prettier-ignore
|
|
36
|
-
const result = css `div { --obj: ${obj}; }`;
|
|
37
|
-
assert.strictEqual(result, 'div { --obj: ; }');
|
|
38
|
-
assert.strictEqual(errorMock.callCount(), 1);
|
|
39
|
-
assert.strictEqual(errorMock.calls[0].arguments[0], 'Objects are not valid in CSS values. Received:');
|
|
40
|
-
assert.strictEqual(errorMock.calls[0].arguments[1], obj);
|
|
41
|
-
});
|
|
42
|
-
await it('renders a string with signals', () => {
|
|
43
|
-
const mockGetter = () => 'red';
|
|
44
|
-
// prettier-ignore
|
|
45
|
-
const result = css `div { color: ${mockGetter}; }`;
|
|
46
|
-
assert.strictEqual(result, 'div { color: red; }');
|
|
47
|
-
});
|
|
48
|
-
});
|