@adia-ai/web-components 0.6.6 → 0.6.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.
- package/CHANGELOG.md +16 -0
- package/USAGE.md +100 -5
- package/bin/doc.mjs +379 -0
- package/components/accordion/accordion.examples.md +49 -0
- package/components/action-list/action-list.examples.md +33 -0
- package/components/agent-artifact/agent-artifact.examples.md +28 -0
- package/components/agent-feedback-bar/agent-feedback-bar.examples.md +24 -0
- package/components/agent-questions/agent-questions.examples.md +13 -0
- package/components/agent-reasoning/agent-reasoning.examples.md +28 -0
- package/components/agent-suggestions/agent-suggestions.examples.md +19 -0
- package/components/agent-trace/agent-trace.examples.md +19 -0
- package/components/alert/alert.examples.md +19 -0
- package/components/aside/aside.examples.md +38 -0
- package/components/avatar/avatar.examples.md +19 -0
- package/components/badge/badge.examples.md +19 -0
- package/components/block/block.examples.md +29 -0
- package/components/breadcrumb/breadcrumb.examples.md +32 -0
- package/components/button/button.examples.md +19 -0
- package/components/calendar-picker/calendar-picker.examples.md +23 -0
- package/components/canvas/canvas.examples.md +49 -0
- package/components/card/card.examples.md +25 -0
- package/components/chart/chart.examples.md +19 -0
- package/components/chart-legend/chart-legend.examples.md +22 -0
- package/components/chat-thread/chat-thread.examples.md +35 -0
- package/components/check/check.examples.md +19 -0
- package/components/code/code.examples.md +31 -0
- package/components/col/col.examples.md +11 -0
- package/components/color-input/color-input.examples.md +19 -0
- package/components/color-picker/color-picker.examples.md +19 -0
- package/components/command/command.examples.md +58 -0
- package/components/demo-toggle/demo-toggle.examples.md +19 -0
- package/components/description-list/description-list.examples.md +37 -0
- package/components/divider/divider.examples.md +31 -0
- package/components/drawer/drawer.examples.md +63 -0
- package/components/embed/embed.examples.md +19 -0
- package/components/empty-state/empty-state.examples.md +21 -0
- package/components/feed/feed.examples.md +19 -0
- package/components/field/field.examples.md +29 -0
- package/components/fields/fields.examples.md +58 -0
- package/components/footer/footer.examples.md +18 -0
- package/components/grid/grid.examples.md +21 -0
- package/components/header/header.examples.md +32 -0
- package/components/heatmap/heatmap.examples.md +19 -0
- package/components/icon/icon.examples.md +19 -0
- package/components/image/image.examples.md +19 -0
- package/components/input/input.examples.md +21 -0
- package/components/inspector/inspector.examples.md +27 -0
- package/components/kbd/kbd.examples.md +29 -0
- package/components/link/link.examples.md +25 -0
- package/components/list/list.examples.md +33 -0
- package/components/menu/menu.examples.md +37 -0
- package/components/modal/modal.examples.md +43 -0
- package/components/nav/nav.examples.md +39 -0
- package/components/nav-group/nav-group.examples.md +35 -0
- package/components/nav-item/nav-item.examples.md +25 -0
- package/components/noodles/noodles.examples.md +30 -0
- package/components/option-card/option-card.examples.md +47 -0
- package/components/otp-input/otp-input.examples.md +19 -0
- package/components/page/page.examples.md +46 -0
- package/components/pagination/pagination.examples.md +19 -0
- package/components/pane/pane.examples.md +40 -0
- package/components/pipeline-status/pipeline-status.examples.md +19 -0
- package/components/popover/popover.examples.md +34 -0
- package/components/progress/progress.examples.md +19 -0
- package/components/progress-row/progress-row.examples.md +19 -0
- package/components/radio/radio.examples.md +19 -0
- package/components/range/range.examples.md +19 -0
- package/components/rating/rating.examples.md +19 -0
- package/components/richtext/richtext.examples.md +19 -0
- package/components/row/row.examples.md +11 -0
- package/components/search/search.examples.md +19 -0
- package/components/section/section.examples.md +37 -0
- package/components/segment/segment.examples.md +32 -0
- package/components/segmented/segmented.examples.md +31 -0
- package/components/select/select.examples.md +49 -0
- package/components/skeleton/skeleton.examples.md +19 -0
- package/components/slider/slider.examples.md +21 -0
- package/components/stack/stack.examples.md +10 -0
- package/components/stat/stat.examples.md +19 -0
- package/components/step-progress/step-progress.examples.md +19 -0
- package/components/stepper/stepper.examples.md +37 -0
- package/components/stream/stream.examples.md +19 -0
- package/components/swatch/swatch.examples.md +23 -0
- package/components/swiper/swiper.examples.md +139 -0
- package/components/switch/switch.examples.md +19 -0
- package/components/table/table.examples.md +19 -0
- package/components/table-toolbar/table-toolbar.examples.md +12 -0
- package/components/tabs/tabs.examples.md +49 -0
- package/components/tag/tag.examples.md +19 -0
- package/components/text/text.examples.md +19 -0
- package/components/textarea/textarea.examples.md +23 -0
- package/components/timeline/timeline.examples.md +35 -0
- package/components/toast/toast.examples.md +19 -0
- package/components/toggle-group/toggle-group.examples.md +33 -0
- package/components/toggle-scheme/toggle-scheme.examples.md +19 -0
- package/components/toolbar/toolbar.examples.md +46 -0
- package/components/tooltip/tooltip.examples.md +25 -0
- package/components/tree/tree.examples.md +57 -0
- package/components/upload/upload.examples.md +19 -0
- package/custom-elements.json +9012 -0
- package/package.json +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.6.7] — 2026-05-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`<name>.examples.md` ships in npm package** (96 components, ~67KB total).
|
|
7
|
+
Generated by `scripts/build/generate-examples-md.mjs` from `<name>.examples.html`.
|
|
8
|
+
External consumers can now read canonical markup fragments directly from
|
|
9
|
+
`node_modules/@adia-ai/web-components/components/<name>/<name>.examples.md`.
|
|
10
|
+
- **`custom-elements.json` ships in npm package** (W3C Custom Elements Manifest v2.1.0).
|
|
11
|
+
Generated from per-component yaml files. Enables IDE LSP autocomplete and
|
|
12
|
+
cross-tool interop (Storybook, VS Code WC extensions).
|
|
13
|
+
- **`npx @adia-ai/web-components doc <name>` CLI** prints yaml summary + live
|
|
14
|
+
demo URL + first example fragment for any component. Bare `doc` lists all.
|
|
15
|
+
- **`USAGE.md § Data binding with data-stream-*`** new top-level section
|
|
16
|
+
covering the declarative `data-stream-*` attribute family (was previously
|
|
17
|
+
undocumented despite being used in 12+ components).
|
|
18
|
+
|
|
3
19
|
## [0.6.6] — 2026-05-18
|
|
4
20
|
|
|
5
21
|
### Added
|
package/USAGE.md
CHANGED
|
@@ -14,11 +14,12 @@ The complete reference for engineers and agents **integrating** AdiaUI into an a
|
|
|
14
14
|
4. [Property binding patterns (templates / framework integration)](#property-binding-patterns)
|
|
15
15
|
5. [Event contract — `CustomEvent` with `detail`](#event-contract)
|
|
16
16
|
6. [Form participation — `UIFormElement` + `ElementInternals`](#form-participation)
|
|
17
|
-
7. [
|
|
18
|
-
8. [
|
|
19
|
-
9. [
|
|
20
|
-
10. [
|
|
21
|
-
11. [
|
|
17
|
+
7. [Data binding with `data-stream-*`](#data-binding-with-data-stream-)
|
|
18
|
+
8. [Lifecycle — `connected` / `render` / `updated` / `disconnected`](#lifecycle)
|
|
19
|
+
9. [Theming, density, size](#theming-density-size)
|
|
20
|
+
10. [Registration — auto vs explicit](#registration--auto-vs-explicit)
|
|
21
|
+
11. [TypeScript](#typescript)
|
|
22
|
+
12. [Anti-patterns](#anti-patterns)
|
|
22
23
|
|
|
23
24
|
---
|
|
24
25
|
|
|
@@ -461,6 +462,100 @@ form.addEventListener('submit', (e) => {
|
|
|
461
462
|
|
|
462
463
|
---
|
|
463
464
|
|
|
465
|
+
## Data binding with `data-stream-*`
|
|
466
|
+
|
|
467
|
+
Many AdiaUI components (`<chart-ui>`, `<heatmap-ui>`, `<table-ui>`, `<stat-ui>`, `<progress-row-ui>`, and ~7 others) support **declarative remote-data binding** via the `data-stream-*` attribute family. You point a component at a URL, and it self-fetches (REST poll) or self-subscribes (SSE) and pushes the result into one of its properties. No JS glue required.
|
|
468
|
+
|
|
469
|
+
This is the canonical "wire a component to a backend" pattern in AdiaUI. Reach for it before writing a `fetch()` loop in your app code.
|
|
470
|
+
|
|
471
|
+
### Concept
|
|
472
|
+
|
|
473
|
+
A component that opts in watches its `data-stream-*` attributes. When `data-stream-src` is set on a connected element, the component starts a transport (poll, SSE, or manual) and assigns each payload to a target property (e.g. `data` on `<table-ui>`, `value` on `<stat-ui>`). Change the attribute and the transport restarts; remove the attribute (or disconnect the element) and the transport tears down.
|
|
474
|
+
|
|
475
|
+
Because the binding is attribute-driven, it survives SSR, server-rendered partials, htmx swaps, framework hydration, and templating engines that have no concept of property assignment.
|
|
476
|
+
|
|
477
|
+
### Attribute reference
|
|
478
|
+
|
|
479
|
+
| Attribute | Purpose | Default |
|
|
480
|
+
|---|---|---|
|
|
481
|
+
| `data-stream-src` | URL — REST endpoint or SSE source. Setting this activates the binding. | (required) |
|
|
482
|
+
| `data-stream-mode` | `"poll"`, `"sse"`, or `"manual"`. `manual` fetches once on connect and on attribute change. | `"poll"` |
|
|
483
|
+
| `data-stream-interval` | Poll interval in milliseconds. Ignored for `sse` / `manual`. | `5000` |
|
|
484
|
+
| `data-stream-path` | Dot-path into the JSON response to extract before binding (e.g. `claims` extracts `response.claims`; `data.items` extracts `response.data.items`). | (whole response) |
|
|
485
|
+
| `data-stream-target` | Which component property receives the payload. | component-specific (`data` for `<table-ui>`, `value` for `<stat-ui>`, `data` for `<chart-ui>`, …) |
|
|
486
|
+
| `data-stream-method` | HTTP method for REST mode. `POST` is supported when you need a request body via headers/config. | `"GET"` |
|
|
487
|
+
| `data-stream-headers` | JSON-stringified object of request headers (e.g. `'{"Authorization":"Bearer …"}'`). | `null` |
|
|
488
|
+
| `data-stream-id` | Logical transport key. Multiple elements with the same `data-stream-id` share one underlying fetch/SSE connection. | (per-element) |
|
|
489
|
+
|
|
490
|
+
### REST polling
|
|
491
|
+
|
|
492
|
+
```html
|
|
493
|
+
<table-ui
|
|
494
|
+
data-stream-src="/api/claims"
|
|
495
|
+
data-stream-interval="10000"
|
|
496
|
+
data-stream-target="data"
|
|
497
|
+
></table-ui>
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
The table fetches `/api/claims` every 10s and assigns the response to its `data` property. If the response is wrapped (e.g. `{ claims: [...] }`), add `data-stream-path="claims"` to drill in.
|
|
501
|
+
|
|
502
|
+
### SSE streaming
|
|
503
|
+
|
|
504
|
+
```html
|
|
505
|
+
<stat-ui
|
|
506
|
+
label="Active"
|
|
507
|
+
data-stream-src="/api/active-count"
|
|
508
|
+
data-stream-mode="sse"
|
|
509
|
+
data-stream-target="value"
|
|
510
|
+
></stat-ui>
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Opens an `EventSource` against `/api/active-count`. Each SSE message's `data` field is JSON-parsed (when possible) and pushed into the stat's `value`. The connection closes on disconnect.
|
|
514
|
+
|
|
515
|
+
### Shared transport
|
|
516
|
+
|
|
517
|
+
When two or more components need the same source, give them a matching `data-stream-id` and they will share a single fetch/SSE subscription:
|
|
518
|
+
|
|
519
|
+
```html
|
|
520
|
+
<table-ui
|
|
521
|
+
data-stream-src="/api/claims"
|
|
522
|
+
data-stream-id="shared-claims"
|
|
523
|
+
data-stream-target="data"
|
|
524
|
+
></table-ui>
|
|
525
|
+
|
|
526
|
+
<stat-ui
|
|
527
|
+
label="Total"
|
|
528
|
+
data-stream-src="/api/claims"
|
|
529
|
+
data-stream-id="shared-claims"
|
|
530
|
+
data-stream-path="length"
|
|
531
|
+
data-stream-target="value"
|
|
532
|
+
></stat-ui>
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
One request feeds both. Each element still applies its own `data-stream-path` and `data-stream-target` independently. The shared transport is reference-counted; the last element to disconnect tears it down.
|
|
536
|
+
|
|
537
|
+
### SSR / server rendering
|
|
538
|
+
|
|
539
|
+
`data-stream-*` is **client-only**. Server-rendered markup that contains these attributes is safe — the attributes are just strings on the element — and the transport only activates once the component is upgraded in the browser. This means you can:
|
|
540
|
+
|
|
541
|
+
- Server-render the initial empty/skeleton state of a `<table-ui>` and let the client take over.
|
|
542
|
+
- Emit `data-stream-*` from any templating layer (Jinja, ERB, Handlebars, htmx fragments) without server-side coupling to the data-stream runtime.
|
|
543
|
+
- Hydrate framework apps without special-casing — React/Vue/Svelte just need to render the attribute; they do not need to subscribe.
|
|
544
|
+
|
|
545
|
+
If you need a server-rendered first paint of *real* data, render it normally (slot or attribute) — the data-stream binding will replace it on first successful payload.
|
|
546
|
+
|
|
547
|
+
### Authoritative source
|
|
548
|
+
|
|
549
|
+
The implementation lives at:
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
packages/web-components/core/data-stream.js
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
A component opts in by declaring a `data_stream:` block in its YAML descriptor (see `packages/web-components/components/*/*.yaml`). That block is the source of truth for which target properties are bindable and which defaults apply for that specific component. When in doubt, read the component's YAML and `core/data-stream.js` — this document is a discoverability summary, not a spec.
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
464
559
|
## Lifecycle
|
|
465
560
|
|
|
466
561
|
`UIElement` exposes four overridable lifecycle methods. Defaults are no-ops. Override what you need:
|
package/bin/doc.mjs
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Usage:
|
|
4
|
+
* npx @adia-ai/web-components doc button
|
|
5
|
+
* npx @adia-ai/web-components doc field
|
|
6
|
+
* npx @adia-ai/web-components doc # list all components
|
|
7
|
+
*
|
|
8
|
+
* Prints a quick summary + live demo URL + first example fragment for any
|
|
9
|
+
* AdiaUI component. Reads from the installed package's yaml/.examples.md
|
|
10
|
+
* (falls back to <name>.examples.html if .md is not present).
|
|
11
|
+
*
|
|
12
|
+
* No external yaml dependency — uses a minimal regex-based parser scoped
|
|
13
|
+
* to the small subset of fields we need: name, tag, component,
|
|
14
|
+
* description, props, slots, events.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
18
|
+
import { resolve, dirname, join } from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
23
|
+
|
|
24
|
+
// bin/ lives at packages/web-components/bin/, components/ is one level up
|
|
25
|
+
const COMPONENTS_DIR = resolve(__dirname, '..', 'components');
|
|
26
|
+
const DEMO_BASE = 'https://ui-kit.exe.xyz/site/components';
|
|
27
|
+
|
|
28
|
+
/* ------------------------------------------------------------------ */
|
|
29
|
+
/* Minimal YAML extractor */
|
|
30
|
+
/* ------------------------------------------------------------------ */
|
|
31
|
+
/**
|
|
32
|
+
* Parses just the subset of YAML used by AdiaUI component yaml files:
|
|
33
|
+
* - top-level scalar keys (name, tag, component, description, …)
|
|
34
|
+
* - top-level mapping keys whose values are mappings of leaf scalars
|
|
35
|
+
* (props, slots, events)
|
|
36
|
+
*
|
|
37
|
+
* Returns:
|
|
38
|
+
* {
|
|
39
|
+
* name, tag, component, description,
|
|
40
|
+
* props: { propName: { description, type, default, enum?, ... } },
|
|
41
|
+
* slots: { slotName: { description } },
|
|
42
|
+
* events: { eventName: { description, type? } },
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* Defensive: any parse error returns a partial object plus an `_errors`
|
|
46
|
+
* array — the caller decides how to surface failures.
|
|
47
|
+
*/
|
|
48
|
+
function parseYaml(source) {
|
|
49
|
+
const out = {
|
|
50
|
+
name: '',
|
|
51
|
+
tag: '',
|
|
52
|
+
component: '',
|
|
53
|
+
description: '',
|
|
54
|
+
props: {},
|
|
55
|
+
slots: {},
|
|
56
|
+
events: {},
|
|
57
|
+
_errors: [],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Strip comments + trailing whitespace, keep blank lines for block detection
|
|
61
|
+
const rawLines = source.split(/\r?\n/);
|
|
62
|
+
const lines = rawLines.map((l) => {
|
|
63
|
+
// strip line comments unless inside a quoted string (rough heuristic)
|
|
64
|
+
const m = l.match(/^([^#"']*)(#.*)?$/);
|
|
65
|
+
return m ? m[1].replace(/\s+$/, '') : l;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/** Find the line range of a top-level key block (indent === 0). */
|
|
69
|
+
function blockRange(key) {
|
|
70
|
+
const startRe = new RegExp(`^${key}\\s*:\\s*(.*)$`);
|
|
71
|
+
let start = -1;
|
|
72
|
+
let inlineValue = null;
|
|
73
|
+
for (let i = 0; i < lines.length; i++) {
|
|
74
|
+
const m = lines[i].match(startRe);
|
|
75
|
+
if (m && !lines[i].startsWith(' ') && !lines[i].startsWith('\t')) {
|
|
76
|
+
start = i;
|
|
77
|
+
inlineValue = m[1];
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (start === -1) return null;
|
|
82
|
+
|
|
83
|
+
let end = lines.length;
|
|
84
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
85
|
+
const l = lines[i];
|
|
86
|
+
if (l === '') continue;
|
|
87
|
+
// next top-level key (no leading whitespace, contains ':')
|
|
88
|
+
if (!/^\s/.test(l) && /^[A-Za-z_$][\w$-]*\s*:/.test(l)) {
|
|
89
|
+
end = i;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { start, end, inlineValue };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Unquote a yaml scalar value (handles "…", '…', |, >, bare). */
|
|
97
|
+
function unquote(v) {
|
|
98
|
+
if (v == null) return '';
|
|
99
|
+
let s = String(v).trim();
|
|
100
|
+
if (s === '') return '';
|
|
101
|
+
if (
|
|
102
|
+
(s.startsWith('"') && s.endsWith('"')) ||
|
|
103
|
+
(s.startsWith("'") && s.endsWith("'"))
|
|
104
|
+
) {
|
|
105
|
+
return s.slice(1, -1);
|
|
106
|
+
}
|
|
107
|
+
return s;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Extract a top-level scalar field (single-line OR block scalar). */
|
|
111
|
+
function scalar(key) {
|
|
112
|
+
const r = blockRange(key);
|
|
113
|
+
if (!r) return '';
|
|
114
|
+
const head = r.inlineValue.trim();
|
|
115
|
+
// block scalar? `description: >-` / `>` / `|`
|
|
116
|
+
if (head === '>' || head === '>-' || head === '|' || head === '|-') {
|
|
117
|
+
const buf = [];
|
|
118
|
+
for (let i = r.start + 1; i < r.end; i++) {
|
|
119
|
+
const l = lines[i];
|
|
120
|
+
if (l === '') {
|
|
121
|
+
buf.push('');
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!/^\s/.test(l)) break;
|
|
125
|
+
buf.push(l.replace(/^\s+/, ''));
|
|
126
|
+
}
|
|
127
|
+
const joined = buf.join(' ').replace(/\s+/g, ' ').trim();
|
|
128
|
+
return joined;
|
|
129
|
+
}
|
|
130
|
+
return unquote(head);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
out.name = scalar('name');
|
|
134
|
+
out.tag = scalar('tag');
|
|
135
|
+
out.component = scalar('component');
|
|
136
|
+
out.description = scalar('description');
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Parse a mapping-of-mappings block (props/slots/events).
|
|
140
|
+
* Each child key is a 2-space-indented identifier, its value is a
|
|
141
|
+
* 4-space-indented mapping of leaf scalars.
|
|
142
|
+
*/
|
|
143
|
+
function mappingOfMappings(key) {
|
|
144
|
+
const r = blockRange(key);
|
|
145
|
+
if (!r) return {};
|
|
146
|
+
const result = {};
|
|
147
|
+
let currentKey = null;
|
|
148
|
+
let currentField = null; // for block-scalar accumulation
|
|
149
|
+
let currentBuf = null;
|
|
150
|
+
let currentIndent = 0;
|
|
151
|
+
|
|
152
|
+
const flushBlockScalar = () => {
|
|
153
|
+
if (currentKey && currentField && currentBuf) {
|
|
154
|
+
const joined = currentBuf.join(' ').replace(/\s+/g, ' ').trim();
|
|
155
|
+
result[currentKey][currentField] = joined;
|
|
156
|
+
}
|
|
157
|
+
currentField = null;
|
|
158
|
+
currentBuf = null;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
for (let i = r.start + 1; i < r.end; i++) {
|
|
162
|
+
const l = lines[i];
|
|
163
|
+
if (l === '') continue;
|
|
164
|
+
const indent = l.match(/^( *)/)[0].length;
|
|
165
|
+
|
|
166
|
+
// 2-space child key: " propName:" or " propName: value"
|
|
167
|
+
if (indent === 2) {
|
|
168
|
+
flushBlockScalar();
|
|
169
|
+
const m = l.match(/^ {2}([^:\s]+)\s*:\s*(.*)$/);
|
|
170
|
+
if (m) {
|
|
171
|
+
currentKey = m[1];
|
|
172
|
+
result[currentKey] = {};
|
|
173
|
+
const v = m[2].trim();
|
|
174
|
+
if (v && v !== '>' && v !== '>-' && v !== '|' && v !== '|-') {
|
|
175
|
+
// shorthand " prop: desc"
|
|
176
|
+
result[currentKey].description = unquote(v);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 4-space leaf field: " description: …"
|
|
183
|
+
if (indent === 4 && currentKey) {
|
|
184
|
+
flushBlockScalar();
|
|
185
|
+
const m = l.match(/^ {4}([^:\s]+)\s*:\s*(.*)$/);
|
|
186
|
+
if (m) {
|
|
187
|
+
const fk = m[1];
|
|
188
|
+
const v = m[2].trim();
|
|
189
|
+
if (v === '>' || v === '>-' || v === '|' || v === '|-') {
|
|
190
|
+
currentField = fk;
|
|
191
|
+
currentBuf = [];
|
|
192
|
+
currentIndent = 6;
|
|
193
|
+
} else {
|
|
194
|
+
result[currentKey][fk] = unquote(v);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// continuation of a block scalar (indent >= currentIndent)
|
|
201
|
+
if (currentField && currentBuf && indent >= currentIndent) {
|
|
202
|
+
currentBuf.push(l.slice(currentIndent));
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 6-space (or deeper) list/enum entries we ignore for now, but
|
|
207
|
+
// capture enum lists for props (best-effort).
|
|
208
|
+
if (indent >= 6 && currentKey) {
|
|
209
|
+
const em = l.match(/^\s+-\s+(.*)$/);
|
|
210
|
+
if (em && currentField === 'enum') {
|
|
211
|
+
currentBuf = currentBuf || [];
|
|
212
|
+
// we don't really store enum lists here; left for the
|
|
213
|
+
// manifest generator which re-parses with its own logic.
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
flushBlockScalar();
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
out.props = mappingOfMappings('props');
|
|
223
|
+
} catch (e) {
|
|
224
|
+
out._errors.push(`props: ${e.message}`);
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
out.slots = mappingOfMappings('slots');
|
|
228
|
+
} catch (e) {
|
|
229
|
+
out._errors.push(`slots: ${e.message}`);
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
out.events = mappingOfMappings('events');
|
|
233
|
+
} catch (e) {
|
|
234
|
+
out._errors.push(`events: ${e.message}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return out;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* ------------------------------------------------------------------ */
|
|
241
|
+
/* Pretty-print helpers */
|
|
242
|
+
/* ------------------------------------------------------------------ */
|
|
243
|
+
function wrap(s, width = 76, indent = ' ') {
|
|
244
|
+
if (!s) return '';
|
|
245
|
+
const words = String(s).split(/\s+/);
|
|
246
|
+
const lines = [];
|
|
247
|
+
let line = '';
|
|
248
|
+
for (const w of words) {
|
|
249
|
+
if ((line + ' ' + w).trim().length > width) {
|
|
250
|
+
lines.push(line);
|
|
251
|
+
line = w;
|
|
252
|
+
} else {
|
|
253
|
+
line = (line ? line + ' ' : '') + w;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (line) lines.push(line);
|
|
257
|
+
return lines.map((l) => indent + l).join('\n');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function printSection(title, entries, keyLabel) {
|
|
261
|
+
const keys = Object.keys(entries || {});
|
|
262
|
+
if (keys.length === 0) return;
|
|
263
|
+
console.log(`${title} (${keys.length})`);
|
|
264
|
+
for (const k of keys) {
|
|
265
|
+
const e = entries[k] || {};
|
|
266
|
+
const meta = [];
|
|
267
|
+
if (e.type) meta.push(e.type);
|
|
268
|
+
if (e.default !== undefined && e.default !== '') meta.push(`default: ${e.default}`);
|
|
269
|
+
const head = meta.length ? ` • ${k} [${meta.join(', ')}]` : ` • ${k}`;
|
|
270
|
+
console.log(head);
|
|
271
|
+
if (e.description) console.log(wrap(e.description, 72, ' '));
|
|
272
|
+
}
|
|
273
|
+
console.log('');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function firstExampleFragment(md) {
|
|
277
|
+
// First markdown ## … block, or whole file if no headings.
|
|
278
|
+
const lines = md.split(/\r?\n/);
|
|
279
|
+
let start = -1;
|
|
280
|
+
let end = lines.length;
|
|
281
|
+
for (let i = 0; i < lines.length; i++) {
|
|
282
|
+
if (/^##\s+/.test(lines[i])) {
|
|
283
|
+
if (start === -1) {
|
|
284
|
+
start = i;
|
|
285
|
+
} else {
|
|
286
|
+
end = i;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (start === -1) return md.trim();
|
|
292
|
+
return lines.slice(start, end).join('\n').trim();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function firstHtmlFragment(html) {
|
|
296
|
+
// Heuristic: first <section> … </section>, else first <!-- example: --> … next, else first ~30 lines.
|
|
297
|
+
const sect = html.match(/<section[\s\S]*?<\/section>/i);
|
|
298
|
+
if (sect) return sect[0].trim();
|
|
299
|
+
const lines = html.split(/\r?\n/);
|
|
300
|
+
return lines.slice(0, 30).join('\n').trim();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* ------------------------------------------------------------------ */
|
|
304
|
+
/* Main */
|
|
305
|
+
/* ------------------------------------------------------------------ */
|
|
306
|
+
function listComponents() {
|
|
307
|
+
let entries;
|
|
308
|
+
try {
|
|
309
|
+
entries = readdirSync(COMPONENTS_DIR);
|
|
310
|
+
} catch (e) {
|
|
311
|
+
console.error(`Cannot read components directory: ${COMPONENTS_DIR}`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
const names = [];
|
|
315
|
+
for (const d of entries) {
|
|
316
|
+
let s;
|
|
317
|
+
try { s = statSync(join(COMPONENTS_DIR, d)); } catch { continue; }
|
|
318
|
+
if (!s.isDirectory()) continue;
|
|
319
|
+
const yamlPath = join(COMPONENTS_DIR, d, `${d}.yaml`);
|
|
320
|
+
if (existsSync(yamlPath)) names.push(d);
|
|
321
|
+
}
|
|
322
|
+
names.sort();
|
|
323
|
+
console.log(`AdiaUI — ${names.length} components\n`);
|
|
324
|
+
for (const c of names) console.log(` ${c}`);
|
|
325
|
+
console.log(`\nRun: npx @adia-ai/web-components doc <name>\n`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const name = process.argv[2];
|
|
329
|
+
if (!name) {
|
|
330
|
+
listComponents();
|
|
331
|
+
process.exit(0);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const yamlPath = join(COMPONENTS_DIR, name, `${name}.yaml`);
|
|
335
|
+
if (!existsSync(yamlPath)) {
|
|
336
|
+
console.error(`Component '${name}' not found in catalog.`);
|
|
337
|
+
console.error(`Try: npx @adia-ai/web-components doc # list all`);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const source = readFileSync(yamlPath, 'utf-8');
|
|
342
|
+
const data = parseYaml(source);
|
|
343
|
+
|
|
344
|
+
console.log('');
|
|
345
|
+
console.log(`${data.name || name} <${data.tag || name + '-ui'}>`);
|
|
346
|
+
console.log('─'.repeat(60));
|
|
347
|
+
if (data.description) {
|
|
348
|
+
console.log(wrap(data.description, 76, ''));
|
|
349
|
+
console.log('');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
printSection('Props', data.props, 'prop');
|
|
353
|
+
printSection('Slots', data.slots, 'slot');
|
|
354
|
+
printSection('Events', data.events, 'event');
|
|
355
|
+
|
|
356
|
+
if (data._errors && data._errors.length) {
|
|
357
|
+
console.log('Parse warnings:');
|
|
358
|
+
for (const e of data._errors) console.log(` - ${e}`);
|
|
359
|
+
console.log('');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log(`Live demo: ${DEMO_BASE}/${name}`);
|
|
363
|
+
console.log('');
|
|
364
|
+
|
|
365
|
+
const examplesMdPath = join(COMPONENTS_DIR, name, `${name}.examples.md`);
|
|
366
|
+
const examplesHtmlPath = join(COMPONENTS_DIR, name, `${name}.examples.html`);
|
|
367
|
+
if (existsSync(examplesMdPath)) {
|
|
368
|
+
const src = readFileSync(examplesMdPath, 'utf-8');
|
|
369
|
+
console.log('Example');
|
|
370
|
+
console.log('─'.repeat(60));
|
|
371
|
+
console.log(firstExampleFragment(src));
|
|
372
|
+
console.log('');
|
|
373
|
+
} else if (existsSync(examplesHtmlPath)) {
|
|
374
|
+
const src = readFileSync(examplesHtmlPath, 'utf-8');
|
|
375
|
+
console.log('Example (HTML)');
|
|
376
|
+
console.log('─'.repeat(60));
|
|
377
|
+
console.log(firstHtmlFragment(src));
|
|
378
|
+
console.log('');
|
|
379
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# accordion — Examples
|
|
2
|
+
|
|
3
|
+
## basic
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<accordion-ui>
|
|
7
|
+
<accordion-item-ui text="What is AdiaUI?">
|
|
8
|
+
<p>AdiaUI is a zero-dependency vanilla JS web component library for building modern interfaces. It uses native custom elements, OKLCH colors, and @scope CSS isolation.</p>
|
|
9
|
+
</accordion-item-ui>
|
|
10
|
+
<accordion-item-ui text="Do I need a build tool?">
|
|
11
|
+
<p>No. AdiaUI components are plain ES modules. Import them directly in a script tag or from a module bundler -- both work without configuration.</p>
|
|
12
|
+
</accordion-item-ui>
|
|
13
|
+
<accordion-item-ui text="How are styles scoped?">
|
|
14
|
+
<p>Each component uses CSS @scope blocks keyed to the element tag name. This provides isolation without Shadow DOM, keeping components inspectable in DevTools.</p>
|
|
15
|
+
</accordion-item-ui>
|
|
16
|
+
</accordion-ui>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## multiple
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<accordion-ui multiple>
|
|
23
|
+
<accordion-item-ui text="Section A" open>
|
|
24
|
+
<p>This section starts open and remains open when you expand other sections.</p>
|
|
25
|
+
</accordion-item-ui>
|
|
26
|
+
<accordion-item-ui text="Section B">
|
|
27
|
+
<p>Open this alongside Section A to see multiple open behavior.</p>
|
|
28
|
+
</accordion-item-ui>
|
|
29
|
+
<accordion-item-ui text="Section C">
|
|
30
|
+
<p>All three can be expanded at the same time.</p>
|
|
31
|
+
</accordion-item-ui>
|
|
32
|
+
</accordion-ui>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## pre-opened
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<accordion-ui>
|
|
39
|
+
<accordion-item-ui text="Closed by default">
|
|
40
|
+
<p>This item is collapsed initially.</p>
|
|
41
|
+
</accordion-item-ui>
|
|
42
|
+
<accordion-item-ui text="Open by default" open>
|
|
43
|
+
<p>This item renders expanded because it has the open attribute.</p>
|
|
44
|
+
</accordion-item-ui>
|
|
45
|
+
<accordion-item-ui text="Also closed">
|
|
46
|
+
<p>Another collapsed item.</p>
|
|
47
|
+
</accordion-item-ui>
|
|
48
|
+
</accordion-ui>
|
|
49
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# action-list — Examples
|
|
2
|
+
|
|
3
|
+
## Basic
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<action-list-ui>
|
|
7
|
+
<action-item-ui text="New Project" value="new"></action-item-ui>
|
|
8
|
+
<action-item-ui text="Import Data" value="import"></action-item-ui>
|
|
9
|
+
<action-item-ui text="Export Report" value="export"></action-item-ui>
|
|
10
|
+
</action-list-ui>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## With Icons
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<action-list-ui>
|
|
17
|
+
<action-item-ui icon="plus" text="New Project" value="new"></action-item-ui>
|
|
18
|
+
<action-item-ui icon="users" text="Invite Team" value="invite"></action-item-ui>
|
|
19
|
+
<action-item-ui icon="download" text="Export Data" value="export"></action-item-ui>
|
|
20
|
+
<action-item-ui icon="gear" text="Settings" value="settings"></action-item-ui>
|
|
21
|
+
</action-list-ui>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Destructive Items
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<action-list-ui>
|
|
28
|
+
<action-item-ui icon="pencil" text="Edit" value="edit"></action-item-ui>
|
|
29
|
+
<action-item-ui icon="copy" text="Duplicate" value="duplicate"></action-item-ui>
|
|
30
|
+
<action-item-ui icon="archive" text="Archive" value="archive"></action-item-ui>
|
|
31
|
+
<action-item-ui icon="trash" text="Delete" value="delete" variant="danger"></action-item-ui>
|
|
32
|
+
</action-list-ui>
|
|
33
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# agent-artifact — Examples
|
|
2
|
+
|
|
3
|
+
## code body
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<agent-artifact-ui title="product-card-v2" kind="A2UI" icon="layout">
|
|
7
|
+
<button-ui slot="primary" text="Open in canvas" icon="arrows-out-simple" variant="outline" size="sm"></button-ui>
|
|
8
|
+
<button-ui slot="secondary" text="Copy" icon="copy" variant="ghost" size="sm"></button-ui>
|
|
9
|
+
</agent-artifact-ui>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## tones
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<agent-artifact-ui title="validation-failed" kind="TICKET" icon="warning" tone="warning">
|
|
16
|
+
<button-ui slot="secondary" text="Download" icon="download" variant="ghost" size="sm"></button-ui>
|
|
17
|
+
<div style="font-size: var(--a-ui-sm); color: var(--a-fg-muted); line-height: 1.5;">Validation score 62/100 — the output is missing a price badge and has an unlabeled button. Retrying would help.</div>
|
|
18
|
+
</agent-artifact-ui>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<agent-artifact-ui title="product-card" kind="A2UI" icon="layout">
|
|
25
|
+
<button-ui slot="primary" text="Open in canvas" icon="arrows-out-simple"></button-ui>
|
|
26
|
+
<button-ui slot="secondary" text="Copy" icon="copy"></button-ui>
|
|
27
|
+
</agent-artifact-ui>
|
|
28
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# agent-feedback-bar — Examples
|
|
2
|
+
|
|
3
|
+
## thumbs only
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<agent-feedback-bar-ui id="demo-basic"></agent-feedback-bar-ui>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## with save
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<agent-feedback-bar-ui id="demo-save" save-label="Save pattern"></agent-feedback-bar-ui>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<agent-feedback-bar-ui save-label="Save pattern"></agent-feedback-bar-ui>
|
|
19
|
+
el.addEventListener('feedback-rate', (e) => persist(e.detail.rating));
|
|
20
|
+
el.addEventListener('feedback-save', async () => {
|
|
21
|
+
const name = await savePattern(...);
|
|
22
|
+
el.setStatus(`Saved as "${name}"`, { lock: 'save' });
|
|
23
|
+
});
|
|
24
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# agent-questions — Examples
|
|
2
|
+
|
|
3
|
+
## single select
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<agent-questions-ui id="demo-single" question="Which direction fits best?" helper="Pick one — we can revisit later."></agent-questions-ui>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## multi select
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<agent-questions-ui id="demo-multi" multi question="Which features should we include?" helper="Select any that apply." submit-label="Generate"></agent-questions-ui>
|
|
13
|
+
```
|