@zubra/runtime 0.0.0-stage → 5.0.3
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/LICENSE +15 -0
- package/README.md +97 -2
- package/dist/production/deep.js +88 -0
- package/dist/production/effect.js +234 -0
- package/dist/production/element.js +1761 -0
- package/dist/production/index.js +12 -0
- package/dist/production/primitives.js +108 -0
- package/dist/production/react.js +125 -0
- package/dist/production/remark.js +173 -0
- package/dist/production/resource.js +76 -0
- package/dist/production/server.js +98 -0
- package/dist/production/signal-impl.js +376 -0
- package/dist/production/signal.js +10 -0
- package/dist/production/spread.js +155 -0
- package/dist/production/vue.js +126 -0
- package/dist/production/zag.js +59 -0
- package/fesm2022/zubra-runtime-angular.mjs +118 -0
- package/package.json +126 -4
- package/src/deep.js +87 -0
- package/src/effect.js +233 -0
- package/src/element.js +1837 -0
- package/src/index.js +11 -0
- package/src/primitives.js +107 -0
- package/src/react.js +124 -0
- package/src/remark.js +172 -0
- package/src/resource.js +75 -0
- package/src/server.js +97 -0
- package/src/signal-impl.js +375 -0
- package/src/signal.js +9 -0
- package/src/spread.js +154 -0
- package/src/vue.js +125 -0
- package/src/zag.js +58 -0
- package/types/angular.d.ts +20 -0
- package/types/effect.d.ts +28 -0
- package/types/index.d.ts +205 -0
- package/types/primitives.d.ts +15 -0
- package/types/react.d.ts +13 -0
- package/types/server.d.ts +27 -0
- package/types/signal.d.ts +46 -0
- package/types/spread.d.ts +5 -0
- package/types/vue.d.ts +8 -0
- package/types/zag.d.ts +9 -0
package/src/zag.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @zubra/runtime/zag: Zag.js state machines driving zubra components.
|
|
2
|
+
//
|
|
3
|
+
// Zag (https://zagjs.com) is a framework-agnostic set of accessible widget behaviours (combobox,
|
|
4
|
+
// date picker, colour picker, tree view, …) as state machines, each with a `connect()` that
|
|
5
|
+
// returns prop getters. In a zubra script:
|
|
6
|
+
//
|
|
7
|
+
// import * as combobox from '@zag-js/combobox'
|
|
8
|
+
// import { id, computed } from '@zubra/runtime'
|
|
9
|
+
// import { useMachine, normalizeProps } from '@zubra/runtime/zag'
|
|
10
|
+
//
|
|
11
|
+
// const uid = id() // once: Zag's ids must be stable
|
|
12
|
+
// const service = useMachine(combobox.machine, () => ({ id: uid, collection, onValueChange }))
|
|
13
|
+
// const api = computed(() => combobox.connect(service.current, normalizeProps))
|
|
14
|
+
//
|
|
15
|
+
// <input {...api.getInputProps()}>
|
|
16
|
+
//
|
|
17
|
+
// `useMachine` runs Zag's own vanilla machine and turns its notifications into a signal, so the
|
|
18
|
+
// `api` computed re-derives when the machine changes, and also when the props function reads zubra
|
|
19
|
+
// state or props that change. A Zag machine can't be restarted once stopped (stopping drops its
|
|
20
|
+
// subscriptions), so each connection of the element gets a fresh one: an element that is moved,
|
|
21
|
+
// or removed and put back, keeps working. (`plan/evidence/2026-11-07-zag-spike.md`.)
|
|
22
|
+
//
|
|
23
|
+
// Zag is an optional peer dependency: install `@zag-js/vanilla` and the machines you use.
|
|
24
|
+
import { VanillaMachine } from '@zag-js/vanilla';
|
|
25
|
+
import { state, onMount } from './element.js';
|
|
26
|
+
|
|
27
|
+
export { normalizeProps } from '@zag-js/vanilla';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Run a Zag machine for this element: started when it connects, stopped when it disconnects.
|
|
31
|
+
* `props` is Zag's props, or a function returning them (read again whenever Zag asks, so it can
|
|
32
|
+
* read zubra state and props). Returns `{ current }`: the machine's service, read reactively.
|
|
33
|
+
*/
|
|
34
|
+
export function useMachine(machine, props = {}) {
|
|
35
|
+
const make = () => new VanillaMachine(machine, props);
|
|
36
|
+
// Before the element connects, a machine that hasn't started: connect() can read it, so the
|
|
37
|
+
// first render has the right attributes.
|
|
38
|
+
const current = state(make(), { equals: () => false });
|
|
39
|
+
const version = state(0);
|
|
40
|
+
let first = true;
|
|
41
|
+
onMount(() => {
|
|
42
|
+
const running = first ? current.get() : make();
|
|
43
|
+
first = false;
|
|
44
|
+
const unsubscribe = running.subscribe(() => version.set(version.get() + 1));
|
|
45
|
+
running.start();
|
|
46
|
+
current.set(running);
|
|
47
|
+
return () => {
|
|
48
|
+
unsubscribe();
|
|
49
|
+
running.stop();
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
get current() {
|
|
54
|
+
version.get();
|
|
55
|
+
return current.get().service;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ControlValueAccessor } from '@angular/forms';
|
|
2
|
+
import type * as i0 from '@angular/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Makes a zubra element a form control (`ngModel`, `formControl`, `formControlName`) through its
|
|
6
|
+
* `<prop>` + `<prop>change` pair. `zubraModel` alone binds the `value` pair (or the only pair);
|
|
7
|
+
* `zubraModel="checked"` names one. A standalone directive: add it to the component's `imports`.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ZubraModel implements ControlValueAccessor {
|
|
10
|
+
/** The prop to bind; empty for the `value` pair, or the only pair. */
|
|
11
|
+
zubraModel: string;
|
|
12
|
+
writeValue(value: unknown): void;
|
|
13
|
+
registerOnChange(fn: (value: unknown) => void): void;
|
|
14
|
+
registerOnTouched(fn: () => void): void;
|
|
15
|
+
setDisabledState(disabled: boolean): void;
|
|
16
|
+
// What Angular's ahead-of-time compiler reads to use the directive in a template (as in any
|
|
17
|
+
// Angular library's typings).
|
|
18
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ZubraModel, never>;
|
|
19
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<ZubraModel, '[zubraModel]', ['zubraModel'], { zubraModel: { alias: 'zubraModel'; required: false } }, {}, never, never, true, never>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Something to run when an effect re-runs or is disposed. */
|
|
2
|
+
export type Cleanup = () => void;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Run `fn` now and again whenever a signal it read changes (batched: several writes in one task
|
|
6
|
+
* cause one re-run, in a microtask). `fn` may return a cleanup. Returns a function that disposes
|
|
7
|
+
* the effect. Effects created inside another effect or scope belong to it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function effect(fn: () => void | Cleanup): () => void;
|
|
10
|
+
|
|
11
|
+
/** An ownership root: disposing, pausing or resuming it applies to every effect inside. */
|
|
12
|
+
export interface Scope {
|
|
13
|
+
run<T>(fn: () => T): T;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
pause(): void;
|
|
16
|
+
resume(): void;
|
|
17
|
+
readonly disposed: boolean;
|
|
18
|
+
readonly paused: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Create a scope (owned by the current one) and run `fn` in it. */
|
|
22
|
+
export declare function scope(fn?: () => void): Scope;
|
|
23
|
+
|
|
24
|
+
/** Apply pending effect re-runs now, parents before children. */
|
|
25
|
+
export declare function flush(): void;
|
|
26
|
+
|
|
27
|
+
/** Resolves once pending effect re-runs have happened. */
|
|
28
|
+
export declare function tick(): Promise<void>;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// @zubra/runtime: what compiled components and their scripts use.
|
|
2
|
+
import type { Signal } from './signal.js';
|
|
3
|
+
|
|
4
|
+
export { Signal, isNative } from './signal.js';
|
|
5
|
+
export { effect, scope, flush, tick, type Cleanup, type Scope } from './effect.js';
|
|
6
|
+
|
|
7
|
+
/** A value, or a signal holding one: what templates and most hooks accept. */
|
|
8
|
+
export type MaybeSignal<T> = T | Signal.State<T> | Signal.Computed<T>;
|
|
9
|
+
|
|
10
|
+
// ---- state ----------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A writable signal (`Signal.State`). An array or plain object is held as a reactive proxy, so
|
|
14
|
+
* mutating it (`push`, `splice`, a property write) updates what read that property; `raw()` gives
|
|
15
|
+
* the original back.
|
|
16
|
+
*/
|
|
17
|
+
export declare function state<T>(value: T, options?: Signal.Options<T>): Signal.State<T>;
|
|
18
|
+
/** The original object behind reactive state's proxy, or the value itself. */
|
|
19
|
+
export declare function raw<T>(value: T): T;
|
|
20
|
+
/** A derived signal (`Signal.Computed`); what it reads is tracked automatically. */
|
|
21
|
+
export declare function computed<T>(fn: () => T, options?: Signal.Options<T>): Signal.Computed<T>;
|
|
22
|
+
/** Call `callback(next, previous)` when `source` changes (not on the first run). */
|
|
23
|
+
export declare function watch<T>(source: (() => T) | MaybeSignal<T>, callback: (next: T, previous: T) => void): void;
|
|
24
|
+
|
|
25
|
+
/** Async data as signals; see `resource()`. Awaitable: resolves to the current run's value. */
|
|
26
|
+
export interface Resource<T> extends PromiseLike<T> {
|
|
27
|
+
/** The latest run's value (or `initial`); kept while the next run is pending. */
|
|
28
|
+
readonly value: T | undefined;
|
|
29
|
+
readonly error: unknown;
|
|
30
|
+
readonly status: 'pending' | 'ready' | 'error';
|
|
31
|
+
readonly loading: boolean;
|
|
32
|
+
/** Run the fetcher again. */
|
|
33
|
+
refresh(): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Run `fetcher` now and whenever a signal it read before its first `await` changes; a new run
|
|
37
|
+
* (or the element's removal) aborts the previous one through `signal`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resource<T>(fetcher: (context: { signal: AbortSignal }) => T | PromiseLike<T>, options?: { initial?: T }): Resource<T>;
|
|
40
|
+
|
|
41
|
+
// ---- lifecycle and the element (call during setup) -----------------------------------------
|
|
42
|
+
|
|
43
|
+
/** Run when the element is connected; may return a cleanup for when it is disconnected. */
|
|
44
|
+
export declare function onMount(fn: () => void | (() => void)): void;
|
|
45
|
+
/** Run when the element is disconnected. */
|
|
46
|
+
export declare function onUnmount(fn: () => void): void;
|
|
47
|
+
/** An id unique to this element and call, for `id`/`for`/`aria-*` attributes. */
|
|
48
|
+
export declare function id(): string;
|
|
49
|
+
/** The component's props: reading one tracks it; writing one updates the element. */
|
|
50
|
+
export declare function props<P extends object = Record<string, unknown>>(): P;
|
|
51
|
+
/** The element whose setup is running. */
|
|
52
|
+
export declare function host<E extends HTMLElement = HTMLElement>(): E;
|
|
53
|
+
/**
|
|
54
|
+
* Fire a DOM event from the component (a bubbling `CustomEvent` with `detail`). The compiler
|
|
55
|
+
* declares every event it sees. Returns false if a listener called `preventDefault()` on a
|
|
56
|
+
* cancelable (`before…`) event.
|
|
57
|
+
*/
|
|
58
|
+
export declare function emit(name: string, detail?: unknown): boolean;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The signal itself, where a script passes a signal `const` along: `watch(signal(count), …)`.
|
|
62
|
+
* The identity function; since 3.0, where a signal `const` in a script means its value, it keeps
|
|
63
|
+
* meaning the signal.
|
|
64
|
+
*/
|
|
65
|
+
export declare function signal<T>(value: T): T;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Whether content was given for a slot (`'default'` for the default slot), as a signal that
|
|
69
|
+
* follows the content. Read it like a value in the template: `<zb-if test={hasFooter}>`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function hasSlot(name?: string): Signal.State<boolean>;
|
|
72
|
+
/** False while the element's markup is the server's (and on the server); true once it has started. The host also gets `:state(hydrated)`. */
|
|
73
|
+
export declare function hydrated(): Signal.State<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* State that follows a prop until it's assigned, and starts over when the prop changes:
|
|
76
|
+
* `let left = from(seconds)` in a `.zb` script. With a second argument, it starts as that
|
|
77
|
+
* value instead: `let running = from(seconds, false)`. Elsewhere, pass functions or signals.
|
|
78
|
+
*/
|
|
79
|
+
export declare function from<T>(source: T | (() => T) | Signal.State<T> | Signal.Computed<T>): Signal.Computed<T> & { set(value: T): void };
|
|
80
|
+
export declare function from<T>(source: unknown, start: T | (() => T) | Signal.State<T> | Signal.Computed<T>): Signal.Computed<T> & { set(value: T): void };
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* In a JSX component's parameters, `value = model(0)` makes `value` two-way: assigning it fires
|
|
84
|
+
* `valuechange` (like `value:model={0}` in `.zb`). Returns its argument.
|
|
85
|
+
*/
|
|
86
|
+
export declare function model<T>(value: T): T;
|
|
87
|
+
|
|
88
|
+
// ---- event helpers (the template's event modifiers, as functions) ---------------------------
|
|
89
|
+
|
|
90
|
+
type Handler<E extends Event = Event> = (this: unknown, event: E) => unknown;
|
|
91
|
+
/** A handler that calls `event.preventDefault()` first (`.prevent`). */
|
|
92
|
+
export declare function prevent<E extends Event>(fn?: Handler<E>): Handler<E>;
|
|
93
|
+
/** A handler that calls `event.stopPropagation()` first (`.stop`). */
|
|
94
|
+
export declare function stop<E extends Event>(fn?: Handler<E>): Handler<E>;
|
|
95
|
+
/** A handler that ignores events from inside the element (`.self`). */
|
|
96
|
+
export declare function selfOnly<E extends Event>(fn?: Handler<E>): Handler<E>;
|
|
97
|
+
/** A handler that submits the element's form after `fn` runs (`.submit`), with validation. */
|
|
98
|
+
export declare function submit<E extends Event>(fn?: (event: E) => unknown): (event: E) => unknown;
|
|
99
|
+
/**
|
|
100
|
+
* A keyboard handler for `'enter'`, `'shift+enter'`, `'ctrl+k'`, … (several: `'enter, space'`).
|
|
101
|
+
* The modifier keys named must be held, and the others not.
|
|
102
|
+
*/
|
|
103
|
+
export declare function keys(combinations: string, fn?: Handler<KeyboardEvent>): Handler<KeyboardEvent>;
|
|
104
|
+
|
|
105
|
+
// ---- styles ---------------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Add stylesheets (CSS text or `CSSStyleSheet`s) to every zubra shadow root, now and later: for
|
|
109
|
+
* app-wide CSS such as Tailwind's output, which page styles can't carry into shadow DOM.
|
|
110
|
+
* Light-DOM components already get page CSS.
|
|
111
|
+
*/
|
|
112
|
+
export declare function adoptStyles(...styles: (string | CSSStyleSheet)[]): CSSStyleSheet[];
|
|
113
|
+
|
|
114
|
+
// ---- context (the Web Components Community Group Context Protocol) -------------------------
|
|
115
|
+
|
|
116
|
+
export interface Context<T> {
|
|
117
|
+
readonly defaultValue: T;
|
|
118
|
+
}
|
|
119
|
+
/** A context key, with the value consumers get when no provider answers. */
|
|
120
|
+
export declare function createContext<T>(defaultValue: T): Context<T>;
|
|
121
|
+
/** Provide `value` for `context` to every element inside this one. */
|
|
122
|
+
export declare function provide<T>(context: Context<T> | unknown, value: MaybeSignal<T>): void;
|
|
123
|
+
/** Read `context` from the nearest provider above this element, as a signal. */
|
|
124
|
+
export declare function inject<T>(context: Context<T>, fallback?: T): Signal.Computed<T>;
|
|
125
|
+
export declare function inject<T = unknown>(context: unknown, fallback?: T): Signal.Computed<T>;
|
|
126
|
+
|
|
127
|
+
export declare class ContextRequestEvent<T = unknown> extends Event {
|
|
128
|
+
constructor(context: unknown, contextTarget: Element, callback: (value: T, unsubscribe?: () => void) => void, subscribe?: boolean);
|
|
129
|
+
readonly context: unknown;
|
|
130
|
+
readonly contextTarget: Element;
|
|
131
|
+
readonly callback: (value: T, unsubscribe?: () => void) => void;
|
|
132
|
+
readonly subscribe?: boolean;
|
|
133
|
+
}
|
|
134
|
+
export declare class ContextProviderEvent extends Event {
|
|
135
|
+
constructor(context: unknown, contextTarget: Element);
|
|
136
|
+
readonly context: unknown;
|
|
137
|
+
readonly contextTarget: Element;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---- form-associated components (`form-associated` on the host) ---------------------------
|
|
141
|
+
|
|
142
|
+
/** What the form submits for this control: follows `source`. */
|
|
143
|
+
export declare function formValue(source: MaybeSignal<string | number | File | FormData | null | undefined> | (() => unknown)): void;
|
|
144
|
+
/** Validation: `check()` returns an error message, or '' / null when the value is valid. */
|
|
145
|
+
export declare function validity(check: () => string | null | undefined | MaybeSignal<string | null | undefined>): void;
|
|
146
|
+
export declare function onFormReset(fn: () => void): void;
|
|
147
|
+
export declare function onFormRestore(fn: (state: string | File | FormData | null, mode: 'restore' | 'autocomplete') => void): void;
|
|
148
|
+
export declare function onFormDisabled(fn: (disabled: boolean) => void): void;
|
|
149
|
+
|
|
150
|
+
// ---- what compiled code uses ---------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
export interface PropSpec {
|
|
153
|
+
attribute: string;
|
|
154
|
+
default: unknown;
|
|
155
|
+
required?: boolean;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** What adapters and tools read from a compiled element class (`Element.zb`). */
|
|
159
|
+
export interface ElementMeta {
|
|
160
|
+
readonly tag: string;
|
|
161
|
+
readonly props: Readonly<Record<string, Readonly<Required<PropSpec>>>>;
|
|
162
|
+
readonly events: readonly string[];
|
|
163
|
+
readonly slots: readonly string[];
|
|
164
|
+
readonly shadow: boolean;
|
|
165
|
+
readonly form: boolean;
|
|
166
|
+
/** The component has a `<style>` (light DOM: slotted content is marked `data-zb-slotted`). */
|
|
167
|
+
readonly styled: boolean;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface ZubraElementClass<E extends HTMLElement = HTMLElement> {
|
|
171
|
+
new (): E & { readonly updateComplete: Promise<void> };
|
|
172
|
+
readonly zubra: ElementMeta;
|
|
173
|
+
readonly formAssociated: boolean;
|
|
174
|
+
readonly observedAttributes: string[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface Definition {
|
|
178
|
+
props?: Record<string, PropSpec>;
|
|
179
|
+
template?: string;
|
|
180
|
+
shadow?: boolean;
|
|
181
|
+
form?: boolean;
|
|
182
|
+
slots?: string[];
|
|
183
|
+
events?: string[];
|
|
184
|
+
/** The component has a `<style>`. */
|
|
185
|
+
styled?: boolean;
|
|
186
|
+
/** Its stylesheet, when the module carries it (otherwise the bundler adds it to the page). */
|
|
187
|
+
styles?: string | CSSStyleSheet | null;
|
|
188
|
+
/** Runs once per element; returns the template's parts. */
|
|
189
|
+
setup?: (props: Record<string, unknown>, emit: (name: string, detail?: unknown) => boolean) => unknown[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @internal Register a compiled component: what the compiler's JavaScript output calls. Its
|
|
194
|
+
* arguments are the compiled-code interface, version `ABI`, not a public API.
|
|
195
|
+
*/
|
|
196
|
+
export declare function $define(tag: string, definition: Definition & { abi: number }): ZubraElementClass;
|
|
197
|
+
/** The compiled-code interface version this runtime implements. */
|
|
198
|
+
export declare const ABI: number;
|
|
199
|
+
|
|
200
|
+
/** Whether a URL is safe for `href`/`src`: relative, or http(s), mailto or tel. */
|
|
201
|
+
export declare function isSafeUrl(value: string): boolean;
|
|
202
|
+
/** @internal Read a value that may be a signal. */
|
|
203
|
+
export declare function $r<T>(value: MaybeSignal<T>): T;
|
|
204
|
+
/** @internal A value as template text. */
|
|
205
|
+
export declare function $t(value: unknown): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One tab stop for a group of items, with the arrow keys, Home and End moving focus among them
|
|
3
|
+
* (the roving tabindex). Returns a cleanup.
|
|
4
|
+
*/
|
|
5
|
+
export declare function rovingFocus(
|
|
6
|
+
container: Element,
|
|
7
|
+
options: { selector: string; orientation?: 'vertical' | 'horizontal' | 'both'; loop?: boolean; onMove?: (item: HTMLElement) => void },
|
|
8
|
+
): () => void;
|
|
9
|
+
/**
|
|
10
|
+
* Type to jump to the next item whose text starts with what was typed. Returns a cleanup.
|
|
11
|
+
*/
|
|
12
|
+
export declare function typeahead(
|
|
13
|
+
container: Element,
|
|
14
|
+
options: { selector: string; text?: (item: HTMLElement) => string; timeout?: number; onMatch?: (item: HTMLElement) => void },
|
|
15
|
+
): () => void;
|
package/types/react.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { ZubraElementClass } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A zubra element as a React component (React 18 and 19): props as properties, `on<Event>`
|
|
6
|
+
* handlers for its events, other props and children passed to the element. The build plugin's
|
|
7
|
+
* generated typings give exact prop types; this one is general.
|
|
8
|
+
*/
|
|
9
|
+
export declare function wrap<E extends HTMLElement>(
|
|
10
|
+
Element: ZubraElementClass<E>,
|
|
11
|
+
): React.ForwardRefExoticComponent<
|
|
12
|
+
React.HTMLAttributes<E> & Record<string, unknown> & { children?: React.ReactNode } & React.RefAttributes<E>
|
|
13
|
+
> & { readonly element: ZubraElementClass<E> };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ZubraElementClass } from './index.js';
|
|
2
|
+
|
|
3
|
+
export interface RenderOptions {
|
|
4
|
+
/** The element's prop values (JSON). */
|
|
5
|
+
props?: Record<string, unknown>;
|
|
6
|
+
/** Other attributes for the host (`class`, `id`, …). `true` writes a boolean attribute; `false` and nullish are left out. */
|
|
7
|
+
attributes?: Record<string, string | number | boolean | null | undefined>;
|
|
8
|
+
/** Supplied content by slot name (`default` for unnamed content), as HTML. */
|
|
9
|
+
slots?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Register how to server-render `tag`. Called by the build plugin's server output. */
|
|
13
|
+
export declare function registerRenderer(tag: string, render: (props: Record<string, unknown>, slots: Record<string, string>) => string): void;
|
|
14
|
+
/** Whether `Element` is a zubra element that can be rendered here. */
|
|
15
|
+
export declare function canRender(Element: unknown): Element is ZubraElementClass;
|
|
16
|
+
/** The element's server-rendered HTML, which it hydrates in the browser. */
|
|
17
|
+
export declare function renderToString(Element: ZubraElementClass, options?: RenderOptions): string;
|
|
18
|
+
/**
|
|
19
|
+
* An element's server-rendered content for a host a framework renders bare: a shadow-DOM
|
|
20
|
+
* element's declarative shadow root, or a light-DOM element's rendered children, plus a form
|
|
21
|
+
* control's hidden fallback input when `name` is given. Empty when it can't be rendered here.
|
|
22
|
+
* The React and Vue wrappers use it; a framework must leave the host's content alone while
|
|
23
|
+
* hydrating (`dangerouslySetInnerHTML`, `innerHTML`).
|
|
24
|
+
*/
|
|
25
|
+
export declare function serverContent(Element: ZubraElementClass, options?: { props?: Record<string, unknown>; name?: string }): string;
|
|
26
|
+
/** `serverContent` for a shadow-DOM element only (the 2.11 name). */
|
|
27
|
+
export declare function shadowContent(Element: ZubraElementClass, options?: { props?: Record<string, unknown>; name?: string }): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// The TC39 Signals API (https://github.com/tc39/proposal-signals): the platform's own when the
|
|
2
|
+
// browser has it, otherwise zubra's implementation.
|
|
3
|
+
|
|
4
|
+
export declare namespace Signal {
|
|
5
|
+
interface Options<T> {
|
|
6
|
+
/** When two values count as the same (no change): `Object.is` by default. */
|
|
7
|
+
equals?: (this: AnySignal<T>, a: T, b: T) => boolean;
|
|
8
|
+
[Signal.subtle.watched]?: (this: AnySignal<T>) => void;
|
|
9
|
+
[Signal.subtle.unwatched]?: (this: AnySignal<T>) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type AnySignal<T = any> = State<T> | Computed<T>;
|
|
13
|
+
type AnySink = Computed<any> | subtle.Watcher;
|
|
14
|
+
|
|
15
|
+
class State<T> {
|
|
16
|
+
constructor(initialValue: T, options?: Options<T>);
|
|
17
|
+
get(): T;
|
|
18
|
+
set(value: T): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class Computed<T> {
|
|
22
|
+
constructor(computation: (this: Computed<T>) => T, options?: Options<T>);
|
|
23
|
+
get(): T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
namespace subtle {
|
|
27
|
+
function untrack<T>(fn: () => T): T;
|
|
28
|
+
function currentComputed(): Computed<any> | undefined;
|
|
29
|
+
function introspectSources(sink: AnySink): AnySignal[];
|
|
30
|
+
function introspectSinks(signal: AnySignal): AnySink[];
|
|
31
|
+
function hasSinks(signal: AnySignal): boolean;
|
|
32
|
+
function hasSources(signal: AnySink): boolean;
|
|
33
|
+
const watched: unique symbol;
|
|
34
|
+
const unwatched: unique symbol;
|
|
35
|
+
|
|
36
|
+
class Watcher {
|
|
37
|
+
constructor(notify: (this: Watcher) => void);
|
|
38
|
+
watch(...signals: AnySignal[]): void;
|
|
39
|
+
unwatch(...signals: AnySignal[]): void;
|
|
40
|
+
getPending(): AnySignal[];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** True when the browser provides `Signal` natively. */
|
|
46
|
+
export declare const isNative: boolean;
|
package/types/vue.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DefineComponent } from 'vue';
|
|
2
|
+
import type { ElementMeta, ZubraElementClass } from './index.js';
|
|
3
|
+
|
|
4
|
+
/** A zubra element as a Vue 3 component: props, events, `v-model` from `<prop>change` pairs. */
|
|
5
|
+
export declare function wrap(Element: ZubraElementClass): DefineComponent<Record<string, unknown>>;
|
|
6
|
+
|
|
7
|
+
/** The component's two-way bindings: `<prop>` + `<prop>change` pairs. */
|
|
8
|
+
export declare function models(meta: Pick<ElementMeta, 'props' | 'events'>): { prop: string; event: string }[];
|
package/types/zag.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a Zag.js machine for this element: started when it connects, stopped when it disconnects
|
|
3
|
+
* (a fresh machine each time it connects). `props` is the machine's props, or a function returning
|
|
4
|
+
* them. `current` is the machine's service, read reactively: pass it to the machine's `connect()`
|
|
5
|
+
* inside a `computed`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useMachine<Service = any>(machine: unknown, props?: Record<string, unknown> | (() => Record<string, unknown>)): { readonly current: Service };
|
|
8
|
+
/** Zag's prop normalizer for the DOM (attribute names, lowercased listeners): pass it to `connect()`. */
|
|
9
|
+
export { normalizeProps } from '@zag-js/vanilla';
|