thunderous 0.0.4 → 0.1.0
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/README.md +63 -25
- package/dist/index.cjs +10 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -35,20 +35,16 @@ const myStyleSheet = css`
|
|
35
35
|
`;
|
36
36
|
|
37
37
|
const MyElement = customElement((params) => {
|
38
|
-
const {
|
38
|
+
const { customCallback, refs, adoptStyleSheet } = params;
|
39
39
|
|
40
40
|
const [count, setCount] = createSignal(0);
|
41
41
|
|
42
|
-
|
43
|
-
refs.increment.addEventListener('click', () => {
|
44
|
-
setCount(count() + 1);
|
45
|
-
});
|
46
|
-
});
|
42
|
+
const increment = customCallback(() => setCount(count() + 1));
|
47
43
|
|
48
44
|
adoptStyleSheet(myStyleSheet);
|
49
45
|
|
50
46
|
return html`
|
51
|
-
<button
|
47
|
+
<button onclick="${increment}">Increment</button>
|
52
48
|
<output>${count}</output>
|
53
49
|
`;
|
54
50
|
});
|
@@ -157,19 +153,15 @@ Creating signals should look pretty familiar to most modern developers.
|
|
157
153
|
|
158
154
|
<!-- prettier-ignore-start -->
|
159
155
|
```ts
|
160
|
-
import { createSignal
|
161
|
-
|
162
|
-
const MyElement = customElement(() => {
|
163
|
-
const [count, setCount] = createSignal(0);
|
156
|
+
import { createSignal } from 'thunderous';
|
164
157
|
|
165
|
-
|
158
|
+
const [count, setCount] = createSignal(0);
|
166
159
|
|
167
|
-
|
160
|
+
console.log(count()); // 0
|
168
161
|
|
169
|
-
|
162
|
+
setCount(1);
|
170
163
|
|
171
|
-
|
172
|
-
});
|
164
|
+
console.log(count()) // 1
|
173
165
|
```
|
174
166
|
<!-- prettier-ignore-end -->
|
175
167
|
|
@@ -223,33 +215,79 @@ Usage:
|
|
223
215
|
|
224
216
|
> NOTICE: Since `attrSignals` is a `Proxy` object, _any_ property will return a signal and auto-bind it to the attribute it corresponds with.
|
225
217
|
|
218
|
+
##### Derived Signals
|
219
|
+
|
220
|
+
If you want to calculate a value based on another signal's value, you should use the `derived()` function. This signal will trigger its subscribers each time the signals inside change.
|
221
|
+
|
222
|
+
```ts
|
223
|
+
import { derived, createSignal } from 'thunderous';
|
224
|
+
|
225
|
+
const [count, setCount] = createSignal(0);
|
226
|
+
|
227
|
+
const timesTen = derived(() => count() * 10);
|
228
|
+
|
229
|
+
console.log(timesTen()); // 0
|
230
|
+
|
231
|
+
setCount(10);
|
232
|
+
|
233
|
+
console.log(timesTen()); // 100
|
234
|
+
```
|
235
|
+
|
236
|
+
##### Effects
|
237
|
+
|
238
|
+
To run a callback each time a signal is changed, use the `createEffect()` function. Any signal used inside will trigger the callback when they're changed.
|
239
|
+
|
240
|
+
```ts
|
241
|
+
import { createEffect } from 'thunderous';
|
242
|
+
|
243
|
+
/* ... */
|
244
|
+
|
245
|
+
createEffect(() => {
|
246
|
+
console.log(count());
|
247
|
+
});
|
248
|
+
```
|
249
|
+
|
226
250
|
#### Refs
|
227
251
|
|
228
|
-
|
252
|
+
The refs property exists for convenience to avoid manually querying the DOM. Since the DOM is only available after rendering, refs will only work in and after the `connectedCallback` method.
|
229
253
|
|
230
254
|
<!-- prettier-ignore-start -->
|
231
255
|
```ts
|
232
256
|
const MyElement = customElement((params) => {
|
233
257
|
const { connectedCallback, refs } = params;
|
234
258
|
|
235
|
-
const [count, setCount] = createSignal(0);
|
236
|
-
|
237
259
|
connectedCallback(() => {
|
238
|
-
refs.
|
239
|
-
setCount(count() + 1);
|
240
|
-
});
|
260
|
+
console.log(refs.heading.textContent); // hello world
|
241
261
|
});
|
242
262
|
|
263
|
+
return html`<h2 ref="heading">hello world</h2>`;
|
264
|
+
});
|
265
|
+
```
|
266
|
+
<!-- prettier-ignore-end -->
|
267
|
+
|
268
|
+
#### Event Binding
|
269
|
+
|
270
|
+
While you could bind events in the `connectedCallback()` with `refs.button.addEventListener('click', handleClick)` for example, it may be more convenient to register a custom callback and bind it to the template.
|
271
|
+
|
272
|
+
<!-- prettier-ignore-start -->
|
273
|
+
```ts
|
274
|
+
const MyElement = customElement((params) => {
|
275
|
+
const { customCallback } = params;
|
276
|
+
|
277
|
+
const [count, setCount] = createSignal(0);
|
278
|
+
|
279
|
+
const increment = customCallback(() => setCount(count() + 1));
|
280
|
+
|
243
281
|
return html`
|
244
|
-
<button
|
282
|
+
<button onclick="${increment}">Increment</button>
|
245
283
|
<output>${count}</output>
|
246
284
|
`;
|
247
285
|
});
|
248
|
-
|
249
|
-
MyElement.define('my-element');
|
250
286
|
```
|
251
287
|
<!-- prettier-ignore-end -->
|
252
288
|
|
289
|
+
> NOTICE: This uses the native HTML inline event-binding syntax. There is no special syntax for `on` attributes, because it simply renders a reference to `this.getRootNode().host` and extracts the callback from there.
|
290
|
+
|
253
291
|
### Defining Custom Elements
|
254
292
|
|
255
293
|
The `customElement()` function allows you to author a web component, returning an `ElementResult` that has some helpful methods like `define()` and `eject()`.
|
package/dist/index.cjs
CHANGED
@@ -93,6 +93,7 @@ var customElement = (render, options) => {
|
|
93
93
|
#formDisabledCallbackFns = /* @__PURE__ */ new Set();
|
94
94
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
95
95
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
96
|
+
__customCallbackFns = /* @__PURE__ */ new Map();
|
96
97
|
#shadowRoot = this.attachShadow({ mode: "closed" });
|
97
98
|
#internals = this.attachInternals();
|
98
99
|
#observer = new MutationObserver((mutations) => {
|
@@ -121,6 +122,11 @@ var customElement = (render, options) => {
|
|
121
122
|
formDisabledCallback: (fn) => this.#formDisabledCallbackFns.add(fn),
|
122
123
|
formResetCallback: (fn) => this.#formResetCallbackFns.add(fn),
|
123
124
|
formStateRestoreCallback: (fn) => this.#formStateRestoreCallbackFns.add(fn),
|
125
|
+
customCallback: (fn) => {
|
126
|
+
const key = crypto.randomUUID();
|
127
|
+
this.__customCallbackFns.set(key, fn);
|
128
|
+
return `{{callback:${key}}}`;
|
129
|
+
},
|
124
130
|
attrSignals: new Proxy(
|
125
131
|
{},
|
126
132
|
{
|
@@ -245,6 +251,7 @@ var html = (strings, ...values) => {
|
|
245
251
|
innerHTML += string + String(value);
|
246
252
|
});
|
247
253
|
const fragment = parseFragment(innerHTML);
|
254
|
+
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
248
255
|
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
249
256
|
const parseChildren = (element) => {
|
250
257
|
for (const child of element.childNodes) {
|
@@ -280,6 +287,9 @@ var html = (strings, ...values) => {
|
|
280
287
|
}
|
281
288
|
child.setAttribute(attr.name, newText);
|
282
289
|
});
|
290
|
+
} else if (callbackBindingRegex.test(attr.value)) {
|
291
|
+
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
292
|
+
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
283
293
|
}
|
284
294
|
}
|
285
295
|
parseChildren(child);
|
package/dist/index.d.cts
CHANGED
@@ -22,6 +22,7 @@ type RenderProps = {
|
|
22
22
|
formDisabledCallback: (fn: () => void) => void;
|
23
23
|
formResetCallback: (fn: () => void) => void;
|
24
24
|
formStateRestoreCallback: (fn: () => void) => void;
|
25
|
+
customCallback: (fn: () => void) => `{{callback:${string}}}`;
|
25
26
|
attrSignals: Record<string, Signal<string | null>>;
|
26
27
|
refs: Record<string, HTMLElement | null>;
|
27
28
|
adoptStyleSheet: (stylesheet: CSSStyleSheet) => void;
|
package/dist/index.d.ts
CHANGED
@@ -22,6 +22,7 @@ type RenderProps = {
|
|
22
22
|
formDisabledCallback: (fn: () => void) => void;
|
23
23
|
formResetCallback: (fn: () => void) => void;
|
24
24
|
formStateRestoreCallback: (fn: () => void) => void;
|
25
|
+
customCallback: (fn: () => void) => `{{callback:${string}}}`;
|
25
26
|
attrSignals: Record<string, Signal<string | null>>;
|
26
27
|
refs: Record<string, HTMLElement | null>;
|
27
28
|
adoptStyleSheet: (stylesheet: CSSStyleSheet) => void;
|
package/dist/index.js
CHANGED
@@ -62,6 +62,7 @@ var customElement = (render, options) => {
|
|
62
62
|
#formDisabledCallbackFns = /* @__PURE__ */ new Set();
|
63
63
|
#formResetCallbackFns = /* @__PURE__ */ new Set();
|
64
64
|
#formStateRestoreCallbackFns = /* @__PURE__ */ new Set();
|
65
|
+
__customCallbackFns = /* @__PURE__ */ new Map();
|
65
66
|
#shadowRoot = this.attachShadow({ mode: "closed" });
|
66
67
|
#internals = this.attachInternals();
|
67
68
|
#observer = new MutationObserver((mutations) => {
|
@@ -90,6 +91,11 @@ var customElement = (render, options) => {
|
|
90
91
|
formDisabledCallback: (fn) => this.#formDisabledCallbackFns.add(fn),
|
91
92
|
formResetCallback: (fn) => this.#formResetCallbackFns.add(fn),
|
92
93
|
formStateRestoreCallback: (fn) => this.#formStateRestoreCallbackFns.add(fn),
|
94
|
+
customCallback: (fn) => {
|
95
|
+
const key = crypto.randomUUID();
|
96
|
+
this.__customCallbackFns.set(key, fn);
|
97
|
+
return `{{callback:${key}}}`;
|
98
|
+
},
|
93
99
|
attrSignals: new Proxy(
|
94
100
|
{},
|
95
101
|
{
|
@@ -214,6 +220,7 @@ var html = (strings, ...values) => {
|
|
214
220
|
innerHTML += string + String(value);
|
215
221
|
});
|
216
222
|
const fragment = parseFragment(innerHTML);
|
223
|
+
const callbackBindingRegex = /(\{\{callback:.+\}\})/;
|
217
224
|
const signalBindingRegex = /(\{\{signal:.+\}\})/;
|
218
225
|
const parseChildren = (element) => {
|
219
226
|
for (const child of element.childNodes) {
|
@@ -249,6 +256,9 @@ var html = (strings, ...values) => {
|
|
249
256
|
}
|
250
257
|
child.setAttribute(attr.name, newText);
|
251
258
|
});
|
259
|
+
} else if (callbackBindingRegex.test(attr.value)) {
|
260
|
+
const uniqueKey = attr.value.replace(/\{\{callback:(.+)\}\}/, "$1");
|
261
|
+
child.setAttribute(attr.name, `this.getRootNode().host.__customCallbackFns.get('${uniqueKey}')(event)`);
|
252
262
|
}
|
253
263
|
}
|
254
264
|
parseChildren(child);
|