@adia-ai/web-components 0.5.5 → 0.5.7

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 (47) hide show
  1. package/components/accordion/accordion-item.a2ui.json +19 -2
  2. package/components/accordion/accordion-item.yaml +20 -0
  3. package/components/accordion/accordion.a2ui.json +1 -1
  4. package/components/accordion/accordion.yaml +1 -1
  5. package/components/accordion/class.js +5 -0
  6. package/components/agent-artifact/agent-artifact.yaml +3 -0
  7. package/components/agent-artifact/class.js +5 -0
  8. package/components/agent-feedback-bar/class.js +9 -3
  9. package/components/calendar-picker/calendar-picker.d.ts +10 -0
  10. package/components/code/code.d.ts +8 -0
  11. package/components/color-picker/class.js +42 -4
  12. package/components/color-picker/color-picker.test.js +96 -0
  13. package/components/color-picker/color-picker.yaml +2 -0
  14. package/components/input/class.js +101 -1
  15. package/components/input/input.a2ui.json +2 -2
  16. package/components/input/input.css +57 -0
  17. package/components/input/input.d.ts +2 -0
  18. package/components/input/input.test.js +123 -0
  19. package/components/input/input.yaml +15 -2
  20. package/components/segmented/segmented.d.ts +3 -3
  21. package/components/select/select.d.ts +5 -3
  22. package/components/slider/slider.d.ts +4 -0
  23. package/components/switch/switch.d.ts +5 -3
  24. package/components/table/class.js +9 -1
  25. package/components/table/table.yaml +4 -0
  26. package/components/table-toolbar/class.js +5 -0
  27. package/components/table-toolbar/table-toolbar.yaml +4 -0
  28. package/components/text/text.a2ui.json +1 -8
  29. package/components/text/text.css +13 -0
  30. package/components/text/text.d.ts +1 -1
  31. package/components/text/text.test.js +106 -0
  32. package/components/text/text.yaml +0 -7
  33. package/components/timeline/class.js +5 -0
  34. package/components/timeline/timeline.yaml +3 -0
  35. package/components/toast/toast.d.ts +35 -0
  36. package/components/toggle-scheme/class.js +31 -0
  37. package/components/toggle-scheme/toggle-scheme.test.js +110 -0
  38. package/components/upload/upload.d.ts +6 -0
  39. package/core/anchor.d.ts +71 -0
  40. package/core/controller.d.ts +171 -0
  41. package/core/markdown.d.ts +26 -0
  42. package/core/polyfills.d.ts +31 -0
  43. package/core/provider.d.ts +82 -0
  44. package/core/streams-bridge.d.ts +78 -0
  45. package/core/transport.d.ts +78 -0
  46. package/package.json +4 -2
  47. package/styles/components.css +2 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * toggle-scheme-ui §200 race-fix tests — v0.5.7 (FEEDBACK-10 §1).
