thunderous 2.4.5 → 2.4.6

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
@@ -102,13 +102,14 @@ var createSignal = (initVal, options) => {
102
102
  const effectRef = effects.get(sym);
103
103
  if (effectRef !== void 0) {
104
104
  try {
105
- effectRef.fn({
105
+ const result = effectRef.fn({
106
106
  lastValue: effectRef.value,
107
107
  destroy: () => {
108
108
  effects.delete(sym);
109
109
  queueMicrotask(() => subscribers.delete(sym));
110
110
  }
111
111
  });
112
+ if (result !== void 0) effectRef.value = result;
112
113
  } catch (error) {
113
114
  console.error("Error in subscriber:", { error, oldValue, newValue, fn: effectRef.fn });
114
115
  }
@@ -149,14 +150,16 @@ var derived = (fn, options) => {
149
150
  };
150
151
  var createEffect = (fn, value) => {
151
152
  const privateIdent = ident = {};
152
- effects.set(ident, { fn, value });
153
+ const effectRef = { fn, value };
154
+ effects.set(ident, effectRef);
153
155
  try {
154
- fn({
156
+ const result = fn({
155
157
  lastValue: value,
156
158
  destroy: () => {
157
159
  effects.delete(privateIdent);
158
160
  }
159
161
  });
162
+ if (result !== void 0) effectRef.value = result;
160
163
  } catch (error) {
161
164
  console.error("Error in effect:", { error, fn });
162
165
  }
@@ -450,15 +453,11 @@ var evaluateBindings = (element, fragment) => {
450
453
  signalEntries.forEach(({ uniqueKey, signal, initialChildren, autoKey }) => {
451
454
  const firstChild = initialChildren[0];
452
455
  const lastChild = initialChildren[initialChildren.length - 1];
453
- if (uniqueKey === void 0 || firstChild === void 0) return;
456
+ if (firstChild === void 0) return;
454
457
  const startAnchor = document.createComment(`${uniqueKey}:start`);
455
458
  firstChild.before(startAnchor);
456
459
  const endAnchor = document.createComment(`${uniqueKey}:end`);
457
- if (lastChild !== void 0) {
458
- lastChild.after(endAnchor);
459
- } else {
460
- startAnchor.after(endAnchor);
461
- }
460
+ lastChild.after(endAnchor);
462
461
  const bindText = (node, signal2) => {
463
462
  createEffect(({ destroy }) => {
464
463
  const result = signal2();
@@ -482,11 +481,6 @@ var evaluateBindings = (element, fragment) => {
482
481
  const newChildren = asNodeList(result, element, autoKey2);
483
482
  const firstChild2 = newChildren[0];
484
483
  if (!Array.isArray(result)) {
485
- if (newChildren.length === 1 && firstChild2 instanceof DocumentFragment) {
486
- destroy();
487
- bindFragment(signal2, initialChildren, autoKey2);
488
- return;
489
- }
490
484
  if (newChildren.length === 1 && firstChild2 instanceof Text) {
491
485
  while (startAnchor.nextSibling !== endAnchor) {
492
486
  startAnchor.nextSibling?.remove();
@@ -505,7 +499,6 @@ var evaluateBindings = (element, fragment) => {
505
499
  for (const persistedChild of oldChildren) {
506
500
  if (persistedChild instanceof Element) {
507
501
  const key = persistedChild.getAttribute("key");
508
- if (key === null) continue;
509
502
  const newChild = queryChildren(newChildren, `[key="${key}"]`);
510
503
  if (newChild === null) {
511
504
  persistedChild.remove();
@@ -565,16 +558,14 @@ var evaluateBindings = (element, fragment) => {
565
558
  startAnchor.after(...children);
566
559
  });
567
560
  };
568
- if (signal !== void 0) {
569
- const currentValue = signal();
570
- if (Array.isArray(currentValue)) {
571
- bindArray(signal, autoKey);
572
- } else if (currentValue instanceof DocumentFragment) {
573
- bindFragment(signal, initialChildren, autoKey);
574
- } else {
575
- const initialChild = initialChildren[0];
576
- bindText(initialChild, signal);
577
- }
561
+ const currentValue = signal();
562
+ if (Array.isArray(currentValue)) {
563
+ bindArray(signal, autoKey);
564
+ } else if (currentValue instanceof DocumentFragment) {
565
+ bindFragment(signal, initialChildren, autoKey);
566
+ } else {
567
+ const initialChild = initialChildren[0];
568
+ bindText(initialChild, signal);
578
569
  }
579
570
  });
580
571
  }
@@ -611,7 +602,6 @@ var evaluateBindings = (element, fragment) => {
611
602
  if (newText !== prevText) child.setAttribute(attrName, newText);
612
603
  }
613
604
  if (attrName.startsWith("prop-id:")) {
614
- if (child.hasAttribute(attrName)) child.removeAttribute(attrName);
615
605
  const propId = attrName.replace("prop-id:", "");
616
606
  const propName = renderState.propertyMap.get(propId);
617
607
  if (propName === void 0) {
@@ -646,9 +636,7 @@ var evaluateBindings = (element, fragment) => {
646
636
  child.__customCallbackFns.set(uniqueKey, callback);
647
637
  }
648
638
  }
649
- if (uniqueKey !== "" && !attrName.startsWith("prop-id:")) {
650
- child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
651
- } else if (attrName.startsWith("prop-id:")) {
639
+ if (attrName.startsWith("prop-id:")) {
652
640
  child.removeAttribute(attrName);
653
641
  const propId = attrName.replace("prop-id:", "");
654
642
  const propName = renderState.propertyMap.get(propId);
@@ -661,6 +649,8 @@ var evaluateBindings = (element, fragment) => {
661
649
  }
662
650
  if (!(propName in child)) logPropertyWarning(propName, child);
663
651
  child[propName] = child.__customCallbackFns.get(uniqueKey);
652
+ } else {
653
+ child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
664
654
  }
665
655
  });
666
656
  } else if (attrName.startsWith("prop-id:")) {
@@ -690,7 +680,7 @@ var html = (strings, ...values) => {
690
680
  } else {
691
681
  value = processValue(value);
692
682
  }
693
- innerHTML2 += str + String(value === null ? "" : value);
683
+ innerHTML2 += str + String(value);
694
684
  return innerHTML2;
695
685
  }, "");
696
686
  if (isServer) return innerHTML;
@@ -711,7 +701,7 @@ var html = (strings, ...values) => {
711
701
  evaluateBindings(fragment, fragment);
712
702
  return fragment;
713
703
  };
714
- var adoptedStylesSupported = typeof window !== "undefined" && window.ShadowRoot?.prototype.hasOwnProperty("adoptedStyleSheets") && window.CSSStyleSheet?.prototype.hasOwnProperty("replace");
704
+ var isAdoptedStylesSupported = () => typeof window !== "undefined" && window.ShadowRoot?.prototype.hasOwnProperty("adoptedStyleSheets") && window.CSSStyleSheet?.prototype.hasOwnProperty("replace");
715
705
  var isCSSStyleSheet = (stylesheet) => {
716
706
  return typeof CSSStyleSheet !== "undefined" && stylesheet instanceof CSSStyleSheet;
717
707
  };
@@ -735,7 +725,7 @@ var css = (strings, ...values) => {
735
725
  if (isServer) {
736
726
  return cssText;
737
727
  }
738
- const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
728
+ const stylesheet = isAdoptedStylesSupported() ? new CSSStyleSheet() : document.createElement("style");
739
729
  const textList = cssText.split(signalBindingRegex);
740
730
  createEffect(() => {
741
731
  const newCSSTextList = [];
@@ -842,7 +832,6 @@ var customElement = (render, options) => {
842
832
  #observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
843
833
  for (const mutation of mutations) {
844
834
  const attrName = mutation.attributeName;
845
- if (mutation.type !== "attributes" || attrName === null) continue;
846
835
  if (!(attrName in this.#attrSignals)) {
847
836
  this.#attrSignals[attrName] = createSignal(this.getAttribute(attrName));
848
837
  }
@@ -1016,9 +1005,7 @@ You must set an initial value before calling a property signal's getter.
1016
1005
  constructor() {
1017
1006
  try {
1018
1007
  super();
1019
- if (!Object.prototype.hasOwnProperty.call(this, "__customCallbackFns")) {
1020
- this.__customCallbackFns = /* @__PURE__ */ new Map();
1021
- }
1008
+ this.__customCallbackFns = /* @__PURE__ */ new Map();
1022
1009
  for (const attr of this.attributes) {
1023
1010
  this.#attrSignals[attr.name] = createSignal(attr.value);
1024
1011
  }
@@ -1029,7 +1016,6 @@ You must set an initial value before calling a property signal's getter.
1029
1016
  { cause: error }
1030
1017
  );
1031
1018
  console.error(_error);
1032
- throw _error;
1033
1019
  }
1034
1020
  }
1035
1021
  connectedCallback() {
@@ -1055,12 +1041,10 @@ You must set an initial value before calling a property signal's getter.
1055
1041
  }
1056
1042
  for (const attrName of Object.keys(this.#attrSignals)) {
1057
1043
  const signal = this.#attrSignals[attrName];
1058
- if (signal) {
1059
- const [getter, setter] = signal;
1060
- const currentValue = this.getAttribute(attrName);
1061
- if (getter() !== currentValue) {
1062
- setter(currentValue);
1063
- }
1044
+ const [getter, setter] = signal;
1045
+ const currentValue = this.getAttribute(attrName);
1046
+ if (getter() !== currentValue) {
1047
+ setter(currentValue);
1064
1048
  }
1065
1049
  }
1066
1050
  if (this.#observer !== null) {
package/dist/index.d.cts CHANGED
@@ -94,7 +94,7 @@ type RegistryArgs = {
94
94
 
95
95
  type Styles = CSSStyleSheet | HTMLStyleElement;
96
96
 
97
- type SignalOptions = { debugMode: boolean; label?: string };
97
+ type SignalOptions = { debugMode?: boolean; label?: string };
98
98
  type SignalGetter<T> = {
99
99
  (options?: SignalOptions): T;
100
100
  getter: true;
package/dist/index.d.ts CHANGED
@@ -94,7 +94,7 @@ type RegistryArgs = {
94
94
 
95
95
  type Styles = CSSStyleSheet | HTMLStyleElement;
96
96
 
97
- type SignalOptions = { debugMode: boolean; label?: string };
97
+ type SignalOptions = { debugMode?: boolean; label?: string };
98
98
  type SignalGetter<T> = {
99
99
  (options?: SignalOptions): T;
100
100
  getter: true;
package/dist/index.js CHANGED
@@ -65,13 +65,14 @@ var createSignal = (initVal, options) => {
65
65
  const effectRef = effects.get(sym);
66
66
  if (effectRef !== void 0) {
67
67
  try {
68
- effectRef.fn({
68
+ const result = effectRef.fn({
69
69
  lastValue: effectRef.value,
70
70
  destroy: () => {
71
71
  effects.delete(sym);
72
72
  queueMicrotask(() => subscribers.delete(sym));
73
73
  }
74
74
  });
75
+ if (result !== void 0) effectRef.value = result;
75
76
  } catch (error) {
76
77
  console.error("Error in subscriber:", { error, oldValue, newValue, fn: effectRef.fn });
77
78
  }
@@ -112,14 +113,16 @@ var derived = (fn, options) => {
112
113
  };
113
114
  var createEffect = (fn, value) => {
114
115
  const privateIdent = ident = {};
115
- effects.set(ident, { fn, value });
116
+ const effectRef = { fn, value };
117
+ effects.set(ident, effectRef);
116
118
  try {
117
- fn({
119
+ const result = fn({
118
120
  lastValue: value,
119
121
  destroy: () => {
120
122
  effects.delete(privateIdent);
121
123
  }
122
124
  });
125
+ if (result !== void 0) effectRef.value = result;
123
126
  } catch (error) {
124
127
  console.error("Error in effect:", { error, fn });
125
128
  }
@@ -413,15 +416,11 @@ var evaluateBindings = (element, fragment) => {
413
416
  signalEntries.forEach(({ uniqueKey, signal, initialChildren, autoKey }) => {
414
417
  const firstChild = initialChildren[0];
415
418
  const lastChild = initialChildren[initialChildren.length - 1];
416
- if (uniqueKey === void 0 || firstChild === void 0) return;
419
+ if (firstChild === void 0) return;
417
420
  const startAnchor = document.createComment(`${uniqueKey}:start`);
418
421
  firstChild.before(startAnchor);
419
422
  const endAnchor = document.createComment(`${uniqueKey}:end`);
420
- if (lastChild !== void 0) {
421
- lastChild.after(endAnchor);
422
- } else {
423
- startAnchor.after(endAnchor);
424
- }
423
+ lastChild.after(endAnchor);
425
424
  const bindText = (node, signal2) => {
426
425
  createEffect(({ destroy }) => {
427
426
  const result = signal2();
@@ -445,11 +444,6 @@ var evaluateBindings = (element, fragment) => {
445
444
  const newChildren = asNodeList(result, element, autoKey2);
446
445
  const firstChild2 = newChildren[0];
447
446
  if (!Array.isArray(result)) {
448
- if (newChildren.length === 1 && firstChild2 instanceof DocumentFragment) {
449
- destroy();
450
- bindFragment(signal2, initialChildren, autoKey2);
451
- return;
452
- }
453
447
  if (newChildren.length === 1 && firstChild2 instanceof Text) {
454
448
  while (startAnchor.nextSibling !== endAnchor) {
455
449
  startAnchor.nextSibling?.remove();
@@ -468,7 +462,6 @@ var evaluateBindings = (element, fragment) => {
468
462
  for (const persistedChild of oldChildren) {
469
463
  if (persistedChild instanceof Element) {
470
464
  const key = persistedChild.getAttribute("key");
471
- if (key === null) continue;
472
465
  const newChild = queryChildren(newChildren, `[key="${key}"]`);
473
466
  if (newChild === null) {
474
467
  persistedChild.remove();
@@ -528,16 +521,14 @@ var evaluateBindings = (element, fragment) => {
528
521
  startAnchor.after(...children);
529
522
  });
530
523
  };
531
- if (signal !== void 0) {
532
- const currentValue = signal();
533
- if (Array.isArray(currentValue)) {
534
- bindArray(signal, autoKey);
535
- } else if (currentValue instanceof DocumentFragment) {
536
- bindFragment(signal, initialChildren, autoKey);
537
- } else {
538
- const initialChild = initialChildren[0];
539
- bindText(initialChild, signal);
540
- }
524
+ const currentValue = signal();
525
+ if (Array.isArray(currentValue)) {
526
+ bindArray(signal, autoKey);
527
+ } else if (currentValue instanceof DocumentFragment) {
528
+ bindFragment(signal, initialChildren, autoKey);
529
+ } else {
530
+ const initialChild = initialChildren[0];
531
+ bindText(initialChild, signal);
541
532
  }
542
533
  });
543
534
  }
@@ -574,7 +565,6 @@ var evaluateBindings = (element, fragment) => {
574
565
  if (newText !== prevText) child.setAttribute(attrName, newText);
575
566
  }
576
567
  if (attrName.startsWith("prop-id:")) {
577
- if (child.hasAttribute(attrName)) child.removeAttribute(attrName);
578
568
  const propId = attrName.replace("prop-id:", "");
579
569
  const propName = renderState.propertyMap.get(propId);
580
570
  if (propName === void 0) {
@@ -609,9 +599,7 @@ var evaluateBindings = (element, fragment) => {
609
599
  child.__customCallbackFns.set(uniqueKey, callback);
610
600
  }
611
601
  }
612
- if (uniqueKey !== "" && !attrName.startsWith("prop-id:")) {
613
- child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
614
- } else if (attrName.startsWith("prop-id:")) {
602
+ if (attrName.startsWith("prop-id:")) {
615
603
  child.removeAttribute(attrName);
616
604
  const propId = attrName.replace("prop-id:", "");
617
605
  const propName = renderState.propertyMap.get(propId);
@@ -624,6 +612,8 @@ var evaluateBindings = (element, fragment) => {
624
612
  }
625
613
  if (!(propName in child)) logPropertyWarning(propName, child);
626
614
  child[propName] = child.__customCallbackFns.get(uniqueKey);
615
+ } else {
616
+ child.setAttribute(attrName, `this.__customCallbackFns.get('${uniqueKey}')(event)`);
627
617
  }
628
618
  });
629
619
  } else if (attrName.startsWith("prop-id:")) {
@@ -653,7 +643,7 @@ var html = (strings, ...values) => {
653
643
  } else {
654
644
  value = processValue(value);
655
645
  }
656
- innerHTML2 += str + String(value === null ? "" : value);
646
+ innerHTML2 += str + String(value);
657
647
  return innerHTML2;
658
648
  }, "");
659
649
  if (isServer) return innerHTML;
@@ -674,7 +664,7 @@ var html = (strings, ...values) => {
674
664
  evaluateBindings(fragment, fragment);
675
665
  return fragment;
676
666
  };
677
- var adoptedStylesSupported = typeof window !== "undefined" && window.ShadowRoot?.prototype.hasOwnProperty("adoptedStyleSheets") && window.CSSStyleSheet?.prototype.hasOwnProperty("replace");
667
+ var isAdoptedStylesSupported = () => typeof window !== "undefined" && window.ShadowRoot?.prototype.hasOwnProperty("adoptedStyleSheets") && window.CSSStyleSheet?.prototype.hasOwnProperty("replace");
678
668
  var isCSSStyleSheet = (stylesheet) => {
679
669
  return typeof CSSStyleSheet !== "undefined" && stylesheet instanceof CSSStyleSheet;
680
670
  };
@@ -698,7 +688,7 @@ var css = (strings, ...values) => {
698
688
  if (isServer) {
699
689
  return cssText;
700
690
  }
701
- const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
691
+ const stylesheet = isAdoptedStylesSupported() ? new CSSStyleSheet() : document.createElement("style");
702
692
  const textList = cssText.split(signalBindingRegex);
703
693
  createEffect(() => {
704
694
  const newCSSTextList = [];
@@ -805,7 +795,6 @@ var customElement = (render, options) => {
805
795
  #observer = options?.observedAttributes !== void 0 ? null : new MutationObserver((mutations) => {
806
796
  for (const mutation of mutations) {
807
797
  const attrName = mutation.attributeName;
808
- if (mutation.type !== "attributes" || attrName === null) continue;
809
798
  if (!(attrName in this.#attrSignals)) {
810
799
  this.#attrSignals[attrName] = createSignal(this.getAttribute(attrName));
811
800
  }
@@ -979,9 +968,7 @@ You must set an initial value before calling a property signal's getter.
979
968
  constructor() {
980
969
  try {
981
970
  super();
982
- if (!Object.prototype.hasOwnProperty.call(this, "__customCallbackFns")) {
983
- this.__customCallbackFns = /* @__PURE__ */ new Map();
984
- }
971
+ this.__customCallbackFns = /* @__PURE__ */ new Map();
985
972
  for (const attr of this.attributes) {
986
973
  this.#attrSignals[attr.name] = createSignal(attr.value);
987
974
  }
@@ -992,7 +979,6 @@ You must set an initial value before calling a property signal's getter.
992
979
  { cause: error }
993
980
  );
994
981
  console.error(_error);
995
- throw _error;
996
982
  }
997
983
  }
998
984
  connectedCallback() {
@@ -1018,12 +1004,10 @@ You must set an initial value before calling a property signal's getter.
1018
1004
  }
1019
1005
  for (const attrName of Object.keys(this.#attrSignals)) {
1020
1006
  const signal = this.#attrSignals[attrName];
1021
- if (signal) {
1022
- const [getter, setter] = signal;
1023
- const currentValue = this.getAttribute(attrName);
1024
- if (getter() !== currentValue) {
1025
- setter(currentValue);
1026
- }
1007
+ const [getter, setter] = signal;
1008
+ const currentValue = this.getAttribute(attrName);
1009
+ if (getter() !== currentValue) {
1010
+ setter(currentValue);
1027
1011
  }
1028
1012
  }
1029
1013
  if (this.#observer !== null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thunderous",
3
- "version": "2.4.5",
3
+ "version": "2.4.6",
4
4
  "description": "A lightweight, functional web components library that brings the power of signals to your UI.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -15,7 +15,8 @@
15
15
  "author": "Jonathan DeWitt <jon.dewitt@thunder.solutions>",
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "https://github.com/Thunder-Solutions/Thunderous"
18
+ "url": "https://github.com/Thunder-Solutions/Thunderous",
19
+ "directory": "packages/thunderous"
19
20
  },
20
21
  "keywords": [
21
22
  "thunderous",
@@ -27,7 +28,7 @@
27
28
  "bugs": {
28
29
  "url": "https://github.com/Thunder-Solutions/Thunderous/issues"
29
30
  },
30
- "homepage": "https://github.com/Thunder-Solutions/Thunderous#readme",
31
+ "homepage": "https://thunderous.dev",
31
32
  "license": "MIT",
32
33
  "peerDependencies": {
33
34
  "@webcomponents/scoped-custom-element-registry": "^0.0.10"
@@ -37,19 +38,29 @@
37
38
  "optional": true
38
39
  }
39
40
  },
41
+ "devDependencies": {
42
+ "@playwright/test": "^1.58.2",
43
+ "@vitest/browser": "^4.1.4",
44
+ "@vitest/browser-playwright": "^4.1.4",
45
+ "@vitest/coverage-istanbul": "^4.1.4",
46
+ "istanbul-merge": "^2.0.0",
47
+ "nyc": "^18.0.0",
48
+ "vitest": "^4.1.4"
49
+ },
40
50
  "scripts": {
41
51
  "demo": "cd demo && npm start",
42
- "demo:ssr": "cd demo && npm run ssr",
52
+ "demo:ssr": "cd demo && pnpm ssr",
43
53
  "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",
54
+ "clean": "rm -rf dist",
55
+ "test": "pnpm test:server & pnpm test:client && pnpm coverage",
56
+ "test:server": "vitest run --config vitest.server.config.ts --coverage",
57
+ "test:client": "vitest run --config vitest.client.config.ts --coverage",
58
+ "coverage": "istanbul-merge --out ./coverage/merged/coverage-final.json ./coverage/server/coverage-final.json ./coverage/client/coverage-final.json && nyc report && nyc check-coverage",
47
59
  "typecheck": "tsc --noEmit",
48
60
  "lint": "eslint .",
49
61
  "lint:fix": "eslint . --fix",
50
62
  "format": "prettier --check . --ignore-path ../../.gitignore",
51
63
  "format:fix": "prettier --write . --ignore-path ../../.gitignore",
52
- "preversion": "npm run typecheck && npm run lint && npm test && npm run build",
53
64
  "version": "node postversion.js"
54
65
  }
55
66
  }