thunderous 1.0.0 → 1.0.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
@@ -469,6 +469,21 @@ if (typeof window !== "undefined") {
469
469
  window.CustomElementRegistry = TrackableCustomElementRegistry;
470
470
  }
471
471
 
472
+ // src/constants.ts
473
+ var DEFAULT_RENDER_OPTIONS = {
474
+ formAssociated: false,
475
+ observedAttributes: [],
476
+ attributesAsProperties: [],
477
+ attachShadow: true,
478
+ shadowRootOptions: {
479
+ mode: "closed",
480
+ delegatesFocus: false,
481
+ clonable: false,
482
+ serializable: false,
483
+ slotAssignment: "named"
484
+ }
485
+ };
486
+
472
487
  // src/signals.ts
473
488
  var subscriber = null;
474
489
  var updateQueue = /* @__PURE__ */ new Set();
@@ -480,7 +495,7 @@ var createSignal = (initVal, options) => {
480
495
  if (subscriber !== null) {
481
496
  subscribers.add(subscriber);
482
497
  }
483
- if (options?.debugMode || getterOptions?.debugMode) {
498
+ if (options?.debugMode === true || getterOptions?.debugMode === true) {
484
499
  queueMicrotask(() => {
485
500
  let label = "anonymous signal";
486
501
  if (options?.label !== void 0) {
@@ -514,7 +529,7 @@ var createSignal = (initVal, options) => {
514
529
  console.error("Error in subscriber:", { error, oldValue, newValue, fn });
515
530
  }
516
531
  }
517
- if (options?.debugMode || setterOptions?.debugMode) {
532
+ if (options?.debugMode === true || setterOptions?.debugMode === true) {
518
533
  let label = "anonymous signal";
519
534
  if (options?.label !== void 0) {
520
535
  label = `(${options.label})`;
@@ -554,6 +569,9 @@ var createEffect = (fn) => {
554
569
  subscriber = null;
555
570
  };
556
571
 
572
+ // src/utilities.ts
573
+ var NOOP = () => void 0;
574
+
557
575
  // src/server-side.ts
558
576
  var isServer = typeof window === "undefined";
559
577
  var serverDefineFns = /* @__PURE__ */ new Set();
@@ -610,29 +628,21 @@ var getServerRenderArgs = (tagName, registry) => ({
610
628
  }
611
629
  });
612
630
  },
613
- attributeChangedCallback: () => {
614
- },
615
- connectedCallback: () => {
616
- },
617
- disconnectedCallback: () => {
618
- },
619
- adoptedCallback: () => {
620
- },
621
- formDisabledCallback: () => {
622
- },
623
- formResetCallback: () => {
624
- },
625
- formStateRestoreCallback: () => {
626
- },
627
- formAssociatedCallback: () => {
628
- },
629
- clientOnlyCallback: () => {
630
- },
631
+ attributeChangedCallback: NOOP,
632
+ connectedCallback: NOOP,
633
+ disconnectedCallback: NOOP,
634
+ adoptedCallback: NOOP,
635
+ formDisabledCallback: NOOP,
636
+ formResetCallback: NOOP,
637
+ formStateRestoreCallback: NOOP,
638
+ formAssociatedCallback: NOOP,
639
+ clientOnlyCallback: NOOP,
631
640
  customCallback: () => `{{callback:unavailable-on-server}}`,
632
641
  attrSignals: new Proxy({}, { get: (_, attr) => createSignal(`{{attr:${String(attr)}}}`) }),
633
642
  propSignals: new Proxy({}, { get: () => createSignal(null) }),
634
643
  refs: {},
635
- // @ts-expect-error // this should be a string for server-side rendering
644
+ // @ts-expect-error // this will be a string for SSR, but this is true for internal cases only.
645
+ // The end user will see the public type, which is either a CSSStyleSheet or HTMLStyleElement.
636
646
  adoptStyleSheet: (cssStr) => {
637
647
  const _serverCss = registry !== void 0 ? registry.__serverCss : serverCss;
638
648
  const cssArr = _serverCss.get(tagName) ?? [];
@@ -663,8 +673,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
663
673
  };
664
674
  var insertTemplates = (tagName, template, inputString) => {
665
675
  return inputString.replace(new RegExp(`(<s*${tagName}([^>]*)>)`, "gm"), ($1, _, $3) => {
666
- const attrs = $3.split(/(?!=")\s+/).filter((attr) => attr !== "").map((attr) => {
667
- const [key, _value] = attr.split("=");
676
+ const attrs = $3.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
677
+ const [_key, _value] = attr.split("=");
678
+ const key = _key.trim();
668
679
  const value = _value?.replace(/"/g, "") ?? "";
669
680
  return [key, value];
670
681
  });
@@ -760,7 +771,7 @@ var html = (strings, ...values) => {
760
771
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
761
772
  const value = signal !== void 0 ? signal() : text;
762
773
  if (value === null) hasNull = true;
763
- newText += value;
774
+ newText += String(value);
764
775
  }
765
776
  if (hasNull && newText === "null") {
766
777
  child.removeAttribute(attr.name);
@@ -809,19 +820,20 @@ var css = (strings, ...values) => {
809
820
  if (isServer) {
810
821
  return cssText;
811
822
  }
812
- let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
823
+ const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
813
824
  const textList = cssText.split(signalBindingRegex);
814
825
  createEffect(() => {
815
826
  const newCSSTextList = [];
816
827
  for (const text of textList) {
817
828
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
818
829
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
819
- const newText = signal !== null ? signal() : text;
830
+ const newValue = signal !== null ? signal() : text;
831
+ const newText = String(newValue);
820
832
  newCSSTextList.push(newText);
821
833
  }
822
834
  const newCSSText = newCSSTextList.join("");
823
835
  if (isCSSStyleSheet(stylesheet)) {
824
- stylesheet.replace(newCSSText);
836
+ stylesheet.replace(newCSSText).catch(console.error);
825
837
  } else {
826
838
  stylesheet.textContent = newCSSText;
827
839
  }
@@ -830,19 +842,6 @@ var css = (strings, ...values) => {
830
842
  };
831
843
 
832
844
  // src/custom-element.ts
833
- var DEFAULT_RENDER_OPTIONS = {
834
- formAssociated: false,
835
- observedAttributes: [],
836
- attributesAsProperties: [],
837
- attachShadow: true,
838
- shadowRootOptions: {
839
- mode: "closed",
840
- delegatesFocus: false,
841
- clonable: false,
842
- serializable: false,
843
- slotAssignment: "named"
844
- }
845
- };
846
845
  var customElement = (render, options) => {
847
846
  const _options = { ...DEFAULT_RENDER_OPTIONS, ...options };
848
847
  const {
@@ -927,8 +926,7 @@ var customElement = (render, options) => {
927
926
  if (mutation.type !== "attributes" || attrName === null) continue;
928
927
  if (!(attrName in this.#attrSignals)) this.#attrSignals[attrName] = createSignal(null);
929
928
  const [getter, setter] = this.#attrSignals[attrName];
930
- const _oldValue = getter();
931
- const oldValue = _oldValue === null ? null : _oldValue;
929
+ const oldValue = getter();
932
930
  const newValue = this.getAttribute(attrName);
933
931
  setter(newValue);
934
932
  for (const fn of this.#attributeChangedFns) {
@@ -1039,7 +1037,7 @@ You must set an initial value before calling a property signal's getter.
1039
1037
  tempContainer.append(fragment.cloneNode(true));
1040
1038
  const fragmentContent = tempContainer.innerHTML;
1041
1039
  root.innerHTML = fragmentContent;
1042
- if (registry !== void 0 && registry.__tagNames !== void 0) {
1040
+ if (registry?.__tagNames !== void 0) {
1043
1041
  for (const tagName of registry.__tagNames) {
1044
1042
  const upgradedElements = root.querySelectorAll(tagName);
1045
1043
  const nonUpgradedElements = fragment.querySelectorAll(tagName);
@@ -1152,7 +1150,7 @@ You must set an initial value before calling a property signal's getter.
1152
1150
  let _registry;
1153
1151
  const elementResult = {
1154
1152
  define(tagName, options2) {
1155
- const registry = _registry !== void 0 ? _registry : customElements;
1153
+ const registry = _registry ?? customElements;
1156
1154
  const nativeRegistry = "eject" in registry ? registry.eject() : registry;
1157
1155
  if (nativeRegistry.get(tagName) !== void 0) {
1158
1156
  console.warn(`Custom element "${tagName}" was already defined. Skipping...`);
package/dist/index.d.cts CHANGED
@@ -645,6 +645,8 @@ type ServerRenderFunction = (args: RenderArgs<CustomElementProps>) => string;
645
645
 
646
646
  type ServerRenderOptions = { serverRender: ServerRenderFunction } & RenderOptions;
647
647
 
648
+ type ServerDefineFn = (tagName: string, htmlString: string) => void;
649
+
648
650
  type RegistryResult = {
649
651
  __serverCss: Map<string, string[]>;
650
652
  __serverRenderOpts: Map<string, ServerRenderOptions>;
@@ -699,7 +701,6 @@ declare const customElement: <Props extends CustomElementProps>(render: RenderFu
699
701
  */
700
702
  declare const createRegistry: (args?: RegistryArgs) => RegistryResult;
701
703
 
702
- type ServerDefineFn = (tagName: string, htmlString: string) => void;
703
704
  declare const onServerDefine: (fn: ServerDefineFn) => void;
704
705
  declare const insertTemplates: (tagName: string, template: string, inputString: string) => string;
705
706
  declare const clientOnlyCallback: (fn: (() => void) | (() => Promise<void>)) => void | Promise<void>;
package/dist/index.d.ts CHANGED
@@ -645,6 +645,8 @@ type ServerRenderFunction = (args: RenderArgs<CustomElementProps>) => string;
645
645
 
646
646
  type ServerRenderOptions = { serverRender: ServerRenderFunction } & RenderOptions;
647
647
 
648
+ type ServerDefineFn = (tagName: string, htmlString: string) => void;
649
+
648
650
  type RegistryResult = {
649
651
  __serverCss: Map<string, string[]>;
650
652
  __serverRenderOpts: Map<string, ServerRenderOptions>;
@@ -699,7 +701,6 @@ declare const customElement: <Props extends CustomElementProps>(render: RenderFu
699
701
  */
700
702
  declare const createRegistry: (args?: RegistryArgs) => RegistryResult;
701
703
 
702
- type ServerDefineFn = (tagName: string, htmlString: string) => void;
703
704
  declare const onServerDefine: (fn: ServerDefineFn) => void;
704
705
  declare const insertTemplates: (tagName: string, template: string, inputString: string) => string;
705
706
  declare const clientOnlyCallback: (fn: (() => void) | (() => Promise<void>)) => void | Promise<void>;
package/dist/index.js CHANGED
@@ -434,6 +434,21 @@ if (typeof window !== "undefined") {
434
434
  window.CustomElementRegistry = TrackableCustomElementRegistry;
435
435
  }
436
436
 
437
+ // src/constants.ts
438
+ var DEFAULT_RENDER_OPTIONS = {
439
+ formAssociated: false,
440
+ observedAttributes: [],
441
+ attributesAsProperties: [],
442
+ attachShadow: true,
443
+ shadowRootOptions: {
444
+ mode: "closed",
445
+ delegatesFocus: false,
446
+ clonable: false,
447
+ serializable: false,
448
+ slotAssignment: "named"
449
+ }
450
+ };
451
+
437
452
  // src/signals.ts
438
453
  var subscriber = null;
439
454
  var updateQueue = /* @__PURE__ */ new Set();
@@ -445,7 +460,7 @@ var createSignal = (initVal, options) => {
445
460
  if (subscriber !== null) {
446
461
  subscribers.add(subscriber);
447
462
  }
448
- if (options?.debugMode || getterOptions?.debugMode) {
463
+ if (options?.debugMode === true || getterOptions?.debugMode === true) {
449
464
  queueMicrotask(() => {
450
465
  let label = "anonymous signal";
451
466
  if (options?.label !== void 0) {
@@ -479,7 +494,7 @@ var createSignal = (initVal, options) => {
479
494
  console.error("Error in subscriber:", { error, oldValue, newValue, fn });
480
495
  }
481
496
  }
482
- if (options?.debugMode || setterOptions?.debugMode) {
497
+ if (options?.debugMode === true || setterOptions?.debugMode === true) {
483
498
  let label = "anonymous signal";
484
499
  if (options?.label !== void 0) {
485
500
  label = `(${options.label})`;
@@ -519,6 +534,9 @@ var createEffect = (fn) => {
519
534
  subscriber = null;
520
535
  };
521
536
 
537
+ // src/utilities.ts
538
+ var NOOP = () => void 0;
539
+
522
540
  // src/server-side.ts
523
541
  var isServer = typeof window === "undefined";
524
542
  var serverDefineFns = /* @__PURE__ */ new Set();
@@ -575,29 +593,21 @@ var getServerRenderArgs = (tagName, registry) => ({
575
593
  }
576
594
  });
577
595
  },
578
- attributeChangedCallback: () => {
579
- },
580
- connectedCallback: () => {
581
- },
582
- disconnectedCallback: () => {
583
- },
584
- adoptedCallback: () => {
585
- },
586
- formDisabledCallback: () => {
587
- },
588
- formResetCallback: () => {
589
- },
590
- formStateRestoreCallback: () => {
591
- },
592
- formAssociatedCallback: () => {
593
- },
594
- clientOnlyCallback: () => {
595
- },
596
+ attributeChangedCallback: NOOP,
597
+ connectedCallback: NOOP,
598
+ disconnectedCallback: NOOP,
599
+ adoptedCallback: NOOP,
600
+ formDisabledCallback: NOOP,
601
+ formResetCallback: NOOP,
602
+ formStateRestoreCallback: NOOP,
603
+ formAssociatedCallback: NOOP,
604
+ clientOnlyCallback: NOOP,
596
605
  customCallback: () => `{{callback:unavailable-on-server}}`,
597
606
  attrSignals: new Proxy({}, { get: (_, attr) => createSignal(`{{attr:${String(attr)}}}`) }),
598
607
  propSignals: new Proxy({}, { get: () => createSignal(null) }),
599
608
  refs: {},
600
- // @ts-expect-error // this should be a string for server-side rendering
609
+ // @ts-expect-error // this will be a string for SSR, but this is true for internal cases only.
610
+ // The end user will see the public type, which is either a CSSStyleSheet or HTMLStyleElement.
601
611
  adoptStyleSheet: (cssStr) => {
602
612
  const _serverCss = registry !== void 0 ? registry.__serverCss : serverCss;
603
613
  const cssArr = _serverCss.get(tagName) ?? [];
@@ -628,8 +638,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
628
638
  };
629
639
  var insertTemplates = (tagName, template, inputString) => {
630
640
  return inputString.replace(new RegExp(`(<s*${tagName}([^>]*)>)`, "gm"), ($1, _, $3) => {
631
- const attrs = $3.split(/(?!=")\s+/).filter((attr) => attr !== "").map((attr) => {
632
- const [key, _value] = attr.split("=");
641
+ const attrs = $3.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
642
+ const [_key, _value] = attr.split("=");
643
+ const key = _key.trim();
633
644
  const value = _value?.replace(/"/g, "") ?? "";
634
645
  return [key, value];
635
646
  });
@@ -725,7 +736,7 @@ var html = (strings, ...values) => {
725
736
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
726
737
  const value = signal !== void 0 ? signal() : text;
727
738
  if (value === null) hasNull = true;
728
- newText += value;
739
+ newText += String(value);
729
740
  }
730
741
  if (hasNull && newText === "null") {
731
742
  child.removeAttribute(attr.name);
@@ -774,19 +785,20 @@ var css = (strings, ...values) => {
774
785
  if (isServer) {
775
786
  return cssText;
776
787
  }
777
- let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
788
+ const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
778
789
  const textList = cssText.split(signalBindingRegex);
779
790
  createEffect(() => {
780
791
  const newCSSTextList = [];
781
792
  for (const text of textList) {
782
793
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
783
794
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
784
- const newText = signal !== null ? signal() : text;
795
+ const newValue = signal !== null ? signal() : text;
796
+ const newText = String(newValue);
785
797
  newCSSTextList.push(newText);
786
798
  }
787
799
  const newCSSText = newCSSTextList.join("");
788
800
  if (isCSSStyleSheet(stylesheet)) {
789
- stylesheet.replace(newCSSText);
801
+ stylesheet.replace(newCSSText).catch(console.error);
790
802
  } else {
791
803
  stylesheet.textContent = newCSSText;
792
804
  }
@@ -795,19 +807,6 @@ var css = (strings, ...values) => {
795
807
  };
796
808
 
797
809
  // src/custom-element.ts
798
- var DEFAULT_RENDER_OPTIONS = {
799
- formAssociated: false,
800
- observedAttributes: [],
801
- attributesAsProperties: [],
802
- attachShadow: true,
803
- shadowRootOptions: {
804
- mode: "closed",
805
- delegatesFocus: false,
806
- clonable: false,
807
- serializable: false,
808
- slotAssignment: "named"
809
- }
810
- };
811
810
  var customElement = (render, options) => {
812
811
  const _options = { ...DEFAULT_RENDER_OPTIONS, ...options };
813
812
  const {
@@ -892,8 +891,7 @@ var customElement = (render, options) => {
892
891
  if (mutation.type !== "attributes" || attrName === null) continue;
893
892
  if (!(attrName in this.#attrSignals)) this.#attrSignals[attrName] = createSignal(null);
894
893
  const [getter, setter] = this.#attrSignals[attrName];
895
- const _oldValue = getter();
896
- const oldValue = _oldValue === null ? null : _oldValue;
894
+ const oldValue = getter();
897
895
  const newValue = this.getAttribute(attrName);
898
896
  setter(newValue);
899
897
  for (const fn of this.#attributeChangedFns) {
@@ -1004,7 +1002,7 @@ You must set an initial value before calling a property signal's getter.
1004
1002
  tempContainer.append(fragment.cloneNode(true));
1005
1003
  const fragmentContent = tempContainer.innerHTML;
1006
1004
  root.innerHTML = fragmentContent;
1007
- if (registry !== void 0 && registry.__tagNames !== void 0) {
1005
+ if (registry?.__tagNames !== void 0) {
1008
1006
  for (const tagName of registry.__tagNames) {
1009
1007
  const upgradedElements = root.querySelectorAll(tagName);
1010
1008
  const nonUpgradedElements = fragment.querySelectorAll(tagName);
@@ -1117,7 +1115,7 @@ You must set an initial value before calling a property signal's getter.
1117
1115
  let _registry;
1118
1116
  const elementResult = {
1119
1117
  define(tagName, options2) {
1120
- const registry = _registry !== void 0 ? _registry : customElements;
1118
+ const registry = _registry ?? customElements;
1121
1119
  const nativeRegistry = "eject" in registry ? registry.eject() : registry;
1122
1120
  if (nativeRegistry.get(tagName) !== void 0) {
1123
1121
  console.warn(`Custom element "${tagName}" was already defined. Skipping...`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thunderous",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -32,13 +32,17 @@
32
32
  "scripts": {
33
33
  "demo": "cd demo && npm start",
34
34
  "www": "cd www && npm run dev",
35
- "build": "tsup src/index.ts --format cjs,esm --dts --no-clean"
35
+ "build": "tsup src/index.ts --format cjs,esm --dts --no-clean",
36
+ "test": "find src -name '*.test.ts' | xargs c8 node --import tsx --test",
37
+ "lint": "eslint ."
36
38
  },
37
39
  "devDependencies": {
38
40
  "@types/dompurify": "^3.2.0",
39
41
  "@types/eslint": "^8.56.10",
40
- "@typescript-eslint/eslint-plugin": "^7.1.1",
41
- "@typescript-eslint/parser": "^7.1.1",
42
+ "@types/node": "^22.10.1",
43
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
44
+ "@typescript-eslint/parser": "^8.17.0",
45
+ "c8": "^10.1.2",
42
46
  "eslint": "^8.57.0",
43
47
  "eslint-plugin-import": "^2.31.0",
44
48
  "eslint-plugin-node": "^11.1.0",
@@ -46,7 +50,7 @@
46
50
  "express": "^4.17.1",
47
51
  "prettier": "^3.3.3",
48
52
  "tsup": "^8.3.0",
49
- "typescript": "^5.6.3",
50
- "tsx": "^4.19.2"
53
+ "tsx": "^4.19.2",
54
+ "typescript": "^5.7.2"
51
55
  }
52
56
  }