thunderous 0.3.4 → 0.4.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
@@ -166,15 +166,19 @@ var html = (strings, ...values) => {
166
166
  const textList = child.data.split(signalBindingRegex);
167
167
  textList.forEach((text, i) => {
168
168
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
169
- const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
170
- const newText = signal !== null ? signal() : text;
171
- const newNode = new Text(newText);
169
+ const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
170
+ const newValue = signal !== void 0 ? signal() : text;
171
+ const newNode = (() => {
172
+ if (typeof newValue === "string") return new Text(newValue);
173
+ if (newValue instanceof DocumentFragment) return newValue;
174
+ return new Text("");
175
+ })();
172
176
  if (i === 0) {
173
177
  child.replaceWith(newNode);
174
178
  } else {
175
179
  element.insertBefore(newNode, child.nextSibling);
176
180
  }
177
- if (signal !== null) {
181
+ if (signal !== void 0 && newNode instanceof Text) {
178
182
  createEffect(() => {
179
183
  newNode.data = signal();
180
184
  });
@@ -190,8 +194,8 @@ var html = (strings, ...values) => {
190
194
  let hasNull = false;
191
195
  for (const text of textList) {
192
196
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
193
- const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
194
- const value = signal !== null ? signal() : text;
197
+ const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
198
+ const value = signal !== void 0 ? signal() : text;
195
199
  if (value === null) hasNull = true;
196
200
  newText += value;
197
201
  }
@@ -350,24 +354,34 @@ var customElement = (render, options) => {
350
354
  }
351
355
  }
352
356
  ),
353
- propSignals: new Proxy(
354
- {},
355
- {
356
- get: (_, prop) => {
357
- if (!(prop in this.#propSignals)) this.#propSignals[prop] = createSignal(null);
358
- const [getter, _setter] = this.#propSignals[prop];
359
- const setter = (newValue) => {
360
- this[prop] = newValue;
361
- _setter(newValue);
362
- };
363
- return [getter, setter];
364
- },
365
- set: () => {
366
- console.error("Signals must be assigned via setters.");
367
- return false;
368
- }
357
+ propSignals: new Proxy({}, {
358
+ get: (_, prop) => {
359
+ if (!(prop in this.#propSignals)) this.#propSignals[prop] = createSignal();
360
+ const [_getter, _setter] = this.#propSignals[prop];
361
+ const setter = (newValue) => {
362
+ this[prop] = newValue;
363
+ _setter(newValue);
364
+ };
365
+ const getter = () => {
366
+ const value = _getter();
367
+ if (value === void 0)
368
+ throw new Error(
369
+ `
370
+
371
+ Property: ${prop}
372
+
373
+ You must set an initial value before calling a property signal's getter.
374
+ `
375
+ );
376
+ return value;
377
+ };
378
+ return [getter, setter];
379
+ },
380
+ set: () => {
381
+ console.error("Signals must be assigned via setters.");
382
+ return false;
369
383
  }
370
- ),
384
+ }),
371
385
  refs: new Proxy(
372
386
  {},
373
387
  {
package/dist/index.d.cts CHANGED
@@ -56,7 +56,8 @@ type ElementResult = {
56
56
  eject: () => CustomElementConstructor;
57
57
  };
58
58
  type AttributeChangedCallback = (name: string, oldValue: string | null, newValue: string | null) => void;
59
- type RenderProps = {
59
+ type CustomElementProps = Record<PropertyKey, unknown>;
60
+ type RenderArgs<Props extends CustomElementProps> = {
60
61
  elementRef: HTMLElement;
61
62
  root: ShadowRoot | HTMLElement;
62
63
  internals: ElementInternals;
@@ -70,7 +71,9 @@ type RenderProps = {
70
71
  formAssociatedCallback: (fn: () => void) => void;
71
72
  customCallback: (fn: () => void) => `{{callback:${string}}}`;
72
73
  attrSignals: Record<string, Signal<string | null>>;
73
- propSignals: Record<string, Signal<unknown>>;
74
+ propSignals: {
75
+ [K in keyof Props]: Signal<Props[K]>;
76
+ };
74
77
  refs: Record<string, HTMLElement | null>;
75
78
  adoptStyleSheet: (stylesheet: Styles) => void;
76
79
  };
@@ -82,7 +85,7 @@ type RenderOptions = {
82
85
  attachShadow: boolean;
83
86
  shadowRootOptions: ShadowRootInit;
84
87
  };
85
- type RenderFunction = (props: RenderProps) => DocumentFragment;
88
+ type RenderFunction<Props extends CustomElementProps> = (args: RenderArgs<Props>) => DocumentFragment;
86
89
  /**
87
90
  * Create a custom element that can be defined for use in the DOM.
88
91
  * @example
@@ -93,7 +96,7 @@ type RenderFunction = (props: RenderProps) => DocumentFragment;
93
96
  * MyElement.define('my-element');
94
97
  * ```
95
98
  */
96
- declare const customElement: (render: RenderFunction, options?: Partial<RenderOptions>) => ElementResult;
99
+ declare const customElement: <Props extends CustomElementProps>(render: RenderFunction<Props>, options?: Partial<RenderOptions>) => ElementResult;
97
100
  type Registry = {
98
101
  register: (tagName: string, element: CustomElementConstructor) => void;
99
102
  getTagName: (element: CustomElementConstructor) => string | undefined;
@@ -110,4 +113,4 @@ type Registry = {
110
113
  */
111
114
  declare const createRegistry: () => Registry;
112
115
 
113
- export { type RenderFunction, type RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
116
+ export { type RenderArgs, type RenderFunction, type RenderArgs as RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
package/dist/index.d.ts CHANGED
@@ -56,7 +56,8 @@ type ElementResult = {
56
56
  eject: () => CustomElementConstructor;
57
57
  };
58
58
  type AttributeChangedCallback = (name: string, oldValue: string | null, newValue: string | null) => void;
59
- type RenderProps = {
59
+ type CustomElementProps = Record<PropertyKey, unknown>;
60
+ type RenderArgs<Props extends CustomElementProps> = {
60
61
  elementRef: HTMLElement;
61
62
  root: ShadowRoot | HTMLElement;
62
63
  internals: ElementInternals;
@@ -70,7 +71,9 @@ type RenderProps = {
70
71
  formAssociatedCallback: (fn: () => void) => void;
71
72
  customCallback: (fn: () => void) => `{{callback:${string}}}`;
72
73
  attrSignals: Record<string, Signal<string | null>>;
73
- propSignals: Record<string, Signal<unknown>>;
74
+ propSignals: {
75
+ [K in keyof Props]: Signal<Props[K]>;
76
+ };
74
77
  refs: Record<string, HTMLElement | null>;
75
78
  adoptStyleSheet: (stylesheet: Styles) => void;
76
79
  };
@@ -82,7 +85,7 @@ type RenderOptions = {
82
85
  attachShadow: boolean;
83
86
  shadowRootOptions: ShadowRootInit;
84
87
  };
85
- type RenderFunction = (props: RenderProps) => DocumentFragment;
88
+ type RenderFunction<Props extends CustomElementProps> = (args: RenderArgs<Props>) => DocumentFragment;
86
89
  /**
87
90
  * Create a custom element that can be defined for use in the DOM.
88
91
  * @example
@@ -93,7 +96,7 @@ type RenderFunction = (props: RenderProps) => DocumentFragment;
93
96
  * MyElement.define('my-element');
94
97
  * ```
95
98
  */
96
- declare const customElement: (render: RenderFunction, options?: Partial<RenderOptions>) => ElementResult;
99
+ declare const customElement: <Props extends CustomElementProps>(render: RenderFunction<Props>, options?: Partial<RenderOptions>) => ElementResult;
97
100
  type Registry = {
98
101
  register: (tagName: string, element: CustomElementConstructor) => void;
99
102
  getTagName: (element: CustomElementConstructor) => string | undefined;
@@ -110,4 +113,4 @@ type Registry = {
110
113
  */
111
114
  declare const createRegistry: () => Registry;
112
115
 
113
- export { type RenderFunction, type RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
116
+ export { type RenderArgs, type RenderFunction, type RenderArgs as RenderProps, type Signal, type SignalGetter, type SignalSetter, createEffect, createRegistry, createSignal, css, customElement, derived, html };
package/dist/index.js CHANGED
@@ -124,15 +124,19 @@ var html = (strings, ...values) => {
124
124
  const textList = child.data.split(signalBindingRegex);
125
125
  textList.forEach((text, i) => {
126
126
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
127
- const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
128
- const newText = signal !== null ? signal() : text;
129
- const newNode = new Text(newText);
127
+ const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
128
+ const newValue = signal !== void 0 ? signal() : text;
129
+ const newNode = (() => {
130
+ if (typeof newValue === "string") return new Text(newValue);
131
+ if (newValue instanceof DocumentFragment) return newValue;
132
+ return new Text("");
133
+ })();
130
134
  if (i === 0) {
131
135
  child.replaceWith(newNode);
132
136
  } else {
133
137
  element.insertBefore(newNode, child.nextSibling);
134
138
  }
135
- if (signal !== null) {
139
+ if (signal !== void 0 && newNode instanceof Text) {
136
140
  createEffect(() => {
137
141
  newNode.data = signal();
138
142
  });
@@ -148,8 +152,8 @@ var html = (strings, ...values) => {
148
152
  let hasNull = false;
149
153
  for (const text of textList) {
150
154
  const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
151
- const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : null;
152
- const value = signal !== null ? signal() : text;
155
+ const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
156
+ const value = signal !== void 0 ? signal() : text;
153
157
  if (value === null) hasNull = true;
154
158
  newText += value;
155
159
  }
@@ -308,24 +312,34 @@ var customElement = (render, options) => {
308
312
  }
309
313
  }
310
314
  ),
311
- propSignals: new Proxy(
312
- {},
313
- {
314
- get: (_, prop) => {
315
- if (!(prop in this.#propSignals)) this.#propSignals[prop] = createSignal(null);
316
- const [getter, _setter] = this.#propSignals[prop];
317
- const setter = (newValue) => {
318
- this[prop] = newValue;
319
- _setter(newValue);
320
- };
321
- return [getter, setter];
322
- },
323
- set: () => {
324
- console.error("Signals must be assigned via setters.");
325
- return false;
326
- }
315
+ propSignals: new Proxy({}, {
316
+ get: (_, prop) => {
317
+ if (!(prop in this.#propSignals)) this.#propSignals[prop] = createSignal();
318
+ const [_getter, _setter] = this.#propSignals[prop];
319
+ const setter = (newValue) => {
320
+ this[prop] = newValue;
321
+ _setter(newValue);
322
+ };
323
+ const getter = () => {
324
+ const value = _getter();
325
+ if (value === void 0)
326
+ throw new Error(
327
+ `
328
+
329
+ Property: ${prop}
330
+
331
+ You must set an initial value before calling a property signal's getter.
332
+ `
333
+ );
334
+ return value;
335
+ };
336
+ return [getter, setter];
337
+ },
338
+ set: () => {
339
+ console.error("Signals must be assigned via setters.");
340
+ return false;
327
341
  }
328
- ),
342
+ }),
329
343
  refs: new Proxy(
330
344
  {},
331
345
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thunderous",
3
- "version": "0.3.4",
3
+ "version": "0.4.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -30,7 +30,8 @@
30
30
  "homepage": "https://github.com/Thunder-Solutions/Thunderous#readme",
31
31
  "license": "MIT",
32
32
  "scripts": {
33
- "demo": "cd demo && rm -rf node_modules && npm i && npm start",
33
+ "demo": "cd demo && npm start",
34
+ "www": "cd www && npm run dev",
34
35
  "build": "tsup src/index.ts --format cjs,esm --dts --no-clean"
35
36
  },
36
37
  "devDependencies": {