3
+ *
4
+ * Verifies the post-connect attribute application is HONORED — not raced over
5
+ * by the synchronous #initState() call in connected(). Per the bug class:
6
+ *
7
+ * 1. template.js scan() strips placeholder attributes pre-insertion
8
+ * 2. replaceChildren() upgrades the element; connectedCallback fires
9
+ * 3. #initState() reads this.scheme (default 'auto')
10
+ * 4. template.js update() then setAttribute('scheme', 'dark')
11
+ * 5. attributeChangedCallback syncs to property — but #initState already ran
12
+ *
13
+ * Pre-§200, step 4 was a no-op for the scheme cascade. Post-§200,
14
+ * attributeChangedCallback re-runs #initState() (until user-touched).
15
+ */
16
+
17
+ import { describe, it, expect, beforeEach } from 'vitest';
18
+ import '../../core/element.js';
19
+ import './toggle-scheme.js';
20
+
21
+ const tick = () => new Promise((r) => queueMicrotask(r));
22
+
23
+ function mount(html) {
24
+ const wrap = document.createElement('div');
25
+ wrap.innerHTML = html;
26
+ document.body.appendChild(wrap);
27
+ return wrap.firstElementChild;
28
+ }
29
+
30
+ describe('toggle-scheme-ui §200 race fix', () => {
31
+ beforeEach(() => {
32
+ document.body.innerHTML = '';
33
+ document.documentElement.style.removeProperty('color-scheme');
34
+ });
35
+
36
+ it('honors post-connect scheme attribute application (reactive consumer)', async () => {
37
+ // Simulate template.js's strip-then-restamp pattern: mount without scheme,
38
+ // then set the attribute immediately afterward (mimics post-connect apply).
39
+ const t = mount('<toggle-scheme-ui></toggle-scheme-ui>');
40
+ await tick();
41
+ t.setAttribute('scheme', 'dark');
42
+ await tick();
43
+ expect(t.activeScheme).toBe('dark');
44
+ expect(document.documentElement.style.colorScheme).toBe('dark');
45
+ });
46
+
47
+ it('honors the initial scheme attribute (no race scenario)', async () => {
48
+ const t = mount('<toggle-scheme-ui scheme="dark"></toggle-scheme-ui>');
49
+ await tick();
50
+ expect(t.activeScheme).toBe('dark');
51
+ });
52
+
53
+ it('user button press locks #userTouched — subsequent attr changes are ignored', async () => {
54
+ const t = mount('<toggle-scheme-ui scheme="dark"></toggle-scheme-ui>');
55
+ await tick();
56
+ expect(t.activeScheme).toBe('dark');
57
+
58
+ // User press: flips to light. #userTouched flips true.
59
+ const btn = t.querySelector(':scope > button-ui');
60
+ btn.dispatchEvent(new CustomEvent('press', { bubbles: true }));
61
+ await tick();
62
+ expect(t.activeScheme).toBe('light');
63
+
64
+ // Consumer re-renders with scheme="dark" — should NOT clobber user choice.
65
+ t.setAttribute('scheme', 'dark');
66
+ await tick();
67
+ expect(t.activeScheme).toBe('light'); // user choice survives
68
+ });
69
+
70
+ it('programmatic setScheme also locks #userTouched', async () => {
71
+ const t = mount('<toggle-scheme-ui scheme="auto"></toggle-scheme-ui>');
72
+ await tick();
73
+
74
+ t.setScheme('dark');
75
+ await tick();
76
+ expect(t.activeScheme).toBe('dark');
77
+
78
+ // Consumer reactive write should NOT override.
79
+ t.setAttribute('scheme', 'light');
80
+ await tick();
81
+ expect(t.activeScheme).toBe('dark');
82
+ });
83
+
84
+ it('toggle() also locks #userTouched', async () => {
85
+ const t = mount('<toggle-scheme-ui scheme="auto"></toggle-scheme-ui>');
86
+ await tick();
87
+ const initial = t.activeScheme; // depends on prefers-color-scheme (likely light in test env)
88
+
89
+ t.toggle();
90
+ await tick();
91
+ expect(t.activeScheme).not.toBe(initial);
92
+
93
+ const afterToggle = t.activeScheme;
94
+ t.setAttribute('scheme', initial === 'dark' ? 'dark' : 'light');
95
+ await tick();
96
+ expect(t.activeScheme).toBe(afterToggle); // user choice survives
97
+ });
98
+
99
+ it('removing the attribute (back to auto) is honored pre-touch', async () => {
100
+ const t = mount('<toggle-scheme-ui scheme="dark"></toggle-scheme-ui>');
101
+ await tick();
102
+ expect(t.activeScheme).toBe('dark');
103
+
104
+ t.removeAttribute('scheme');
105
+ await tick();
106
+ // After removal, attr is null; #initState falls to auto → resolves
107
+ // prefers-color-scheme. Test env should resolve to light by default.
108
+ expect(['light', 'dark']).toContain(t.activeScheme);
109
+ });
110
+ });
@@ -17,6 +17,12 @@ export type UploadChangeEvent = CustomEvent<UploadChangeEventDetail>;
17
17
  export class UIUpload extends UIFormElement {
18
18
  /** Files currently selected. */
19
19
  readonly files: FileList | File[];
20
+ /** §207 (v0.5.7): label rendered above the dropzone. */
21
+ label: string;
22
+ /** §207 (v0.5.7): MIME-type accept filter (e.g. `"image/*"` or `".pdf,.txt"`). */
23
+ accept: string;
24
+ /** §207 (v0.5.7): allow multi-file selection. */
25
+ multiple: boolean;
20
26
 
21
27
  addEventListener<K extends keyof HTMLElementEventMap>(
22
28
  type: K,
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Anchor positioning — positions a popover/panel relative to an anchor
3
+ * element. Uses native CSS Anchor Positioning when supported (Chrome
4
+ * 125+), falls back to a JS implementation (`getBoundingClientRect()` +
5
+ * `position: fixed`) otherwise.
6
+ *
7
+ * Works with the Popover API: the popover renders in the top layer via
8
+ * `showPopover()` on a `popover="manual"` or `popover="auto"` element,
9
+ * and the position is wired with either `anchor()` + `position-area` or
10
+ * manual coords.
11
+ *
12
+ * Runtime exports mirror `core/anchor.js`. `.d.ts` authored in v0.5.6
13
+ * §191 to close the §178 audit-script baseline missing-sibling gap.
14
+ *
15
+ * @see ./anchor.js (runtime SoT)
16
+ * @see ../USAGE.md (consumer guide)
17
+ */
18
+
19
+ /**
20
+ * Placement vocabulary for {@link anchorPopover}. Mirrors a subset of
21
+ * the floating-ui / Popper conventions. `-start` aligns the popover's
22
+ * leading edge to the anchor's leading edge along the perpendicular
23
+ * axis; `-end` aligns the trailing edges; bare (no suffix) centers.
24
+ */
25
+ export type Placement =
26
+ | 'bottom'
27
+ | 'bottom-start'
28
+ | 'bottom-end'
29
+ | 'top'
30
+ | 'top-start'
31
+ | 'top-end'
32
+ | 'left'
33
+ | 'left-start'
34
+ | 'left-end'
35
+ | 'right'
36
+ | 'right-start'
37
+ | 'right-end';
38
+
39
+ /**
40
+ * Options for {@link anchorPopover}.
41
+ */
42
+ export interface AnchorOptions {
43
+ /** Where to place the popover relative to its anchor. Default: `bottom-start`. */
44
+ placement?: Placement;
45
+ /** Pixel gap on the main (anchor-adjacent) axis. Default: 4. */
46
+ gap?: number;
47
+ /**
48
+ * When true, the popover's `width` is constrained to match the
49
+ * anchor's width — useful for combobox-style listboxes.
50
+ */
51
+ matchWidth?: boolean;
52
+ }
53
+
54
+ /**
55
+ * `true` when the current browser supports the CSS Anchor Positioning
56
+ * primitives the native path uses (`anchor-name`, `position-area`).
57
+ * `false` otherwise (browser falls back to the JS positioning path).
58
+ */
59
+ export const supportsAnchorCSS: boolean;
60
+
61
+ /**
62
+ * Position `popover` relative to `anchor`. Picks the native CSS Anchor
63
+ * Positioning path when available, otherwise the JS fallback. Returns a
64
+ * cleanup function — call it to detach listeners / restore inline
65
+ * styles.
66
+ */
67
+ export function anchorPopover(
68
+ anchor: Element,
69
+ popover: HTMLElement,
70
+ options?: AnchorOptions,
71
+ ): () => void;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Controller pattern — host-attached state objects that reflect into
3
+ * the DOM + notify subscribers on change. `BaseController` is the
4
+ * minimal contract; `RouteController` is the canonical routing-state
5
+ * implementation used by `<router-ui>` (see `core/provider.js`).
6
+ *
7
+ * Runtime exports mirror `core/controller.js`. `.d.ts` authored in
8
+ * v0.5.6 §191 to close the §178 audit-script baseline missing-sibling
9
+ * gap.
10
+ *
11
+ * @see ./controller.js (runtime SoT)
12
+ * @see ./provider.js (`<router-ui>` consumer of `RouteController`)
13
+ */
14
+
15
+ /**
16
+ * Static schema each {@link BaseController} subclass should declare so
17
+ * the dev-warn at `connect()` time can identify the controller in
18
+ * diagnostics. Optional but conventional.
19
+ */
20
+ export interface ControllerSchema {
21
+ /** Stable lowercase controller identifier (e.g. `"route"`). */
22
+ name: string;
23
+ /** Map of public state field names → human-readable type label. */
24
+ state?: Record<string, string>;
25
+ /** List of canonical command names available on the controller. */
26
+ commands?: ReadonlyArray<string>;
27
+ /** Host attributes the controller writes via `reflect()`. */
28
+ attributes?: ReadonlyArray<string>;
29
+ }
30
+
31
+ /**
32
+ * Base class for host-attached controllers.
33
+ *
34
+ * Subclasses MUST implement `getState()` and SHOULD declare a static
35
+ * `schema`; the constructor warns when these are missing the first
36
+ * time the controller is connected.
37
+ */
38
+ export class BaseController {
39
+ /** Optional schema (subclasses declare via `static schema = …`). */
40
+ static schema?: ControllerSchema;
41
+
42
+ /** The host element this controller is attached to, or `null`. */
43
+ readonly host: Element | null;
44
+
45
+ /**
46
+ * Wire the controller to a host element. Calls
47
+ * {@link onConnect} + {@link reflect} once.
48
+ */
49
+ connect(host: Element): void;
50
+
51
+ /**
52
+ * Detach from `host` (or the currently-connected host if omitted).
53
+ * Calls {@link onDisconnect}.
54
+ */
55
+ disconnect(host?: Element): void;
56
+
57
+ /**
58
+ * Subscribe to state-change notifications. Returns an unsubscribe
59
+ * function.
60
+ */
61
+ subscribe(fn: () => void): () => void;
62
+
63
+ /**
64
+ * Run subscriber callbacks + `reflect()` after a state mutation.
65
+ * Subclasses call this from their command implementations.
66
+ */
67
+ notify(): void;
68
+
69
+ /** Lifecycle hook — override to wire listeners at connect time. */
70
+ onConnect(host: Element): void;
71
+
72
+ /** Lifecycle hook — override to release listeners at disconnect time. */
73
+ onDisconnect(host: Element): void;
74
+
75
+ /**
76
+ * Override to write controller state into the host (attributes,
77
+ * data-* properties, etc.). Called on every {@link notify} + at
78
+ * `connect()`.
79
+ */
80
+ reflect(): void;
81
+
82
+ /**
83
+ * Return the controller's current public state. Subclasses MUST
84
+ * override. The default implementation throws.
85
+ */
86
+ getState(): unknown;
87
+ }
88
+
89
+ /**
90
+ * A single route declaration consumed by {@link RouteController}.
91
+ */
92
+ export interface Route {
93
+ /**
94
+ * Path pattern. Static segments match literally; segments prefixed
95
+ * with `:` are captured into `params`. e.g. `/users/:id`.
96
+ */
97
+ path: string;
98
+ /** Optional content URL for `<router-ui>` to fetch + inject. */
99
+ content?: string;
100
+ /** Optional document title to set when the route matches. */
101
+ title?: string;
102
+ /** Optional section identifier (consumer-defined). */
103
+ section?: string;
104
+ /** Open-ended — route definitions can carry arbitrary metadata. */
105
+ [key: string]: unknown;
106
+ }
107
+
108
+ /**
109
+ * Public state shape returned by {@link RouteController.getState}.
110
+ */
111
+ export interface RouteState {
112
+ /** Current pathname being matched. */
113
+ path: string;
114
+ /** Captured `:param` values from the matched route. */
115
+ params: Record<string, string>;
116
+ /** The matched route declaration, or `null` if no match. */
117
+ route: Route | null;
118
+ /** Previous pathname (before the most recent navigation). */
119
+ previous: string;
120
+ }
121
+
122
+ /**
123
+ * Imperative commands exposed by {@link RouteController}. Wire-up
124
+ * stable across both code-driven navigation + DOM-driven link clicks
125
+ * (the latter via `<router-ui>`'s click delegation).
126
+ */
127
+ export interface RouteCommands {
128
+ /** Push a new pathname onto the history stack + re-match routes. */
129
+ navigate(path: string): void;
130
+ /** Replace the current history entry's pathname + re-match. */
131
+ replace(path: string): void;
132
+ /** Equivalent to `history.back()` when `historySync` is on. */
133
+ back(): void;
134
+ /** Equivalent to `history.forward()` when `historySync` is on. */
135
+ forward(): void;
136
+ /** Swap the routes table at runtime (re-matches the current path). */
137
+ setRoutes(routes: ReadonlyArray<Route>): void;
138
+ }
139
+
140
+ /**
141
+ * Constructor options for {@link RouteController}.
142
+ */
143
+ export interface RouteControllerOptions {
144
+ /** Initial routes table. May be empty + updated later via `setRoutes`. */
145
+ routes?: ReadonlyArray<Route>;
146
+ /** Initial pathname (defaults to `location.pathname`). */
147
+ initial?: string;
148
+ /**
149
+ * When `true` (default), navigate/replace push to History API +
150
+ * `popstate` syncs state on browser back/forward.
151
+ */
152
+ historySync?: boolean;
153
+ }
154
+
155
+ /**
156
+ * Routing-state controller. Used by `<router-ui>` (see
157
+ * `core/provider.js`) as the canonical history-syncing route matcher.
158
+ * Can also be used standalone — `notify()` fires whenever the path
159
+ * changes; `getState()` returns the current match.
160
+ */
161
+ export class RouteController extends BaseController {
162
+ static schema: ControllerSchema;
163
+
164
+ constructor(options?: RouteControllerOptions);
165
+
166
+ /** Public state — path, params, matched route, previous path. */
167
+ getState(): RouteState;
168
+
169
+ /** Imperative API; wire from command palette / link handlers. */
170
+ commands: RouteCommands;
171
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Minimal markdown → HTML renderer for LLM output. Handles fenced code
3
+ * blocks, inline code, bold, italic, links, lists, headings, and
4
+ * paragraphs. No external dependencies.
5
+ *
6
+ * Fenced code blocks with a language identifier emit `<code-ui
7
+ * language="…">…</code-ui>` so the syntax-highlight upgrade picks them
8
+ * up automatically (see SPEC-CODE-EDITOR-001). Unlabeled fences keep
9
+ * the bare `<pre><code>…</code></pre>` form.
10
+ *
11
+ * Runtime exports mirror `core/markdown.js`. `.d.ts` authored in v0.5.6
12
+ * §191 to close the §178 audit-script baseline missing-sibling gap.
13
+ *
14
+ * @see ./markdown.js (runtime SoT)
15
+ */
16
+
17
+ /**
18
+ * Render a markdown source string to HTML.
19
+ *
20
+ * The output is a sanitized HTML string suitable for direct
21
+ * `element.innerHTML` assignment — text content is HTML-escaped before
22
+ * inline formatting is applied. Consumer is responsible for any
23
+ * additional context-specific sanitization (e.g. URL-scheme allowlisting
24
+ * for the link targets).
25
+ */
26
+ export function renderMarkdown(src: string): string;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Optional polyfills — for consumers extending BELOW the library's
3
+ * stated baseline (Chromium 125+, Safari 17.4+, Firefox 129+).
4
+ *
5
+ * **Side-effect-only module.** Importing this file runs feature checks
6
+ * at module-evaluation time and dynamically loads polyfills only when
7
+ * the runtime lacks support:
8
+ *
9
+ * - Popover API (consumers extending to Firefox < 125 / Safari < 17)
10
+ * - CSS Anchor Positioning (consumers extending to Safari < 26 /
11
+ * Firefox < 147)
12
+ *
13
+ * Browsers with native support skip the download. The polyfill
14
+ * packages (`@oddbird/popover-polyfill`, `@oddbird/css-anchor-positioning`)
15
+ * are optional — if not installed, the import silently fails.
16
+ *
17
+ * Consumers on the stated baseline should NOT import this module — the
18
+ * runtime checks resolve to no-op, but skipping the file avoids the
19
+ * conditional `import()` setup entirely.
20
+ *
21
+ * Runtime mirror: `core/polyfills.js`. `.d.ts` authored in v0.5.6 §191
22
+ * to close the §178 audit-script baseline missing-sibling gap.
23
+ *
24
+ * @see ./polyfills.js (runtime SoT)
25
+ */
26
+
27
+ // Side-effect-only module — no exports. The empty `export {}` marks
28
+ // the file as an ES module so TypeScript treats `import '...polyfills.js'`
29
+ // as a valid module side-effect import without complaining about a
30
+ // missing module shape.
31
+ export {};
@@ -0,0 +1,82 @@
1
+ /**
2
+ * `<router-ui>` provider — declarative + imperative client-side
3
+ * routing built on {@link RouteController} (re-declared here for
4
+ * historical reasons; the canonical export lives in `core/controller.js`).
5
+ *
6
+ * Two consumer paths:
7
+ *
8
+ * 1. **Declarative** — assign `router.routes = [...]` and the provider
9
+ * instantiates its own controller, wires `popstate`, intercepts
10
+ * same-origin link clicks, fetches each matched route's `content`
11
+ * URL, and injects into the host element.
12
+ *
13
+ * 2. **Controller-driven** — construct a {@link RouteController}
14
+ * yourself + assign to `router.controller`. Useful when multiple
15
+ * UI surfaces need to share routing state.
16
+ *
17
+ * Side-effect: importing this module calls
18
+ * `customElements.define('router-ui', UIRouter)`.
19
+ *
20
+ * Runtime exports mirror `core/provider.js`. `.d.ts` authored in v0.5.6
21
+ * §191 to close the §178 audit-script baseline missing-sibling gap.
22
+ *
23
+ * @see ./provider.js (runtime SoT — also defines `customElements`)
24
+ * @see ./controller.d.ts (canonical `RouteController` typing)
25
+ */
26
+
27
+ import { UIElement } from './element.js';
28
+ import type { Route, RouteCommands, RouteState, ControllerSchema, RouteControllerOptions } from './controller.js';
29
+ import { BaseController } from './controller.js';
30
+
31
+ /**
32
+ * Routing-state controller. Re-declared from `core/controller.js` for
33
+ * historical compatibility — both files define the same class shape;
34
+ * consumers can import either. New code should prefer
35
+ * `import { RouteController } from '@adia-ai/web-components/core/controller'`
36
+ * for the canonical path.
37
+ */
38
+ export class RouteController extends BaseController {
39
+ static schema: ControllerSchema;
40
+ constructor(options?: RouteControllerOptions);
41
+ getState(): RouteState;
42
+ commands: RouteCommands;
43
+ }
44
+
45
+ /**
46
+ * Optional async transform applied to fetched route content before
47
+ * injection. Useful for wrapping content in a layout shell.
48
+ */
49
+ export type TemplateResolver = (html: string, route: Route) => string | Promise<string>;
50
+
51
+ /**
52
+ * `<router-ui>` custom element. Side-effect-registered on module load.
53
+ */
54
+ export class UIRouter extends UIElement {
55
+ /** Currently-bound controller (declarative-mode controller is auto-created). */
56
+ controller?: RouteController;
57
+
58
+ /** Optional template wrapper hook — see {@link TemplateResolver}. */
59
+ templateResolver?: TemplateResolver;
60
+
61
+ /**
62
+ * Declarative-mode setter — assigning routes auto-creates an
63
+ * internal {@link RouteController} on first assignment, or
64
+ * `setRoutes`-replaces the table on subsequent ones.
65
+ */
66
+ set routes(list: ReadonlyArray<Route>);
67
+
68
+ /** Shortcut for `controller.commands.navigate(path)`. */
69
+ navigate(path: string): void;
70
+
71
+ /** Shortcut for `controller.commands.replace(path)`. */
72
+ replace(path: string): void;
73
+ }
74
+
75
+ /**
76
+ * `router-ui` is registered as a side-effect of module load.
77
+ */
78
+ declare global {
79
+ interface HTMLElementTagNameMap {
80
+ 'router-ui': UIRouter;
81
+ }
82
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * streams-bridge — proxy data-stream signals into A2UI surface data
3
+ * models (per OD-CHART-16 option b).
4
+ *
5
+ * The bridge duck-types the renderer (it needs `.process()`, nothing
6
+ * else), so it works with any A2UI-protocol consumer — the actual
7
+ * `A2UIRenderer` from `@adia-ai/a2ui-runtime`, a custom renderer, or
8
+ * a test stub.
9
+ *
10
+ * Contract:
11
+ * - One-way only: stream → data model. A2UI writes back to its model
12
+ * (e.g. via `update-data-model` wiring actions) do NOT propagate
13
+ * into the stream signal.
14
+ * - Tear down with the returned dispose function. Dispose detaches
15
+ * the effect; it does NOT release the stream's refcount.
16
+ * - `select` uses dot-separated path syntax (matches
17
+ * `data-stream-path` on the trait). `path` uses slash-separated
18
+ * syntax (matches A2UI bindings).
19
+ *
20
+ * Runtime exports mirror `core/streams-bridge.js`. `.d.ts` authored in
21
+ * v0.5.6 §191 to close the §178 audit-script baseline missing-sibling
22
+ * gap.
23
+ *
24
+ * @see ./streams-bridge.js (runtime SoT)
25
+ * @see ./data-stream.js (the stream registry the bridge reads from)
26
+ */
27
+
28
+ /**
29
+ * Minimal renderer contract the bridge requires. The actual
30
+ * `A2UIRenderer` from `@adia-ai/a2ui-runtime` satisfies this surface,
31
+ * as does any custom renderer that handles
32
+ * `{ type: 'updateDataModel', ... }` actions.
33
+ */
34
+ export interface BridgeRenderer {
35
+ process(action: {
36
+ type: 'updateDataModel';
37
+ surfaceId: string;
38
+ path: string;
39
+ value: unknown;
40
+ }): void;
41
+ }
42
+
43
+ /**
44
+ * Bridge options shared by {@link bridgeStream} and
45
+ * {@link bridgeStreamAsync}.
46
+ */
47
+ export interface BridgeOptions {
48
+ /** Target surface ID inside the renderer's data model. */
49
+ surfaceId: string;
50
+ /** Stream registry ID (the same string passed to `acquireStream`). */
51
+ streamId: string;
52
+ /** Slash-separated A2UI data-model path inside the surface. */
53
+ path: string;
54
+ /** Optional dot-separated path to a sub-value within the stream's signal value. */
55
+ select?: string;
56
+ }
57
+
58
+ /**
59
+ * Bridge a registered stream into a renderer's surface data model.
60
+ *
61
+ * If the stream is not yet registered, logs a warning and returns a
62
+ * no-op dispose. Use {@link bridgeStreamAsync} when the stream might
63
+ * register after this call (e.g. DOM source connecting on the same
64
+ * tick as the bridge wiring).
65
+ *
66
+ * Returns a dispose function — call it to detach the effect.
67
+ */
68
+ export function bridgeStream(renderer: BridgeRenderer, opts: BridgeOptions): () => void;
69
+
70
+ /**
71
+ * Async variant — awaits the stream's registration before attaching
72
+ * the effect. Resolves once the bridge is wired (the resolved value
73
+ * is the dispose function).
74
+ */
75
+ export function bridgeStreamAsync(
76
+ renderer: BridgeRenderer,
77
+ opts: BridgeOptions,
78
+ ): Promise<() => void>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Transport — `fetch` wrapper with timeout, exponential-backoff
3
+ * retries, and a normalized {@link TransportError} for predictable
4
+ * downstream handling.
5
+ *
6
+ * Zero dependencies. Vanilla-JS-friendly — drop into CodePen,
7
+ * StackBlitz, or any vanilla project.
8
+ *
9
+ * Runtime exports mirror `core/transport.js`. `.d.ts` authored in
10
+ * v0.5.6 §191 to close the §178 audit-script baseline missing-sibling
11
+ * gap.
12
+ *
13
+ * @see ./transport.js (runtime SoT)
14
+ */
15
+
16
+ /**
17
+ * Discriminator for {@link TransportError} kinds. Lets consumers
18
+ * branch on user-cancellation (`abort`) vs network errors (`network`)
19
+ * vs HTTP-level non-2xx (`http`) vs timeout exhaustion (`timeout`).
20
+ */
21
+ export type TransportErrorKind = 'abort' | 'timeout' | 'network' | 'http';
22
+
23
+ /**
24
+ * Options for {@link request} and {@link json}.
25
+ */
26
+ export interface TransportOptions {
27
+ /** Standard `fetch` init forwarded as-is (method, headers, body, …). */
28
+ init?: RequestInit;
29
+ /** Per-request timeout in ms. Default: 30 000. Aborts the underlying fetch. */
30
+ timeout?: number;
31
+ /** Retry attempts on 5xx + network failures. Default: 0. */
32
+ retries?: number;
33
+ /** Base retry delay in ms; exponential backoff applies. Default: 1000. */
34
+ retryDelay?: number;
35
+ /** External `AbortSignal` — aborts the request + skips retries. */
36
+ signal?: AbortSignal;
37
+ }
38
+
39
+ /**
40
+ * Resilient `fetch` with timeout + retries. Returns the raw `Response`
41
+ * — consumers handle status codes (the `request()` path does NOT throw
42
+ * on non-2xx responses; use {@link json} when 2xx-only is desired).
43
+ *
44
+ * Throws {@link TransportError} on:
45
+ * - Caller-driven abort (`kind: 'abort'`)
46
+ * - Timeout exhaustion (`kind: 'timeout'`)
47
+ * - Network failure after retries exhausted (`kind: 'network'`)
48
+ */
49
+ export function request(url: string, options?: TransportOptions): Promise<Response>;
50
+
51
+ /**
52
+ * JSON-typed variant of {@link request}. On 2xx responses, returns the
53
+ * parsed JSON body. On non-2xx responses, throws {@link TransportError}
54
+ * with `kind: 'http'` + the status code + the body (parsed as JSON if
55
+ * possible, else raw text).
56
+ */
57
+ export function json<T = unknown>(url: string, options?: TransportOptions): Promise<T>;
58
+
59
+ /**
60
+ * Normalized error thrown by {@link request} and {@link json}. The
61
+ * `kind` discriminator lets consumers branch on user-cancellation vs
62
+ * timeout vs network vs HTTP-level failures.
63
+ *
64
+ * Inherits `message` + `cause` from `Error`.
65
+ */
66
+ export class TransportError extends Error {
67
+ /** Error category — see {@link TransportErrorKind}. */
68
+ kind: TransportErrorKind;
69
+ /** HTTP status code on `kind: 'http'`; `undefined` otherwise. */
70
+ status?: number;
71
+ /** Response body on `kind: 'http'` (parsed JSON or raw text). */
72
+ body?: unknown;
73
+
74
+ constructor(
75
+ message: string,
76
+ options?: { kind?: TransportErrorKind; status?: number; body?: unknown; cause?: unknown },
77
+ );
78
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adia-ai/web-components",
3
- "version": "0.5.5",
4
- "description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
3
+ "version": "0.5.7",
4
+ "description": "AdiaUI web components vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",
7
7
  "exports": {
@@ -28,6 +28,8 @@
28
28
  "default": "./components/*/class.js"
29
29
  },
30
30
  "./components/*.css": "./components/*/*.css",
31
+ "./components/*/*.css": "./components/*/*.css",
32
+ "./components/*/css/*.css": "./components/*/css/*.css",
31
33
  "./styles/*": "./styles/*",
32
34
  "./traits": "./traits/index.js",
33
35
  "./traits/*": "./traits/*.js",