@adia-ai/web-components 0.4.5 → 0.4.6
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 +63 -24
- package/USAGE.md +584 -0
- package/components/calendar-picker/calendar-picker.d.ts +27 -0
- package/components/check/check.d.ts +30 -0
- package/components/code/code.d.ts +39 -0
- package/components/color-picker/color-picker.d.ts +37 -0
- package/components/index.js +1 -0
- package/components/input/input.d.ts +61 -0
- package/components/option-card/option-card.d.ts +30 -0
- package/components/otp-input/otp-input.d.ts +25 -0
- package/components/pane/pane.css +10 -0
- package/components/pane/pane.js +28 -4
- package/components/radio/radio.d.ts +28 -0
- package/components/range/range.d.ts +31 -0
- package/components/rating/rating.d.ts +33 -0
- package/components/search/search.d.ts +35 -0
- package/components/segmented/segmented.d.ts +24 -0
- package/components/select/select.d.ts +57 -0
- package/components/slider/slider.d.ts +31 -0
- package/components/switch/switch.d.ts +30 -0
- package/components/textarea/textarea.d.ts +31 -0
- package/components/toggle-scheme/toggle-scheme.a2ui.json +197 -0
- package/components/toggle-scheme/toggle-scheme.css +20 -0
- package/components/toggle-scheme/toggle-scheme.js +277 -0
- package/components/toggle-scheme/toggle-scheme.yaml +173 -0
- package/components/upload/upload.d.ts +27 -0
- package/core/element.d.ts +174 -0
- package/core/form.d.ts +108 -0
- package/core/index.d.ts +11 -0
- package/core/index.js +1 -0
- package/core/register.d.ts +25 -0
- package/core/register.js +58 -0
- package/core/signals.d.ts +94 -0
- package/core/template.d.ts +70 -0
- package/index.d.ts +161 -0
- package/package.json +21 -6
- package/traits/CATEGORIES.md +1 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIElement — light-DOM reactive base class.
|
|
3
|
+
*
|
|
4
|
+
* Every primitive in `@adia-ai/web-components` extends this (or `UIFormElement`
|
|
5
|
+
* for form-bearing primitives). Provides signal-backed property reactivity,
|
|
6
|
+
* lifecycle hooks (`connected`/`render`/`updated`/`disconnected`), and
|
|
7
|
+
* tagged-template rendering.
|
|
8
|
+
*
|
|
9
|
+
* @see ../USAGE.md#lifecycle
|
|
10
|
+
* @see ../USAGE.md#property-reactivity-signal-backed
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReadonlySignal, Signal } from './signals.js';
|
|
14
|
+
import type { TemplateResult } from './template.js';
|
|
15
|
+
|
|
16
|
+
/** Property declaration in a component's `static properties = { … }` map. */
|
|
17
|
+
export interface PropertyConfig<T = unknown> {
|
|
18
|
+
/** Coercion target — `Boolean`, `Number`, `String`, or custom. */
|
|
19
|
+
type?: BooleanConstructor | NumberConstructor | StringConstructor | (new (...args: unknown[]) => T);
|
|
20
|
+
/** Initial value. Defaults to `undefined`. */
|
|
21
|
+
default?: T;
|
|
22
|
+
/** Mirror property changes to an HTML attribute. */
|
|
23
|
+
reflect?: boolean;
|
|
24
|
+
/** Custom attribute name. Default: kebab-case of property key. */
|
|
25
|
+
attribute?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Map of property name → config. The shape consumed by `static properties`. */
|
|
29
|
+
export type PropertiesMap = Record<string, PropertyConfig>;
|
|
30
|
+
|
|
31
|
+
/** Trait name + config tuple passed via `static traits`. */
|
|
32
|
+
export type TraitDeclaration = string | { name: string; [opt: string]: unknown };
|
|
33
|
+
|
|
34
|
+
/** Map of slot name → markup string. Consumed by `static parts`. */
|
|
35
|
+
export type PartsMap = Record<string, string>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Light-DOM reactive base class. Subclass to author a primitive.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* class MyWidget extends UIElement {
|
|
42
|
+
* static properties = { label: { type: String, default: '' } };
|
|
43
|
+
* render() { this.textContent = this.label; }
|
|
44
|
+
* }
|
|
45
|
+
* customElements.define('my-widget', MyWidget);
|
|
46
|
+
*/
|
|
47
|
+
export class UIElement extends HTMLElement {
|
|
48
|
+
/**
|
|
49
|
+
* Property declarations — signal-backed getters/setters wired by the
|
|
50
|
+
* constructor. Override in subclasses.
|
|
51
|
+
*/
|
|
52
|
+
static properties: PropertiesMap;
|
|
53
|
+
|
|
54
|
+
/** Trait declarations — applied during `connectedCallback`. */
|
|
55
|
+
static traits: readonly TraitDeclaration[];
|
|
56
|
+
|
|
57
|
+
/** Slot blueprints used by `ensure(slotName)`. */
|
|
58
|
+
static parts?: PartsMap;
|
|
59
|
+
|
|
60
|
+
/** Stylesheets to adopt onto the document on first render. */
|
|
61
|
+
static styles?: CSSStyleSheet | readonly CSSStyleSheet[];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Pure-function template — called inside the host's render effect. Reading
|
|
65
|
+
* `this.foo` inside subscribes the effect to the `foo` signal.
|
|
66
|
+
*
|
|
67
|
+
* Override OR return `null` and update DOM imperatively in `render()`.
|
|
68
|
+
*/
|
|
69
|
+
static template: <T extends UIElement>(host: T) => TemplateResult | null;
|
|
70
|
+
|
|
71
|
+
/** Observed attribute names — derived from `static properties`. */
|
|
72
|
+
static readonly observedAttributes: readonly string[];
|
|
73
|
+
|
|
74
|
+
/** ElementInternals — attached in the constructor; carries form state etc. */
|
|
75
|
+
readonly internals: ElementInternals;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Setup hook — called after construction + insertion, before the first render
|
|
79
|
+
* effect installs. Set up listeners on document / external targets here.
|
|
80
|
+
*
|
|
81
|
+
* Override in subclasses; default is a no-op. Runs inside `untracked()` so
|
|
82
|
+
* reads don't leak subscriptions to outer effects.
|
|
83
|
+
*/
|
|
84
|
+
connected(): void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Imperative update hook — called every time any property signal mutates.
|
|
88
|
+
* Reading `this.foo` here subscribes the effect to `foo`.
|
|
89
|
+
*
|
|
90
|
+
* Override in subclasses; default is a no-op.
|
|
91
|
+
*/
|
|
92
|
+
render(): void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Post-render hook — called after `render()`. `changed` is a map of every
|
|
96
|
+
* property that mutated this tick, keyed by property name with old value.
|
|
97
|
+
*
|
|
98
|
+
* Override in subclasses; default is a no-op.
|
|
99
|
+
*/
|
|
100
|
+
updated(changed: ReadonlyMap<string, unknown>): void;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Teardown hook — called on element removal. Clean up listeners + intervals
|
|
104
|
+
* + observers here.
|
|
105
|
+
*
|
|
106
|
+
* Override in subclasses; default is a no-op.
|
|
107
|
+
*/
|
|
108
|
+
disconnected(): void;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Error hook — called when the host's render effect throws. Receives the
|
|
112
|
+
* thrown value. Default behavior: rethrow.
|
|
113
|
+
*/
|
|
114
|
+
onError?(err: unknown): void;
|
|
115
|
+
|
|
116
|
+
// ── Standard custom-element callbacks (overridable but rarely needed) ──
|
|
117
|
+
|
|
118
|
+
connectedCallback(): void;
|
|
119
|
+
disconnectedCallback(): void;
|
|
120
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
121
|
+
|
|
122
|
+
// ── Convenience helpers ──
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create a local signal bound to this element's lifetime. Disposed on
|
|
126
|
+
* `disconnectedCallback`.
|
|
127
|
+
*/
|
|
128
|
+
signal<T>(initial: T): Signal<T>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get or stamp a slot child by name. If a `[slot="name"]` child exists,
|
|
132
|
+
* returns it; otherwise stamps the blueprint from `static parts[name]`,
|
|
133
|
+
* appends it, and returns the new node.
|
|
134
|
+
*/
|
|
135
|
+
ensure(slotName: string): Element | null;
|
|
136
|
+
|
|
137
|
+
/** Remove the `[slot="name"]` child if present. */
|
|
138
|
+
drop(slotName: string): void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Keyed-reconcile a parent's children against `items`. Used internally by
|
|
142
|
+
* the `repeat` directive; consumers rarely call directly.
|
|
143
|
+
*/
|
|
144
|
+
reconcile<T>(
|
|
145
|
+
parent: Element,
|
|
146
|
+
items: readonly T[],
|
|
147
|
+
keyFn: (item: T, i: number) => string | number,
|
|
148
|
+
stampFn: (item: T, i: number, existing: Element | null) => Element,
|
|
149
|
+
): void;
|
|
150
|
+
|
|
151
|
+
// ── Controller pattern (optional advanced) ──
|
|
152
|
+
|
|
153
|
+
/** Set the controller; calls connect/disconnect on it through lifecycle. */
|
|
154
|
+
set controller(c: UIController | null);
|
|
155
|
+
get controller(): UIController | null;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Factory — create an instance of this element with the given props applied.
|
|
159
|
+
* Tag must already be registered.
|
|
160
|
+
*/
|
|
161
|
+
static create<T extends typeof UIElement>(
|
|
162
|
+
this: T,
|
|
163
|
+
props?: Partial<InstanceType<T>>,
|
|
164
|
+
): InstanceType<T>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Controller — optional pluggable behavior attached to a UIElement via
|
|
169
|
+
* `element.controller = …`. Lifecycle mirrors the host.
|
|
170
|
+
*/
|
|
171
|
+
export interface UIController {
|
|
172
|
+
connect?(host: UIElement): void;
|
|
173
|
+
disconnect?(host: UIElement): void;
|
|
174
|
+
}
|
package/core/form.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIFormElement — base class for form-bearing primitives.
|
|
3
|
+
*
|
|
4
|
+
* Extends UIElement with `ElementInternals` form participation, value sync,
|
|
5
|
+
* constraint validation, and the standard validity surface. 15 primitives
|
|
6
|
+
* extend this: input, select, slider, switch, segmented, check, radio,
|
|
7
|
+
* textarea, range, color-picker, rating, option-card, search, otp-input, code.
|
|
8
|
+
*
|
|
9
|
+
* @see ../USAGE.md#form-participation
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { UIElement, type PropertiesMap } from './element.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Form-participating reactive base class. Subclass to author a form-bearing
|
|
16
|
+
* primitive. `static formAssociated = true` is already set; consumer subclasses
|
|
17
|
+
* shouldn't override it.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* class MyField extends UIFormElement {
|
|
21
|
+
* static properties = {
|
|
22
|
+
* ...UIFormElement.properties,
|
|
23
|
+
* maxItems: { type: Number, default: 10 },
|
|
24
|
+
* };
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
export class UIFormElement extends UIElement {
|
|
28
|
+
/** Marks the element as form-associated. Do not override. */
|
|
29
|
+
static readonly formAssociated: true;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Base property set inherited by every form-bearing primitive. Subclasses
|
|
33
|
+
* spread this into their own `static properties`.
|
|
34
|
+
*/
|
|
35
|
+
static properties: PropertiesMap & {
|
|
36
|
+
name: { type: StringConstructor; default: ''; reflect: true };
|
|
37
|
+
value: { type: StringConstructor; default: ''; reflect: true };
|
|
38
|
+
disabled: { type: BooleanConstructor; default: false; reflect: true };
|
|
39
|
+
required: { type: BooleanConstructor; default: false; reflect: true };
|
|
40
|
+
readonly: { type: BooleanConstructor; default: false; reflect: true };
|
|
41
|
+
error: { type: StringConstructor; default: ''; reflect: true };
|
|
42
|
+
hint: { type: StringConstructor; default: ''; reflect: true };
|
|
43
|
+
pattern: { type: StringConstructor; default: ''; reflect: true };
|
|
44
|
+
minlength: { type: NumberConstructor; default: null; reflect: true };
|
|
45
|
+
maxlength: { type: NumberConstructor; default: null; reflect: true };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// ── Inherited UIFormElement properties (typed) ──
|
|
49
|
+
/** Form field name — submitted as key in FormData. */
|
|
50
|
+
name: string;
|
|
51
|
+
/** Submitted value. Subclasses may narrow the type (e.g. `slider-ui` to `number`). */
|
|
52
|
+
value: string;
|
|
53
|
+
/** Disabled state — reflected, blocks interaction. */
|
|
54
|
+
disabled: boolean;
|
|
55
|
+
/** Required state — checked against value emptiness on validation. */
|
|
56
|
+
required: boolean;
|
|
57
|
+
/** Read-only state — reflected, blocks user input but submits value. */
|
|
58
|
+
readonly: boolean;
|
|
59
|
+
/** Current error message — surfaces via `:invalid` + reportValidity. */
|
|
60
|
+
error: string;
|
|
61
|
+
/** Hint text — usually rendered below the control. */
|
|
62
|
+
hint: string;
|
|
63
|
+
/** Regex pattern — value must match if set. */
|
|
64
|
+
pattern: string;
|
|
65
|
+
/** Minimum length — `null` to disable. */
|
|
66
|
+
minlength: number | null;
|
|
67
|
+
/** Maximum length — `null` to disable. */
|
|
68
|
+
maxlength: number | null;
|
|
69
|
+
|
|
70
|
+
// ── ElementInternals accessors ──
|
|
71
|
+
|
|
72
|
+
/** The form this element is associated with, or `null` if not in a form. */
|
|
73
|
+
readonly form: HTMLFormElement | null;
|
|
74
|
+
/** Labels associated with this element via `for` / wrapping. */
|
|
75
|
+
readonly labels: NodeList;
|
|
76
|
+
/** Current validity state. */
|
|
77
|
+
readonly validity: ValidityState;
|
|
78
|
+
/** Localized validation message. */
|
|
79
|
+
readonly validationMessage: string;
|
|
80
|
+
/** Whether the element will be validated when its form is submitted. */
|
|
81
|
+
readonly willValidate: boolean;
|
|
82
|
+
|
|
83
|
+
/** Returns true if the element passes all constraint validations. */
|
|
84
|
+
checkValidity(): boolean;
|
|
85
|
+
|
|
86
|
+
/** Like `checkValidity()` but also surfaces error UI if invalid. */
|
|
87
|
+
reportValidity(): boolean;
|
|
88
|
+
|
|
89
|
+
// ── Manual validation control ──
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Run constraint validation against the current value. Returns true if valid.
|
|
93
|
+
* Sets `error` + surfaces UI if invalid.
|
|
94
|
+
*/
|
|
95
|
+
validate(): boolean;
|
|
96
|
+
|
|
97
|
+
/** Mark the element invalid with a custom error message. */
|
|
98
|
+
setInvalid(message: string): void;
|
|
99
|
+
|
|
100
|
+
/** Clear the invalid state. */
|
|
101
|
+
setValid(): void;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Update the form-submission value + run constraint checks. Called internally
|
|
105
|
+
* on input/change; consumers rarely call directly.
|
|
106
|
+
*/
|
|
107
|
+
syncValue(value: string): void;
|
|
108
|
+
}
|
package/core/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types — re-exports the public API surface from `core/`.
|
|
3
|
+
*
|
|
4
|
+
* @see ../USAGE.md
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * from './signals.js';
|
|
8
|
+
export * from './template.js';
|
|
9
|
+
export * from './element.js';
|
|
10
|
+
export * from './form.js';
|
|
11
|
+
export * from './register.js';
|
package/core/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from './element.js';
|
|
|
16
16
|
export * from './form.js';
|
|
17
17
|
export * from './signals.js';
|
|
18
18
|
export * from './template.js';
|
|
19
|
+
export * from './register.js';
|
|
19
20
|
export * from './controller.js';
|
|
20
21
|
export * from './provider.js';
|
|
21
22
|
export * from './anchor.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom-element registration helpers.
|
|
3
|
+
*
|
|
4
|
+
* @see ../USAGE.md#registration--auto-vs-explicit
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register a custom element. Same semantics as `customElements.define` — throws
|
|
9
|
+
* if `tagName` is already registered.
|
|
10
|
+
*/
|
|
11
|
+
export function register(tagName: string, ctor: CustomElementConstructor): void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Register a custom element only if the tag isn't already taken. Useful when
|
|
15
|
+
* multiple sources may try to register the same tag (e.g. when a host page
|
|
16
|
+
* imports the AdiaUI bundle AND a downstream consumer imports per-component
|
|
17
|
+
* subpaths). Without this, the second `customElements.define` throws.
|
|
18
|
+
*
|
|
19
|
+
* Returns `true` if registration happened, `false` if the tag was already
|
|
20
|
+
* registered.
|
|
21
|
+
*/
|
|
22
|
+
export function defineIfFree(tagName: string, ctor: CustomElementConstructor): boolean;
|
|
23
|
+
|
|
24
|
+
/** Returns true if the given tag is already registered. */
|
|
25
|
+
export function isRegistered(tagName: string): boolean;
|
package/core/register.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom-element registration helpers.
|
|
3
|
+
*
|
|
4
|
+
* The package's components auto-register their tags at the bottom of each
|
|
5
|
+
* component `.js` file (the de-facto web-components convention). These
|
|
6
|
+
* helpers give consumers controllable alternatives:
|
|
7
|
+
*
|
|
8
|
+
* - `register(tagName, ctor)` — direct alias for `customElements.define`.
|
|
9
|
+
* No magic; provided so consumers can write the registration call without
|
|
10
|
+
* importing the constructor globally.
|
|
11
|
+
*
|
|
12
|
+
* - `defineIfFree(tagName, ctor)` — no-op if the tag is already registered.
|
|
13
|
+
* Use this when multiple packages may try to register the same tag (e.g.
|
|
14
|
+
* when a host page imports the AdiaUI bundle AND a downstream consumer
|
|
15
|
+
* also imports per-component subpaths). Without this, the second
|
|
16
|
+
* `customElements.define` throws `NotSupportedError`.
|
|
17
|
+
*
|
|
18
|
+
* @see ../USAGE.md#registration--auto-vs-explicit
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Register a custom element. Same semantics as `customElements.define`;
|
|
23
|
+
* throws if `tagName` is already registered.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} tagName The kebab-case tag name (e.g. `'my-slider'`)
|
|
26
|
+
* @param {CustomElementConstructor} ctor The class to register
|
|
27
|
+
*/
|
|
28
|
+
export function register(tagName, ctor) {
|
|
29
|
+
customElements.define(tagName, ctor);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Register a custom element only if the tag isn't already taken. Useful for
|
|
34
|
+
* conflict-safe registration when multiple sources may want to register the
|
|
35
|
+
* same tag.
|
|
36
|
+
*
|
|
37
|
+
* Returns `true` if registration happened, `false` if the tag was already
|
|
38
|
+
* registered.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} tagName The kebab-case tag name
|
|
41
|
+
* @param {CustomElementConstructor} ctor The class to register
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
export function defineIfFree(tagName, ctor) {
|
|
45
|
+
if (customElements.get(tagName)) return false;
|
|
46
|
+
customElements.define(tagName, ctor);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check whether a tag is already registered.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} tagName
|
|
54
|
+
* @returns {boolean}
|
|
55
|
+
*/
|
|
56
|
+
export function isRegistered(tagName) {
|
|
57
|
+
return Boolean(customElements.get(tagName));
|
|
58
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive signals — the primitive that UIElement's property system is built on.
|
|
3
|
+
*
|
|
4
|
+
* @see ../USAGE.md#property-reactivity-signal-backed
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Read-only signal. Reading `.value` inside an `effect()` subscribes that effect. */
|
|
8
|
+
export interface ReadonlySignal<T> {
|
|
9
|
+
readonly value: T;
|
|
10
|
+
/** Read without creating a subscription. */
|
|
11
|
+
peek(): T;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Mutable signal. Writing `.value` notifies all subscribers. */
|
|
15
|
+
export interface Signal<T> extends ReadonlySignal<T> {
|
|
16
|
+
value: T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Computed signal — derived from other signals; recomputes lazily. */
|
|
20
|
+
export type ComputedSignal<T> = ReadonlySignal<T>;
|
|
21
|
+
|
|
22
|
+
/** Effect options. */
|
|
23
|
+
export interface EffectOptions {
|
|
24
|
+
/** Host tag name for diagnostic logging. */
|
|
25
|
+
host?: string;
|
|
26
|
+
/** Called when the effect body throws. Receives the error. */
|
|
27
|
+
onError?: ((err: unknown) => void) | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Cleanup function returned by `effect()`. Call to dispose the subscription. */
|
|
31
|
+
export type EffectDisposer = () => void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a mutable signal. Reading `.value` inside an `effect()` subscribes it.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const count = signal(0);
|
|
38
|
+
* effect(() => console.log(count.value)); // subscribes
|
|
39
|
+
* count.value = 1; // logs 1
|
|
40
|
+
*/
|
|
41
|
+
export function signal<T>(initial: T): Signal<T>;
|
|
42
|
+
export function signal<T = undefined>(): Signal<T | undefined>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create a computed signal — re-derives when any dependency changes. Lazy:
|
|
46
|
+
* recomputes only when read.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const a = signal(2);
|
|
50
|
+
* const b = signal(3);
|
|
51
|
+
* const sum = computed(() => a.value + b.value);
|
|
52
|
+
* sum.value; // 5
|
|
53
|
+
*/
|
|
54
|
+
export function computed<T>(fn: () => T): ComputedSignal<T>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Run `fn` inside a reactive context. Re-runs when any signal read during the
|
|
58
|
+
* last run changes. Returns a disposer.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const dispose = effect(() => console.log(count.value));
|
|
62
|
+
* // later
|
|
63
|
+
* dispose();
|
|
64
|
+
*/
|
|
65
|
+
export function effect(fn: () => void, opts?: EffectOptions): EffectDisposer;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Batch multiple signal mutations into one effect re-run. Useful for atomic
|
|
69
|
+
* updates that touch several signals.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* batch(() => {
|
|
73
|
+
* a.value = 1;
|
|
74
|
+
* b.value = 2;
|
|
75
|
+
* }); // effect runs once after both mutations
|
|
76
|
+
*/
|
|
77
|
+
export function batch(fn: () => void): void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Read signals inside `fn` without subscribing the surrounding effect.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* effect(() => {
|
|
84
|
+
* const snapshot = untracked(() => other.value); // does NOT subscribe
|
|
85
|
+
* console.log(active.value, snapshot); // only `active` subscribes
|
|
86
|
+
* });
|
|
87
|
+
*/
|
|
88
|
+
export function untracked<T>(fn: () => T): T;
|
|
89
|
+
|
|
90
|
+
/** Type guard — true if `v` looks like a signal. */
|
|
91
|
+
export function isSignal(v: unknown): v is ReadonlySignal<unknown>;
|
|
92
|
+
|
|
93
|
+
/** Brand symbol — identifies signal objects. Exported for advanced introspection. */
|
|
94
|
+
export const SIGNAL: unique symbol;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight tagged-template rendering — `html`, `css`, `repeat`, `stamp`.
|
|
3
|
+
*
|
|
4
|
+
* Detects signal/function bound values and wraps them in `effect()` so the
|
|
5
|
+
* binding re-fires on dependency change. Static values bypass — see USAGE.md
|
|
6
|
+
* § property-binding-patterns for the eager-evaluation trap.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ReadonlySignal } from './signals.js';
|
|
10
|
+
|
|
11
|
+
/** Result of an `html\`…\`` call — pass to `stamp()` to mount in a container. */
|
|
12
|
+
export interface TemplateResult {
|
|
13
|
+
readonly strings: TemplateStringsArray;
|
|
14
|
+
readonly values: readonly unknown[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tagged template for HTML — returns a `TemplateResult` that `stamp()` mounts.
|
|
19
|
+
*
|
|
20
|
+
* - `attr=${value}` — attribute binding (string-coerced, removed if null/false)
|
|
21
|
+
* - `.prop=${value}` — JS property binding (signal/function = reactive)
|
|
22
|
+
* - `@event=${handler}` — event listener binding
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* html`<button-ui .disabled=${isLoading} @click=${onSave}>Save</button-ui>`
|
|
26
|
+
*/
|
|
27
|
+
export function html(strings: TemplateStringsArray, ...values: unknown[]): TemplateResult;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Tagged template for CSS — returns a `CSSStyleSheet`. Use as `static styles =
|
|
31
|
+
* css\`…\`` on a component or feed to `document.adoptedStyleSheets`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const sheet = css`button { color: red; }`;
|
|
35
|
+
* document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
36
|
+
*/
|
|
37
|
+
export function css(strings: TemplateStringsArray, ...values: unknown[]): CSSStyleSheet;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Mount or update a `TemplateResult` inside a container. Re-running with a
|
|
41
|
+
* different result with the same `strings` reuses the template; different
|
|
42
|
+
* `strings` re-mounts.
|
|
43
|
+
*/
|
|
44
|
+
export function stamp(result: TemplateResult, container: Element): void;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Internal — disposes effects attached to template parts. You won't call this
|
|
48
|
+
* directly unless implementing a custom directive.
|
|
49
|
+
*/
|
|
50
|
+
export function disposeParts(parts: readonly unknown[]): void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Keyed list directive — minimal-ops re-render of dynamic lists. Reuses DOM
|
|
54
|
+
* elements across re-renders by `key`.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* html`<ul>${repeat(
|
|
58
|
+
* items.value,
|
|
59
|
+
* (item) => item.id,
|
|
60
|
+
* (item) => html`<li>${item.name}</li>`
|
|
61
|
+
* )}</ul>`
|
|
62
|
+
*/
|
|
63
|
+
export function repeat<T>(
|
|
64
|
+
items: readonly T[],
|
|
65
|
+
keyFn: (item: T, index: number) => string | number,
|
|
66
|
+
tplFn: (item: T, index: number) => TemplateResult,
|
|
67
|
+
): unknown;
|
|
68
|
+
|
|
69
|
+
/** Internal symbol — key-map storage on container nodes for `repeat()`. */
|
|
70
|
+
export const KEY_MAP: unique symbol;
|