elements-kit 0.0.19 → 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 +51 -104
- package/dist/{attributes-aiRoArZz.d.mts → attributes-DILeh3-s.d.mts} +42 -9
- package/dist/attributes.d.mts +1 -1
- package/dist/attributes.mjs +32 -0
- package/dist/{custom-elements-bVYOkHKt.d.mts → custom-elements-D5_NMNyD.d.mts} +18 -0
- package/dist/custom-elements.d.mts +1 -1
- package/dist/custom-elements.mjs +18 -0
- package/dist/{element-DxmInKJw.mjs → element-w1GCIMVp.mjs} +1 -1
- package/dist/for.d.mts +31 -2
- package/dist/for.mjs +16 -1
- package/dist/{infer-Dv5Wk-7E.d.mts → infer-DuFY-y2b.d.mts} +66 -27
- package/dist/integrations/react.d.mts +1 -1
- package/dist/jsx-runtime/index.d.mts +1 -1
- package/dist/jsx-runtime/index.mjs +1 -1
- package/dist/signals/index.d.mts +1 -1
- package/dist/signals/index.mjs +21 -2
- package/dist/{slot-Kb61AcgW.mjs → slot-CKtUoy2X.mjs} +0 -1
- package/dist/{slot-B5_VHB7E.d.mts → slot-D5iBUSAm.d.mts} +8 -1
- package/dist/slot.d.mts +1 -1
- package/dist/slot.mjs +1 -1
- package/dist/utilities/active-element.d.mts +1 -1
- package/dist/utilities/async.d.mts +39 -1
- package/dist/utilities/async.mjs +37 -0
- package/dist/utilities/debounced.d.mts +12 -1
- package/dist/utilities/debounced.mjs +11 -0
- package/dist/utilities/element-rect.d.mts +1 -1
- package/dist/utilities/element-scroll.d.mts +1 -1
- package/dist/utilities/environment.d.mts +2 -0
- package/dist/utilities/environment.mjs +2 -0
- package/dist/utilities/event-driven.d.mts +1 -1
- package/dist/utilities/event-listener.d.mts +12 -1
- package/dist/utilities/focus-within.d.mts +1 -1
- package/dist/utilities/hover.d.mts +1 -1
- package/dist/utilities/interval.d.mts +14 -1
- package/dist/utilities/location.d.mts +1 -1
- package/dist/utilities/media-devices.d.mts +1 -1
- package/dist/utilities/media-player.d.mts +1 -1
- package/dist/utilities/media-query.d.mts +1 -1
- package/dist/utilities/network.d.mts +1 -1
- package/dist/utilities/orientation.d.mts +1 -1
- package/dist/utilities/previous.d.mts +13 -1
- package/dist/utilities/previous.mjs +12 -0
- package/dist/utilities/promise.d.mts +7 -1
- package/dist/utilities/retry.d.mts +15 -0
- package/dist/utilities/retry.mjs +15 -0
- package/dist/utilities/routing.d.mts +12 -1
- package/dist/utilities/routing.mjs +11 -0
- package/dist/utilities/search-params.d.mts +1 -1
- package/dist/utilities/storage.d.mts +18 -1
- package/dist/utilities/storage.mjs +17 -0
- package/dist/utilities/throttled.d.mts +12 -1
- package/dist/utilities/throttled.mjs +11 -0
- package/dist/utilities/timeout.d.mts +1 -1
- package/dist/utilities/window-focus.d.mts +1 -1
- package/dist/utilities/window-size.d.mts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,94 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="docs/public/og.svg" alt="ElementsKit" width="600" />
|
|
3
|
-
</p>
|
|
1
|
+
# ElementsKit 🌱
|
|
4
2
|
|
|
5
|
-
|
|
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
|
|
11
|
-
import {
|
|
12
|
-
|
|
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
|
-
};
|
|
6
|
+
import { signal, computed } from "elements-kit/signals";
|
|
7
|
+
import { render } from "elements-kit/render";
|
|
8
|
+
import type { ReactiveProps } from "elements-kit/jsx-runtime";
|
|
20
9
|
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
function Counter(props: ReactiveProps<{ initial?: number }>) {
|
|
11
|
+
const count = signal(props.initial() ?? 0);
|
|
12
|
+
const doubled = computed(() => count() * 2);
|
|
23
13
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
32
|
-
}
|
|
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
|
+
);
|
|
33
21
|
}
|
|
34
22
|
|
|
35
|
-
|
|
23
|
+
render(document.getElementById("app")!, () => <Counter initial={0} />);
|
|
36
24
|
```
|
|
37
25
|
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Packages
|
|
41
|
-
|
|
42
|
-
Every feature is a separate subpath export — import only what you use.
|
|
43
|
-
|
|
44
|
-
| Entry | Purpose |
|
|
45
|
-
|-------|---------|
|
|
46
|
-
| `elements-kit` | `For` component and core re-exports |
|
|
47
|
-
| `elements-kit/signals` | `signal`, `computed`, `effect`, `effectScope`, `batch`, `untracked`, `trigger`, `onCleanup`, `MaybeReactive`, `resolve`, `resolveProps`, `@reactive` |
|
|
48
|
-
| `elements-kit/render` | `render(target, setup)` — mount a node with a scoped lifetime; returns `unmount` |
|
|
49
|
-
| `elements-kit/attributes` | `@attributes` decorator + `ATTRIBUTES` symbol |
|
|
50
|
-
| `elements-kit/slot` | `Slot`, `Slots`, `SLOTS` symbol — comment-marker DOM regions |
|
|
51
|
-
| `elements-kit/custom-elements` | `defineElement`, `CustomElementRegistry` |
|
|
52
|
-
| `elements-kit/for` | `For` keyed-list component |
|
|
53
|
-
| `elements-kit/jsx-runtime` | JSX factory + type helpers (`ElementProps`, `Props`, `ComponentProps`, `MaybeReactiveProps`, `ReactiveProps`, `Require`) — configure via `jsxImportSource` |
|
|
54
|
-
| `elements-kit/integrations/react` | `useSignal`, `useScope` React bridge hooks |
|
|
55
|
-
| `elements-kit/utilities/*` | Reactive browser-API utilities — see [src/utilities/README.md](src/utilities/README.md) |
|
|
56
|
-
|
|
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
26
|
## Installation
|
|
93
27
|
|
|
94
28
|
```sh
|
|
@@ -106,7 +40,35 @@ Configure JSX in your `tsconfig.json`:
|
|
|
106
40
|
}
|
|
107
41
|
```
|
|
108
42
|
|
|
109
|
-
|
|
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.
|
|
56
|
+
|
|
57
|
+
## Packages
|
|
58
|
+
|
|
59
|
+
Every feature is a separate subpath export — import only what you use.
|
|
60
|
+
|
|
61
|
+
| Entry | Purpose |
|
|
62
|
+
|-------|---------|
|
|
63
|
+
| `elements-kit/signals` | `signal`, `computed`, `effect`, `effectScope`, `batch`, `untracked`, `trigger`, `onCleanup`, `MaybeReactive`, `resolve`, `resolveProps`, `@reactive` |
|
|
64
|
+
| `elements-kit/render` | `render(target, setup)` — mount a node with a scoped lifetime; returns `unmount` |
|
|
65
|
+
| `elements-kit/attributes` | `@attributes` decorator + `ATTRIBUTES` symbol |
|
|
66
|
+
| `elements-kit/slot` | `Slot`, `Slots`, `SLOTS` symbol — comment-marker DOM regions |
|
|
67
|
+
| `elements-kit/custom-elements` | `defineElement`, `CustomElementRegistry` |
|
|
68
|
+
| `elements-kit/for` | `For` keyed-list component |
|
|
69
|
+
| `elements-kit/jsx-runtime` | JSX factory + type helpers (`ElementProps`, `Props`, `ComponentProps`, `MaybeReactiveProps`, `ReactiveProps`, `Require`) — configure via `jsxImportSource` |
|
|
70
|
+
| `elements-kit/integrations/react` | `useSignal`, `useScope` React bridge hooks |
|
|
71
|
+
| `elements-kit/utilities/*` | Reactive browser-API utilities — see [src/utilities/README.md](src/utilities/README.md) |
|
|
110
72
|
|
|
111
73
|
## Signals
|
|
112
74
|
|
|
@@ -161,8 +123,6 @@ 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.
|
|
@@ -198,8 +158,6 @@ const name = signal("Alice");
|
|
|
198
158
|
| `style:color={value}` | Reactive inline style property |
|
|
199
159
|
| `prop:foo={val}` | Force property assignment (skips `setAttribute`) |
|
|
200
160
|
|
|
201
|
-
---
|
|
202
|
-
|
|
203
161
|
## Class Components
|
|
204
162
|
|
|
205
163
|
Any class with a `render()` method returning an `Element` is a component. Components own their state and produce elements.
|
|
@@ -225,8 +183,6 @@ class Counter {
|
|
|
225
183
|
const unmount = render(document.getElementById("app")!, () => <Counter/>);
|
|
226
184
|
```
|
|
227
185
|
|
|
228
|
-
---
|
|
229
|
-
|
|
230
186
|
## Custom Elements
|
|
231
187
|
|
|
232
188
|
ElementsKit enhances native `HTMLElement` subclasses — start with the platform, add only what you need.
|
|
@@ -289,8 +245,6 @@ declare module "elements-kit/custom-elements" {
|
|
|
289
245
|
|
|
290
246
|
See [Types](docs/src/content/docs/elements/types.mdx) for the full set of prop-inference helpers.
|
|
291
247
|
|
|
292
|
-
---
|
|
293
|
-
|
|
294
248
|
## React Integration
|
|
295
249
|
|
|
296
250
|
Connect signals and stores to React components via `useSyncExternalStore`:
|
|
@@ -315,8 +269,6 @@ function CartSummary() {
|
|
|
315
269
|
|
|
316
270
|
The same `cart` store drives custom elements, React trees, and plain scripts — all in sync.
|
|
317
271
|
|
|
318
|
-
---
|
|
319
|
-
|
|
320
272
|
## Utilities
|
|
321
273
|
|
|
322
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).
|
|
@@ -343,8 +295,6 @@ import { windowFocused } from "elements-kit/utilities/window-focus";
|
|
|
343
295
|
effect(() => console.log("online:", online(), "focused:", windowFocused()));
|
|
344
296
|
```
|
|
345
297
|
|
|
346
|
-
---
|
|
347
|
-
|
|
348
298
|
## Async & Promise
|
|
349
299
|
|
|
350
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).
|
|
@@ -435,8 +385,6 @@ const fetchTodo = async(() => {
|
|
|
435
385
|
effect(() => console.log(fetchTodo.state, fetchTodo.value));
|
|
436
386
|
```
|
|
437
387
|
|
|
438
|
-
---
|
|
439
|
-
|
|
440
388
|
## `For` — Keyed List Rendering
|
|
441
389
|
|
|
442
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`.
|
|
@@ -456,8 +404,6 @@ import { For } from "elements-kit/for";
|
|
|
456
404
|
</ul>
|
|
457
405
|
```
|
|
458
406
|
|
|
459
|
-
---
|
|
460
|
-
|
|
461
407
|
## Prop types
|
|
462
408
|
|
|
463
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).
|
|
@@ -484,8 +430,6 @@ function Greeting(props: ReactiveProps<{ name: string }>) {
|
|
|
484
430
|
|
|
485
431
|
`resolveProps` stays exported for non-JSX call sites or nested prop bags.
|
|
486
432
|
|
|
487
|
-
---
|
|
488
|
-
|
|
489
433
|
## `@reactive()` Decorator
|
|
490
434
|
|
|
491
435
|
Makes any class field reactive — reads subscribe, writes trigger updates.
|
|
@@ -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:
|
|
@@ -544,7 +486,12 @@ class XPicker extends HTMLElement {
|
|
|
544
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
|
-
*
|
|
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 };
|
package/dist/attributes.d.mts
CHANGED
|
@@ -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-
|
|
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 };
|
package/dist/attributes.mjs
CHANGED
|
@@ -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);
|
|
@@ -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,2 +1,2 @@
|
|
|
1
|
-
import { n as defineElement, t as CustomElementRegistry } from "./custom-elements-
|
|
1
|
+
import { n as defineElement, t as CustomElementRegistry } from "./custom-elements-D5_NMNyD.mjs";
|
|
2
2
|
export { CustomElementRegistry, defineElement };
|
package/dist/custom-elements.mjs
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Register a custom element with the browser and return its class.
|
|
4
4
|
* Pair with a module augmentation of `CustomElementRegistry` to get typed JSX.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { defineElement } from "elements-kit/custom-elements";
|
|
9
|
+
*
|
|
10
|
+
* class XCounter extends HTMLElement {}
|
|
11
|
+
*
|
|
12
|
+
* defineElement("x-counter", XCounter);
|
|
13
|
+
*
|
|
14
|
+
* declare module "elements-kit/custom-elements" {
|
|
15
|
+
* interface CustomElementRegistry {
|
|
16
|
+
* "x-counter": typeof XCounter;
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* // JSX now gets typed props + typed ref
|
|
21
|
+
* // <x-counter />
|
|
22
|
+
* ```
|
|
5
23
|
*/
|
|
6
24
|
function defineElement(tag, cls, options) {
|
|
7
25
|
customElements.define(tag, cls, options);
|
|
@@ -2,7 +2,7 @@ import { c as effectScope, g as untracked, p as onCleanup, s as effect } from ".
|
|
|
2
2
|
import "./polyfill-B1lNNcum.mjs";
|
|
3
3
|
import { isReactive, resolveProps } from "./signals/index.mjs";
|
|
4
4
|
import { on } from "./utilities/event-listener.mjs";
|
|
5
|
-
import { i as resolveNode$1, n as Slot, r as Slots, t as SLOTS } from "./slot-
|
|
5
|
+
import { i as resolveNode$1, n as Slot, r as Slots, t as SLOTS } from "./slot-CKtUoy2X.mjs";
|
|
6
6
|
//#region \0rolldown/runtime.js
|
|
7
7
|
var __defProp = Object.defineProperty;
|
|
8
8
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
package/dist/for.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as Props, s as Require } from "./infer-
|
|
1
|
+
import { i as Props, s as Require } from "./infer-DuFY-y2b.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/for.d.ts
|
|
4
4
|
type KeyFn<T> = (item: T, index: number) => string | number;
|
|
@@ -30,8 +30,37 @@ type RenderFn<T> = (item: T, index: number) => Element | DocumentFragment | null
|
|
|
30
30
|
* Props for `<For>`, derived from its public instance fields.
|
|
31
31
|
* All props are optional — the class initializes sane defaults at runtime.
|
|
32
32
|
* Non-function props also accept a reactive getter.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* import { signal } from "elements-kit/signals";
|
|
37
|
+
* import { For } from "elements-kit";
|
|
38
|
+
*
|
|
39
|
+
* const todos = signal([{ id: 1, text: "write docs" }]);
|
|
40
|
+
*
|
|
41
|
+
* const props: ForProps<{ id: number; text: string }> = {
|
|
42
|
+
* each: todos,
|
|
43
|
+
* by: (t) => t.id,
|
|
44
|
+
* children: (t) => <li>{t.text}</li>,
|
|
45
|
+
* };
|
|
46
|
+
* ```
|
|
33
47
|
*/
|
|
34
48
|
type ForProps<T> = Require<Props<For<T>>, "each" | "children">;
|
|
49
|
+
/**
|
|
50
|
+
* Keyed list renderer. See {@link ForProps} for prop details.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* import { signal } from "elements-kit/signals";
|
|
55
|
+
* import { For } from "elements-kit";
|
|
56
|
+
*
|
|
57
|
+
* const todos = signal([{ id: 1, text: "write docs" }]);
|
|
58
|
+
*
|
|
59
|
+
* <For each={todos} by={(t) => t.id}>
|
|
60
|
+
* {(t) => <li>{t.text}</li>}
|
|
61
|
+
* </For>
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
35
64
|
declare class For<T = unknown> {
|
|
36
65
|
#private;
|
|
37
66
|
constructor(_props?: ForProps<T>);
|
|
@@ -42,4 +71,4 @@ declare class For<T = unknown> {
|
|
|
42
71
|
render(): DocumentFragment;
|
|
43
72
|
}
|
|
44
73
|
//#endregion
|
|
45
|
-
export { For
|
|
74
|
+
export { For };
|
package/dist/for.mjs
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { n as disposeElement } from "./element-
|
|
1
|
+
import { n as disposeElement } from "./element-w1GCIMVp.mjs";
|
|
2
2
|
import { c as effectScope, g as untracked, h as trigger, m as signal, p as onCleanup, s as effect } from "./lib-D6duEs38.mjs";
|
|
3
3
|
import "./signals/index.mjs";
|
|
4
4
|
//#region src/for.ts
|
|
5
|
+
/**
|
|
6
|
+
* Keyed list renderer. See {@link ForProps} for prop details.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { signal } from "elements-kit/signals";
|
|
11
|
+
* import { For } from "elements-kit";
|
|
12
|
+
*
|
|
13
|
+
* const todos = signal([{ id: 1, text: "write docs" }]);
|
|
14
|
+
*
|
|
15
|
+
* <For each={todos} by={(t) => t.id}>
|
|
16
|
+
* {(t) => <li>{t.text}</li>}
|
|
17
|
+
* </For>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
5
20
|
var For = class {
|
|
6
21
|
constructor(_props) {}
|
|
7
22
|
#each = signal([]);
|