thunderous 2.4.1 → 2.4.3
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 +23 -25
- package/dist/index.d.cts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +23 -25
- 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
|
|
@@ -299,8 +299,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
|
|
|
299
299
|
return finalScopedRenderString;
|
|
300
300
|
};
|
|
301
301
|
var insertTemplates = (tagName, template, inputString) => {
|
|
302
|
-
|
|
303
|
-
|
|
302
|
+
const tagRegex = new RegExp(`<\\s*${tagName}((?:\\s+[^>]*)*)\\s*>`, "gm");
|
|
303
|
+
return inputString.replace(tagRegex, ($match, $1) => {
|
|
304
|
+
const attrs = $1.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
|
|
304
305
|
const [_key, _value] = attr.split("=");
|
|
305
306
|
const key = _key.trim();
|
|
306
307
|
const value = _value?.replace(/"/g, "") ?? "";
|
|
@@ -310,7 +311,7 @@ var insertTemplates = (tagName, template, inputString) => {
|
|
|
310
311
|
for (const [key, value] of attrs) {
|
|
311
312
|
scopedResult = scopedResult.replace(new RegExp(`{{attr:${key}}}`, "gm"), value);
|
|
312
313
|
}
|
|
313
|
-
return $
|
|
314
|
+
return $match + scopedResult;
|
|
314
315
|
});
|
|
315
316
|
};
|
|
316
317
|
var clientOnlyCallback = (fn) => {
|
|
@@ -459,10 +460,6 @@ var evaluateBindings = (element, fragment) => {
|
|
|
459
460
|
createEffect(
|
|
460
461
|
({ lastValue: oldChildren, destroy }) => {
|
|
461
462
|
const result = signal2();
|
|
462
|
-
console.trace("Binding array:", {
|
|
463
|
-
result: result.map((node) => node.cloneNode(true)),
|
|
464
|
-
oldChildren
|
|
465
|
-
});
|
|
466
463
|
const newChildren = asNodeList(result, element);
|
|
467
464
|
const firstChild = newChildren[0];
|
|
468
465
|
if (!Array.isArray(result) && newChildren.length === 1 && firstChild instanceof DocumentFragment) {
|
|
@@ -712,7 +709,7 @@ var css = (strings, ...values) => {
|
|
|
712
709
|
}
|
|
713
710
|
const newCSSText = newCSSTextList.join("");
|
|
714
711
|
if (isCSSStyleSheet(stylesheet)) {
|
|
715
|
-
stylesheet.
|
|
712
|
+
stylesheet.replaceSync(newCSSText);
|
|
716
713
|
} else {
|
|
717
714
|
stylesheet.textContent = newCSSText;
|
|
718
715
|
}
|
|
@@ -741,6 +738,7 @@ var customElement = (render, options) => {
|
|
|
741
738
|
if (shadowRootOptions.registry !== void 0 && "scoped" in shadowRootOptions.registry && shadowRootOptions.registry.scoped) {
|
|
742
739
|
return shadowRootOptions.registry;
|
|
743
740
|
}
|
|
741
|
+
return void 0;
|
|
744
742
|
})();
|
|
745
743
|
return {
|
|
746
744
|
define(tagName) {
|
|
@@ -800,8 +798,8 @@ var customElement = (render, options) => {
|
|
|
800
798
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
|
801
799
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
|
802
800
|
#clientOnlyCallbackFns = /* @__PURE__ */ new Set();
|
|
803
|
-
#shadowRoot = attachShadow ? this.attachShadow(shadowRootOptions) : null;
|
|
804
801
|
#internals = this.attachInternals();
|
|
802
|
+
#shadowRoot = attachShadow ? this.#internals.shadowRoot ?? this.attachShadow(shadowRootOptions) : null;
|
|
805
803
|
#observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
|
|
806
804
|
for (const mutation of mutations) {
|
|
807
805
|
const attrName = mutation.attributeName;
|
|
@@ -854,7 +852,7 @@ Element: <${this.tagName.toLowerCase()}>
|
|
|
854
852
|
this[prop] = newValue;
|
|
855
853
|
_setter(newValue, options2);
|
|
856
854
|
};
|
|
857
|
-
const getter = (options2) => {
|
|
855
|
+
const getter = ((options2) => {
|
|
858
856
|
const value = _getter(options2);
|
|
859
857
|
if (value === void 0 && !allowUndefined) {
|
|
860
858
|
const error = new Error(
|
|
@@ -866,7 +864,7 @@ You must set an initial value before calling a property signal's getter.
|
|
|
866
864
|
throw error;
|
|
867
865
|
}
|
|
868
866
|
return value;
|
|
869
|
-
};
|
|
867
|
+
});
|
|
870
868
|
getter.getter = true;
|
|
871
869
|
const publicSignal = [getter, setter];
|
|
872
870
|
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
|
|
@@ -264,8 +264,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
|
|
|
264
264
|
return finalScopedRenderString;
|
|
265
265
|
};
|
|
266
266
|
var insertTemplates = (tagName, template, inputString) => {
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
const tagRegex = new RegExp(`<\\s*${tagName}((?:\\s+[^>]*)*)\\s*>`, "gm");
|
|
268
|
+
return inputString.replace(tagRegex, ($match, $1) => {
|
|
269
|
+
const attrs = $1.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
|
|
269
270
|
const [_key, _value] = attr.split("=");
|
|
270
271
|
const key = _key.trim();
|
|
271
272
|
const value = _value?.replace(/"/g, "") ?? "";
|
|
@@ -275,7 +276,7 @@ var insertTemplates = (tagName, template, inputString) => {
|
|
|
275
276
|
for (const [key, value] of attrs) {
|
|
276
277
|
scopedResult = scopedResult.replace(new RegExp(`{{attr:${key}}}`, "gm"), value);
|
|
277
278
|
}
|
|
278
|
-
return $
|
|
279
|
+
return $match + scopedResult;
|
|
279
280
|
});
|
|
280
281
|
};
|
|
281
282
|
var clientOnlyCallback = (fn) => {
|
|
@@ -424,10 +425,6 @@ var evaluateBindings = (element, fragment) => {
|
|
|
424
425
|
createEffect(
|
|
425
426
|
({ lastValue: oldChildren, destroy }) => {
|
|
426
427
|
const result = signal2();
|
|
427
|
-
console.trace("Binding array:", {
|
|
428
|
-
result: result.map((node) => node.cloneNode(true)),
|
|
429
|
-
oldChildren
|
|
430
|
-
});
|
|
431
428
|
const newChildren = asNodeList(result, element);
|
|
432
429
|
const firstChild = newChildren[0];
|
|
433
430
|
if (!Array.isArray(result) && newChildren.length === 1 && firstChild instanceof DocumentFragment) {
|
|
@@ -677,7 +674,7 @@ var css = (strings, ...values) => {
|
|
|
677
674
|
}
|
|
678
675
|
const newCSSText = newCSSTextList.join("");
|
|
679
676
|
if (isCSSStyleSheet(stylesheet)) {
|
|
680
|
-
stylesheet.
|
|
677
|
+
stylesheet.replaceSync(newCSSText);
|
|
681
678
|
} else {
|
|
682
679
|
stylesheet.textContent = newCSSText;
|
|
683
680
|
}
|
|
@@ -706,6 +703,7 @@ var customElement = (render, options) => {
|
|
|
706
703
|
if (shadowRootOptions.registry !== void 0 && "scoped" in shadowRootOptions.registry && shadowRootOptions.registry.scoped) {
|
|
707
704
|
return shadowRootOptions.registry;
|
|
708
705
|
}
|
|
706
|
+
return void 0;
|
|
709
707
|
})();
|
|
710
708
|
return {
|
|
711
709
|
define(tagName) {
|
|
@@ -765,8 +763,8 @@ var customElement = (render, options) => {
|
|
|
765
763
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
|
766
764
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
|
767
765
|
#clientOnlyCallbackFns = /* @__PURE__ */ new Set();
|
|
768
|
-
#shadowRoot = attachShadow ? this.attachShadow(shadowRootOptions) : null;
|
|
769
766
|
#internals = this.attachInternals();
|
|
767
|
+
#shadowRoot = attachShadow ? this.#internals.shadowRoot ?? this.attachShadow(shadowRootOptions) : null;
|
|
770
768
|
#observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
|
|
771
769
|
for (const mutation of mutations) {
|
|
772
770
|
const attrName = mutation.attributeName;
|
|
@@ -819,7 +817,7 @@ Element: <${this.tagName.toLowerCase()}>
|
|
|
819
817
|
this[prop] = newValue;
|
|
820
818
|
_setter(newValue, options2);
|
|
821
819
|
};
|
|
822
|
-
const getter = (options2) => {
|
|
820
|
+
const getter = ((options2) => {
|
|
823
821
|
const value = _getter(options2);
|
|
824
822
|
if (value === void 0 && !allowUndefined) {
|
|
825
823
|
const error = new Error(
|
|
@@ -831,7 +829,7 @@ You must set an initial value before calling a property signal's getter.
|
|
|
831
829
|
throw error;
|
|
832
830
|
}
|
|
833
831
|
return value;
|
|
834
|
-
};
|
|
832
|
+
});
|
|
835
833
|
getter.getter = true;
|
|
836
834
|
const publicSignal = [getter, setter];
|
|
837
835
|
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.3",
|
|
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
|
-
});
|