elements-kit 0.0.18 → 0.0.20

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.
Files changed (110) hide show
  1. package/README.md +65 -118
  2. package/dist/{attributes-Dtn68R1u.d.mts → attributes-DILeh3-s.d.mts} +42 -9
  3. package/dist/attributes.d.mts +1 -1
  4. package/dist/attributes.mjs +32 -0
  5. package/dist/{define-CjbTZ3VG.d.mts → custom-elements-D5_NMNyD.d.mts} +20 -2
  6. package/dist/custom-elements.d.mts +2 -74
  7. package/dist/custom-elements.mjs +15 -86
  8. package/dist/{element-CGVy_8TW.mjs → element-w1GCIMVp.mjs} +33 -21
  9. package/dist/for.d.mts +31 -2
  10. package/dist/for.mjs +18 -2
  11. package/dist/infer-DuFY-y2b.d.mts +657 -0
  12. package/dist/integrations/react.d.mts +1 -1
  13. package/dist/integrations/react.mjs +6 -4
  14. package/dist/jsx-runtime/index.d.mts +2 -73
  15. package/dist/jsx-runtime/index.mjs +8 -14
  16. package/dist/{signals-J8dK_rA4.mjs → lib-D6duEs38.mjs} +1 -105
  17. package/dist/render.d.mts +21 -0
  18. package/dist/render.mjs +32 -0
  19. package/dist/scope-DM2gzOkb.mjs +45 -0
  20. package/dist/signals/index.d.mts +1 -1
  21. package/dist/signals/index.mjs +134 -1
  22. package/dist/{slot-Kb61AcgW.mjs → slot-CKtUoy2X.mjs} +0 -1
  23. package/dist/{slot-C7GQZe-r.d.mts → slot-D5iBUSAm.d.mts} +18 -1
  24. package/dist/slot.d.mts +1 -1
  25. package/dist/slot.mjs +1 -1
  26. package/dist/{test.BmQO5GaM-DfGStnii.mjs → test.BmQO5GaM-BeO5pvCo.mjs} +1 -1
  27. package/dist/utilities/_observe.mjs +2 -1
  28. package/dist/utilities/active-element.d.mts +1 -1
  29. package/dist/utilities/active-element.mjs +2 -1
  30. package/dist/utilities/active-element.test.mjs +1 -1
  31. package/dist/utilities/async.d.mts +39 -1
  32. package/dist/utilities/async.mjs +39 -1
  33. package/dist/utilities/async.test.mjs +3 -2
  34. package/dist/utilities/debounced.d.mts +12 -1
  35. package/dist/utilities/debounced.mjs +13 -1
  36. package/dist/utilities/debounced.test.mjs +3 -2
  37. package/dist/utilities/element-rect.d.mts +1 -1
  38. package/dist/utilities/element-rect.mjs +2 -1
  39. package/dist/utilities/element-rect.test.mjs +3 -2
  40. package/dist/utilities/element-scroll.d.mts +1 -1
  41. package/dist/utilities/element-scroll.test.mjs +3 -2
  42. package/dist/utilities/environment.d.mts +2 -0
  43. package/dist/utilities/environment.mjs +2 -0
  44. package/dist/utilities/event-driven.d.mts +1 -1
  45. package/dist/utilities/event-driven.mjs +2 -1
  46. package/dist/utilities/event-listener.d.mts +12 -1
  47. package/dist/utilities/event-listener.mjs +2 -1
  48. package/dist/utilities/event-listener.test.mjs +3 -2
  49. package/dist/utilities/focus-within.d.mts +1 -1
  50. package/dist/utilities/focus-within.mjs +2 -1
  51. package/dist/utilities/focus-within.test.mjs +3 -2
  52. package/dist/utilities/hover.d.mts +1 -1
  53. package/dist/utilities/hover.mjs +2 -1
  54. package/dist/utilities/hover.test.mjs +3 -2
  55. package/dist/utilities/intersection-observer.test.mjs +3 -2
  56. package/dist/utilities/interval.d.mts +14 -1
  57. package/dist/utilities/interval.mjs +2 -1
  58. package/dist/utilities/interval.test.mjs +3 -2
  59. package/dist/utilities/location.d.mts +1 -1
  60. package/dist/utilities/location.mjs +2 -1
  61. package/dist/utilities/location.test.mjs +1 -1
  62. package/dist/utilities/long-press.test.mjs +3 -2
  63. package/dist/utilities/media-devices.d.mts +1 -1
  64. package/dist/utilities/media-devices.mjs +2 -1
  65. package/dist/utilities/media-devices.test.mjs +3 -2
  66. package/dist/utilities/media-player.d.mts +1 -1
  67. package/dist/utilities/media-player.test.mjs +3 -2
  68. package/dist/utilities/media-query.d.mts +1 -1
  69. package/dist/utilities/media-query.mjs +2 -1
  70. package/dist/utilities/mutation-observer.test.mjs +3 -2
  71. package/dist/utilities/network.d.mts +1 -1
  72. package/dist/utilities/network.mjs +2 -1
  73. package/dist/utilities/network.test.mjs +1 -1
  74. package/dist/utilities/on-click-outside.test.mjs +3 -2
  75. package/dist/utilities/orientation.d.mts +1 -1
  76. package/dist/utilities/orientation.mjs +2 -1
  77. package/dist/utilities/previous.d.mts +13 -1
  78. package/dist/utilities/previous.mjs +14 -1
  79. package/dist/utilities/previous.test.mjs +3 -2
  80. package/dist/utilities/promise.d.mts +7 -1
  81. package/dist/utilities/promise.mjs +2 -1
  82. package/dist/utilities/promise.test.mjs +3 -2
  83. package/dist/utilities/retry.d.mts +15 -0
  84. package/dist/utilities/retry.mjs +17 -1
  85. package/dist/utilities/retry.test.mjs +3 -2
  86. package/dist/utilities/routing.d.mts +12 -1
  87. package/dist/utilities/routing.mjs +13 -1
  88. package/dist/utilities/routing.test.mjs +1 -1
  89. package/dist/utilities/search-params.d.mts +1 -1
  90. package/dist/utilities/search-params.test.mjs +3 -2
  91. package/dist/utilities/ssr.test.mjs +1 -1
  92. package/dist/utilities/storage.d.mts +18 -1
  93. package/dist/utilities/storage.mjs +17 -0
  94. package/dist/utilities/storage.test.mjs +3 -2
  95. package/dist/utilities/throttled.d.mts +12 -1
  96. package/dist/utilities/throttled.mjs +13 -1
  97. package/dist/utilities/throttled.test.mjs +3 -2
  98. package/dist/utilities/timeout.d.mts +1 -1
  99. package/dist/utilities/timeout.mjs +2 -1
  100. package/dist/utilities/timeout.test.mjs +3 -2
  101. package/dist/utilities/window-focus.d.mts +1 -1
  102. package/dist/utilities/window-focus.mjs +2 -1
  103. package/dist/utilities/window-size.d.mts +1 -1
  104. package/dist/utilities/window-size.mjs +2 -1
  105. package/dist/utilities/window-size.test.mjs +1 -1
  106. package/package.json +1 -1
  107. package/dist/index-DydGTqZU.d.mts +0 -315
  108. package/dist/infer-BfzRJoCn.d.mts +0 -203
  109. package/dist/polyfill-BVNd6ogU.d.mts +0 -9
  110. /package/dist/{magic-string.es-i62WTP6J.mjs → magic-string.es-cTgJnTCj.mjs} +0 -0
