thunderous 1.0.0 → 1.0.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/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,14 +569,27 @@ 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();
560
578
  var onServerDefine = (fn) => {
561
579
  serverDefineFns.add(fn);
562
580
  };
563
- var serverDefine = ({ tagName, serverRender, options, scopedRegistry, parentRegistry }) => {
581
+ var serverDefine = ({
582
+ tagName,
583
+ serverRender,
584
+ options,
585
+ elementResult,
586
+ scopedRegistry,
587
+ parentRegistry
588
+ }) => {
564
589
  if (parentRegistry !== void 0) {
590
+ if (parentRegistry.getTagName(elementResult) !== tagName.toUpperCase()) {
591
+ parentRegistry.define(tagName, elementResult);
592
+ }
565
593
  parentRegistry.__serverRenderOpts.set(tagName, { serverRender, ...options });
566
594
  if (parentRegistry.scoped) return;
567
595
  }
@@ -610,29 +638,21 @@ var getServerRenderArgs = (tagName, registry) => ({
610
638
  }
611
639
  });
612
640
  },
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
- },
641
+ attributeChangedCallback: NOOP,
642
+ connectedCallback: NOOP,
643
+ disconnectedCallback: NOOP,
644
+ adoptedCallback: NOOP,
645
+ formDisabledCallback: NOOP,
646
+ formResetCallback: NOOP,
647
+ formStateRestoreCallback: NOOP,
648
+ formAssociatedCallback: NOOP,
649
+ clientOnlyCallback: NOOP,
631
650
  customCallback: () => `{{callback:unavailable-on-server}}`,
632
651
  attrSignals: new Proxy({}, { get: (_, attr) => createSignal(`{{attr:${String(attr)}}}`) }),
633
652
  propSignals: new Proxy({}, { get: () => createSignal(null) }),
634
653
  refs: {},
635
- // @ts-expect-error // this should be a string for server-side rendering
654
+ // @ts-expect-error // this will be a string for SSR, but this is true for internal cases only.
655
+ // The end user will see the public type, which is either a CSSStyleSheet or HTMLStyleElement.
636
656
  adoptStyleSheet: (cssStr) => {
637
657
  const _serverCss = registry !== void 0 ? registry.__serverCss : serverCss;
638
658
  const cssArr = _serverCss.get(tagName) ?? [];
@@ -663,8 +683,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
663
683
  };
664
684
  var insertTemplates = (tagName, template, inputString) => {
665
685
  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("=");
686
+ const attrs = $3.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
687
+ const [_key, _value] = attr.split("=");
688
+ const key = _key.trim();
668
689
  const value = _value?.replace(/"/g, "") ?? "";
669
690
  return [key, value];
670
691
  });
@@ -760,7 +781,7 @@ var html = (strings, ...values) => {
760
781
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
761
782
  const value = signal !== void 0 ? signal() : text;
762
783
  if (value === null) hasNull = true;
763
- newText += value;
784
+ newText += String(value);
764
785
  }
