thunderous 0.2.0 → 0.2.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/README.md +21 -0
- package/dist/index.cjs +166 -98
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +166 -98
- package/package.json +1 -1
package/README.md
CHANGED
@@ -227,6 +227,27 @@ createEffect(() => {
|
|
227
227
|
});
|
228
228
|
```
|
229
229
|
|
230
|
+
##### Debugging Signals
|
231
|
+
|
232
|
+
If you're having a tough time tracing an issue, you can provide the `debugMode` option to any signal to log potentially helpful information to the console. For differentiating values, you can also provide an optional `label` property to easily associate logs with their respective sources. These options can be passed to signals themselves, or to specific calls to setters and getters.
|
233
|
+
|
234
|
+
```ts
|
235
|
+
const [count, setCount] = createSignal(0, {
|
236
|
+
debugMode: true,
|
237
|
+
label: 'count signal',
|
238
|
+
});
|
239
|
+
|
240
|
+
setCount(1, {
|
241
|
+
debugMode: true,
|
242
|
+
label: 'start count',
|
243
|
+
});
|
244
|
+
|
245
|
+
const newCount = count({
|
246
|
+
debugMode: true,
|
247
|
+
label: 'new count',
|
248
|
+
});
|
249
|
+
```
|
250
|
+
|
230
251
|
#### Refs
|
231
252
|
|
232
253
|
The refs property exists for convenience to avoid manually querying the DOM. Since the DOM is only available after rendering, refs will only work in and after the `connectedCallback` method.
|
package/dist/index.cjs
CHANGED
@@ -48,19 +48,64 @@ var setInnerHTML = (element, html2) => {
|
|
48
48
|
|
49
49
|
// src/signals.ts
|
50
50
|
var subscriber = null;
|
51
|
-
var
|
51
|
+
var updateQueue = /* @__PURE__ */ new Set();
|
52
|
+
var isBatchingUpdates = false;
|
53
|
+
var createSignal = (initVal, options) => {
|
52
54
|
const subscribers = /* @__PURE__ */ new Set();
|
53
55
|
let value = initVal;
|
54
|
-
const getter = () => {
|
56
|
+
const getter = (getterOptions) => {
|
55
57
|
if (subscriber !== null) {
|
56
58
|
subscribers.add(subscriber);
|
57
59
|
}
|
60
|
+
if ((options == null ? void 0 : options.debugMode) || (getterOptions == null ? void 0 : getterOptions.debugMode)) {
|
61
|
+
requestAnimationFrame(() => {
|
62
|
+
let label = "anonymous signal";
|
63
|
+
if ((options == null ? void 0 : options.label) !== void 0) {
|
64
|
+
label = `(${options.label})`;
|
65
|
+
if ((getterOptions == null ? void 0 : getterOptions.label) !== void 0) {
|
66
|
+
label += ` ${getterOptions.label}`;
|
67
|
+
}
|
68
|
+
} else if ((getterOptions == null ? void 0 : getterOptions.label) !== void 0) {
|
69
|
+
label = getterOptions.label;
|
70
|
+
}
|
71
|
+
console.log("Signal retrieved:", { value, subscribers, label });
|
72
|
+
});
|
73
|
+
}
|
58
74
|
return value;
|
59
75
|
};
|
60
|
-
const setter = (newValue) => {
|
76
|
+
const setter = (newValue, setterOptions) => {
|
77
|
+
const isObject = typeof newValue === "object" && newValue !== null;
|
78
|
+
if (!isObject && value === newValue) return;
|
79
|
+
const oldValue = value;
|
61
80
|
value = newValue;
|
62
81
|
for (const fn of subscribers) {
|
63
|
-
fn
|
82
|
+
updateQueue.add(fn);
|
83
|
+
}
|
84
|
+
if (!isBatchingUpdates) {
|
85
|
+
isBatchingUpdates = true;
|
86
|
+
requestAnimationFrame(() => {
|
87
|
+
for (const fn of updateQueue) {
|
88
|
+
try {
|
89
|
+
fn();
|
90
|
+
} catch (error) {
|
91
|
+
console.error("Error in subscriber:", { error, oldValue, newValue, fn });
|
92
|
+
}
|
93
|
+
}
|
94
|
+
if ((options == null ? void 0 : options.debugMode) || (setterOptions == null ? void 0 : setterOptions.debugMode)) {
|
95
|
+
let label = "anonymous signal";
|
96
|
+
if ((options == null ? void 0 : options.label) !== void 0) {
|
97
|
+
label = `(${options.label})`;
|
98
|
+
if ((setterOptions == null ? void 0 : setterOptions.label) !== void 0) {
|
99
|
+
label += ` ${setterOptions.label}`;
|
100
|
+
}
|
101
|
+
} else if ((setterOptions == null ? void 0 : setterOptions.label) !== void 0) {
|
102
|
+
label = setterOptions.label;
|
103
|
+
}
|
104
|
+
console.log("Signal set:", { oldValue, newValue, subscribers, label });
|
105
|
+
}
|
106
|
+
updateQueue.clear();
|
107
|
+
isBatchingUpdates = false;
|
108
|
+
});
|
64
109
|
}
|
65
110
|
};
|
66
111
|
return [getter, setter];
|
@@ -68,16 +113,124 @@ var createSignal = (initVal) => {
|
|
68
113
|
var derived = (fn) => {
|
69
114
|
const [getter, setter] = createSignal();
|
70
115
|
createEffect(() => {
|
71
|
-
|
116
|
+
try {
|
117
|
+
setter(fn());
|
118
|
+
} catch (error) {
|
119
|
+
console.error("Error in derived signal:", { error, fn });
|
120
|
+
}
|
72
121
|
});
|
73
122
|
return getter;
|
74
123
|
};
|
75
124
|
var createEffect = (fn) => {
|
76
125
|
subscriber = fn;
|
77
|
-
|
126
|
+
try {
|
127
|
+
fn();
|
128
|
+
} catch (error) {
|
129
|
+
console.error("Error in effect:", { error, fn });
|
130
|
+
}
|
78
131
|
subscriber = null;
|
79
132
|
};
|
80
133
|
|
134
|
+
// src/render.ts
|
135
|
+
var html = (strings, ...values) => {
|
136
|
+
let innerHTML = "";
|
137
|
+
const signalMap = /* @__PURE__ */ new Map();
|
138
|
+
strings.forEach((string, i) => {
|
139
|
+
let value = values[i] ?? "";
|
140
|
+
if (typeof value === "function") {
|
141
|
+
const uniqueKey = crypto.randomUUID();
|
142
|
+
signalMap.set(uniqueKey, value);
|
143
|
+
value = `{{signal:${uniqueKey}}}`;
|
144
|
+
}
|
145
|
+
innerHTML += string + String(value);
|
146
|
+
});
|
147
|
+
const fragment = parseFragment(innerHTML);
|
148
|
+
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
149
|
+
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
150
|
+
const parseChildren = (element) => {
|
151
|
+
for (const child of element.childNodes) {
|
152
|
+
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
153
|
+
const textList = child.data.split(signalBindingRegex);
|
154
|
+
textList.forEach((text, i) => {
|
155
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
156
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
157
|
+
const newText = signal !== null ? signal() : text;
|
158
|
+
const newNode = new Text(newText);
|
159
|
+
if (i === 0) {
|
160
|
+
child.replaceWith(newNode);
|
161
|
+
} else {
|
162
|
+
element.insertBefore(newNode, child.nextSibling);
|
163
|
+
}
|
164
|
+
if (signal !== null) {
|
165
|
+
createEffect(() => {
|
166
|
+
newNode.data = signal();
|
167
|
+
});
|
168
|
+
}
|
169
|
+
});
|
170
|
+
}
|
171
|
+
if (child instanceof Element) {
|
172
|
+
for (const attr of child.attributes) {
|
173
|
+
if (signalBindingRegex.test(attr.value)) {
|
174
|
+
const textList = attr.value.split(signalBindingRegex);
|
175
|
+
createEffect(() => {
|
176
|
+
let newText = "";
|
177
|
+
for (const text of textList) {
|
178
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
179
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
180
|
+
newText += signal !== null ? signal() : text;
|
181
|
+
}
|
182
|
+
child.setAttribute(attr.name, newText);
|
183
|
+
});
|
184
|
+
} else if (callbackBindingRegex.test(attr.value)) {
|
185
|
+
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
186
|
+
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
187
|
+
}
|
188
|
+
}
|
189
|
+
parseChildren(child);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
};
|
193
|
+
parseChildren(fragment);
|
194
|
+
return fragment;
|
195
|
+
};
|
196
|
+
var _a, _b;
|
197
|
+
var adoptedStylesSupported = typeof window !== "undefined" && ((_a = window.ShadowRoot) == null ? void 0 : _a.prototype.hasOwnProperty("adoptedStyleSheets")) && ((_b = window.CSSStyleSheet) == null ? void 0 : _b.prototype.hasOwnProperty("replace"));
|
198
|
+
var isCSSStyleSheet = (stylesheet) => {
|
199
|
+
return typeof CSSStyleSheet !== "undefined" && stylesheet instanceof CSSStyleSheet;
|
200
|
+
};
|
201
|
+
var css = (strings, ...values) => {
|
202
|
+
let cssText = "";
|
203
|
+
const signalMap = /* @__PURE__ */ new Map();
|
204
|
+
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
205
|
+
strings.forEach((string, i) => {
|
206
|
+
let value = values[i] ?? "";
|
207
|
+
if (typeof value === "function") {
|
208
|
+
const uniqueKey = crypto.randomUUID();
|
209
|
+
signalMap.set(uniqueKey, value);
|
210
|
+
value = `{{signal:${uniqueKey}}}`;
|
211
|
+
}
|
212
|
+
cssText += string + String(value);
|
213
|
+
});
|
214
|
+
let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
|
215
|
+
const textList = cssText.split(signalBindingRegex);
|
216
|
+
createEffect(() => {
|
217
|
+
const newCSSTextList = [];
|
218
|
+
for (const text of textList) {
|
219
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
220
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
221
|
+
const newText = signal !== null ? signal() : text;
|
222
|
+
newCSSTextList.push(newText);
|
223
|
+
}
|
224
|
+
const newCSSText = newCSSTextList.join("");
|
225
|
+
if (isCSSStyleSheet(stylesheet)) {
|
226
|
+
stylesheet.replace(newCSSText);
|
227
|
+
} else {
|
228
|
+
stylesheet.textContent = newCSSText;
|
229
|
+
}
|
230
|
+
});
|
231
|
+
return stylesheet;
|
232
|
+
};
|
233
|
+
|
81
234
|
// src/custom-element.ts
|
82
235
|
var DEFAULT_RENDER_OPTIONS = {
|
83
236
|
formAssociated: false,
|
@@ -154,7 +307,13 @@ var customElement = (render, options) => {
|
|
154
307
|
}
|
155
308
|
),
|
156
309
|
adoptStyleSheet: (stylesheet) => {
|
157
|
-
|
310
|
+
if (isCSSStyleSheet(stylesheet)) {
|
311
|
+
this.#shadowRoot.adoptedStyleSheets.push(stylesheet);
|
312
|
+
} else {
|
313
|
+
requestAnimationFrame(() => {
|
314
|
+
this.#shadowRoot.appendChild(stylesheet);
|
315
|
+
});
|
316
|
+
}
|
158
317
|
}
|
159
318
|
});
|
160
319
|
setInnerHTML(this.#shadowRoot, fragment);
|
@@ -251,97 +410,6 @@ var createRegistry = () => {
|
|
251
410
|
getTagName: (element) => registry.get(element)
|
252
411
|
};
|
253
412
|
};
|
254
|
-
|
255
|
-
// src/render.ts
|
256
|
-
var html = (strings, ...values) => {
|
257
|
-
let innerHTML = "";
|
258
|
-
const signalMap = /* @__PURE__ */ new Map();
|
259
|
-
strings.forEach((string, i) => {
|
260
|
-
let value = values[i] ?? "";
|
261
|
-
if (typeof value === "function") {
|
262
|
-
const uniqueKey = crypto.randomUUID();
|
263
|
-
signalMap.set(uniqueKey, value);
|
264
|
-
value = `{{signal:${uniqueKey}}}`;
|
265
|
-
}
|
266
|
-
innerHTML += string + String(value);
|
267
|
-
});
|
268
|
-
const fragment = parseFragment(innerHTML);
|
269
|
-
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
270
|
-
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
271
|
-
const parseChildren = (element) => {
|
272
|
-
for (const child of element.childNodes) {
|
273
|
-
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
274
|
-
const textList = child.data.split(signalBindingRegex);
|
275
|
-
textList.forEach((text, i) => {
|
276
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
277
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
278
|
-
const newText = signal !== null ? signal() : text;
|
279
|
-
const newNode = new Text(newText);
|
280
|
-
if (i === 0) {
|
281
|
-
child.replaceWith(newNode);
|
282
|
-
} else {
|
283
|
-
element.insertBefore(newNode, child.nextSibling);
|
284
|
-
}
|
285
|
-
if (signal !== null) {
|
286
|
-
createEffect(() => {
|
287
|
-
newNode.data = signal();
|
288
|
-
});
|
289
|
-
}
|
290
|
-
});
|
291
|
-
}
|
292
|
-
if (child instanceof Element) {
|
293
|
-
for (const attr of child.attributes) {
|
294
|
-
if (signalBindingRegex.test(attr.value)) {
|
295
|
-
const textList = attr.value.split(signalBindingRegex);
|
296
|
-
createEffect(() => {
|
297
|
-
let newText = "";
|
298
|
-
for (const text of textList) {
|
299
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
300
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
301
|
-
newText += signal !== null ? signal() : text;
|
302
|
-
}
|
303
|
-
child.setAttribute(attr.name, newText);
|
304
|
-
});
|
305
|
-
} else if (callbackBindingRegex.test(attr.value)) {
|
306
|
-
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
307
|
-
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
308
|
-
}
|
309
|
-
}
|
310
|
-
parseChildren(child);
|
311
|
-
}
|
312
|
-
}
|
313
|
-
};
|
314
|
-
parseChildren(fragment);
|
315
|
-
return fragment;
|
316
|
-
};
|
317
|
-
var css = (strings, ...values) => {
|
318
|
-
let cssText = "";
|
319
|
-
const signalMap = /* @__PURE__ */ new Map();
|
320
|
-
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
321
|
-
strings.forEach((string, i) => {
|
322
|
-
let value = values[i] ?? "";
|
323
|
-
if (typeof value === "function") {
|
324
|
-
const uniqueKey = crypto.randomUUID();
|
325
|
-
signalMap.set(uniqueKey, value);
|
326
|
-
value = `{{signal:${uniqueKey}}}`;
|
327
|
-
}
|
328
|
-
cssText += string + String(value);
|
329
|
-
});
|
330
|
-
const stylesheet = new CSSStyleSheet();
|
331
|
-
const textList = cssText.split(signalBindingRegex);
|
332
|
-
createEffect(() => {
|
333
|
-
const newCSSTextList = [];
|
334
|
-
for (const text of textList) {
|
335
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
336
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
337
|
-
const newText = signal !== null ? signal() : text;
|
338
|
-
newCSSTextList.push(newText);
|
339
|
-
}
|
340
|
-
const newCSSText = newCSSTextList.join("");
|
341
|
-
stylesheet.replace(newCSSText);
|
342
|
-
});
|
343
|
-
return stylesheet;
|
344
|
-
};
|
345
413
|
// Annotate the CommonJS export names for ESM import in node:
|
346
414
|
0 && (module.exports = {
|
347
415
|
createEffect,
|
package/dist/index.d.cts
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
|
2
|
-
type
|
1
|
+
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
2
|
+
type Styles = CSSStyleSheet | HTMLStyleElement;
|
3
|
+
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => Styles;
|
4
|
+
|
5
|
+
type SignalOptions = {
|
6
|
+
debugMode: boolean;
|
7
|
+
label?: string;
|
8
|
+
};
|
9
|
+
type SignalGetter<T> = (options?: SignalOptions) => T;
|
10
|
+
type SignalSetter<T> = (newValue: T, options?: SignalOptions) => void;
|
3
11
|
type Signal<T = unknown> = [SignalGetter<T>, SignalSetter<T>];
|
4
|
-
declare const createSignal: <T = undefined>(initVal?: T) => Signal<T>;
|
12
|
+
declare const createSignal: <T = undefined>(initVal?: T, options?: SignalOptions) => Signal<T>;
|
5
13
|
declare const derived: <T>(fn: () => T) => SignalGetter<T>;
|
6
14
|
declare const createEffect: (fn: () => void) => void;
|
7
15
|
|
@@ -25,7 +33,7 @@ type RenderProps = {
|
|
25
33
|
customCallback: (fn: () => void) => `{{callback:${string}}}`;
|
26
34
|
attrSignals: Record<string, Signal<string | null>>;
|
27
35
|
refs: Record<string, HTMLElement | null>;
|
28
|
-
adoptStyleSheet: (stylesheet:
|
36
|
+
adoptStyleSheet: (stylesheet: Styles) => void;
|
29
37
|
};
|
30
38
|
type RenderOptions = {
|
31
39
|
formAssociated: boolean;
|
@@ -39,7 +47,4 @@ type Registry = {
|
|
39
47
|
};
|
40
48
|
declare const createRegistry: () => Registry;
|
41
49
|
|
42
|
-
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
43
|
-
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => CSSStyleSheet;
|
44
|
-
|
45
50
|
export { type RenderFunction, type RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
|
package/dist/index.d.ts
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
|
2
|
-
type
|
1
|
+
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
2
|
+
type Styles = CSSStyleSheet | HTMLStyleElement;
|
3
|
+
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => Styles;
|
4
|
+
|
5
|
+
type SignalOptions = {
|
6
|
+
debugMode: boolean;
|
7
|
+
label?: string;
|
8
|
+
};
|
9
|
+
type SignalGetter<T> = (options?: SignalOptions) => T;
|
10
|
+
type SignalSetter<T> = (newValue: T, options?: SignalOptions) => void;
|
3
11
|
type Signal<T = unknown> = [SignalGetter<T>, SignalSetter<T>];
|
4
|
-
declare const createSignal: <T = undefined>(initVal?: T) => Signal<T>;
|
12
|
+
declare const createSignal: <T = undefined>(initVal?: T, options?: SignalOptions) => Signal<T>;
|
5
13
|
declare const derived: <T>(fn: () => T) => SignalGetter<T>;
|
6
14
|
declare const createEffect: (fn: () => void) => void;
|
7
15
|
|
@@ -25,7 +33,7 @@ type RenderProps = {
|
|
25
33
|
customCallback: (fn: () => void) => `{{callback:${string}}}`;
|
26
34
|
attrSignals: Record<string, Signal<string | null>>;
|
27
35
|
refs: Record<string, HTMLElement | null>;
|
28
|
-
adoptStyleSheet: (stylesheet:
|
36
|
+
adoptStyleSheet: (stylesheet: Styles) => void;
|
29
37
|
};
|
30
38
|
type RenderOptions = {
|
31
39
|
formAssociated: boolean;
|
@@ -39,7 +47,4 @@ type Registry = {
|
|
39
47
|
};
|
40
48
|
declare const createRegistry: () => Registry;
|
41
49
|
|
42
|
-
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
43
|
-
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => CSSStyleSheet;
|
44
|
-
|
45
50
|
export { type RenderFunction, type RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
|
package/dist/index.js
CHANGED
@@ -17,19 +17,64 @@ var setInnerHTML = (element, html2) => {
|
|
17
17
|
|
18
18
|
// src/signals.ts
|
19
19
|
var subscriber = null;
|
20
|
-
var
|
20
|
+
var updateQueue = /* @__PURE__ */ new Set();
|
21
|
+
var isBatchingUpdates = false;
|
22
|
+
var createSignal = (initVal, options) => {
|
21
23
|
const subscribers = /* @__PURE__ */ new Set();
|
22
24
|
let value = initVal;
|
23
|
-
const getter = () => {
|
25
|
+
const getter = (getterOptions) => {
|
24
26
|
if (subscriber !== null) {
|
25
27
|
subscribers.add(subscriber);
|
26
28
|
}
|
29
|
+
if ((options == null ? void 0 : options.debugMode) || (getterOptions == null ? void 0 : getterOptions.debugMode)) {
|
30
|
+
requestAnimationFrame(() => {
|
31
|
+
let label = "anonymous signal";
|
32
|
+
if ((options == null ? void 0 : options.label) !== void 0) {
|
33
|
+
label = `(${options.label})`;
|
34
|
+
if ((getterOptions == null ? void 0 : getterOptions.label) !== void 0) {
|
35
|
+
label += ` ${getterOptions.label}`;
|
36
|
+
}
|
37
|
+
} else if ((getterOptions == null ? void 0 : getterOptions.label) !== void 0) {
|
38
|
+
label = getterOptions.label;
|
39
|
+
}
|
40
|
+
console.log("Signal retrieved:", { value, subscribers, label });
|
41
|
+
});
|
42
|
+
}
|
27
43
|
return value;
|
28
44
|
};
|
29
|
-
const setter = (newValue) => {
|
45
|
+
const setter = (newValue, setterOptions) => {
|
46
|
+
const isObject = typeof newValue === "object" && newValue !== null;
|
47
|
+
if (!isObject && value === newValue) return;
|
48
|
+
const oldValue = value;
|
30
49
|
value = newValue;
|
31
50
|
for (const fn of subscribers) {
|
32
|
-
fn
|
51
|
+
updateQueue.add(fn);
|
52
|
+
}
|
53
|
+
if (!isBatchingUpdates) {
|
54
|
+
isBatchingUpdates = true;
|
55
|
+
requestAnimationFrame(() => {
|
56
|
+
for (const fn of updateQueue) {
|
57
|
+
try {
|
58
|
+
fn();
|
59
|
+
} catch (error) {
|
60
|
+
console.error("Error in subscriber:", { error, oldValue, newValue, fn });
|
61
|
+
}
|
62
|
+
}
|
63
|
+
if ((options == null ? void 0 : options.debugMode) || (setterOptions == null ? void 0 : setterOptions.debugMode)) {
|
64
|
+
let label = "anonymous signal";
|
65
|
+
if ((options == null ? void 0 : options.label) !== void 0) {
|
66
|
+
label = `(${options.label})`;
|
67
|
+
if ((setterOptions == null ? void 0 : setterOptions.label) !== void 0) {
|
68
|
+
label += ` ${setterOptions.label}`;
|
69
|
+
}
|
70
|
+
} else if ((setterOptions == null ? void 0 : setterOptions.label) !== void 0) {
|
71
|
+
label = setterOptions.label;
|
72
|
+
}
|
73
|
+
console.log("Signal set:", { oldValue, newValue, subscribers, label });
|
74
|
+
}
|
75
|
+
updateQueue.clear();
|
76
|
+
isBatchingUpdates = false;
|
77
|
+
});
|
33
78
|
}
|
34
79
|
};
|
35
80
|
return [getter, setter];
|
@@ -37,16 +82,124 @@ var createSignal = (initVal) => {
|
|
37
82
|
var derived = (fn) => {
|
38
83
|
const [getter, setter] = createSignal();
|
39
84
|
createEffect(() => {
|
40
|
-
|
85
|
+
try {
|
86
|
+
setter(fn());
|
87
|
+
} catch (error) {
|
88
|
+
console.error("Error in derived signal:", { error, fn });
|
89
|
+
}
|
41
90
|
});
|
42
91
|
return getter;
|
43
92
|
};
|
44
93
|
var createEffect = (fn) => {
|
45
94
|
subscriber = fn;
|
46
|
-
|
95
|
+
try {
|
96
|
+
fn();
|
97
|
+
} catch (error) {
|
98
|
+
console.error("Error in effect:", { error, fn });
|
99
|
+
}
|
47
100
|
subscriber = null;
|
48
101
|
};
|
49
102
|
|
103
|
+
// src/render.ts
|
104
|
+
var html = (strings, ...values) => {
|
105
|
+
let innerHTML = "";
|
106
|
+
const signalMap = /* @__PURE__ */ new Map();
|
107
|
+
strings.forEach((string, i) => {
|
108
|
+
let value = values[i] ?? "";
|
109
|
+
if (typeof value === "function") {
|
110
|
+
const uniqueKey = crypto.randomUUID();
|
111
|
+
signalMap.set(uniqueKey, value);
|
112
|
+
value = `{{signal:${uniqueKey}}}`;
|
113
|
+
}
|
114
|
+
innerHTML += string + String(value);
|
115
|
+
});
|
116
|
+
const fragment = parseFragment(innerHTML);
|
117
|
+
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
118
|
+
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
119
|
+
const parseChildren = (element) => {
|
120
|
+
for (const child of element.childNodes) {
|
121
|
+
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
122
|
+
const textList = child.data.split(signalBindingRegex);
|
123
|
+
textList.forEach((text, i) => {
|
124
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
125
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
126
|
+
const newText = signal !== null ? signal() : text;
|
127
|
+
const newNode = new Text(newText);
|
128
|
+
if (i === 0) {
|
129
|
+
child.replaceWith(newNode);
|
130
|
+
} else {
|
131
|
+
element.insertBefore(newNode, child.nextSibling);
|
132
|
+
}
|
133
|
+
if (signal !== null) {
|
134
|
+
createEffect(() => {
|
135
|
+
newNode.data = signal();
|
136
|
+
});
|
137
|
+
}
|
138
|
+
});
|
139
|
+
}
|
140
|
+
if (child instanceof Element) {
|
141
|
+
for (const attr of child.attributes) {
|
142
|
+
if (signalBindingRegex.test(attr.value)) {
|
143
|
+
const textList = attr.value.split(signalBindingRegex);
|
144
|
+
createEffect(() => {
|
145
|
+
let newText = "";
|
146
|
+
for (const text of textList) {
|
147
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
148
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
149
|
+
newText += signal !== null ? signal() : text;
|
150
|
+
}
|
151
|
+
child.setAttribute(attr.name, newText);
|
152
|
+
});
|
153
|
+
} else if (callbackBindingRegex.test(attr.value)) {
|
154
|
+
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
155
|
+
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
parseChildren(child);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
};
|
162
|
+
parseChildren(fragment);
|
163
|
+
return fragment;
|
164
|
+
};
|
165
|
+
var _a, _b;
|
166
|
+
var adoptedStylesSupported = typeof window !== "undefined" && ((_a = window.ShadowRoot) == null ? void 0 : _a.prototype.hasOwnProperty("adoptedStyleSheets")) && ((_b = window.CSSStyleSheet) == null ? void 0 : _b.prototype.hasOwnProperty("replace"));
|
167
|
+
var isCSSStyleSheet = (stylesheet) => {
|
168
|
+
return typeof CSSStyleSheet !== "undefined" && stylesheet instanceof CSSStyleSheet;
|
169
|
+
};
|
170
|
+
var css = (strings, ...values) => {
|
171
|
+
let cssText = "";
|
172
|
+
const signalMap = /* @__PURE__ */ new Map();
|
173
|
+
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
174
|
+
strings.forEach((string, i) => {
|
175
|
+
let value = values[i] ?? "";
|
176
|
+
if (typeof value === "function") {
|
177
|
+
const uniqueKey = crypto.randomUUID();
|
178
|
+
signalMap.set(uniqueKey, value);
|
179
|
+
value = `{{signal:${uniqueKey}}}`;
|
180
|
+
}
|
181
|
+
cssText += string + String(value);
|
182
|
+
});
|
183
|
+
let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
|
184
|
+
const textList = cssText.split(signalBindingRegex);
|
185
|
+
createEffect(() => {
|
186
|
+
const newCSSTextList = [];
|
187
|
+
for (const text of textList) {
|
188
|
+
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
189
|
+
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
190
|
+
const newText = signal !== null ? signal() : text;
|
191
|
+
newCSSTextList.push(newText);
|
192
|
+
}
|
193
|
+
const newCSSText = newCSSTextList.join("");
|
194
|
+
if (isCSSStyleSheet(stylesheet)) {
|
195
|
+
stylesheet.replace(newCSSText);
|
196
|
+
} else {
|
197
|
+
stylesheet.textContent = newCSSText;
|
198
|
+
}
|
199
|
+
});
|
200
|
+
return stylesheet;
|
201
|
+
};
|
202
|
+
|
50
203
|
// src/custom-element.ts
|
51
204
|
var DEFAULT_RENDER_OPTIONS = {
|
52
205
|
formAssociated: false,
|
@@ -123,7 +276,13 @@ var customElement = (render, options) => {
|
|
123
276
|
}
|
124
277
|
),
|
125
278
|
adoptStyleSheet: (stylesheet) => {
|
126
|
-
|
279
|
+
if (isCSSStyleSheet(stylesheet)) {
|
280
|
+
this.#shadowRoot.adoptedStyleSheets.push(stylesheet);
|
281
|
+
} else {
|
282
|
+
requestAnimationFrame(() => {
|
283
|
+
this.#shadowRoot.appendChild(stylesheet);
|
284
|
+
});
|
285
|
+
}
|
127
286
|
}
|
128
287
|
});
|
129
288
|
setInnerHTML(this.#shadowRoot, fragment);
|
@@ -220,97 +379,6 @@ var createRegistry = () => {
|
|
220
379
|
getTagName: (element) => registry.get(element)
|
221
380
|
};
|
222
381
|
};
|
223
|
-
|
224
|
-
// src/render.ts
|
225
|
-
var html = (strings, ...values) => {
|
226
|
-
let innerHTML = "";
|
227
|
-
const signalMap = /* @__PURE__ */ new Map();
|
228
|
-
strings.forEach((string, i) => {
|
229
|
-
let value = values[i] ?? "";
|
230
|
-
if (typeof value === "function") {
|
231
|
-
const uniqueKey = crypto.randomUUID();
|
232
|
-
signalMap.set(uniqueKey, value);
|
233
|
-
value = `{{signal:${uniqueKey}}}`;
|
234
|
-
}
|
235
|
-
innerHTML += string + String(value);
|
236
|
-
});
|
237
|
-
const fragment = parseFragment(innerHTML);
|
238
|
-
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
239
|
-
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
240
|
-
const parseChildren = (element) => {
|
241
|
-
for (const child of element.childNodes) {
|
242
|
-
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
243
|
-
const textList = child.data.split(signalBindingRegex);
|
244
|
-
textList.forEach((text, i) => {
|
245
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
246
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
247
|
-
const newText = signal !== null ? signal() : text;
|
248
|
-
const newNode = new Text(newText);
|
249
|
-
if (i === 0) {
|
250
|
-
child.replaceWith(newNode);
|
251
|
-
} else {
|
252
|
-
element.insertBefore(newNode, child.nextSibling);
|
253
|
-
}
|
254
|
-
if (signal !== null) {
|
255
|
-
createEffect(() => {
|
256
|
-
newNode.data = signal();
|
257
|
-
});
|
258
|
-
}
|
259
|
-
});
|
260
|
-
}
|
261
|
-
if (child instanceof Element) {
|
262
|
-
for (const attr of child.attributes) {
|
263
|
-
if (signalBindingRegex.test(attr.value)) {
|
264
|
-
const textList = attr.value.split(signalBindingRegex);
|
265
|
-
createEffect(() => {
|
266
|
-
let newText = "";
|
267
|
-
for (const text of textList) {
|
268
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
269
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
270
|
-
newText += signal !== null ? signal() : text;
|
271
|
-
}
|
272
|
-
child.setAttribute(attr.name, newText);
|
273
|
-
});
|
274
|
-
} else if (callbackBindingRegex.test(attr.value)) {
|
275
|
-
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
276
|
-
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
277
|
-
}
|
278
|
-
}
|
279
|
-
parseChildren(child);
|
280
|
-
}
|
281
|
-
}
|
282
|
-
};
|
283
|
-
parseChildren(fragment);
|
284
|
-
return fragment;
|
285
|
-
};
|
286
|
-
var css = (strings, ...values) => {
|
287
|
-
let cssText = "";
|
288
|
-
const signalMap = /* @__PURE__ */ new Map();
|
289
|
-
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
290
|
-
strings.forEach((string, i) => {
|
291
|
-
let value = values[i] ?? "";
|
292
|
-
if (typeof value === "function") {
|
293
|
-
const uniqueKey = crypto.randomUUID();
|
294
|
-
signalMap.set(uniqueKey, value);
|
295
|
-
value = `{{signal:${uniqueKey}}}`;
|
296
|
-
}
|
297
|
-
cssText += string + String(value);
|
298
|
-
});
|
299
|
-
const stylesheet = new CSSStyleSheet();
|
300
|
-
const textList = cssText.split(signalBindingRegex);
|
301
|
-
createEffect(() => {
|
302
|
-
const newCSSTextList = [];
|
303
|
-
for (const text of textList) {
|
304
|
-
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
305
|
-
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
|
306
|
-
const newText = signal !== null ? signal() : text;
|
307
|
-
newCSSTextList.push(newText);
|
308
|
-
}
|
309
|
-
const newCSSText = newCSSTextList.join("");
|
310
|
-
stylesheet.replace(newCSSText);
|
311
|
-
});
|
312
|
-
return stylesheet;
|
313
|
-
};
|
314
382
|
export {
|
315
383
|
createEffect,
|
316
384
|
createRegistry,
|