package/README.md CHANGED
@@ -1,41 +1,58 @@
1
- <p align="center">
2
- <img src="docs/public/og.svg" alt="ElementsKit" width="600" />
3
- </p>
1
+ # ElementsKit 🌱
4
2
 
5
- # ElementsKit
6
-
7
- **Universal reactive primitives for the web.** Signals, JSX, and custom elements that work anywhere — standalone, inside React, Vue, or any framework, or as the foundation of your own component model.
3
+ **Universal reactive primitives for the web.** Signals, JSX, custom elements, and browser-API helpers. Import one at a time, compose them, or use any of them inside vanilla JS, React, Vue, or any framework.
8
4
 
9
5
  ```tsx
10
- import { signal, computed, reactive } from "elements-kit/signals";
11
- import { attributes, ATTRIBUTES as attr } from "elements-kit/attributes";
6
+ import { signal, computed } from "elements-kit/signals";
7
+ import { render } from "elements-kit/render";
8
+ import type { ReactiveProps } from "elements-kit/jsx-runtime";
9
+
10
+ function Counter(props: ReactiveProps<{ initial?: number }>) {
11
+ const count = signal(props.initial() ?? 0);
12
+ const doubled = computed(() => count() * 2);
13
+
14
+ return (
15
+ <section>
16
+ <p><strong>{count}</strong> × 2 = <strong>{doubled}</strong></p>
17
+ <button on:click={() => count(count() + 1)}>+1</button>{" "}
18
+ <button on:click={() => count(count() - 1)}>−1</button>
19
+ </section>
20
+ );
21
+ }
12
22
 
13
- @attributes
14
- class CounterElement extends HTMLElement {
15
- static [attr] = {
16
- count(this: CounterElement, value: string | null) {
17
- this.count = Number(value ?? 0);
18
- },
19
- };
23
+ render(document.getElementById("app")!, () => <Counter initial={0} />);
24
+ ```
20
25
 
