elements-kit 0.19.0 → 0.21.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 +14 -0
- package/dist/await.d.mts +53 -0
- package/dist/await.mjs +70 -0
- package/dist/{custom-elements-D5CgfNKc.d.mts → custom-elements-BGcU6ldL.d.mts} +2 -0
- package/dist/custom-elements.d.mts +1 -1
- package/dist/{element-xQwq4ulc.mjs → element-D3om9yA6.mjs} +71 -4
- package/dist/for.d.mts +20 -26
- package/dist/for.mjs +29 -4
- package/dist/fragment-ROPRBJQd.mjs +61 -0
- package/dist/hydrate/index.d.mts +41 -0
- package/dist/hydrate/index.mjs +2 -0
- package/dist/hydrate-6Qx4n4Su.mjs +380 -0
- package/dist/integrations/astro-client.d.mts +17 -0
- package/dist/integrations/astro-client.mjs +23 -0
- package/dist/integrations/astro-server.d.mts +15 -0
- package/dist/integrations/astro-server.mjs +39 -0
- package/dist/integrations/astro-slots.d.mts +12 -0
- package/dist/integrations/astro-slots.mjs +30 -0
- package/dist/integrations/astro.d.mts +46 -0
- package/dist/integrations/astro.mjs +64 -0
- package/dist/integrations/react.d.mts +1 -1
- package/dist/integrations/react.mjs +2 -2
- package/dist/jsx-runtime/index.d.mts +1 -1
- package/dist/jsx-runtime/index.mjs +2 -20
- package/dist/{lib-Dkc7cV5F.mjs → lib-DYypKhxk.mjs} +63 -5
- package/dist/render.mjs +1 -1
- package/dist/{scope-CnEvL9Nd.mjs → scope-zbEG299F.mjs} +1 -1
- package/dist/server/index.d.mts +43 -0
- package/dist/server/index.mjs +2 -0
- package/dist/server-iFSng50i.mjs +385 -0
- package/dist/signals/index.d.mts +2 -2
- package/dist/signals/index.mjs +5 -3
- package/dist/{slot-B8y0aEoz.d.mts → slot-BFWXeFRl.d.mts} +6 -0
- package/dist/{slot-Cne__au7.mjs → slot-Dvf30O0B.mjs} +12 -1
- package/dist/slot.d.mts +1 -1
- package/dist/slot.mjs +1 -1
- package/dist/{infer-B7T5hi_D.d.mts → types-CUvFIgPa.d.mts} +140 -141
- package/dist/ui/badge/badge.css +5 -5
- package/dist/ui/button/button.css +15 -15
- package/dist/ui/card/card.css +2 -2
- package/dist/ui/group/group.css +61 -0
- package/dist/ui/otp-input/index.d.mts +132 -0
- package/dist/ui/otp-input/index.mjs +328 -0
- package/dist/ui/otp-input/otp-input.css +157 -0
- package/dist/ui/overlay/index.css +52 -4
- package/dist/ui/overlay/index.d.mts +237 -63
- package/dist/ui/overlay/index.mjs +659 -67
- package/dist/ui/overlay/overlay.css +58 -2
- package/dist/ui/styles/index.css +662 -0
- package/dist/ui/styles/radius.css +7 -7
- package/dist/utilities/_observe.mjs +1 -1
- package/dist/utilities/active-element.d.mts +1 -1
- package/dist/utilities/active-element.mjs +1 -1
- package/dist/utilities/async.d.mts +19 -2
- package/dist/utilities/async.mjs +49 -2
- package/dist/utilities/context.mjs +1 -1
- package/dist/utilities/debounced.d.mts +1 -1
- package/dist/utilities/debounced.mjs +1 -1
- package/dist/utilities/dom-lifecycle.bench.mjs +3255 -1
- package/dist/utilities/dom-lifecycle.mjs +1 -1
- package/dist/utilities/element-rect.d.mts +1 -1
- package/dist/utilities/element-rect.mjs +1 -1
- package/dist/utilities/element-scroll.d.mts +1 -1
- package/dist/utilities/event-driven.d.mts +1 -1
- package/dist/utilities/event-driven.mjs +1 -1
- package/dist/utilities/event-listener.d.mts +1 -1
- package/dist/utilities/event-listener.mjs +1 -1
- package/dist/utilities/focus-within.d.mts +1 -1
- package/dist/utilities/focus-within.mjs +1 -1
- package/dist/utilities/hover.d.mts +1 -1
- package/dist/utilities/hover.mjs +1 -1
- package/dist/utilities/interval.d.mts +1 -1
- package/dist/utilities/interval.mjs +1 -1
- package/dist/utilities/location.d.mts +1 -1
- package/dist/utilities/location.mjs +1 -1
- package/dist/utilities/media-devices.d.mts +1 -1
- package/dist/utilities/media-devices.mjs +1 -1
- package/dist/utilities/media-player.d.mts +1 -1
- package/dist/utilities/media-query.d.mts +1 -1
- package/dist/utilities/media-query.mjs +1 -1
- package/dist/utilities/network.d.mts +1 -1
- package/dist/utilities/network.mjs +1 -1
- package/dist/utilities/orientation.d.mts +1 -1
- package/dist/utilities/orientation.mjs +1 -1
- package/dist/utilities/previous.d.mts +1 -1
- package/dist/utilities/previous.mjs +1 -1
- package/dist/utilities/promise.d.mts +19 -2
- package/dist/utilities/promise.mjs +33 -3
- package/dist/utilities/retry.mjs +1 -1
- package/dist/utilities/routing.d.mts +1 -1
- package/dist/utilities/routing.mjs +1 -1
- package/dist/utilities/search-params.d.mts +1 -1
- package/dist/utilities/storage.d.mts +1 -1
- package/dist/utilities/throttled.d.mts +1 -1
- package/dist/utilities/throttled.mjs +1 -1
- package/dist/utilities/timeout.d.mts +1 -1
- package/dist/utilities/timeout.mjs +1 -1
- package/dist/utilities/window-focus.d.mts +1 -1
- package/dist/utilities/window-focus.mjs +1 -1
- package/dist/utilities/window-size.d.mts +1 -1
- package/dist/utilities/window-size.mjs +1 -1
- package/package.json +23 -1
- package/dist/benchmark.CX_oY03V-CSLAXL5f.mjs +0 -5145
- package/dist/magic-string.es-CXefOmkB.mjs +0 -1011
- package/dist/test.BmQO5GaM-Ddz9cDxc.mjs +0 -8266
- package/dist/utilities/active-element.test.d.mts +0 -1
- package/dist/utilities/active-element.test.mjs +0 -25
- package/dist/utilities/async.test.d.mts +0 -1
- package/dist/utilities/async.test.mjs +0 -275
- package/dist/utilities/context.test.d.mts +0 -1
- package/dist/utilities/context.test.mjs +0 -171
- package/dist/utilities/debounced.test.d.mts +0 -1
- package/dist/utilities/debounced.test.mjs +0 -68
- package/dist/utilities/dom-lifecycle.test.d.mts +0 -1
- package/dist/utilities/dom-lifecycle.test.mjs +0 -228
- package/dist/utilities/element-rect.test.d.mts +0 -1
- package/dist/utilities/element-rect.test.mjs +0 -101
- package/dist/utilities/element-scroll.test.d.mts +0 -1
- package/dist/utilities/element-scroll.test.mjs +0 -27
- package/dist/utilities/event-listener.test.d.mts +0 -1
- package/dist/utilities/event-listener.test.mjs +0 -60
- package/dist/utilities/focus-within.test.d.mts +0 -1
- package/dist/utilities/focus-within.test.mjs +0 -51
- package/dist/utilities/form-object.test.d.mts +0 -1
- package/dist/utilities/form-object.test.mjs +0 -408
- package/dist/utilities/hover.test.d.mts +0 -1
- package/dist/utilities/hover.test.mjs +0 -54
- package/dist/utilities/intersection-observer.test.d.mts +0 -1
- package/dist/utilities/intersection-observer.test.mjs +0 -46
- package/dist/utilities/interval.test.d.mts +0 -1
- package/dist/utilities/interval.test.mjs +0 -115
- package/dist/utilities/location.test.d.mts +0 -1
- package/dist/utilities/location.test.mjs +0 -61
- package/dist/utilities/long-press.test.d.mts +0 -1
- package/dist/utilities/long-press.test.mjs +0 -54
- package/dist/utilities/media-devices.test.d.mts +0 -1
- package/dist/utilities/media-devices.test.mjs +0 -44
- package/dist/utilities/media-player.test.d.mts +0 -1
- package/dist/utilities/media-player.test.mjs +0 -102
- package/dist/utilities/mutation-observer.test.d.mts +0 -1
- package/dist/utilities/mutation-observer.test.mjs +0 -48
- package/dist/utilities/network.test.d.mts +0 -1
- package/dist/utilities/network.test.mjs +0 -30
- package/dist/utilities/on-click-outside.test.d.mts +0 -1
- package/dist/utilities/on-click-outside.test.mjs +0 -45
- package/dist/utilities/previous.test.d.mts +0 -1
- package/dist/utilities/previous.test.mjs +0 -90
- package/dist/utilities/promise.test.d.mts +0 -1
- package/dist/utilities/promise.test.mjs +0 -158
- package/dist/utilities/retry.test.d.mts +0 -1
- package/dist/utilities/retry.test.mjs +0 -85
- package/dist/utilities/routing.test.d.mts +0 -1
- package/dist/utilities/routing.test.mjs +0 -129
- package/dist/utilities/search-params.test.d.mts +0 -1
- package/dist/utilities/search-params.test.mjs +0 -37
- package/dist/utilities/ssr.test.d.mts +0 -1
- package/dist/utilities/ssr.test.mjs +0 -65
- package/dist/utilities/storage.test.d.mts +0 -1
- package/dist/utilities/storage.test.mjs +0 -139
- package/dist/utilities/throttled.test.d.mts +0 -1
- package/dist/utilities/throttled.test.mjs +0 -58
- package/dist/utilities/timeout.test.d.mts +0 -1
- package/dist/utilities/timeout.test.mjs +0 -121
- package/dist/utilities/window-size.test.d.mts +0 -1
- package/dist/utilities/window-size.test.mjs +0 -43
package/README.md
CHANGED
|
@@ -67,7 +67,11 @@ Every feature is a separate subpath export — import only what you use.
|
|
|
67
67
|
| `elements-kit/custom-elements` | `defineElement`, `CustomElementRegistry` |
|
|
68
68
|
| `elements-kit/for` | `For` keyed-list component |
|
|
69
69
|
| `elements-kit/jsx-runtime` | JSX factory + type helpers (`ElementProps`, `Props`, `ComponentProps`, `MaybeReactiveProps`, `ReactiveProps`, `Require`) — configure via `jsxImportSource` |
|
|
70
|
+
| `elements-kit/server` | `renderToStream`, `renderToString` — streaming HTML rendering in any JS runtime (Node, edge/Workers), no DOM required *(experimental)* |
|
|
71
|
+
| `elements-kit/hydrate` | `hydrate(container, () => <App/>)` — adopt server-rendered DOM and make it interactive *(experimental)* |
|
|
72
|
+
| `elements-kit/await` | `Await` — loading boundary (Suspense equivalent); code splitting = `async` + dynamic import *(experimental)* |
|
|
70
73
|
| `elements-kit/integrations/react` | `useSignal`, `useScope` React bridge hooks |
|
|
74
|
+
| `elements-kit/integrations/astro` | `elementsKit()` Astro integration — elements-kit components as server-rendered, hydrated islands *(experimental)* |
|
|
71
75
|
| `elements-kit/utilities/*` | Reactive browser-API utilities — see [src/utilities/README.md](src/utilities/README.md) |
|
|
72
76
|
|
|
73
77
|
## Signals
|
|
@@ -488,6 +492,16 @@ class XPicker extends HTMLElement {
|
|
|
488
492
|
// ElementProps<typeof XPicker> now includes `on:commit`
|
|
489
493
|
```
|
|
490
494
|
|
|
495
|
+
## Roadmap
|
|
496
|
+
|
|
497
|
+
Directions under consideration for the SSR/islands layer (nothing here is committed):
|
|
498
|
+
|
|
499
|
+
- **Declarative Shadow DOM & custom-element SSR** — emit `<template shadowrootmode>` on the server and claim shadow roots at hydration, so elements-kit custom elements server-render inside *any* framework's HTML.
|
|
500
|
+
- **`ErrorBoundary` + `Await` error fallback** — first-class rejection handling; today a rejected awaitable settles into its reason.
|
|
501
|
+
- **Out-of-order streaming + richer `ek-data` serialization** — stream fallbacks immediately and swap content in when ready (today `Await` holds the stream); serialize Dates/Maps/cyclic values instead of JSON-only.
|
|
502
|
+
- **Astro extras** — View Transitions survival, a custom `client:interaction` directive, a live `server:defer` demo.
|
|
503
|
+
- **Hardening toward stable** — real-Astro end-to-end tests in CI (dev + build/preview), an Astro renderer-contract type-pin, SSR↔client parity and escaping property tests, seeding-alignment and stream-robustness suites. The `server` / `hydrate` / `await` / `integrations/astro` entries drop their *experimental* badges when this lands.
|
|
504
|
+
|
|
491
505
|
## Learn more
|
|
492
506
|
|
|
493
507
|
- [Documentation site](docs/) — guides, playgrounds, reference
|
package/dist/await.d.mts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { t as Child } from "./types-CUvFIgPa.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/await.d.ts
|
|
4
|
+
/** @internal Metadata stamped on an Await region getter (see claim walk). */
|
|
5
|
+
interface AsyncRegionMeta {
|
|
6
|
+
/** ek-data ids the server consumed for this region. */
|
|
7
|
+
ids: number;
|
|
8
|
+
/** True while any of the region's awaitables is pending. */
|
|
9
|
+
pending(): boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Loading boundary for async children — elements-kit's `Suspense` equivalent.
|
|
13
|
+
*
|
|
14
|
+
* Direct async children (`promise`/`async` values — including the
|
|
15
|
+
* code-splitting pattern `async(() => import("./chart"))`) are detected
|
|
16
|
+
* automatically; pass `when` to gate on arbitrary awaitables instead. While
|
|
17
|
+
* anything is pending the client renders `fallback`; once everything settles
|
|
18
|
+
* the children show. The server never renders the fallback — the stream
|
|
19
|
+
* awaits and emits the real content. During hydration the server content
|
|
20
|
+
* stays visible while the region is pending (no fallback flash).
|
|
21
|
+
*
|
|
22
|
+
* Prefer a thunk fallback (`fallback={() => <Spinner/>}`) so it renders
|
|
23
|
+
* fresh each time the boundary re-enters a pending state.
|
|
24
|
+
*
|
|
25
|
+
* @example Code splitting with `async` + dynamic import:
|
|
26
|
+
* ```tsx
|
|
27
|
+
* const chart = async(() => import("./chart").then((m) => m.default));
|
|
28
|
+
*
|
|
29
|
+
* function Panel() {
|
|
30
|
+
* chart.run(); // server: awaited · hydration: deferred · client: import
|
|
31
|
+
* return (
|
|
32
|
+
* <Await fallback={() => <em>loading…</em>}>{chart}</Await>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Passing props to a code-split component:
|
|
38
|
+
* ```tsx
|
|
39
|
+
* const chart = async(() => import("./chart").then((m) => m.default));
|
|
40
|
+
* chart.run();
|
|
41
|
+
*
|
|
42
|
+
* <Await fallback={() => <em>loading…</em>}>
|
|
43
|
+
* {promise(chart.then((C) => () => <C data={data} />))}
|
|
44
|
+
* </Await>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function Await(props: {
|
|
48
|
+
fallback?: Child | (() => Child);
|
|
49
|
+
when?: unknown;
|
|
50
|
+
children?: Child;
|
|
51
|
+
}): Element;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { AsyncRegionMeta, Await };
|
package/dist/await.mjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { f as effectsInert, t as ASYNC_REGION } from "./lib-DYypKhxk.mjs";
|
|
2
|
+
import { isReactive } from "./signals/index.mjs";
|
|
3
|
+
import { isReactivePromiseLike, promise } from "./utilities/promise.mjs";
|
|
4
|
+
import { isAsyncLike } from "./utilities/async.mjs";
|
|
5
|
+
//#region src/await.ts
|
|
6
|
+
function isThenable(value) {
|
|
7
|
+
return value != null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
8
|
+
}
|
|
9
|
+
function toAwaitables(value) {
|
|
10
|
+
const list = Array.isArray(value) ? value.flat(Infinity) : [value];
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const item of list) if (isReactivePromiseLike(item) || isAsyncLike(item)) out.push(item);
|
|
13
|
+
else if (isThenable(item)) out.push(promise(item));
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Loading boundary for async children — elements-kit's `Suspense` equivalent.
|
|
18
|
+
*
|
|
19
|
+
* Direct async children (`promise`/`async` values — including the
|
|
20
|
+
* code-splitting pattern `async(() => import("./chart"))`) are detected
|
|
21
|
+
* automatically; pass `when` to gate on arbitrary awaitables instead. While
|
|
22
|
+
* anything is pending the client renders `fallback`; once everything settles
|
|
23
|
+
* the children show. The server never renders the fallback — the stream
|
|
24
|
+
* awaits and emits the real content. During hydration the server content
|
|
25
|
+
* stays visible while the region is pending (no fallback flash).
|
|
26
|
+
*
|
|
27
|
+
* Prefer a thunk fallback (`fallback={() => <Spinner/>}`) so it renders
|
|
28
|
+
* fresh each time the boundary re-enters a pending state.
|
|
29
|
+
*
|
|
30
|
+
* @example Code splitting with `async` + dynamic import:
|
|
31
|
+
* ```tsx
|
|
32
|
+
* const chart = async(() => import("./chart").then((m) => m.default));
|
|
33
|
+
*
|
|
34
|
+
* function Panel() {
|
|
35
|
+
* chart.run(); // server: awaited · hydration: deferred · client: import
|
|
36
|
+
* return (
|
|
37
|
+
* <Await fallback={() => <em>loading…</em>}>{chart}</Await>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example Passing props to a code-split component:
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const chart = async(() => import("./chart").then((m) => m.default));
|
|
45
|
+
* chart.run();
|
|
46
|
+
*
|
|
47
|
+
* <Await fallback={() => <em>loading…</em>}>
|
|
48
|
+
* {promise(chart.then((C) => () => <C data={data} />))}
|
|
49
|
+
* </Await>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
function Await(props) {
|
|
53
|
+
const read = (value) => typeof value === "function" && !isReactive(value) ? value() : value;
|
|
54
|
+
const children = read(props.children);
|
|
55
|
+
const when = read(props.when);
|
|
56
|
+
const fromChildren = toAwaitables(children);
|
|
57
|
+
const awaitables = when != null ? toAwaitables(when) : fromChildren;
|
|
58
|
+
if (awaitables.length === 0) return children;
|
|
59
|
+
if (effectsInert()) return promise(Promise.all(awaitables).then(() => () => children));
|
|
60
|
+
const fallback = props.fallback;
|
|
61
|
+
const pending = () => awaitables.some((a) => a.state === "pending");
|
|
62
|
+
const region = () => pending() ? read(fallback) : children;
|
|
63
|
+
region[ASYNC_REGION] = {
|
|
64
|
+
ids: 1 + fromChildren.length,
|
|
65
|
+
pending
|
|
66
|
+
};
|
|
67
|
+
return region;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { Await };
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
* }
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
+
type RegisteredElementInstances = { [K in keyof ElementsKit.CustomElementRegistry]: ElementsKit.CustomElementRegistry[K] extends (abstract new (...args: any[]) => infer I) ? I : never };
|
|
22
23
|
declare global {
|
|
23
24
|
namespace ElementsKit {
|
|
24
25
|
interface CustomElementRegistry {}
|
|
25
26
|
}
|
|
27
|
+
interface HTMLElementTagNameMap extends RegisteredElementInstances {}
|
|
26
28
|
}
|
|
27
29
|
type CustomElementRegistry = ElementsKit.CustomElementRegistry;
|
|
28
30
|
type AnyCtor = CustomElementConstructor;
|
|
@@ -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-BGcU6ldL.mjs";
|
|
2
2
|
export { CustomElementRegistry, defineElement };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as untracked, _ as onCleanup, d as effectScope, u as effect } from "./lib-DYypKhxk.mjs";
|
|
2
2
|
import "./polyfill-CdZVCxdo.mjs";
|
|
3
3
|
import { isReactive, resolveProps } from "./signals/index.mjs";
|
|
4
4
|
import { on } from "./utilities/event-listener.mjs";
|
|
5
|
-
import { n as Slot, r as resolveNode$1, t as SLOTS } from "./slot-
|
|
5
|
+
import { n as Slot, r as resolveNode$1, t as SLOTS } from "./slot-Dvf30O0B.mjs";
|
|
6
6
|
//#region src/jsx-runtime/constants.ts
|
|
7
7
|
/**
|
|
8
8
|
* IDL properties that take precedence over the default `setAttribute` path.
|
|
@@ -80,6 +80,59 @@ const Properties = new Set([
|
|
|
80
80
|
"sharedstoragewritable",
|
|
81
81
|
"defaultValue"
|
|
82
82
|
]);
|
|
83
|
+
/**
|
|
84
|
+
* Content attributes with boolean semantics: presence means true. Emitters
|
|
85
|
+
* write them bare when the value is truthy and omit them entirely when falsy
|
|
86
|
+
* — never `disabled="0"`. Synced from `dom-expressions/src/constants.js`.
|
|
87
|
+
*/
|
|
88
|
+
const BooleanAttributes = new Set([
|
|
89
|
+
"allowfullscreen",
|
|
90
|
+
"async",
|
|
91
|
+
"alpha",
|
|
92
|
+
"autofocus",
|
|
93
|
+
"autoplay",
|
|
94
|
+
"checked",
|
|
95
|
+
"controls",
|
|
96
|
+
"default",
|
|
97
|
+
"disabled",
|
|
98
|
+
"formnovalidate",
|
|
99
|
+
"hidden",
|
|
100
|
+
"indeterminate",
|
|
101
|
+
"inert",
|
|
102
|
+
"ismap",
|
|
103
|
+
"loop",
|
|
104
|
+
"multiple",
|
|
105
|
+
"muted",
|
|
106
|
+
"nomodule",
|
|
107
|
+
"novalidate",
|
|
108
|
+
"open",
|
|
109
|
+
"playsinline",
|
|
110
|
+
"readonly",
|
|
111
|
+
"required",
|
|
112
|
+
"reversed",
|
|
113
|
+
"seamless",
|
|
114
|
+
"selected",
|
|
115
|
+
"adauctionheaders",
|
|
116
|
+
"browsingtopics",
|
|
117
|
+
"credentialless",
|
|
118
|
+
"defaultchecked",
|
|
119
|
+
"defaultmuted",
|
|
120
|
+
"defaultselected",
|
|
121
|
+
"defer",
|
|
122
|
+
"disablepictureinpicture",
|
|
123
|
+
"disableremoteplayback",
|
|
124
|
+
"preservespitch",
|
|
125
|
+
"shadowrootclonable",
|
|
126
|
+
"shadowrootcustomelementregistry",
|
|
127
|
+
"shadowrootdelegatesfocus",
|
|
128
|
+
"shadowrootserializable",
|
|
129
|
+
"sharedstoragewritable"
|
|
130
|
+
]);
|
|
131
|
+
/** React-compat property→attribute aliases (dom-expressions `Aliases`). */
|
|
132
|
+
const AttrAliases = {
|
|
133
|
+
className: "class",
|
|
134
|
+
htmlFor: "for"
|
|
135
|
+
};
|
|
83
136
|
/** Properties whose assignment replaces the element's children. */
|
|
84
137
|
const ChildProperties = new Set([
|
|
85
138
|
"innerHTML",
|
|
@@ -460,6 +513,17 @@ function setAttribute(el, key, value) {
|
|
|
460
513
|
el.setAttribute(key, next);
|
|
461
514
|
}
|
|
462
515
|
//#endregion
|
|
516
|
+
//#region src/jsx-runtime/renderer.ts
|
|
517
|
+
const ACTIVE_RENDERER = Symbol.for("elements-kit.active-renderer");
|
|
518
|
+
const slot = globalThis;
|
|
519
|
+
/** Install or clear (`null`) the active renderer. */
|
|
520
|
+
function setRenderer(renderer) {
|
|
521
|
+
slot[ACTIVE_RENDERER] = renderer;
|
|
522
|
+
}
|
|
523
|
+
function getRenderer() {
|
|
524
|
+
return slot[ACTIVE_RENDERER] ?? null;
|
|
525
|
+
}
|
|
526
|
+
//#endregion
|
|
463
527
|
//#region src/jsx-runtime/dispose.ts
|
|
464
528
|
const DISPOSABLES = /* @__PURE__ */ new WeakMap();
|
|
465
529
|
const sharedDispose = function() {
|
|
@@ -483,7 +547,10 @@ function attachDisposables(target, disposers) {
|
|
|
483
547
|
}
|
|
484
548
|
//#endregion
|
|
485
549
|
//#region src/jsx-runtime/element.ts
|
|
486
|
-
function createElement(type,
|
|
550
|
+
function createElement(type, allProps = {}) {
|
|
551
|
+
const renderer = getRenderer();
|
|
552
|
+
if (renderer) return renderer.jsx(type, allProps);
|
|
553
|
+
const { ref, ...props } = allProps;
|
|
487
554
|
if (typeof type === "function" && !type.prototype?.render) return createFunctionElement(type, props, ref);
|
|
488
555
|
return createNodeElement(type, props, ref);
|
|
489
556
|
}
|
|
@@ -537,4 +604,4 @@ function renderNode(node) {
|
|
|
537
604
|
return renderNode(node.render());
|
|
538
605
|
}
|
|
539
606
|
//#endregion
|
|
540
|
-
export { disposeElement as n,
|
|
607
|
+
export { mountChild as a, BooleanAttributes as c, applyProps as i, ChildProperties as l, disposeElement as n, resolveChild as o, setRenderer as r, AttrAliases as s, createElement as t, Properties as u };
|
package/dist/for.d.mts
CHANGED
|
@@ -1,31 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as Require, m as Props } from "./types-CUvFIgPa.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/for.d.ts
|
|
4
4
|
type KeyFn<T> = (item: T, index: number) => string | number;
|
|
5
5
|
type RenderFn<T> = (item: T, index: number) => Element | DocumentFragment | null;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* 4. Backward scan of the middle region — move or create entries so that
|
|
15
|
-
* each entry's range lands immediately before the already-correct cursor.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* <For each={visibleTodos} by={(todo) => todo.id}>
|
|
20
|
-
* {(todo) => <li>{todo.text}</li>}
|
|
21
|
-
* </For>
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* Props:
|
|
25
|
-
* each — reactive getter returning the array (e.g. a `computed`)
|
|
26
|
-
* by — extracts a stable key per item (default: index)
|
|
27
|
-
* children — render function called once per new key
|
|
28
|
-
*/
|
|
6
|
+
interface Entry {
|
|
7
|
+
/** Marks the start of this item's DOM range. */
|
|
8
|
+
start: Comment;
|
|
9
|
+
/** Marks the end of this item's DOM range. */
|
|
10
|
+
end: Comment;
|
|
11
|
+
/** Disposes effects/onCleanup registered by the render callback for this item. */
|
|
12
|
+
dispose: () => void;
|
|
13
|
+
}
|
|
29
14
|
/**
|
|
30
15
|
* Props for `<For>`, derived from its public instance fields.
|
|
31
16
|
* All props are optional — the class initializes sane defaults at runtime.
|
|
@@ -65,10 +50,19 @@ declare class For<T = unknown> {
|
|
|
65
50
|
#private;
|
|
66
51
|
constructor(_props?: ForProps<T>);
|
|
67
52
|
get each(): T[];
|
|
68
|
-
set each(v: T[]);
|
|
53
|
+
set each(v: T[] | (() => T[]));
|
|
69
54
|
by: KeyFn<T>;
|
|
70
55
|
children: RenderFn<T>;
|
|
71
56
|
render(): DocumentFragment;
|
|
57
|
+
/**
|
|
58
|
+
* @internal Hydrate support: adopt server-rendered range markers and
|
|
59
|
+
* pre-claimed entries instead of creating a fresh range. The first
|
|
60
|
+
* reconcile run sees matching key order and performs no DOM operations;
|
|
61
|
+
* later `each` changes reconcile against the adopted entries as usual.
|
|
62
|
+
*/
|
|
63
|
+
hydrateRange(start: Comment, end: Comment, entries: ReadonlyMap<string | number, Entry>, order: ReadonlyArray<string | number>): void;
|
|
72
64
|
}
|
|
65
|
+
/** @internal Cross-instance-safe For check (identity or brand). */
|
|
66
|
+
declare function isForComponent(type: unknown): boolean;
|
|
73
67
|
//#endregion
|
|
74
|
-
export { For };
|
|
68
|
+
export { Entry, For, isForComponent };
|
package/dist/for.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as untracked, S as trigger, _ as onCleanup, d as effectScope, u as effect, x as signal } from "./lib-DYypKhxk.mjs";
|
|
2
2
|
import "./signals/index.mjs";
|
|
3
|
-
import { n as disposeElement } from "./element-
|
|
3
|
+
import { n as disposeElement } from "./element-D3om9yA6.mjs";
|
|
4
4
|
//#region src/for.ts
|
|
5
5
|
/**
|
|
6
6
|
* Keyed list renderer. See {@link ForProps} for prop details.
|
|
@@ -21,7 +21,8 @@ var For = class {
|
|
|
21
21
|
constructor(_props) {}
|
|
22
22
|
#each = signal([]);
|
|
23
23
|
get each() {
|
|
24
|
-
|
|
24
|
+
const v = this.#each();
|
|
25
|
+
return typeof v === "function" ? v() : v;
|
|
25
26
|
}
|
|
26
27
|
set each(v) {
|
|
27
28
|
if (v === untracked(this.#each)) {
|
|
@@ -49,6 +50,24 @@ var For = class {
|
|
|
49
50
|
});
|
|
50
51
|
return fragment;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* @internal Hydrate support: adopt server-rendered range markers and
|
|
55
|
+
* pre-claimed entries instead of creating a fresh range. The first
|
|
56
|
+
* reconcile run sees matching key order and performs no DOM operations;
|
|
57
|
+
* later `each` changes reconcile against the adopted entries as usual.
|
|
58
|
+
*/
|
|
59
|
+
hydrateRange(start, end, entries, order) {
|
|
60
|
+
this.#start = start;
|
|
61
|
+
this.#end = end;
|
|
62
|
+
for (const [key, entry] of entries) this.#cache.set(key, entry);
|
|
63
|
+
this.#order = [...order];
|
|
64
|
+
effect(() => this.#reconcile());
|
|
65
|
+
onCleanup(() => {
|
|
66
|
+
for (const entry of this.#cache.values()) cleanEntry(entry);
|
|
67
|
+
this.#cache.clear();
|
|
68
|
+
this.#order = [];
|
|
69
|
+
});
|
|
70
|
+
}
|
|
52
71
|
#reconcile() {
|
|
53
72
|
const parent = this.#start.parentNode;
|
|
54
73
|
if (!parent) return;
|
|
@@ -148,5 +167,11 @@ function moveEntry(parent, entry, before) {
|
|
|
148
167
|
range.setEndAfter(entry.end);
|
|
149
168
|
parent.insertBefore(range.extractContents(), before);
|
|
150
169
|
}
|
|
170
|
+
const FOR_BRAND = Symbol.for("elements-kit.for");
|
|
171
|
+
For[FOR_BRAND] = true;
|
|
172
|
+
/** @internal Cross-instance-safe For check (identity or brand). */
|
|
173
|
+
function isForComponent(type) {
|
|
174
|
+
return type === For || typeof type === "function" && type[FOR_BRAND] === true;
|
|
175
|
+
}
|
|
151
176
|
//#endregion
|
|
152
|
-
export { For };
|
|
177
|
+
export { For, isForComponent };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { _ as onCleanup, u as effect } from "./lib-DYypKhxk.mjs";
|
|
2
|
+
import "./signals/index.mjs";
|
|
3
|
+
import { a as mountChild } from "./element-D3om9yA6.mjs";
|
|
4
|
+
import { n as Slot } from "./slot-Dvf30O0B.mjs";
|
|
5
|
+
//#region src/jsx-runtime/fragment.ts
|
|
6
|
+
/**
|
|
7
|
+
* Parse an HTML string script-inertly: markup renders, `<script>` tags are
|
|
8
|
+
* created but never execute (template parsing sets the "already started"
|
|
9
|
+
* flag). Sanitizing the input is the caller's responsibility.
|
|
10
|
+
*/
|
|
11
|
+
function parseHtml(html) {
|
|
12
|
+
const template = document.createElement("template");
|
|
13
|
+
template.innerHTML = html;
|
|
14
|
+
return template.content;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Used by the JSX transform for `<>...</>` fragments.
|
|
18
|
+
*
|
|
19
|
+
* Each child is routed through `mountChild`, which handles Nodes, strings,
|
|
20
|
+
* numbers, arrays, and reactive getters — matching the behavior of any other
|
|
21
|
+
* JSX container. `mountChild` also wires each child's cleanup via its own
|
|
22
|
+
* `effectScope`, which links to the enclosing `effectScope` created by
|
|
23
|
+
* `createElement(Fragment, ...)` for disposal propagation.
|
|
24
|
+
*
|
|
25
|
+
* **Raw HTML mode** — `<Fragment html>{markup}</Fragment>`: the child is a
|
|
26
|
+
* `MaybeReactive<string>` rendered as markup inside a Slot region (comment
|
|
27
|
+
* markers), so the server renderer and the hydration claim pass share the
|
|
28
|
+
* region boundary. Reactive sources re-render the region on change. This is
|
|
29
|
+
* the library's only raw-HTML sink: the string is NOT escaped — sanitize
|
|
30
|
+
* untrusted input at the call site. `<script>` tags never execute.
|
|
31
|
+
*/
|
|
32
|
+
function Fragment(props) {
|
|
33
|
+
const fragment = document.createDocumentFragment();
|
|
34
|
+
if ("html" in props && props.html) {
|
|
35
|
+
const slot = new Slot();
|
|
36
|
+
fragment.appendChild(slot.render());
|
|
37
|
+
const source = props.children;
|
|
38
|
+
if (typeof source === "function") {
|
|
39
|
+
effect(() => {
|
|
40
|
+
const value = source();
|
|
41
|
+
slot.set(parseHtml(value == null ? "" : String(value)));
|
|
42
|
+
});
|
|
43
|
+
onCleanup(() => slot.clear());
|
|
44
|
+
} else if (source != null) slot.set(parseHtml(String(source)));
|
|
45
|
+
return fragment;
|
|
46
|
+
}
|
|
47
|
+
const children = props.children;
|
|
48
|
+
const raw = typeof children === "function" ? children() : children;
|
|
49
|
+
if (raw == null) return fragment;
|
|
50
|
+
const nodes = Array.isArray(raw) ? raw.flat(Infinity) : [raw];
|
|
51
|
+
for (const child of nodes) mountChild(fragment, child);
|
|
52
|
+
return fragment;
|
|
53
|
+
}
|
|
54
|
+
const FRAGMENT_BRAND = Symbol.for("elements-kit.fragment");
|
|
55
|
+
Fragment[FRAGMENT_BRAND] = true;
|
|
56
|
+
/** @internal Cross-instance-safe Fragment check (identity or brand). */
|
|
57
|
+
function isFragmentComponent(type) {
|
|
58
|
+
return type === Fragment || typeof type === "function" && type[FRAGMENT_BRAND] === true;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { isFragmentComponent as n, parseHtml as r, Fragment as t };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/hydrate/claim.d.ts
|
|
2
|
+
interface MismatchInfo {
|
|
3
|
+
expected: string;
|
|
4
|
+
found: Node | null;
|
|
5
|
+
}
|
|
6
|
+
type OnMismatch = (info: MismatchInfo) => void;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/hydrate/index.d.ts
|
|
9
|
+
interface HydrateOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Called when the server DOM does not match the component tree. The
|
|
12
|
+
* mismatched subtree is discarded and rendered fresh; the caller owns
|
|
13
|
+
* logging/reporting.
|
|
14
|
+
*/
|
|
15
|
+
onMismatch?: OnMismatch;
|
|
16
|
+
}
|
|
17
|
+
interface HydrateResult {
|
|
18
|
+
/** Tear down every effect, handler and live binding wired by hydration. */
|
|
19
|
+
dispose: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Make server-rendered HTML interactive by re-executing the component tree
|
|
23
|
+
* in claim mode: existing DOM nodes are adopted instead of rebuilt, `on:`
|
|
24
|
+
* handlers attach to the claimed nodes, and dynamic children bind live to
|
|
25
|
+
* the server-emitted slot markers.
|
|
26
|
+
*
|
|
27
|
+
* The component code runs once on the client (closures are recreated by
|
|
28
|
+
* re-execution — no serialized handlers). Async children keep their
|
|
29
|
+
* server-rendered content visible until the client-side value settles.
|
|
30
|
+
*
|
|
31
|
+
* Server/client trees must match; on mismatch the affected subtree is
|
|
32
|
+
* rendered fresh and `options.onMismatch` is invoked.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* const { dispose } = hydrate(document.getElementById("app")!, () => <App />);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function hydrate(container: Element, app: () => unknown, options?: HydrateOptions): HydrateResult;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { HydrateOptions, HydrateResult, type MismatchInfo, type OnMismatch, hydrate };
|