thunderous 2.0.7 → 2.1.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/dist/index.cjs +53 -15
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +53 -15
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
@@ -136,6 +136,14 @@ var createEffect = (fn) => {
|
|
136
136
|
|
137
137
|
// src/utilities.ts
|
138
138
|
var NOOP = () => void 0;
|
139
|
+
var queryComment = (node, comment) => {
|
140
|
+
for (const child of node.childNodes) {
|
141
|
+
if (child.nodeType === Node.COMMENT_NODE && child.nodeValue === comment) {
|
142
|
+
return child;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
return null;
|
146
|
+
};
|
139
147
|
|
140
148
|
// src/server-side.ts
|
141
149
|
var isServer = typeof window === "undefined";
|
@@ -287,12 +295,19 @@ var logValueError = (value) => {
|
|
287
295
|
value
|
288
296
|
);
|
289
297
|
};
|
290
|
-
var
|
298
|
+
var logPropertyWarning = (propName, element) => {
|
299
|
+
console.warn(
|
300
|
+
`Property "${propName}" does not exist on element:`,
|
301
|
+
element,
|
302
|
+
"\n\nThunderous will attempt to set the property anyway, but this may result in unexpected behavior. Please make sure the property exists on the element prior to setting it."
|
303
|
+
);
|
304
|
+
};
|
305
|
+
var arrayToDocumentFragment = (array, parent, uniqueKey) => {
|
291
306
|
const documentFragment = new DocumentFragment();
|
292
307
|
let count = 0;
|
293
308
|
const keys = /* @__PURE__ */ new Set();
|
294
309
|
for (const item of array) {
|
295
|
-
const node = createNewNode(item, parent);
|
310
|
+
const node = createNewNode(item, parent, uniqueKey);
|
296
311
|
if (node instanceof DocumentFragment) {
|
297
312
|
const child = node.firstElementChild;
|
298
313
|
if (node.children.length > 1) {
|
@@ -322,11 +337,13 @@ var arrayToDocumentFragment = (array, parent) => {
|
|
322
337
|
}
|
323
338
|
documentFragment.append(node);
|
324
339
|
}
|
340
|
+
const comment = document.createComment(uniqueKey);
|
341
|
+
documentFragment.append(comment);
|
325
342
|
return documentFragment;
|
326
343
|
};
|
327
|
-
var createNewNode = (value, parent) => {
|
344
|
+
var createNewNode = (value, parent, uniqueKey) => {
|
328
345
|
if (typeof value === "string") return new Text(value);
|
329
|
-
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent);
|
346
|
+
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent, uniqueKey);
|
330
347
|
if (value instanceof DocumentFragment) return value;
|
331
348
|
return new Text("");
|
332
349
|
};
|
@@ -366,7 +383,7 @@ var evaluateBindings = (element, fragment) => {
|
|
366
383
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
367
384
|
const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
|
368
385
|
const newValue = signal !== void 0 ? signal() : text;
|
369
|
-
const newNode = createNewNode(newValue, element);
|
386
|
+
const newNode = createNewNode(newValue, element, uniqueKey);
|
370
387
|
if (i === 0) {
|
371
388
|
child.replaceWith(newNode);
|
372
389
|
} else {
|
@@ -380,13 +397,12 @@ var evaluateBindings = (element, fragment) => {
|
|
380
397
|
let init = false;
|
381
398
|
createEffect(() => {
|
382
399
|
const result = signal();
|
383
|
-
const nextNode = createNewNode(result, element);
|
400
|
+
const nextNode = createNewNode(result, element, uniqueKey);
|
384
401
|
if (nextNode instanceof Text) {
|
385
402
|
throw new TypeError(
|
386
403
|
"Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
|
387
404
|
);
|
388
405
|
}
|
389
|
-
let lastSibling = element.lastChild;
|
390
406
|
for (const child2 of element.children) {
|
391
407
|
const key = child2.getAttribute("key");
|
392
408
|
if (key === null) continue;
|
@@ -395,6 +411,7 @@ var evaluateBindings = (element, fragment) => {
|
|
395
411
|
child2.remove();
|
396
412
|
}
|
397
413
|
}
|
414
|
+
let anchor = queryComment(element, uniqueKey);
|
398
415
|
for (const child2 of nextNode.children) {
|
399
416
|
const key = child2.getAttribute("key");
|
400
417
|
const matchingNode = element.querySelector(`[key="${key}"]`);
|
@@ -404,10 +421,12 @@ var evaluateBindings = (element, fragment) => {
|
|
404
421
|
matchingNode.setAttribute(attr.name, attr.value);
|
405
422
|
}
|
406
423
|
matchingNode.replaceChildren(...child2.childNodes);
|
407
|
-
|
424
|
+
anchor = matchingNode.nextSibling;
|
408
425
|
child2.replaceWith(matchingNode);
|
409
426
|
}
|
410
|
-
|
427
|
+
const nextAnchor = queryComment(nextNode, uniqueKey);
|
428
|
+
nextAnchor?.remove();
|
429
|
+
element.insertBefore(nextNode, anchor);
|
411
430
|
if (!init) init = true;
|
412
431
|
});
|
413
432
|
}
|
@@ -421,22 +440,31 @@ var evaluateBindings = (element, fragment) => {
|
|
421
440
|
}
|
422
441
|
} else if (child instanceof Element) {
|
423
442
|
for (const attr of child.attributes) {
|
443
|
+
const attrName = attr.name;
|
424
444
|
if (SIGNAL_BINDING_REGEX.test(attr.value)) {
|
425
445
|
const textList = attr.value.split(SIGNAL_BINDING_REGEX);
|
426
446
|
createEffect(() => {
|
427
447
|
let newText = "";
|
428
448
|
let hasNull = false;
|
449
|
+
let signal;
|
429
450
|
for (const text of textList) {
|
430
451
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
431
|
-
|
452
|
+
signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
|
432
453
|
const value = signal !== void 0 ? signal() : text;
|
433
454
|
if (value === null) hasNull = true;
|
434
455
|
newText += String(value);
|
435
456
|
}
|
436
|
-
if (hasNull && newText === "null") {
|
437
|
-
child.removeAttribute(
|
457
|
+
if (hasNull && newText === "null" || attrName.startsWith("prop:")) {
|
458
|
+
child.removeAttribute(attrName);
|
438
459
|
} else {
|
439
|
-
child.setAttribute(
|
460
|
+
child.setAttribute(attrName, newText);
|
461
|
+
}
|
462
|
+
if (attrName.startsWith("prop:")) {
|
463
|
+
child.removeAttribute(attrName);
|
464
|
+
const propName = attrName.replace("prop:", "");
|
465
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
466
|
+
const newValue = hasNull && newText === "null" ? null : newText;
|
467
|
+
child[propName] = signal !== void 0 ? signal() : newValue;
|
440
468
|
}
|
441
469
|
});
|
442
470
|
} else if (LEGACY_CALLBACK_BINDING_REGEX.test(attr.value)) {
|
@@ -458,10 +486,20 @@ var evaluateBindings = (element, fragment) => {
|
|
458
486
|
child.__customCallbackFns.set(uniqueKey, callback);
|
459
487
|
}
|
460
488
|
}
|
461
|
-
if (uniqueKey !== "") {
|
462
|
-
child.setAttribute(
|
489
|
+
if (uniqueKey !== "" && !attrName.startsWith("prop:")) {
|
490
|
+
child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
|
491
|
+
} else if (attrName.startsWith("prop:")) {
|
492
|
+
child.removeAttribute(attrName);
|
493
|
+
const propName = attrName.replace("prop:", "");
|
494
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
495
|
+
child[propName] = child.__customCallbackFns.get(uniqueKey);
|
463
496
|
}
|
464
497
|
});
|
498
|
+
} else if (attrName.startsWith("prop:")) {
|
499
|
+
child.removeAttribute(attrName);
|
500
|
+
const propName = attrName.replace("prop:", "");
|
501
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
502
|
+
child[propName] = attr.value;
|
465
503
|
}
|
466
504
|
}
|
467
505
|
evaluateBindings(child, fragment);
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
@@ -101,6 +101,14 @@ var createEffect = (fn) => {
|
|
101
101
|
|
102
102
|
// src/utilities.ts
|
103
103
|
var NOOP = () => void 0;
|
104
|
+
var queryComment = (node, comment) => {
|
105
|
+
for (const child of node.childNodes) {
|
106
|
+
if (child.nodeType === Node.COMMENT_NODE && child.nodeValue === comment) {
|
107
|
+
return child;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
return null;
|
111
|
+
};
|
104
112
|
|
105
113
|
// src/server-side.ts
|
106
114
|
var isServer = typeof window === "undefined";
|
@@ -252,12 +260,19 @@ var logValueError = (value) => {
|
|
252
260
|
value
|
253
261
|
);
|
254
262
|
};
|
255
|
-
var
|
263
|
+
var logPropertyWarning = (propName, element) => {
|
264
|
+
console.warn(
|
265
|
+
`Property "${propName}" does not exist on element:`,
|
266
|
+
element,
|
267
|
+
"\n\nThunderous will attempt to set the property anyway, but this may result in unexpected behavior. Please make sure the property exists on the element prior to setting it."
|
268
|
+
);
|
269
|
+
};
|
270
|
+
var arrayToDocumentFragment = (array, parent, uniqueKey) => {
|
256
271
|
const documentFragment = new DocumentFragment();
|
257
272
|
let count = 0;
|
258
273
|
const keys = /* @__PURE__ */ new Set();
|
259
274
|
for (const item of array) {
|
260
|
-
const node = createNewNode(item, parent);
|
275
|
+
const node = createNewNode(item, parent, uniqueKey);
|
261
276
|
if (node instanceof DocumentFragment) {
|
262
277
|
const child = node.firstElementChild;
|
263
278
|
if (node.children.length > 1) {
|
@@ -287,11 +302,13 @@ var arrayToDocumentFragment = (array, parent) => {
|
|
287
302
|
}
|
288
303
|
documentFragment.append(node);
|
289
304
|
}
|
305
|
+
const comment = document.createComment(uniqueKey);
|
306
|
+
documentFragment.append(comment);
|
290
307
|
return documentFragment;
|
291
308
|
};
|
292
|
-
var createNewNode = (value, parent) => {
|
309
|
+
var createNewNode = (value, parent, uniqueKey) => {
|
293
310
|
if (typeof value === "string") return new Text(value);
|
294
|
-
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent);
|
311
|
+
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent, uniqueKey);
|
295
312
|
if (value instanceof DocumentFragment) return value;
|
296
313
|
return new Text("");
|
297
314
|
};
|
@@ -331,7 +348,7 @@ var evaluateBindings = (element, fragment) => {
|
|
331
348
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
332
349
|
const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
|
333
350
|
const newValue = signal !== void 0 ? signal() : text;
|
334
|
-
const newNode = createNewNode(newValue, element);
|
351
|
+
const newNode = createNewNode(newValue, element, uniqueKey);
|
335
352
|
if (i === 0) {
|
336
353
|
child.replaceWith(newNode);
|
337
354
|
} else {
|
@@ -345,13 +362,12 @@ var evaluateBindings = (element, fragment) => {
|
|
345
362
|
let init = false;
|
346
363
|
createEffect(() => {
|
347
364
|
const result = signal();
|
348
|
-
const nextNode = createNewNode(result, element);
|
365
|
+
const nextNode = createNewNode(result, element, uniqueKey);
|
349
366
|
if (nextNode instanceof Text) {
|
350
367
|
throw new TypeError(
|
351
368
|
"Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
|
352
369
|
);
|
353
370
|
}
|
354
|
-
let lastSibling = element.lastChild;
|
355
371
|
for (const child2 of element.children) {
|
356
372
|
const key = child2.getAttribute("key");
|
357
373
|
if (key === null) continue;
|
@@ -360,6 +376,7 @@ var evaluateBindings = (element, fragment) => {
|
|
360
376
|
child2.remove();
|
361
377
|
}
|
362
378
|
}
|
379
|
+
let anchor = queryComment(element, uniqueKey);
|
363
380
|
for (const child2 of nextNode.children) {
|
364
381
|
const key = child2.getAttribute("key");
|
365
382
|
const matchingNode = element.querySelector(`[key="${key}"]`);
|
@@ -369,10 +386,12 @@ var evaluateBindings = (element, fragment) => {
|
|
369
386
|
matchingNode.setAttribute(attr.name, attr.value);
|
370
387
|
}
|
371
388
|
matchingNode.replaceChildren(...child2.childNodes);
|
372
|
-
|
389
|
+
anchor = matchingNode.nextSibling;
|
373
390
|
child2.replaceWith(matchingNode);
|
374
391
|
}
|
375
|
-
|
392
|
+
const nextAnchor = queryComment(nextNode, uniqueKey);
|
393
|
+
nextAnchor?.remove();
|
394
|
+
element.insertBefore(nextNode, anchor);
|
376
395
|
if (!init) init = true;
|
377
396
|
});
|
378
397
|
}
|
@@ -386,22 +405,31 @@ var evaluateBindings = (element, fragment) => {
|
|
386
405
|
}
|
387
406
|
} else if (child instanceof Element) {
|
388
407
|
for (const attr of child.attributes) {
|
408
|
+
const attrName = attr.name;
|
389
409
|
if (SIGNAL_BINDING_REGEX.test(attr.value)) {
|
390
410
|
const textList = attr.value.split(SIGNAL_BINDING_REGEX);
|
391
411
|
createEffect(() => {
|
392
412
|
let newText = "";
|
393
413
|
let hasNull = false;
|
414
|
+
let signal;
|
394
415
|
for (const text of textList) {
|
395
416
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
396
|
-
|
417
|
+
signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
|
397
418
|
const value = signal !== void 0 ? signal() : text;
|
398
419
|
if (value === null) hasNull = true;
|
399
420
|
newText += String(value);
|
400
421
|
}
|
401
|
-
if (hasNull && newText === "null") {
|
402
|
-
child.removeAttribute(
|
422
|
+
if (hasNull && newText === "null" || attrName.startsWith("prop:")) {
|
423
|
+
child.removeAttribute(attrName);
|
403
424
|
} else {
|
404
|
-
child.setAttribute(
|
425
|
+
child.setAttribute(attrName, newText);
|
426
|
+
}
|
427
|
+
if (attrName.startsWith("prop:")) {
|
428
|
+
child.removeAttribute(attrName);
|
429
|
+
const propName = attrName.replace("prop:", "");
|
430
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
431
|
+
const newValue = hasNull && newText === "null" ? null : newText;
|
432
|
+
child[propName] = signal !== void 0 ? signal() : newValue;
|
405
433
|
}
|
406
434
|
});
|
407
435
|
} else if (LEGACY_CALLBACK_BINDING_REGEX.test(attr.value)) {
|
@@ -423,10 +451,20 @@ var evaluateBindings = (element, fragment) => {
|
|
423
451
|
child.__customCallbackFns.set(uniqueKey, callback);
|
424
452
|
}
|
425
453
|
}
|
426
|
-
if (uniqueKey !== "") {
|
427
|
-
child.setAttribute(
|
454
|
+
if (uniqueKey !== "" && !attrName.startsWith("prop:")) {
|
455
|
+
child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
|
456
|
+
} else if (attrName.startsWith("prop:")) {
|
457
|
+
child.removeAttribute(attrName);
|
458
|
+
const propName = attrName.replace("prop:", "");
|
459
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
460
|
+
child[propName] = child.__customCallbackFns.get(uniqueKey);
|
428
461
|
}
|
429
462
|
});
|
463
|
+
} else if (attrName.startsWith("prop:")) {
|
464
|
+
child.removeAttribute(attrName);
|
465
|
+
const propName = attrName.replace("prop:", "");
|
466
|
+
if (!(propName in child)) logPropertyWarning(propName, child);
|
467
|
+
child[propName] = attr.value;
|
430
468
|
}
|
431
469
|
}
|
432
470
|
evaluateBindings(child, fragment);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "thunderous",
|
3
|
-
"version": "2.0
|
3
|
+
"version": "2.1.0",
|
4
4
|
"description": "",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./dist/index.cjs",
|
@@ -35,7 +35,10 @@
|
|
35
35
|
"www": "cd www && npm run dev",
|
36
36
|
"build": "tsup src/index.ts --format cjs,esm --dts --no-clean",
|
37
37
|
"test": "find src -name '*.test.ts' | xargs c8 node --import tsx --test",
|
38
|
-
"lint": "tsc && eslint ."
|
38
|
+
"lint": "tsc && eslint .",
|
39
|
+
"version:patch": "npm run build && npm version patch && cd demo && npm version patch && cd ../www && npm version patch && git add -A && git commit -m 'bump version'",
|
40
|
+
"version:minor": "npm run build && npm version minor && cd demo && npm version minor && cd ../www && npm version minor && git add -A && git commit -m 'bump version'",
|
41
|
+
"version:major": "npm run build && npm version major && cd demo && npm version major && cd ../www && npm version major && git add -A && git commit -m 'bump version'"
|
39
42
|
},
|
40
43
|
"devDependencies": {
|
41
44
|
"@types/dompurify": "^3.2.0",
|