elements-kit 0.22.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/await.mjs +1 -1
- package/dist/environment-CTAGxqz_.d.mts +19 -0
- package/dist/hydrate/index.mjs +1 -1
- package/dist/{hydrate-CHomBRY9.mjs → hydrate-DvWdnV-e.mjs} +1 -1
- package/dist/integrations/astro-client.mjs +1 -1
- package/dist/ui/otp-input/index.d.mts +5 -4
- package/dist/ui/otp-input/index.mjs +5 -5
- package/dist/utilities/async.d.mts +1 -1
- package/dist/utilities/async.mjs +13 -5
- package/dist/utilities/environment.d.mts +2 -7
- package/dist/utilities/environment.mjs +13 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ ElementsKit is a library of reactive primitives, not a framework. Each piece is
|
|
|
52
52
|
|
|
53
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
54
|
|
|
55
|
-
- **Bundler-friendly.** Every primitive is its own subpath — `elements-kit/signals`, `elements-kit/utilities/*`, `elements-kit/integrations/*`. Import only what you need.
|
|
55
|
+
- **Bundler-friendly.** Every primitive is its own subpath — `elements-kit/signals`, `elements-kit/utilities/*`, `elements-kit/ui/*`, `elements-kit/integrations/*`. Import only what you need.
|
|
56
56
|
|
|
57
57
|
## Packages
|
|
58
58
|
|
|
@@ -73,6 +73,7 @@ Every feature is a separate subpath export — import only what you use.
|
|
|
73
73
|
| `elements-kit/integrations/react` | `useSignal`, `useScope` React bridge hooks |
|
|
74
74
|
| `elements-kit/integrations/astro` | `elementsKit()` Astro integration — elements-kit components as server-rendered, hydrated islands *(experimental)* |
|
|
75
75
|
| `elements-kit/utilities/*` | Reactive browser-API utilities — see [src/utilities/README.md](src/utilities/README.md) |
|
|
76
|
+
| `elements-kit/ui/*` | Accessible UI component styles (CSS) + an optional base theme (`elements-kit/ui/styles.css`); plus the `otp-input` custom element and `overlay` positioning/interaction behaviors. Catalog in [src/ui/README.md](src/ui/README.md) |
|
|
76
77
|
|
|
77
78
|
## Signals
|
|
78
79
|
|
|
@@ -340,7 +341,7 @@ await op; // awaitable (delegates to .then/.catch/.finally via .raw)
|
|
|
340
341
|
op.stop(); // halt reruns + fire registered cleanup
|
|
341
342
|
```
|
|
342
343
|
|
|
343
|
-
Reactive state getters: `.state
|
|
344
|
+
Reactive state getters: `.state` (`"idle" | "pending" | "fulfilled" | "rejected"` — `idle` before the first run, so `.pending` is `false` until you trigger one), `.value`, `.reason`, `.result`, `.pending`, `.raw` (the underlying `ComputedPromise`).
|
|
344
345
|
|
|
345
346
|
One-shot mutation (no tracking):
|
|
346
347
|
|
package/dist/await.mjs
CHANGED
|
@@ -22,7 +22,7 @@ function Await(props) {
|
|
|
22
22
|
if (awaitables.length === 0) return children;
|
|
23
23
|
if (effectsInert()) return promise(Promise.all(awaitables).then(() => () => children));
|
|
24
24
|
const fallback = props.fallback;
|
|
25
|
-
const pending = () => awaitables.some((a) => a.state
|
|
25
|
+
const pending = () => awaitables.some((a) => a.state !== "fulfilled" && a.state !== "rejected");
|
|
26
26
|
const region = () => pending() ? read(fallback) : children;
|
|
27
27
|
region[ASYNC_REGION] = {
|
|
28
28
|
ids: 1 + fromChildren.length,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/utilities/environment.d.ts
|
|
2
|
+
/** `true` when running in a browser (both `window` and `document` exist). */
|
|
3
|
+
declare const isBrowser: boolean;
|
|
4
|
+
/**
|
|
5
|
+
* `HTMLElement` in the browser; an empty stand-in on the server.
|
|
6
|
+
*
|
|
7
|
+
* A custom-element class evaluates its `extends` clause at module load, but
|
|
8
|
+
* `HTMLElement` is undefined in Node — so importing an element module during
|
|
9
|
+
* SSR (e.g. an Astro `client:load` island) throws `HTMLElement is not defined`
|
|
10
|
+
* before any `isBrowser` guard can run. Elements are never *constructed* on the
|
|
11
|
+
* server (the streaming renderer emits plain tags), so a stub base is enough to
|
|
12
|
+
* let the class definition load; the guarded `customElements.define` still only
|
|
13
|
+
* registers in a real browser.
|
|
14
|
+
*/
|
|
15
|
+
declare const HTMLElementBase: typeof HTMLElement;
|
|
16
|
+
/** A shared `Disposable` whose `Symbol.dispose` is a no-op — useful as a safe default. */
|
|
17
|
+
declare const noopDisposable: Disposable;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { isBrowser as n, noopDisposable as r, HTMLElementBase as t };
|
package/dist/hydrate/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as hydrate } from "../hydrate-
|
|
1
|
+
import { t as hydrate } from "../hydrate-DvWdnV-e.mjs";
|
|
2
2
|
export { hydrate };
|
|
@@ -158,7 +158,7 @@ function claimAsync(cur, p, om) {
|
|
|
158
158
|
}
|
|
159
159
|
const slot = claimSlot(cur, om);
|
|
160
160
|
effect(() => {
|
|
161
|
-
if (p.state
|
|
161
|
+
if (p.state !== "fulfilled" && p.state !== "rejected") return;
|
|
162
162
|
slot.set(resolveChild(p.result));
|
|
163
163
|
});
|
|
164
164
|
onCleanup(() => slot.clear());
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as createElement } from "../element-Di0PYFX1.mjs";
|
|
2
2
|
import { render } from "../render.mjs";
|
|
3
|
-
import { t as hydrate } from "../hydrate-
|
|
3
|
+
import { t as hydrate } from "../hydrate-DvWdnV-e.mjs";
|
|
4
4
|
import { withSlotProps } from "./astro-slots.mjs";
|
|
5
5
|
//#region src/integrations/astro-client.ts
|
|
6
6
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { n as AttrChangeHandler, t as ATTRIBUTES } from "../../attributes-DILeh3-s.mjs";
|
|
2
|
+
import { t as HTMLElementBase } from "../../environment-CTAGxqz_.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/ui/otp-input/otp-input.d.ts
|
|
4
5
|
/**
|
|
@@ -30,7 +31,7 @@ import { n as AttrChangeHandler, t as ATTRIBUTES } from "../../attributes-DILeh3
|
|
|
30
31
|
* </x-otp-input>
|
|
31
32
|
* ```
|
|
32
33
|
*/
|
|
33
|
-
declare class XOtpInput extends
|
|
34
|
+
declare class XOtpInput extends HTMLElementBase {
|
|
34
35
|
#private;
|
|
35
36
|
static formAssociated: boolean;
|
|
36
37
|
static [ATTRIBUTES]: {
|
|
@@ -82,7 +83,7 @@ declare global {
|
|
|
82
83
|
* `<x-otp-input>` paints its character and active / caret / disabled state by
|
|
83
84
|
* index; all styling lives in the companion CSS.
|
|
84
85
|
*/
|
|
85
|
-
declare class XOtpSlot extends
|
|
86
|
+
declare class XOtpSlot extends HTMLElementBase {
|
|
86
87
|
static [ATTRIBUTES]: {
|
|
87
88
|
index: AttrChangeHandler<XOtpSlot>;
|
|
88
89
|
};
|
|
@@ -102,7 +103,7 @@ declare global {
|
|
|
102
103
|
* `<x-otp-slot>`s into one attached group. All layout lives in CSS; this only
|
|
103
104
|
* applies a `group` role so the visual grouping is exposed to assistive tech.
|
|
104
105
|
*/
|
|
105
|
-
declare class XOtpGroup extends
|
|
106
|
+
declare class XOtpGroup extends HTMLElementBase {
|
|
106
107
|
connectedCallback(): void;
|
|
107
108
|
}
|
|
108
109
|
declare global {
|
|
@@ -118,7 +119,7 @@ declare global {
|
|
|
118
119
|
* `<x-otp-separator>` — decorative divider authored between OTP groups (e.g. a
|
|
119
120
|
* dash between a 3-3 split). Purely visual: `aria-hidden`, glyph drawn in CSS.
|
|
120
121
|
*/
|
|
121
|
-
declare class XOtpSeparator extends
|
|
122
|
+
declare class XOtpSeparator extends HTMLElementBase {
|
|
122
123
|
connectedCallback(): void;
|
|
123
124
|
}
|
|
124
125
|
declare global {
|
|
@@ -3,7 +3,7 @@ import { l as computed, u as effect, x as signal } from "../../lib-DYypKhxk.mjs"
|
|
|
3
3
|
import "../../signals/index.mjs";
|
|
4
4
|
import { on } from "../../utilities/event-listener.mjs";
|
|
5
5
|
import { render } from "../../render.mjs";
|
|
6
|
-
import { isBrowser } from "../../utilities/environment.mjs";
|
|
6
|
+
import { HTMLElementBase, isBrowser } from "../../utilities/environment.mjs";
|
|
7
7
|
//#region src/ui/otp-input/otp-input.shadow.css?inline
|
|
8
8
|
var otp_input_shadow_default = ".x-otp-input__field {\n color: #0000;\n caret-color: #0000;\n width: 100%;\n height: 100%;\n font: inherit;\n letter-spacing: inherit;\n pointer-events: auto;\n background: none;\n border: 0;\n outline: none;\n margin: 0;\n padding: 0;\n position: absolute;\n inset: 0;\n}\n\n.x-otp-input__field::selection {\n color: #0000;\n background-color: #0000;\n}\n";
|
|
9
9
|
//#endregion
|
|
@@ -43,7 +43,7 @@ SHADOW_SHEET?.replaceSync(otp_input_shadow_default);
|
|
|
43
43
|
* </x-otp-input>
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
var XOtpInput = class XOtpInput extends
|
|
46
|
+
var XOtpInput = class XOtpInput extends HTMLElementBase {
|
|
47
47
|
static formAssociated = true;
|
|
48
48
|
static [ATTRIBUTES] = {
|
|
49
49
|
value(value) {
|
|
@@ -293,7 +293,7 @@ if (isBrowser && !customElements.get("x-otp-input")) customElements.define("x-ot
|
|
|
293
293
|
* `<x-otp-input>` paints its character and active / caret / disabled state by
|
|
294
294
|
* index; all styling lives in the companion CSS.
|
|
295
295
|
*/
|
|
296
|
-
var XOtpSlot = class extends
|
|
296
|
+
var XOtpSlot = class extends HTMLElementBase {
|
|
297
297
|
connectedCallback() {
|
|
298
298
|
this.setAttribute("aria-hidden", "true");
|
|
299
299
|
}
|
|
@@ -306,7 +306,7 @@ if (isBrowser && !customElements.get("x-otp-slot")) customElements.define("x-otp
|
|
|
306
306
|
* `<x-otp-slot>`s into one attached group. All layout lives in CSS; this only
|
|
307
307
|
* applies a `group` role so the visual grouping is exposed to assistive tech.
|
|
308
308
|
*/
|
|
309
|
-
var XOtpGroup = class extends
|
|
309
|
+
var XOtpGroup = class extends HTMLElementBase {
|
|
310
310
|
connectedCallback() {
|
|
311
311
|
if (!this.hasAttribute("role")) this.setAttribute("role", "group");
|
|
312
312
|
}
|
|
@@ -318,7 +318,7 @@ if (isBrowser && !customElements.get("x-otp-group")) customElements.define("x-ot
|
|
|
318
318
|
* `<x-otp-separator>` — decorative divider authored between OTP groups (e.g. a
|
|
319
319
|
* dash between a 3-3 split). Purely visual: `aria-hidden`, glyph drawn in CSS.
|
|
320
320
|
*/
|
|
321
|
-
var XOtpSeparator = class extends
|
|
321
|
+
var XOtpSeparator = class extends HTMLElementBase {
|
|
322
322
|
connectedCallback() {
|
|
323
323
|
this.setAttribute("aria-hidden", "true");
|
|
324
324
|
}
|
|
@@ -38,7 +38,7 @@ declare class Async<TInput = undefined, TOutput = unknown> {
|
|
|
38
38
|
set fn(fn: MaybeReactive<Fn<TInput, TOutput>>);
|
|
39
39
|
get raw(): ComputedPromise<TOutput | undefined>;
|
|
40
40
|
get pending(): boolean;
|
|
41
|
-
get state(): "pending" | "fulfilled" | "rejected";
|
|
41
|
+
get state(): "idle" | "pending" | "fulfilled" | "rejected";
|
|
42
42
|
get value(): TOutput | undefined;
|
|
43
43
|
get reason(): unknown;
|
|
44
44
|
get result(): unknown;
|
package/dist/utilities/async.mjs
CHANGED
|
@@ -9,6 +9,7 @@ function flushDeferredAsyncRuns() {
|
|
|
9
9
|
deferredRuns.clear();
|
|
10
10
|
for (const run of runs) run();
|
|
11
11
|
}
|
|
12
|
+
const IDLE = promise(() => {});
|
|
12
13
|
/**
|
|
13
14
|
* Reactive wrapper around an async function. Exposes the current run as
|
|
14
15
|
* reactive signals (`state`, `value`, `reason`, `result`, `pending`) and
|
|
@@ -44,15 +45,16 @@ var Async = class {
|
|
|
44
45
|
set fn(fn) {
|
|
45
46
|
this.#fn(resolve(fn));
|
|
46
47
|
}
|
|
47
|
-
#current = signal(
|
|
48
|
+
#current = signal(IDLE);
|
|
48
49
|
get raw() {
|
|
49
50
|
return this.#current();
|
|
50
51
|
}
|
|
51
52
|
get pending() {
|
|
52
|
-
return this.
|
|
53
|
+
return this.state === "pending";
|
|
53
54
|
}
|
|
54
55
|
get state() {
|
|
55
|
-
|
|
56
|
+
const current = this.#current();
|
|
57
|
+
return current === IDLE ? "idle" : current.state;
|
|
56
58
|
}
|
|
57
59
|
get value() {
|
|
58
60
|
return this.raw.value;
|
|
@@ -77,7 +79,12 @@ var Async = class {
|
|
|
77
79
|
* `ReactivePromise`. See `ReactivePromise[SEED]`.
|
|
78
80
|
*/
|
|
79
81
|
[SEED](value) {
|
|
80
|
-
|
|
82
|
+
let current = this.#current();
|
|
83
|
+
if (current === IDLE) {
|
|
84
|
+
current = promise(() => {});
|
|
85
|
+
this.#current(current);
|
|
86
|
+
}
|
|
87
|
+
const seed = current[SEED];
|
|
81
88
|
seed?.(value);
|
|
82
89
|
}
|
|
83
90
|
/**
|
|
@@ -89,7 +96,8 @@ var Async = class {
|
|
|
89
96
|
const pendingRun = deferredRuns.get(this);
|
|
90
97
|
deferredRuns.delete(this);
|
|
91
98
|
if (record) {
|
|
92
|
-
|
|
99
|
+
const state = untracked(() => this.state);
|
|
100
|
+
if (state !== "fulfilled" && state !== "rejected") this[SEED](record.value);
|
|
93
101
|
return;
|
|
94
102
|
}
|
|
95
103
|
pendingRun?.();
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
declare const isBrowser: boolean;
|
|
4
|
-
/** A shared `Disposable` whose `Symbol.dispose` is a no-op — useful as a safe default. */
|
|
5
|
-
declare const noopDisposable: Disposable;
|
|
6
|
-
//#endregion
|
|
7
|
-
export { isBrowser, noopDisposable };
|
|
1
|
+
import { n as isBrowser, r as noopDisposable, t as HTMLElementBase } from "../environment-CTAGxqz_.mjs";
|
|
2
|
+
export { HTMLElementBase, isBrowser, noopDisposable };
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
//#region src/utilities/environment.ts
|
|
2
2
|
/** `true` when running in a browser (both `window` and `document` exist). */
|
|
3
3
|
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
4
|
+
/**
|
|
5
|
+
* `HTMLElement` in the browser; an empty stand-in on the server.
|
|
6
|
+
*
|
|
7
|
+
* A custom-element class evaluates its `extends` clause at module load, but
|
|
8
|
+
* `HTMLElement` is undefined in Node — so importing an element module during
|
|
9
|
+
* SSR (e.g. an Astro `client:load` island) throws `HTMLElement is not defined`
|
|
10
|
+
* before any `isBrowser` guard can run. Elements are never *constructed* on the
|
|
11
|
+
* server (the streaming renderer emits plain tags), so a stub base is enough to
|
|
12
|
+
* let the class definition load; the guarded `customElements.define` still only
|
|
13
|
+
* registers in a real browser.
|
|
14
|
+
*/
|
|
15
|
+
const HTMLElementBase = isBrowser ? HTMLElement : class {};
|
|
4
16
|
/** A shared `Disposable` whose `Symbol.dispose` is a no-op — useful as a safe default. */
|
|
5
17
|
const noopDisposable = { [Symbol.dispose]() {} };
|
|
6
18
|
//#endregion
|
|
7
|
-
export { isBrowser, noopDisposable };
|
|
19
|
+
export { HTMLElementBase, isBrowser, noopDisposable };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elements-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.22.
|
|
4
|
+
"version": "0.22.1",
|
|
5
5
|
"description": "A lightweight reactive UI library that transforms native HTMLElements into reactive components with signals. Ideal for framework-agnostic applications and web components.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"webcomponents",
|