21
- @reactive() count = 0;
22
- doubled = computed(() => this.count * 2);
26
+ ## Installation
23
27
 
24
- connectedCallback() {
25
- this.appendChild(
26
- <section>
27
- <p>Count: <strong>{() => this.count}</strong> — Doubled: <strong>{this.doubled}</strong></p>
28
- <button onClick={() => this.count++}>+1</button>{" "}
29
- <button onClick={() => this.count--}>−1</button>
30
- </section> as Element,
31
- );
28
+ ```sh
29
+ npm install elements-kit
30
+ ```
31
+
32
+ Configure JSX in your `tsconfig.json`:
33
+
34
+ ```json
35
+ {
36
+ "compilerOptions": {
37
+ "jsx": "react-jsx",
38
+ "jsxImportSource": "elements-kit"
32
39
  }
33
40
  }
34
-
35
- customElements.define("x-counter", CounterElement);
36
41
  ```
37
42
 
38
- ---
43
+ ## Why ElementsKit
44
+
45
+ ElementsKit is a library of reactive primitives, not a framework. Each piece is its own import, runs on its own, and composes with the others — inside React, inside a custom element, or on its own in a script.
46
+
47
+ - **Compose, don't configure.** Small focused APIs — `signal`, `computed`, `on`, `fromEvent`, `async`. Combine primitives instead of maintaining an overloaded interface.
48
+
49
+ - **Close to the platform.** JSX compiles to `document.createElement`. `promise` extends `Promise`. Custom elements *are* `HTMLElement`. Thin or absent abstraction layers — no virtual DOM, no proxies, no build steps.
50
+
51
+ - **Predictable and explicit — no magic.** `signal/compose` are reactive; nothing else is. No heuristic dependency tracking, no hidden subscriptions.
52
+
53
+ - **Designed for the AI age.** Code is cheap; maintenance still isn't. Primitives compose into higher-level blocks. Swap one block at a time instead of maintaining long lines of code.
54
+
55
+ - **Bundler-friendly.** Every primitive is its own subpath — `elements-kit/signals`, `elements-kit/utilities/*`, `elements-kit/integrations/*`. Import only what you need.
39
56
 
40
57
  ## Packages
41
58
 
@@ -43,71 +60,16 @@ Every feature is a separate subpath export — import only what you use.
43
60
 
44
61
  | Entry | Purpose |
45
62
  |-------|---------|
46
- | `elements-kit` | `For` component and core re-exports |
47
63
  | `elements-kit/signals` | `signal`, `computed`, `effect`, `effectScope`, `batch`, `untracked`, `trigger`, `onCleanup`, `MaybeReactive`, `resolve`, `resolveProps`, `@reactive` |
48
64
  | `elements-kit/render` | `render(target, setup)` — mount a node with a scoped lifetime; returns `unmount` |
49
65
  | `elements-kit/attributes` | `@attributes` decorator + `ATTRIBUTES` symbol |
50
66
  | `elements-kit/slot` | `Slot`, `Slots`, `SLOTS` symbol — comment-marker DOM regions |
51
67
  | `elements-kit/custom-elements` | `defineElement`, `CustomElementRegistry` |
52
68
  | `elements-kit/for` | `For` keyed-list component |
53
- | `elements-kit/jsx-runtime` | JSX factory + type helpers (`ElementProps`, `Props`, `ComponentProps`, `MaybeReactiveProps`, `Require`) — configure via `jsxImportSource` |
69
+ | `elements-kit/jsx-runtime` | JSX factory + type helpers (`ElementProps`, `Props`, `ComponentProps`, `MaybeReactiveProps`, `ReactiveProps`, `Require`) — configure via `jsxImportSource` |
54
70
  | `elements-kit/integrations/react` | `useSignal`, `useScope` React bridge hooks |
55
71
  | `elements-kit/utilities/*` | Reactive browser-API utilities — see [src/utilities/README.md](src/utilities/README.md) |
56
72
 
57
- ## Repository
58
-
59
- - [src/](src/) — library source ([signals](src/signals/), [jsx-runtime](src/jsx-runtime/), [utilities](src/utilities/), [integrations](src/integrations/))
60
- - [docs/](docs/) — Astro + Starlight documentation site
61
- - [example/](example/) — Vite sandbox
62
- - [ARCHITECTURE.md](ARCHITECTURE.md) — how the library works (reactive model, JSX, custom elements, cleanup)
63
- - [CONTRIBUTING.md](CONTRIBUTING.md) — quick start, quality bars, versioning, PR checklist
64
- - [DOCS.md](DOCS.md) — doc-authoring rules
65
- - [AGENTS.md](AGENTS.md) — agent navigation map
66
- - [src/utilities/README.md](src/utilities/README.md) — utilities catalog and dependency graph
67
-
68
- ---
69
-
70
- ## Why ElementsKit
71
-
72
- Modern UI frameworks solve reactivity and rendering together — you adopt the whole system or none of it. ElementsKit separates the two:
73
-
74
- - **Signals** are the reactive core — fine-grained, framework-agnostic, composable with any rendering model.
75
- - **JSX** compiles to real `document.createElement` calls — no virtual DOM, no runtime overhead.
76
- - **Custom elements** are standard browser components — ElementsKit enhances them with signals and JSX without wrapping or abstracting the platform.
77
-
78
- Use one piece, or all three. Integrate with React for complex UIs. Build web components that work anywhere HTML does.
79
-
80
- ### Primitives first, composable abstractions
81
-
82
- Small primitives, one job each, typed interfaces at every boundary. Abstraction is assembled, not inherited — compose upward from `signal` → `sync(fromEvent(...), ...)` → `<For>` and stop at the level your feature needs. Designed for AI agents as much as for humans: each step is verifiable on its own, and there's no framework-specific mental model to learn before writing the first line.
83
-
84
- - **No prop matrices.** No single-system components with forty flags where legal combinations aren't obvious until you read the source.
85
- - **No hidden coupling.** Blocks meet at their types; invariants don't leak across layers.
86
- - **Close to the platform.** `promise` wraps a native `Promise`. JSX compiles to `document.createElement`. Custom elements are `HTMLElement` subclasses. You already know the underlying shape.
87
- - **Minimal surface.** `async` has no cache, no query client, no query/mutation split. If you need those, compose them on top — don't inherit them by default.
88
- - **Swap, don't rewrite.** Replace one block (`throttled` → `debounced`) without touching the ones around it.
89
-
90
- ---
91
-
92
- ## Installation
93
-
94
- ```sh
95
- npm install elements-kit
96
- ```
97
-
98
- Configure JSX in your `tsconfig.json`:
99
-
100
- ```json
101
- {
102
- "compilerOptions": {
103
- "jsx": "react-jsx",
104
- "jsxImportSource": "elements-kit"
105
- }
106
- }
107
- ```
108
-
109
- ---
110
-
111
73
  ## Signals
112
74
 
113
75
  Fine-grained reactive state. Signals track their dependencies automatically — only the exact computeds and effects that depend on a changed signal are re-evaluated.
@@ -161,15 +123,13 @@ export const cart = new CartStore();
161
123
 
162
124
  Stores are **framework-agnostic** — the same instance drives a custom element, a React component, and a plain effect in sync.
163
125
 
164
- ---
165
-
166
126
  ## JSX → DOM
167
127
 
168
128
  JSX compiles directly to `document.createElement`. No virtual DOM, no diffing.
169
129
 
170
130
  ```tsx
171
131
  // This:
172
- const el = <button onClick={() => count(count() + 1)}>{count}</button>;
132
+ const el = <button on:click={() => count(count() + 1)}>{count}</button>;
173
133
 
174
134
  // Is equivalent to:
175
135
  const el = document.createElement("button");
@@ -193,14 +153,11 @@ const name = signal("Alice");
193
153
  | Syntax | Effect |
194
154
  |--------|--------|
195
155
  | `{signal}` / `{() => fn()}` | Live-bound reactive child |
196
- | `onClick={fn}` | Event listener (camelCase `onclick`) |
197
- | `on:click={fn}` | Explicit event namespace |
156
+ | `on:click={fn}` | Event listener (case-preserving event name) |
198
157
  | `class:active={bool}` | Reactive `classList.toggle` |
199
158
  | `style:color={value}` | Reactive inline style property |
200
159
  | `prop:foo={val}` | Force property assignment (skips `setAttribute`) |
201
160
 
202
- ---
203
-
204
161
  ## Class Components
205
162
 
206
163
  Any class with a `render()` method returning an `Element` is a component. Components own their state and produce elements.
@@ -217,7 +174,7 @@ class Counter {
217
174
  return (
218
175
  <section>
219
176
  <p>{() => this.count} × 2 = {this.doubled}</p>
220
- <button onClick={() => this.count++}>+1</button>
177
+ <button on:click={() => this.count++}>+1</button>
221
178
  </section>
222
179
  ) as Element;
223
180
  }
@@ -226,8 +183,6 @@ class Counter {
226
183
  const unmount = render(document.getElementById("app")!, () => <Counter/>);
227
184
  ```
228
185
 
229
- ---
230
-
231
186
  ## Custom Elements
232
187
 
233
188
  ElementsKit enhances native `HTMLElement` subclasses — start with the platform, add only what you need.
@@ -254,7 +209,7 @@ class CounterElement extends HTMLElement {
254
209
  this.#unmount = render(this, () => (
255
210
  <section>
256
211
  <p>{() => this.count} × 2 = {this.doubled}</p>
257
- <button onClick={() => this.count++}>+1</button>
212
+ <button on:click={() => this.count++}>+1</button>
258
213
  </section>
259
214
  ));