765
786
  if (hasNull && newText === "null") {
766
787
  child.removeAttribute(attr.name);
@@ -809,19 +830,20 @@ var css = (strings, ...values) => {
809
830
  if (isServer) {
810
831
  return cssText;
811
832
  }
812
- let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
833
+ const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
813
834
  const textList = cssText.split(signalBindingRegex);
814
835
  createEffect(() => {
815
836
  const newCSSTextList = [];
816
837
  for (const text of textList) {
817
838
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
818
839
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
819
- const newText = signal !== null ? signal() : text;
840
+ const newValue = signal !== null ? signal() : text;
841
+ const newText = String(newValue);
820
842
  newCSSTextList.push(newText);
821
843
  }
822
844
  const newCSSText = newCSSTextList.join("");
823
845
  if (isCSSStyleSheet(stylesheet)) {
824
- stylesheet.replace(newCSSText);
846
+ stylesheet.replace(newCSSText).catch(console.error);
825
847
  } else {
826
848
  stylesheet.textContent = newCSSText;
827
849
  }
@@ -830,19 +852,6 @@ var css = (strings, ...values) => {
830
852
  };
831
853
 
832
854
  // 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
855
  var customElement = (render, options) => {
847
856
  const _options = { ...DEFAULT_RENDER_OPTIONS, ...options };
848
857
  const {
@@ -871,7 +880,8 @@ var customElement = (render, options) => {
871
880
  serverRender,
872
881
  options: allOptions,
873
882
  scopedRegistry,
874
- parentRegistry: _registry2
883
+ parentRegistry: _registry2,
884
+ elementResult: this
875
885
  });
876
886
  return this;
877
887
  },
@@ -927,8 +937,7 @@ var customElement = (render, options) => {
927
937
  if (mutation.type !== "attributes" || attrName === null) continue;
928
938
  if (!(attrName in this.#attrSignals)) this.#attrSignals[attrName] = createSignal(null);
929
939
  const [getter, setter] = this.#attrSignals[attrName];
930
- const _oldValue = getter();
931
- const oldValue = _oldValue === null ? null : _oldValue;
940
+ const oldValue = getter();
932
941
  const newValue = this.getAttribute(attrName);
933
942
  setter(newValue);
934
943
  for (const fn of this.#attributeChangedFns) {
@@ -1039,7 +1048,7 @@ You must set an initial value before calling a property signal's getter.
1039
1048
  tempContainer.append(fragment.cloneNode(true));
1040
1049
  const fragmentContent = tempContainer.innerHTML;
1041
1050
  root.innerHTML = fragmentContent;
1042
- if (registry !== void 0 && registry.__tagNames !== void 0) {
1051
+ if (registry?.__tagNames !== void 0) {
1043
1052
  for (const tagName of registry.__tagNames) {
1044
1053
  const upgradedElements = root.querySelectorAll(tagName);
1045
1054
  const nonUpgradedElements = fragment.querySelectorAll(tagName);
@@ -1152,7 +1161,7 @@ You must set an initial value before calling a property signal's getter.
1152
1161
  let _registry;
1153
1162
  const elementResult = {
1154
1163
  define(tagName, options2) {
1155
- const registry = _registry !== void 0 ? _registry : customElements;
1164
+ const registry = _registry ?? customElements;
1156
1165
  const nativeRegistry = "eject" in registry ? registry.eject() : registry;
1157
1166
  if (nativeRegistry.get(tagName) !== void 0) {
1158
1167
  console.warn(`Custom element "${tagName}" was already defined. Skipping...`);
@@ -1179,6 +1188,7 @@ You must set an initial value before calling a property signal's getter.
1179
1188
  var createRegistry = (args) => {
1180
1189
  const { scoped = false } = args ?? {};
1181
1190
  const customElementMap = /* @__PURE__ */ new Map();
1191
+ const elementResultMap = /* @__PURE__ */ new Map();
1182
1192
  const customElementTags = /* @__PURE__ */ new Set();
1183
1193
  const nativeRegistry = (() => {
1184
1194
  if (isServer) return;
@@ -1190,30 +1200,42 @@ var createRegistry = (args) => {
1190
1200
  __serverRenderOpts: /* @__PURE__ */ new Map(),
1191
1201
  define(tagName, ElementResult, options) {
1192
1202
  const isResult = "eject" in ElementResult;
1193
- if (isServer) {
1194
- if (isResult) ElementResult.register(this).define(tagName, options);
1203
+ const upperCaseTagName = tagName.toUpperCase();
1204
+ if (customElementTags.has(upperCaseTagName)) {
1205
+ console.warn(`Custom element tag name "${upperCaseTagName}" was already defined. Skipping...`);
1195
1206
  return this;
1196
1207
  }
1197
- const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1198
- if (customElementMap.has(CustomElement)) {
1199
- console.warn(`Custom element class "${CustomElement.constructor.name}" was already defined. Skipping...`);
1200
- return this;
1208
+ if (isResult) {
1209
+ if (elementResultMap.has(ElementResult)) {
1210
+ console.warn(`${upperCaseTagName} was already defined. Skipping...`);
1211
+ return this;
1212
+ }
1201
1213
  }
1202
- if (customElementTags.has(tagName)) {
1203
- console.warn(`Custom element tag name "${tagName}" was already defined. Skipping...`);
1204
- return this;
1214
+ if (!isServer) {
1215
+ const CustomElement2 = isResult ? ElementResult.eject() : ElementResult;
1216
+ if (customElementMap.has(CustomElement2)) {
1217
+ console.warn(`Custom element class "${CustomElement2.constructor.name}" was already defined. Skipping...`);
1218
+ return this;
1219
+ }
1220
+ customElementMap.set(CustomElement2, upperCaseTagName);
1205
1221
  }
1206
- customElementMap.set(CustomElement, tagName.toUpperCase());
1207
- customElementTags.add(tagName);
1208
- if (CustomElement === void 0) {
1209
- console.error(`Custom element class for tag name "${tagName}" was not found. You must register it first.`);
1222
+ if (isResult) elementResultMap.set(ElementResult, upperCaseTagName);
1223
+ customElementTags.add(upperCaseTagName);
1224
+ if (isServer) {
1225
+ if (isResult) ElementResult.register(this).define(tagName, options);
1210
1226
  return this;
1211
1227
  }
1228
+ const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1212
1229
  nativeRegistry?.define(tagName, CustomElement, options);
1213
1230
  return this;
1214
1231
  },
1215
1232
  getTagName: (ElementResult) => {
1216
- const CustomElement = "eject" in ElementResult ? ElementResult.eject() : ElementResult;
1233
+ const isResult = "eject" in ElementResult;
1234
+ if (isServer) {
1235
+ if (isResult) return elementResultMap.get(ElementResult);
1236
+ return;
1237
+ }
1238
+ const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1217
1239
  return customElementMap.get(CustomElement);
1218
1240
  },
1219
1241
  getAllTagNames: () => Array.from(customElementTags),
package/dist/index.d.cts CHANGED
@@ -645,16 +645,18 @@ type ServerRenderFunction = (args: RenderArgs<CustomElementProps>) => string;
645
645
 
646
646
  type ServerRenderOptions = { serverRender: ServerRenderFunction } & RenderOptions;
647
647
 
648
+ type ServerDefineFn = (tagName: TagName, htmlString: string) => void;
649
+
648
650
  type RegistryResult = {
649
- __serverCss: Map<string, string[]>;
650
- __serverRenderOpts: Map<string, ServerRenderOptions>;
651
+ __serverCss: Map<TagName, string[]>;
652
+ __serverRenderOpts: Map<TagName, ServerRenderOptions>;
651
653
  define: (
652
654
  tagName: TagName,
653
655
  CustomElement: CustomElementConstructor | ElementResult,
654
656
  options?: ElementDefinitionOptions,
655
657
  ) => RegistryResult;
656
- getTagName: (CustomElement: CustomElementConstructor | ElementResult) => string | undefined;
657
- getAllTagNames: () => string[];
658
+ getTagName: (CustomElement: CustomElementConstructor | ElementResult) => TagName | undefined;
659
+ getAllTagNames: () => TagName[];
658
660
  eject: () => CustomElementRegistry;
659
661
  scoped: boolean;
660
662
  };
@@ -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,16 +645,18 @@ type ServerRenderFunction = (args: RenderArgs<CustomElementProps>) => string;
645
645
 
646
646
  type ServerRenderOptions = { serverRender: ServerRenderFunction } & RenderOptions;
647
647
 
648
+ type ServerDefineFn = (tagName: TagName, htmlString: string) => void;
649
+
648
650
  type RegistryResult = {
649
- __serverCss: Map<string, string[]>;
650
- __serverRenderOpts: Map<string, ServerRenderOptions>;
651
+ __serverCss: Map<TagName, string[]>;
652
+ __serverRenderOpts: Map<TagName, ServerRenderOptions>;
651
653
  define: (
652
654
  tagName: TagName,
653
655
  CustomElement: CustomElementConstructor | ElementResult,
654
656
  options?: ElementDefinitionOptions,
655
657
  ) => RegistryResult;
656
- getTagName: (CustomElement: CustomElementConstructor | ElementResult) => string | undefined;
657
- getAllTagNames: () => string[];
658
+ getTagName: (CustomElement: CustomElementConstructor | ElementResult) => TagName | undefined;
659
+ getAllTagNames: () => TagName[];
658
660
  eject: () => CustomElementRegistry;
659
661
  scoped: boolean;
660
662
  };
@@ -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,14 +534,27 @@ 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();
525
543
  var onServerDefine = (fn) => {
526
544
  serverDefineFns.add(fn);
527
545
  };
528
- var serverDefine = ({ tagName, serverRender, options, scopedRegistry, parentRegistry }) => {
546
+ var serverDefine = ({
547
+ tagName,
548
+ serverRender,
549
+ options,
550
+ elementResult,
551
+ scopedRegistry,
552
+ parentRegistry
553
+ }) => {
529
554
  if (parentRegistry !== void 0) {
555
+ if (parentRegistry.getTagName(elementResult) !== tagName.toUpperCase()) {
556
+ parentRegistry.define(tagName, elementResult);
557
+ }
530
558
  parentRegistry.__serverRenderOpts.set(tagName, { serverRender, ...options });
531
559
  if (parentRegistry.scoped) return;
532
560
  }
@@ -575,29 +603,21 @@ var getServerRenderArgs = (tagName, registry) => ({
575
603
  }
576
604
  });
577
605
  },
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
- },
606
+ attributeChangedCallback: NOOP,
607
+ connectedCallback: NOOP,
608
+ disconnectedCallback: NOOP,
609
+ adoptedCallback: NOOP,
610
+ formDisabledCallback: NOOP,
611
+ formResetCallback: NOOP,
612
+ formStateRestoreCallback: NOOP,
613
+ formAssociatedCallback: NOOP,
614
+ clientOnlyCallback: NOOP,
596
615
  customCallback: () => `{{callback:unavailable-on-server}}`,
597
616
  attrSignals: new Proxy({}, { get: (_, attr) => createSignal(`{{attr:${String(attr)}}}`) }),
598
617
  propSignals: new Proxy({}, { get: () => createSignal(null) }),
599
618
  refs: {},
600
- // @ts-expect-error // this should be a string for server-side rendering
619
+ // @ts-expect-error // this will be a string for SSR, but this is true for internal cases only.
620
+ // The end user will see the public type, which is either a CSSStyleSheet or HTMLStyleElement.
601
621
  adoptStyleSheet: (cssStr) => {
602
622
  const _serverCss = registry !== void 0 ? registry.__serverCss : serverCss;
603
623
  const cssArr = _serverCss.get(tagName) ?? [];
@@ -628,8 +648,9 @@ var wrapTemplate = ({ tagName, serverRender, options }) => {
628
648
  };
629
649
  var insertTemplates = (tagName, template, inputString) => {
630
650
  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("=");
651
+ const attrs = $3.split(/(?<=")\s+/).filter((attr) => attr.trim() !== "").map((attr) => {
652
+ const [_key, _value] = attr.split("=");
653
+ const key = _key.trim();
633
654
  const value = _value?.replace(/"/g, "") ?? "";
634
655
  return [key, value];
635
656
  });
@@ -725,7 +746,7 @@ var html = (strings, ...values) => {
725
746
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
726
747
  const value = signal !== void 0 ? signal() : text;
727
748
  if (value === null) hasNull = true;
728
- newText += value;
749
+ newText += String(value);
729
750
  }
730
751
  if (hasNull && newText === "null") {
731
752
  child.removeAttribute(attr.name);
@@ -774,19 +795,20 @@ var css = (strings, ...values) => {
774
795
  if (isServer) {
775
796
  return cssText;
776
797
  }
777
- let stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
798
+ const stylesheet = adoptedStylesSupported ? new CSSStyleSheet() : document.createElement("style");
778
799
  const textList = cssText.split(signalBindingRegex);
779
800
  createEffect(() => {
780
801
  const newCSSTextList = [];
781
802
  for (const text of textList) {
782
803
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
783
804
  const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
784
- const newText = signal !== null ? signal() : text;
805
+ const newValue = signal !== null ? signal() : text;
806
+ const newText = String(newValue);
785
807
  newCSSTextList.push(newText);
786
808
  }
787
809
  const newCSSText = newCSSTextList.join("");
788
810
  if (isCSSStyleSheet(stylesheet)) {
789
- stylesheet.replace(newCSSText);
811
+ stylesheet.replace(newCSSText).catch(console.error);
790
812
  } else {
791
813
  stylesheet.textContent = newCSSText;
792
814
  }
@@ -795,19 +817,6 @@ var css = (strings, ...values) => {
795
817
  };
796
818
 
797
819
  // 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
820
  var customElement = (render, options) => {
812
821
  const _options = { ...DEFAULT_RENDER_OPTIONS, ...options };
813
822
  const {
@@ -836,7 +845,8 @@ var customElement = (render, options) => {
836
845
  serverRender,
837
846
  options: allOptions,
838
847
  scopedRegistry,
839
- parentRegistry: _registry2
848
+ parentRegistry: _registry2,
849
+ elementResult: this
840
850
  });
841
851
  return this;
842
852
  },
@@ -892,8 +902,7 @@ var customElement = (render, options) => {
892
902
  if (mutation.type !== "attributes" || attrName === null) continue;
893
903
  if (!(attrName in this.#attrSignals)) this.#attrSignals[attrName] = createSignal(null);
894
904
  const [getter, setter] = this.#attrSignals[attrName];
895
- const _oldValue = getter();
896
- const oldValue = _oldValue === null ? null : _oldValue;
905
+ const oldValue = getter();
897
906
  const newValue = this.getAttribute(attrName);
898
907
  setter(newValue);
899
908
  for (const fn of this.#attributeChangedFns) {
@@ -1004,7 +1013,7 @@ You must set an initial value before calling a property signal's getter.
1004
1013
  tempContainer.append(fragment.cloneNode(true));
1005
1014
  const fragmentContent = tempContainer.innerHTML;
1006
1015
  root.innerHTML = fragmentContent;
1007
- if (registry !== void 0 && registry.__tagNames !== void 0) {
1016
+ if (registry?.__tagNames !== void 0) {
1008
1017
  for (const tagName of registry.__tagNames) {
1009
1018
  const upgradedElements = root.querySelectorAll(tagName);
1010
1019
  const nonUpgradedElements = fragment.querySelectorAll(tagName);
@@ -1117,7 +1126,7 @@ You must set an initial value before calling a property signal's getter.
1117
1126
  let _registry;
1118
1127
  const elementResult = {
1119
1128
  define(tagName, options2) {
1120
- const registry = _registry !== void 0 ? _registry : customElements;
1129
+ const registry = _registry ?? customElements;
1121
1130
  const nativeRegistry = "eject" in registry ? registry.eject() : registry;
1122
1131
  if (nativeRegistry.get(tagName) !== void 0) {
1123
1132
  console.warn(`Custom element "${tagName}" was already defined. Skipping...`);
@@ -1144,6 +1153,7 @@ You must set an initial value before calling a property signal's getter.
1144
1153
  var createRegistry = (args) => {
1145
1154
  const { scoped = false } = args ?? {};
1146
1155
  const customElementMap = /* @__PURE__ */ new Map();
1156
+ const elementResultMap = /* @__PURE__ */ new Map();
1147
1157
  const customElementTags = /* @__PURE__ */ new Set();
1148
1158
  const nativeRegistry = (() => {
1149
1159
  if (isServer) return;
@@ -1155,30 +1165,42 @@ var createRegistry = (args) => {
1155
1165
  __serverRenderOpts: /* @__PURE__ */ new Map(),
1156
1166
  define(tagName, ElementResult, options) {
1157
1167
  const isResult = "eject" in ElementResult;
1158
- if (isServer) {
1159
- if (isResult) ElementResult.register(this).define(tagName, options);
1168
+ const upperCaseTagName = tagName.toUpperCase();
1169
+ if (customElementTags.has(upperCaseTagName)) {
1170
+ console.warn(`Custom element tag name "${upperCaseTagName}" was already defined. Skipping...`);
1160
1171
  return this;
1161
1172
  }
1162
- const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1163
- if (customElementMap.has(CustomElement)) {
1164
- console.warn(`Custom element class "${CustomElement.constructor.name}" was already defined. Skipping...`);
1165
- return this;
1173
+ if (isResult) {
1174
+ if (elementResultMap.has(ElementResult)) {
1175
+ console.warn(`${upperCaseTagName} was already defined. Skipping...`);
1176
+ return this;
1177
+ }
1166
1178
  }
1167
- if (customElementTags.has(tagName)) {
1168
- console.warn(`Custom element tag name "${tagName}" was already defined. Skipping...`);
1169
- return this;
1179
+ if (!isServer) {
1180
+ const CustomElement2 = isResult ? ElementResult.eject() : ElementResult;
1181
+ if (customElementMap.has(CustomElement2)) {
1182
+ console.warn(`Custom element class "${CustomElement2.constructor.name}" was already defined. Skipping...`);
1183
+ return this;
1184
+ }
1185
+ customElementMap.set(CustomElement2, upperCaseTagName);
1170
1186
  }
1171
- customElementMap.set(CustomElement, tagName.toUpperCase());
1172
- customElementTags.add(tagName);
1173
- if (CustomElement === void 0) {
1174
- console.error(`Custom element class for tag name "${tagName}" was not found. You must register it first.`);
1187
+ if (isResult) elementResultMap.set(ElementResult, upperCaseTagName);
1188
+ customElementTags.add(upperCaseTagName);
1189
+ if (isServer) {
1190
+ if (isResult) ElementResult.register(this).define(tagName, options);
1175
1191
  return this;
1176
1192
  }
1193
+ const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1177
1194
  nativeRegistry?.define(tagName, CustomElement, options);
1178
1195
  return this;
1179
1196
  },
1180
1197
  getTagName: (ElementResult) => {
1181
- const CustomElement = "eject" in ElementResult ? ElementResult.eject() : ElementResult;
1198
+ const isResult = "eject" in ElementResult;
1199
+ if (isServer) {
1200
+ if (isResult) return elementResultMap.get(ElementResult);
1201
+ return;
1202
+ }
1203
+ const CustomElement = isResult ? ElementResult.eject() : ElementResult;
1182
1204
  return customElementMap.get(CustomElement);
1183
1205
  },
1184
1206
  getAllTagNames: () => Array.from(customElementTags),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thunderous",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
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": "tsc && 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
  }