thunderous 2.0.8 → 2.1.1

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 CHANGED
@@ -193,21 +193,27 @@ var getServerRenderArgs = (tagName, registry) => ({
193
193
  get elementRef() {
194
194
  return new Proxy({}, {
195
195
  get: () => {
196
- throw new Error("The `elementRef` property is not available on the server.");
196
+ const error = new Error("The `elementRef` property is not available on the server.");
197
+ console.error(error);
198
+ throw error;
197
199
  }
198
200
  });
199
201
  },
200
202
  get root() {
201
203
  return new Proxy({}, {
202
204
  get: () => {
203
- throw new Error("The `root` property is not available on the server.");
205
+ const error = new Error("The `root` property is not available on the server.");
206
+ console.error(error);
207
+ throw error;
204
208
  }
205
209
  });
206
210
  },
207
211
  get internals() {
208
212
  return new Proxy({}, {
209
213
  get: () => {
210
- throw new Error("The `internals` property is not available on the server.");
214
+ const error = new Error("The `internals` property is not available on the server.");
215
+ console.error(error);
216
+ throw error;
211
217
  }
212
218
  });
213
219
  },
@@ -295,6 +301,13 @@ var logValueError = (value) => {
295
301
  value
296
302
  );
297
303
  };
304
+ var logPropertyWarning = (propName, element) => {
305
+ console.warn(
306
+ `Property "${propName}" does not exist on element:`,
307
+ element,
308
+ "\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."
309
+ );
310
+ };
298
311
  var arrayToDocumentFragment = (array, parent, uniqueKey) => {
299
312
  const documentFragment = new DocumentFragment();
300
313
  let count = 0;
@@ -377,7 +390,6 @@ var evaluateBindings = (element, fragment) => {
377
390
  const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
378
391
  const newValue = signal !== void 0 ? signal() : text;
379
392
  const newNode = createNewNode(newValue, element, uniqueKey);
380
- const clone = newNode.cloneNode(true);
381
393
  if (i === 0) {
382
394
  child.replaceWith(newNode);
383
395
  } else {
@@ -393,9 +405,11 @@ var evaluateBindings = (element, fragment) => {
393
405
  const result = signal();
394
406
  const nextNode = createNewNode(result, element, uniqueKey);
395
407
  if (nextNode instanceof Text) {
396
- throw new TypeError(
408
+ const error = new TypeError(
397
409
  "Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
398
410
  );
411
+ console.error(error);
412
+ throw error;
399
413
  }
400
414
  for (const child2 of element.children) {
401
415
  const key = child2.getAttribute("key");
@@ -434,22 +448,31 @@ var evaluateBindings = (element, fragment) => {
434
448
  }
435
449
  } else if (child instanceof Element) {
436
450
  for (const attr of child.attributes) {
451
+ const attrName = attr.name;
437
452
  if (SIGNAL_BINDING_REGEX.test(attr.value)) {
438
453
  const textList = attr.value.split(SIGNAL_BINDING_REGEX);
439
454
  createEffect(() => {
440
455
  let newText = "";
441
456
  let hasNull = false;
457
+ let signal;
442
458
  for (const text of textList) {
443
459
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
444
- const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
460
+ signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
445
461
  const value = signal !== void 0 ? signal() : text;
446
462
  if (value === null) hasNull = true;
447
463
  newText += String(value);
448
464
  }
449
- if (hasNull && newText === "null") {
450
- child.removeAttribute(attr.name);
465
+ if (hasNull && newText === "null" || attrName.startsWith("prop:")) {
466
+ child.removeAttribute(attrName);
451
467
  } else {
452
- child.setAttribute(attr.name, newText);
468
+ child.setAttribute(attrName, newText);
469
+ }
470
+ if (attrName.startsWith("prop:")) {
471
+ child.removeAttribute(attrName);
472
+ const propName = attrName.replace("prop:", "");
473
+ if (!(propName in child)) logPropertyWarning(propName, child);
474
+ const newValue = hasNull && newText === "null" ? null : newText;
475
+ child[propName] = signal !== void 0 ? signal() : newValue;
453
476
  }
454
477
  });
455
478
  } else if (LEGACY_CALLBACK_BINDING_REGEX.test(attr.value)) {
@@ -471,10 +494,20 @@ var evaluateBindings = (element, fragment) => {
471
494
  child.__customCallbackFns.set(uniqueKey, callback);
472
495
  }
473
496
  }
474
- if (uniqueKey !== "") {
475
- child.setAttribute(attr.name, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
497
+ if (uniqueKey !== "" && !attrName.startsWith("prop:")) {
498
+ child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
499
+ } else if (attrName.startsWith("prop:")) {
500
+ child.removeAttribute(attrName);
501
+ const propName = attrName.replace("prop:", "");
502
+ if (!(propName in child)) logPropertyWarning(propName, child);
503
+ child[propName] = child.__customCallbackFns.get(uniqueKey);
476
504
  }
477
505
  });
506
+ } else if (attrName.startsWith("prop:")) {
507
+ child.removeAttribute(attrName);
508
+ const propName = attrName.replace("prop:", "");
509
+ if (!(propName in child)) logPropertyWarning(propName, child);
510
+ child[propName] = attr.value;
478
511
  }
479
512
  }
480
513
  evaluateBindings(child, fragment);
@@ -591,7 +624,9 @@ var customElement = (render, options) => {
591
624
  return this;
592
625
  },
593
626
  eject() {
594
- throw new Error("Cannot eject a custom element on the server.");
627
+ const error = new Error("Cannot eject a custom element on the server.");
628
+ console.error(error);
629
+ throw error;
595
630
  }
596
631
  };
597
632
  }
@@ -689,15 +724,15 @@ var customElement = (render, options) => {
689
724
  };
690
725
  const getter = () => {
691
726
  const value = _getter();
692
- if (value === void 0)
693
- throw new Error(
694
- `
695
-
696
- Property: ${prop}
697
-
727
+ if (value === void 0) {
728
+ const error = new Error(
729
+ `Error accessing property: "${prop}"
698
730
  You must set an initial value before calling a property signal's getter.
699
731
  `
700
732
  );
733
+ console.error(error);
734
+ throw error;
735
+ }
701
736
  return value;
702
737
  };
703
738
  getter.getter = true;
@@ -763,7 +798,16 @@ You must set an initial value before calling a property signal's getter.
763
798
  return observedAttributes;
764
799
  }
765
800
  constructor() {
766
- super();
801
+ try {
802
+ super();
803
+ } catch (error) {
804
+ const _error = new Error(
805
+ "Error instantiating element:\nThis usually occurs if you have errors in the function body of your component. Check prior logs for possible causes.\n",
806
+ { cause: error }
807
+ );
808
+ console.error(_error);
809
+ throw _error;
810
+ }
767
811
  if (!Object.prototype.hasOwnProperty.call(this, "__customCallbackFns")) {
768
812
  this.__customCallbackFns = /* @__PURE__ */ new Map();
769
813
  }
@@ -945,7 +989,9 @@ var createRegistry = (args) => {
945
989
  getAllTagNames: () => Array.from(customElementTags),
946
990
  eject: () => {
947
991
  if (nativeRegistry === void 0) {
948
- throw new Error("Cannot eject a registry on the server.");
992
+ const error = new Error("Cannot eject a registry on the server.");
993
+ console.error(error);
994
+ throw error;
949
995
  }
950
996
  return nativeRegistry;
951
997
  },
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ declare global {
2
2
  interface DocumentFragment {
3
3
  host: HTMLElement;
4
4
  }
5
- interface Element {
5
+ interface Node {
6
6
  __customCallbackFns?: Map<string, AnyFn>;
7
7
  }
8
8
  interface CustomElementRegistry {
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ declare global {
2
2
  interface DocumentFragment {
3
3
  host: HTMLElement;
4
4
  }
5
- interface Element {
5
+ interface Node {
6
6
  __customCallbackFns?: Map<string, AnyFn>;
7
7
  }
8
8
  interface CustomElementRegistry {
package/dist/index.js CHANGED
@@ -158,21 +158,27 @@ var getServerRenderArgs = (tagName, registry) => ({
158
158
  get elementRef() {
159
159
  return new Proxy({}, {
160
160
  get: () => {
161
- throw new Error("The `elementRef` property is not available on the server.");
161
+ const error = new Error("The `elementRef` property is not available on the server.");
162
+ console.error(error);
163
+ throw error;
162
164
  }
163
165
  });
164
166
  },
165
167
  get root() {
166
168
  return new Proxy({}, {
167
169
  get: () => {
168
- throw new Error("The `root` property is not available on the server.");
170
+ const error = new Error("The `root` property is not available on the server.");
171
+ console.error(error);
172
+ throw error;
169
173
  }
170
174
  });
171
175
  },
172
176
  get internals() {
173
177
  return new Proxy({}, {
174
178
  get: () => {
175
- throw new Error("The `internals` property is not available on the server.");
179
+ const error = new Error("The `internals` property is not available on the server.");
180
+ console.error(error);
181
+ throw error;
176
182
  }
177
183
  });
178
184
  },
@@ -260,6 +266,13 @@ var logValueError = (value) => {
260
266
  value
261
267
  );
262
268
  };
269
+ var logPropertyWarning = (propName, element) => {
270
+ console.warn(
271
+ `Property "${propName}" does not exist on element:`,
272
+ element,
273
+ "\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."
274
+ );
275
+ };
263
276
  var arrayToDocumentFragment = (array, parent, uniqueKey) => {
264
277
  const documentFragment = new DocumentFragment();
265
278
  let count = 0;
@@ -342,7 +355,6 @@ var evaluateBindings = (element, fragment) => {
342
355
  const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
343
356
  const newValue = signal !== void 0 ? signal() : text;
344
357
  const newNode = createNewNode(newValue, element, uniqueKey);
345
- const clone = newNode.cloneNode(true);
346
358
  if (i === 0) {
347
359
  child.replaceWith(newNode);
348
360
  } else {
@@ -358,9 +370,11 @@ var evaluateBindings = (element, fragment) => {
358
370
  const result = signal();
359
371
  const nextNode = createNewNode(result, element, uniqueKey);
360
372
  if (nextNode instanceof Text) {
361
- throw new TypeError(
373
+ const error = new TypeError(
362
374
  "Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
363
375
  );
376
+ console.error(error);
377
+ throw error;
364
378
  }
365
379
  for (const child2 of element.children) {
366
380
  const key = child2.getAttribute("key");
@@ -399,22 +413,31 @@ var evaluateBindings = (element, fragment) => {
399
413
  }
400
414
  } else if (child instanceof Element) {
401
415
  for (const attr of child.attributes) {
416
+ const attrName = attr.name;
402
417
  if (SIGNAL_BINDING_REGEX.test(attr.value)) {
403
418
  const textList = attr.value.split(SIGNAL_BINDING_REGEX);
404
419
  createEffect(() => {
405
420
  let newText = "";
406
421
  let hasNull = false;
422
+ let signal;
407
423
  for (const text of textList) {
408
424
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
409
- const signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
425
+ signal = uniqueKey !== text ? renderState.signalMap.get(uniqueKey) : void 0;
410
426
  const value = signal !== void 0 ? signal() : text;
411
427
  if (value === null) hasNull = true;
412
428
  newText += String(value);
413
429
  }
414
- if (hasNull && newText === "null") {
415
- child.removeAttribute(attr.name);
430
+ if (hasNull && newText === "null" || attrName.startsWith("prop:")) {
431
+ child.removeAttribute(attrName);
416
432
  } else {
417
- child.setAttribute(attr.name, newText);
433
+ child.setAttribute(attrName, newText);
434
+ }
435
+ if (attrName.startsWith("prop:")) {
436
+ child.removeAttribute(attrName);
437
+ const propName = attrName.replace("prop:", "");
438
+ if (!(propName in child)) logPropertyWarning(propName, child);
439
+ const newValue = hasNull && newText === "null" ? null : newText;
440
+ child[propName] = signal !== void 0 ? signal() : newValue;
418
441
  }
419
442
  });
420
443
  } else if (LEGACY_CALLBACK_BINDING_REGEX.test(attr.value)) {
@@ -436,10 +459,20 @@ var evaluateBindings = (element, fragment) => {
436
459
  child.__customCallbackFns.set(uniqueKey, callback);
437
460
  }
438
461
  }
439
- if (uniqueKey !== "") {
440
- child.setAttribute(attr.name, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
462
+ if (uniqueKey !== "" && !attrName.startsWith("prop:")) {
463
+ child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
464
+ } else if (attrName.startsWith("prop:")) {
465
+ child.removeAttribute(attrName);
466
+ const propName = attrName.replace("prop:", "");
467
+ if (!(propName in child)) logPropertyWarning(propName, child);
468
+ child[propName] = child.__customCallbackFns.get(uniqueKey);
441
469
  }
442
470
  });
471
+ } else if (attrName.startsWith("prop:")) {
472
+ child.removeAttribute(attrName);
473
+ const propName = attrName.replace("prop:", "");
474
+ if (!(propName in child)) logPropertyWarning(propName, child);
475
+ child[propName] = attr.value;
443
476
  }
444
477
  }
445
478
  evaluateBindings(child, fragment);
@@ -556,7 +589,9 @@ var customElement = (render, options) => {
556
589
  return this;
557
590
  },
558
591
  eject() {
559
- throw new Error("Cannot eject a custom element on the server.");
592
+ const error = new Error("Cannot eject a custom element on the server.");
593
+ console.error(error);
594
+ throw error;
560
595
  }
561
596
  };
562
597
  }
@@ -654,15 +689,15 @@ var customElement = (render, options) => {
654
689
  };
655
690
  const getter = () => {
656
691
  const value = _getter();
657
- if (value === void 0)
658
- throw new Error(
659
- `
660
-
661
- Property: ${prop}
662
-
692
+ if (value === void 0) {
693
+ const error = new Error(
694
+ `Error accessing property: "${prop}"
663
695
  You must set an initial value before calling a property signal's getter.
664
696
  `
665
697
  );
698
+ console.error(error);
699
+ throw error;
700
+ }
666
701
  return value;
667
702
  };
668
703
  getter.getter = true;
@@ -728,7 +763,16 @@ You must set an initial value before calling a property signal's getter.
728
763
  return observedAttributes;
729
764
  }
730
765
  constructor() {
731
- super();
766
+ try {
767
+ super();
768
+ } catch (error) {
769
+ const _error = new Error(
770
+ "Error instantiating element:\nThis usually occurs if you have errors in the function body of your component. Check prior logs for possible causes.\n",
771
+ { cause: error }
772
+ );
773
+ console.error(_error);
774
+ throw _error;
775
+ }
732
776
  if (!Object.prototype.hasOwnProperty.call(this, "__customCallbackFns")) {
733
777
  this.__customCallbackFns = /* @__PURE__ */ new Map();
734
778
  }
@@ -910,7 +954,9 @@ var createRegistry = (args) => {
910
954
  getAllTagNames: () => Array.from(customElementTags),
911
955
  eject: () => {
912
956
  if (nativeRegistry === void 0) {
913
- throw new Error("Cannot eject a registry on the server.");
957
+ const error = new Error("Cannot eject a registry on the server.");
958
+ console.error(error);
959
+ throw error;
914
960
  }
915
961
  return nativeRegistry;
916
962
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thunderous",
3
- "version": "2.0.8",
3
+ "version": "2.1.1",
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",