260
215
  }
@@ -288,9 +243,7 @@ declare module "elements-kit/custom-elements" {
288
243
  // Now `<x-counter count={5} />` is fully typed — no hand-written `declare global` block.
289
244
  ```
290
245
 
291
- See [Types](docs/src/content/docs/writing-ui/types.mdx) for the full set of prop-inference helpers.
292
-
293
- ---
246
+ See [Types](docs/src/content/docs/elements/types.mdx) for the full set of prop-inference helpers.
294
247
 
295
248
  ## React Integration
296
249
 
@@ -316,8 +269,6 @@ function CartSummary() {
316
269
 
317
270
  The same `cart` store drives custom elements, React trees, and plain scripts — all in sync.
318
271
 
319
- ---
320
-
321
272
  ## Utilities
322
273
 
323
274
  Pre-built reactive wrappers around common browser APIs. Each utility lives at its own subpath (`elements-kit/utilities/<name>`) and ships as its own entry — you pay only for what you import. Full catalog in [src/utilities/README.md](src/utilities/README.md).
@@ -344,8 +295,6 @@ import { windowFocused } from "elements-kit/utilities/window-focus";
344
295
  effect(() => console.log("online:", online(), "focused:", windowFocused()));
345
296
  ```
346
297
 
347
- ---
348
-
349
298
  ## Async & Promise
350
299
 
351
300
  Two primitives convert imperative async work into reactive state: `promise` (minimal, any `Promise` → reactive state) and `async` (full controller with start/stop/run and optional reactive input).
@@ -436,8 +385,6 @@ const fetchTodo = async(() => {
436
385
  effect(() => console.log(fetchTodo.state, fetchTodo.value));
437
386
  ```
438
387
 
439
- ---
440
-
441
388
  ## `For` — Keyed List Rendering
442
389
 
443
390
  Reconciles a reactive array into the DOM. Each item renders once per key — no full re-renders on reorder, add, or remove. `T` is inferred from `each`.
@@ -457,34 +404,31 @@ import { For } from "elements-kit/for";
457
404
  </ul>
458
405
  ```
459
406
 
460
- ---
461
-
462
407
  ## Prop types
463
408
 
464
- Six type helpers derive JSX prop shapes from your components — no parallel `declare global` block to maintain. Full guide at [docs/src/content/docs/writing-ui/types.mdx](docs/src/content/docs/writing-ui/types.mdx).
409
+ Six type helpers derive JSX prop shapes from your components — no parallel `declare global` block to maintain. Full guide at [docs/src/content/docs/elements/types.mdx](docs/src/content/docs/elements/types.mdx).
465
410
 
466
411
  | Helper | For |
467
412
  | ------ | --- |
468
413
  | `ElementProps<typeof Cls>` | `HTMLElement` subclass — full surface (attrs, events, slots, children) |
469
414
  | `Props<C>` | Class instance, constructor, or function component — unified |
470
415
  | `ComponentProps<typeof Cls>` | Class components with `constructor(props: P)` |
471
- | `MaybeReactiveProps<P>` | Wrap every prop in `MaybeReactive` |
416
+ | `MaybeReactiveProps<P>` | Caller-facing — wrap every prop in `MaybeReactive` (what parents pass) |
417
+ | `ReactiveProps<P>` | Component-facing — every prop becomes a `Computed<T>` getter (what function components receive) |
472
418
  | `MaybeReactive<T>` | Scalar value-or-getter (from `elements-kit/signals`) |
473
419
  | `Require<P, K>` | Promote optional keys to required |
474
420
 
475
- Function components pair `MaybeReactiveProps<P>` on the signature with `resolveProps` at the top of the body each key becomes a callable getter, subscribing to updates on read:
421
+ The JSX runtime auto-wraps function-component props each key arrives as a callable getter that subscribes on read. Pair the signature with `ReactiveProps<P>` and read `props.x()`:
476
422
 
477
423
  ```tsx
478
- import { resolveProps } from "elements-kit/signals";
479
- import type { MaybeReactiveProps } from "elements-kit/jsx-runtime";
424
+ import type { ReactiveProps } from "elements-kit/jsx-runtime";
480
425
 
481
- function Greeting(raw: MaybeReactiveProps<{ name: string }>) {
482
- const props = resolveProps(raw);
426
+ function Greeting(props: ReactiveProps<{ name: string }>) {
483
427
  return <p>Hello, {props.name}</p>;
484
428
  }
485
429
  ```
486
430
 
487
- ---
431
+ `resolveProps` stays exported for non-JSX call sites or nested prop bags.
488
432
 
489
433
  ## `@reactive()` Decorator
490
434
 
@@ -503,8 +447,6 @@ class TodoApp {
503
447
  }
504
448
  ```
505
449
 
506
- ---
507
-
508
450
  ## `@attributes` Decorator
509
451
 
510
452
  Wires `observedAttributes` and `attributeChangedCallback` from a static map:
@@ -541,10 +483,15 @@ For typed events, declare a `static events` map:
541
483
  class XPicker extends HTMLElement {
542
484
  declare static events: { commit: CustomEvent<number> };
543
485
  }
544
- // ElementProps<typeof XPicker> now includes `on:commit` / `onCommit`
486
+ // ElementProps<typeof XPicker> now includes `on:commit`
545
487
  ```
546
488
 
547
- ---
489
+ ## Learn more
490
+
491
+ - [Documentation site](docs/) — guides, playgrounds, reference
492
+ - [Philosophy](docs/src/content/docs/getting-started/philosophy.mdx) — deeper reasoning behind the five principles
493
+ - [ARCHITECTURE.md](ARCHITECTURE.md) — how the library works
494
+ - [CONTRIBUTING.md](CONTRIBUTING.md) — build, test, PR checklist
548
495
 
549
496
  ## Roadmap
550
497
 
@@ -1,7 +1,28 @@
1
1
  //#region src/attributes.d.ts
2
+ /**
3
+ * Handler signature for a single observed attribute.
4
+ *
5
+ * `this` is bound to the element instance, letting the handler assign
6
+ * directly to reactive properties. `value` is the raw HTML string (or `null`
7
+ * when the attribute is removed) — conversion to typed JS is the handler's job.
8
+ */
2
9
  interface AttrChangeHandler<T> {
3
10
  (this: T, value: string | null, oldValue?: string | null): void;
4
11
  }
12
+ /**
13
+ * Static-field key used by the `@attributes` decorator (and
14
+ * {@link dispatchAttrChange} / {@link observedAttributes}) to locate the
15
+ * attribute handler map on a custom-element class.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * class MyElement extends HTMLElement {
20
+ * static [ATTRIBUTES]: Attributes<MyElement> = {
21
+ * name(value) { this.name = value ?? ""; },
22
+ * };
23
+ * }
24
+ * ```
25
+ */
5
26
  declare const ATTRIBUTES: unique symbol;
6
27
  /**
7
28
  * Dispatches an attribute change to the matching handler in the static `attributes` map,
@@ -27,6 +48,10 @@ declare function dispatchAttrChange<T extends {
27
48
  [ATTRIBUTES]: Record<string, AttrChangeHandler<T>>;
28
49
  };
29
50
  }>(this: T, name: string, oldValue: string | null, newValue: string | null): void;
51
+ /**
52
+ * Shape of the static `[ATTRIBUTES]` map: attribute name → handler bound to
53
+ * the element instance `T`.
54
+ */
30
55
  type Attributes<T> = Record<string, AttrChangeHandler<T>>;
31
56
  /**
32
57
  * Returns a deduplicated array of all observed attribute names for a custom element class and its ancestors.
@@ -63,6 +88,22 @@ declare function observedAttributes(cls: {
63
88
  observedAttributes?: string[];
64
89
  prototype: unknown;
65
90
  }): string[];
91
+ /**
92
+ * Pre-decoration shape required by `@attributes` — a class constructor
93
+ * carrying a static `[ATTRIBUTES]` handler map.
94
+ */
95
+ type AttributeTarget<T extends abstract new (...args: any[]) => HTMLElement> = T & {
96
+ [ATTRIBUTES]: Record<string, AttrChangeHandler<InstanceType<T>>>;
97
+ };
98
+ /**
99
+ * Post-decoration shape returned by `@attributes`: adds `observedAttributes`
100
+ * to the constructor and `attributeChangedCallback` to the prototype.
101
+ */
102
+ type AttributeDecorated<T extends abstract new (...args: any[]) => HTMLElement> = T & (new (...args: any[]) => InstanceType<T> & {
103
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
104
+ }) & {
105
+ observedAttributes: string[];
106
+ };
66
107
  /**
67
108
  * A class decorator that automatically wires up `observedAttributes` and `attributeChangedCallback`
68
109
  * from a static `[ATTRIBUTES]` map.
@@ -71,7 +112,7 @@ declare function observedAttributes(cls: {
71
112
  *
72
113
  * @example
73
114
  * ```ts
74
- * @attributes
115
+ * \@attributes
75
116
  * class MyElement extends HTMLElement {
76
117
  * static [ATTRIBUTES] = {
77
118
  * count(this: MyElement, value: string | null) {
@@ -81,14 +122,6 @@ declare function observedAttributes(cls: {
81
122
  * }
82
123
  * ```
83
124
  */
84
- type AttributeTarget<T extends abstract new (...args: any[]) => HTMLElement> = T & {
85
- [ATTRIBUTES]: Record<string, AttrChangeHandler<InstanceType<T>>>;
86
- };
87
- type AttributeDecorated<T extends abstract new (...args: any[]) => HTMLElement> = T & (new (...args: any[]) => InstanceType<T> & {
88
- attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
89
- }) & {
90
- observedAttributes: string[];
91
- };
92
125
  declare function attributes<T extends abstract new (...args: any[]) => HTMLElement>(target: AttributeTarget<T>, context: ClassDecoratorContext<T>): AttributeDecorated<T>;
93
126
  //#endregion
94
127
  export { Attributes as a, observedAttributes as c, AttributeTarget as i, AttrChangeHandler as n, attributes as o, AttributeDecorated as r, dispatchAttrChange as s, ATTRIBUTES as t };
@@ -1,2 +1,2 @@
1
- import { a as Attributes, c as observedAttributes, i as AttributeTarget, n as AttrChangeHandler, o as attributes, r as AttributeDecorated, s as dispatchAttrChange, t as ATTRIBUTES } from "./attributes-Dtn68R1u.mjs";
1
+ import { a as Attributes, c as observedAttributes, i as AttributeTarget, n as AttrChangeHandler, o as attributes, r as AttributeDecorated, s as dispatchAttrChange, t as ATTRIBUTES } from "./attributes-DILeh3-s.mjs";
2
2
  export { ATTRIBUTES, AttrChangeHandler, AttributeDecorated, AttributeTarget, Attributes, attributes, dispatchAttrChange, observedAttributes };
@@ -1,4 +1,18 @@
1
1
  //#region src/attributes.ts
2
+ /**
3
+ * Static-field key used by the `@attributes` decorator (and
4
+ * {@link dispatchAttrChange} / {@link observedAttributes}) to locate the
5
+ * attribute handler map on a custom-element class.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * class MyElement extends HTMLElement {
10
+ * static [ATTRIBUTES]: Attributes<MyElement> = {
11
+ * name(value) { this.name = value ?? ""; },
12
+ * };
13
+ * }
14
+ * ```
15
+ */
2
16
  const ATTRIBUTES = Symbol("attributes");
3
17
  /**
4
18
  * Dispatches an attribute change to the matching handler in the static `attributes` map,
@@ -68,6 +82,24 @@ function observedAttributes(cls) {
68
82
  }
69
83
  return Array.from(s);
70
84
  }
85
+ /**
86
+ * A class decorator that automatically wires up `observedAttributes` and `attributeChangedCallback`
87
+ * from a static `[ATTRIBUTES]` map.
88
+ *
89
+ * The `this` type inside attribute handlers is automatically inferred from the decorated class.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * \@attributes
94
+ * class MyElement extends HTMLElement {
95
+ * static [ATTRIBUTES] = {
96
+ * count(this: MyElement, value: string | null) {
97
+ * this.count = Number(value);
98
+ * },
99
+ * };
100
+ * }
101
+ * ```
102
+ */
71
103
  function attributes(target, context) {
72
104
  context.addInitializer(function() {
73
105
  target.observedAttributes = observedAttributes(target);
@@ -1,11 +1,11 @@
1
- //#region src/define.d.ts
1
+ //#region src/custom-elements.d.ts
2
2
  /**
3
3
  * Registry of custom-element tags to their constructors.
4
4
  * Users augment this interface to add typed JSX support for their elements:
5
5
  *
6
6
  * @example
7
7
  * ```ts
8
- * declare module "elements-kit" {
8
+ * declare module "elements-kit/custom-elements" {
9
9
  * interface CustomElementRegistry {
10
10
  * "x-range": typeof XRange;
11
11
  * }
@@ -17,6 +17,24 @@ type AnyCtor = CustomElementConstructor;
17
17
  /**
18
18
  * Register a custom element with the browser and return its class.
19
19
  * Pair with a module augmentation of `CustomElementRegistry` to get typed JSX.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * import { defineElement } from "elements-kit/custom-elements";
24
+ *
25
+ * class XCounter extends HTMLElement {}
26
+ *
27
+ * defineElement("x-counter", XCounter);
28
+ *
29
+ * declare module "elements-kit/custom-elements" {
30
+ * interface CustomElementRegistry {
31
+ * "x-counter": typeof XCounter;
32
+ * }
33
+ * }
34
+ *
35
+ * // JSX now gets typed props + typed ref
36
+ * // <x-counter />
37
+ * ```
20
38
  */
21
39
  declare function defineElement<Tag extends `${string}-${string}`, C extends AnyCtor>(tag: Tag, cls: C, options?: ElementDefinitionOptions): C;
22
40
  //#endregion
@@ -1,74 +1,2 @@
1
- import { n as defineElement, t as CustomElementRegistry } from "./define-CjbTZ3VG.mjs";
2
-
3
- //#region src/custom-elements.d.ts
4
- /**
5
- * Runs `setup` inside a fresh `effectScope` and returns both its result and
6
- * the scope's dispose handle.
7
- *
8
- * Use this wherever you need to run reactive code with an explicit lifetime
9
- * outside the JSX element flow — most commonly inside a custom element's
10
- * `connectedCallback`. `onCleanup`, nested `effect`s and any other
11
- * scope-bound registrations made in `setup` are owned by the returned
12
- * `dispose`.
13
- *
14
- * `untracked` detaches the new scope from any enclosing effect so it isn't
15
- * torn down when that effect re-runs — its lifetime is solely the caller's
16
- * responsibility.
17
- *
18
- * @example
19
- * ```ts
20
- * class Clock extends HTMLElement {
21
- * #dispose?: () => void;
22
- *
23
- * connectedCallback() {
24
- * const { dispose } = renderScope(() => {
25
- * const id = setInterval(() => (this.textContent = String(Date.now())), 1000);
26
- * onCleanup(() => clearInterval(id));
27
- * });
28
- * this.#dispose = dispose;
29
- * }
30
- *
31
- * disconnectedCallback() {
32
- * this.#dispose?.();
33
- * this.#dispose = undefined;
34
- * }
35
- * }
36
- * ```
37
- */
38
- declare function renderScope<T>(setup: () => T): {
39
- result: T;
40
- dispose: () => void;
41
- };
42
- /**
43
- * Runs `setup` inside an `effectScope` tied to `el`'s connected lifetime.
44
- *
45
- * Call from `connectedCallback`. Effects, `onCleanup` registrations, and
46
- * reactive reads inside `setup` belong to this scope. Pair with
47
- * {@link disconnectedScope} from `disconnectedCallback` to dispose.
48
- *
49
- * Safe to call more than once (e.g. if the element is reconnected after
50
- * disconnection): the previous scope is disposed first.
51
- *
52
- * @example
53
- * ```ts
54
- * class Clock extends HTMLElement {
55
- * connectedCallback() {
56
- * connectedScope(this, () => {
57
- * const id = setInterval(() => this.textContent = String(Date.now()), 1000);
58
- * onCleanup(() => clearInterval(id));
59
- * });
60
- * }
61
- * disconnectedCallback() {
62
- * disconnectedScope(this);
63
- * }
64
- * }
65
- * ```
66
- */
67
- declare function connectedScope(el: HTMLElement, setup: () => void): void;
68
- /**
69
- * Disposes the scope previously created by {@link connectedScope} for `el`.
70
- * No-op if there is no active scope.
71
- */
72
- declare function disconnectedScope(el: HTMLElement): void;
73
- //#endregion
74
- export { type CustomElementRegistry, connectedScope, defineElement, disconnectedScope, renderScope };
1
+ import { n as defineElement, t as CustomElementRegistry } from "./custom-elements-D5_NMNyD.mjs";
2
+ export { CustomElementRegistry, defineElement };