@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.
Files changed (37) hide show
  1. package/README.md +63 -24
  2. package/USAGE.md +584 -0
  3. package/components/calendar-picker/calendar-picker.d.ts +27 -0
  4. package/components/check/check.d.ts +30 -0
  5. package/components/code/code.d.ts +39 -0
  6. package/components/color-picker/color-picker.d.ts +37 -0
  7. package/components/index.js +1 -0
  8. package/components/input/input.d.ts +61 -0
  9. package/components/option-card/option-card.d.ts +30 -0
  10. package/components/otp-input/otp-input.d.ts +25 -0
  11. package/components/pane/pane.css +10 -0
  12. package/components/pane/pane.js +28 -4
  13. package/components/radio/radio.d.ts +28 -0
  14. package/components/range/range.d.ts +31 -0
  15. package/components/rating/rating.d.ts +33 -0
  16. package/components/search/search.d.ts +35 -0
  17. package/components/segmented/segmented.d.ts +24 -0
  18. package/components/select/select.d.ts +57 -0
  19. package/components/slider/slider.d.ts +31 -0
  20. package/components/switch/switch.d.ts +30 -0
  21. package/components/textarea/textarea.d.ts +31 -0
  22. package/components/toggle-scheme/toggle-scheme.a2ui.json +197 -0
  23. package/components/toggle-scheme/toggle-scheme.css +20 -0
  24. package/components/toggle-scheme/toggle-scheme.js +277 -0
  25. package/components/toggle-scheme/toggle-scheme.yaml +173 -0
  26. package/components/upload/upload.d.ts +27 -0
  27. package/core/element.d.ts +174 -0
  28. package/core/form.d.ts +108 -0
  29. package/core/index.d.ts +11 -0
  30. package/core/index.js +1 -0
  31. package/core/register.d.ts +25 -0
  32. package/core/register.js +58 -0
  33. package/core/signals.d.ts +94 -0
  34. package/core/template.d.ts +70 -0
  35. package/index.d.ts +161 -0
  36. package/package.json +21 -6
  37. 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
+ }
@@ -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;
@@ -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;