@adia-ai/web-components 0.0.27 → 0.0.29

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 (93) hide show
  1. package/README.md +4 -8
  2. package/a2ui/index.js +1 -1
  3. package/components/agent-questions/agent-questions.css +20 -1
  4. package/components/agent-trace/agent-trace.css +17 -12
  5. package/components/badge/badge.js +9 -1
  6. package/components/breadcrumb/breadcrumb.a2ui.json +16 -1
  7. package/components/breadcrumb/breadcrumb.css +27 -0
  8. package/components/breadcrumb/breadcrumb.js +95 -17
  9. package/components/breadcrumb/breadcrumb.yaml +15 -1
  10. package/components/canvas/canvas.js +1 -1
  11. package/components/chart/chart.css +20 -13
  12. package/components/chart/chart.js +49 -17
  13. package/components/chart-legend/chart-legend.css +30 -54
  14. package/components/chart-legend/chart-legend.js +48 -30
  15. package/components/command/command.js +52 -1
  16. package/components/feed/feed-item.yaml +50 -0
  17. package/components/feed/feed.a2ui.json +59 -0
  18. package/components/feed/feed.css +150 -0
  19. package/components/feed/feed.js +385 -0
  20. package/components/feed/feed.yaml +33 -0
  21. package/components/index.js +2 -0
  22. package/components/swatch/swatch.a2ui.json +116 -0
  23. package/components/swatch/swatch.css +141 -0
  24. package/components/swatch/swatch.js +121 -0
  25. package/components/swatch/swatch.yaml +101 -0
  26. package/components/timeline/timeline.css +5 -1
  27. package/components/toast/toast.js +48 -178
  28. package/components/tooltip/tooltip.css +3 -3
  29. package/core/provider.js +1 -0
  30. package/index.css +3 -2
  31. package/index.js +15 -7
  32. package/package.json +1 -5
  33. package/styles/components.css +1 -0
  34. package/patterns/a2ui-root/a2ui-root.a2ui.json +0 -125
  35. package/patterns/a2ui-root/a2ui-root.js +0 -191
  36. package/patterns/a2ui-root/a2ui-root.yaml +0 -87
  37. package/patterns/adia-chat/adia-chat.a2ui.json +0 -149
  38. package/patterns/adia-chat/adia-chat.css +0 -10
  39. package/patterns/adia-chat/adia-chat.js +0 -297
  40. package/patterns/adia-chat/adia-chat.yaml +0 -118
  41. package/patterns/adia-chat/css/adia-chat.empty.css +0 -12
  42. package/patterns/adia-chat/css/adia-chat.layout.css +0 -60
  43. package/patterns/adia-chat/css/adia-chat.markdown.css +0 -74
  44. package/patterns/adia-chat/css/adia-chat.messages.css +0 -87
  45. package/patterns/adia-chat/css/adia-chat.streaming.css +0 -30
  46. package/patterns/adia-chat/css/adia-chat.tokens.css +0 -95
  47. package/patterns/adia-editor/adia-editor.a2ui.json +0 -73
  48. package/patterns/adia-editor/adia-editor.css +0 -6
  49. package/patterns/adia-editor/adia-editor.js +0 -56
  50. package/patterns/adia-editor/adia-editor.yaml +0 -59
  51. package/patterns/adia-editor/css/adia-editor.layout.css +0 -171
  52. package/patterns/adia-editor/css/adia-editor.tokens.css +0 -28
  53. package/patterns/app-nav/app-nav.a2ui.json +0 -89
  54. package/patterns/app-nav/app-nav.css +0 -92
  55. package/patterns/app-nav/app-nav.js +0 -112
  56. package/patterns/app-nav/app-nav.yaml +0 -54
  57. package/patterns/app-nav-group/app-nav-group.a2ui.json +0 -82
  58. package/patterns/app-nav-group/app-nav-group.css +0 -264
  59. package/patterns/app-nav-group/app-nav-group.js +0 -116
  60. package/patterns/app-nav-group/app-nav-group.yaml +0 -59
  61. package/patterns/app-nav-item/app-nav-item.a2ui.json +0 -83
  62. package/patterns/app-nav-item/app-nav-item.css +0 -162
  63. package/patterns/app-nav-item/app-nav-item.js +0 -42
  64. package/patterns/app-nav-item/app-nav-item.yaml +0 -62
  65. package/patterns/app-shell/app-shell.a2ui.json +0 -129
  66. package/patterns/app-shell/app-shell.css +0 -14
  67. package/patterns/app-shell/app-shell.js +0 -251
  68. package/patterns/app-shell/app-shell.yaml +0 -89
  69. package/patterns/app-shell/css/app-shell.collapsed.css +0 -86
  70. package/patterns/app-shell/css/app-shell.helpers.css +0 -42
  71. package/patterns/app-shell/css/app-shell.main.css +0 -172
  72. package/patterns/app-shell/css/app-shell.shell.css +0 -44
  73. package/patterns/app-shell/css/app-shell.sidebar.css +0 -161
  74. package/patterns/app-shell/css/app-shell.templates.css +0 -214
  75. package/patterns/app-shell/css/app-shell.tokens.css +0 -119
  76. package/patterns/gen-ui/gen-ui.a2ui.json +0 -72
  77. package/patterns/gen-ui/gen-ui.css +0 -83
  78. package/patterns/gen-ui/gen-ui.js +0 -136
  79. package/patterns/gen-ui/gen-ui.yaml +0 -43
  80. package/patterns/index.js +0 -11
  81. package/patterns/section-nav/section-nav.a2ui.json +0 -91
  82. package/patterns/section-nav/section-nav.css +0 -60
  83. package/patterns/section-nav/section-nav.js +0 -42
  84. package/patterns/section-nav/section-nav.yaml +0 -58
  85. package/patterns/section-nav-group/section-nav-group.a2ui.json +0 -95
  86. package/patterns/section-nav-group/section-nav-group.css +0 -74
  87. package/patterns/section-nav-group/section-nav-group.js +0 -84
  88. package/patterns/section-nav-group/section-nav-group.yaml +0 -66
  89. package/patterns/section-nav-item/section-nav-item.a2ui.json +0 -97
  90. package/patterns/section-nav-item/section-nav-item.css +0 -106
  91. package/patterns/section-nav-item/section-nav-item.js +0 -66
  92. package/patterns/section-nav-item/section-nav-item.yaml +0 -70
  93. package/styles/layouts/admin.css +0 -7
@@ -0,0 +1,121 @@
1
+ /**
2
+ * <swatch-ui> — color / style sample primitive.
3
+ *
4
+ * A small inline tile representing one visual sample — a chart series's
5
+ * legend marker, a design-token step in a color or spacing scale, a
6
+ * theme-preview pill. Replaces docs-only `<span data-swatch>` usage and
7
+ * the per-shape CSS that used to live inside chart-legend-ui.
8
+ *
9
+ * Usage:
10
+ * <swatch-ui shape="dot" color="var(--a-data-0)" label="Revenue"></swatch-ui>
11
+ * <swatch-ui shape="block" size="lg" color="var(--a-neutral-50)" label="50"></swatch-ui>
12
+ * <swatch-ui shape="line" color="#0ea5e9">Forecast</swatch-ui>
13
+ *
14
+ * Attributes:
15
+ * shape — block | dot | square | line | dashed (default square)
16
+ * size — sm | md | lg (default md). lg is the 40px-tall token-scale block.
17
+ * color — any CSS color (or var() ref). Sets --swatch-color internally.
18
+ * label — optional text label rendered beside / below the swatch
19
+ *
20
+ * Slots:
21
+ * default — rich label content; takes precedence over [label] attr
22
+ *
23
+ * Stamping is light-DOM with two children:
24
+ * <span data-tile></span> — the colored shape
25
+ * <span data-label></span> — the label text (omitted when no label/slot)
26
+ */
27
+
28
+ import { AdiaElement } from '../../core/element.js';
29
+
30
+ const SHAPES = new Set(['block', 'dot', 'square', 'line', 'dashed']);
31
+ const SIZES = new Set(['sm', 'md', 'lg']);
32
+
33
+ class AdiaSwatch extends AdiaElement {
34
+ static properties = {
35
+ shape: { type: String, default: 'square', reflect: true },
36
+ size: { type: String, default: 'md', reflect: true },
37
+ color: { type: String, default: '', reflect: true },
38
+ label: { type: String, default: '', reflect: true },
39
+ };
40
+
41
+ static template = () => null;
42
+
43
+ #tileEl = null;
44
+ #labelEl = null;
45
+ #stamped = false;
46
+
47
+ connected() {
48
+ this.#stamp();
49
+ }
50
+
51
+ render() {
52
+ this.#stamp();
53
+ this.#sync();
54
+ }
55
+
56
+ #stamp() {
57
+ if (this.#stamped) return;
58
+ // Capture pre-existing default-slot content so consumer-authored
59
+ // children (e.g. <swatch-ui>Forecast</swatch-ui>) survive stamping.
60
+ const slotted = Array.from(this.childNodes).filter(n =>
61
+ !(n.nodeType === 1 && (n.dataset?.tile !== undefined || n.dataset?.label !== undefined))
62
+ );
63
+ this.innerHTML = '';
64
+
65
+ this.#tileEl = document.createElement('span');
66
+ this.#tileEl.setAttribute('data-tile', '');
67
+ this.#tileEl.setAttribute('aria-hidden', 'true');
68
+ this.appendChild(this.#tileEl);
69
+
70
+ this.#labelEl = document.createElement('span');
71
+ this.#labelEl.setAttribute('data-label', '');
72
+ if (slotted.length) {
73
+ for (const n of slotted) this.#labelEl.appendChild(n);
74
+ }
75
+ this.appendChild(this.#labelEl);
76
+
77
+ this.#stamped = true;
78
+ }
79
+
80
+ #sync() {
81
+ if (!this.#tileEl || !this.#labelEl) return;
82
+
83
+ // Normalize enum values; fall back silently when a consumer sets a typo.
84
+ const shape = SHAPES.has(this.shape) ? this.shape : 'square';
85
+ const size = SIZES.has(this.size) ? this.size : 'md';
86
+ if (shape !== this.shape) this.setAttribute('shape', shape);
87
+ if (size !== this.size) this.setAttribute('size', size);
88
+
89
+ // Color: only write the inline custom property when [color] is set
90
+ // explicitly; otherwise leave whatever the consumer wrote via
91
+ // style="--swatch-color: …" alone.
92
+ if (this.color) {
93
+ this.style.setProperty('--swatch-color', this.color);
94
+ }
95
+
96
+ // Label: prefer slotted content (already in #labelEl from #stamp);
97
+ // when label-attr is set and the slot is empty, write the attribute.
98
+ if (!this.#labelEl.firstChild && this.label) {
99
+ this.#labelEl.textContent = this.label;
100
+ } else if (this.#labelEl.firstChild?.nodeType === 3 && this.label) {
101
+ // Pure-text node from a previous label-attr render — keep it
102
+ // synced to the current attr value.
103
+ this.#labelEl.textContent = this.label;
104
+ }
105
+
106
+ // Hide the label box when there's no content. Empty-but-stamped span
107
+ // would otherwise eat the layout gap.
108
+ const hasLabel = this.#labelEl.textContent.trim().length > 0
109
+ || (this.#labelEl.firstElementChild != null);
110
+ this.#labelEl.toggleAttribute('hidden', !hasLabel);
111
+ }
112
+
113
+ disconnected() {
114
+ this.#tileEl = null;
115
+ this.#labelEl = null;
116
+ this.#stamped = false;
117
+ }
118
+ }
119
+
120
+ customElements.define('swatch-ui', AdiaSwatch);
121
+ export { AdiaSwatch };
@@ -0,0 +1,101 @@
1
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
+ name: AdiaSwatch
3
+ tag: swatch-ui
4
+ component: Swatch
5
+ category: display
6
+ version: 1
7
+ description: |
8
+ Color/style swatch primitive — a small inline tile representing a single
9
+ visual sample. Renders as block, dot, square, line, or dashed depending on
10
+ shape; pairs with an optional label slot or attribute. Composed by chart-
11
+ legend-ui's per-row swatch and consumed directly by the token-colors /
12
+ spacing demo pages.
13
+ props:
14
+ shape:
15
+ description: Visual shape — block (filled tile), dot (small circle), square (small filled square), line (solid hairline), dashed (dashed hairline).
16
+ type: string
17
+ default: square
18
+ reflect: true
19
+ enum:
20
+ - block
21
+ - dot
22
+ - square
23
+ - line
24
+ - dashed
25
+ size:
26
+ description: Size preset — sm / md / lg. Drives the swatch's intrinsic dimensions; lg is reserved for the token-scale demo (40 px tall).
27
+ type: string
28
+ default: md
29
+ reflect: true
30
+ enum:
31
+ - sm
32
+ - md
33
+ - lg
34
+ color:
35
+ description: Swatch color. Accepts any CSS color value or var() reference. Sets the internal --swatch-color custom property; consumers can also set --swatch-color via inline style.
36
+ type: string
37
+ default: ""
38
+ reflect: true
39
+ label:
40
+ description: Optional label rendered next to (or below, for shape="block") the swatch. Use the default slot for richer content.
41
+ type: string
42
+ default: ""
43
+ reflect: true
44
+ events: {}
45
+ slots:
46
+ default:
47
+ description: Optional rich label content. When present, replaces the [label] attribute's text.
48
+ states:
49
+ - name: idle
50
+ description: Default, ready for display.
51
+ traits: []
52
+ tokens:
53
+ --swatch-color:
54
+ description: Resolved color of the swatch fill / line. Wins over the [color] attr if set inline.
55
+ a2ui:
56
+ rules: []
57
+ anti_patterns: []
58
+ examples:
59
+ - name: basic-swatch
60
+ description: A single dot swatch with text label, e.g. as a chart-legend row.
61
+ a2ui: >-
62
+ [
63
+ {
64
+ "id": "root",
65
+ "component": "Swatch",
66
+ "shape": "dot",
67
+ "color": "var(--a-data-0)",
68
+ "label": "Revenue"
69
+ }
70
+ ]
71
+ - name: token-block
72
+ description: Block swatch for a token-scale step.
73
+ a2ui: >-
74
+ [
75
+ {
76
+ "id": "root",
77
+ "component": "Swatch",
78
+ "shape": "block",
79
+ "size": "lg",
80
+ "color": "var(--a-neutral-50)",
81
+ "label": "50"
82
+ }
83
+ ]
84
+ keywords:
85
+ - swatch
86
+ - color
87
+ - chip
88
+ - sample
89
+ - palette
90
+ - legend
91
+ - step
92
+ - token
93
+ synonyms:
94
+ color-chip:
95
+ - swatch
96
+ - chip
97
+ color-sample:
98
+ - swatch
99
+ related:
100
+ - chart-legend-ui
101
+ - tag-ui
@@ -347,7 +347,11 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
347
347
  :scope > [data-timeline-toggle] {
348
348
  position: absolute;
349
349
  inset-inline-end: 0;
350
- top: calc((1.4em - 1em) / 2);
350
+ /* Place the chevron's icon-center on row 1's optical center.
351
+ The button has --a-space-0-5 vertical padding, so the icon
352
+ sits that much lower inside the box; we subtract that so the
353
+ icon (not the box) lines up with the time-slot text center. */
354
+ top: calc((1.4em - 1em) / 2 - var(--a-space-0-5));
351
355
  background: none;
352
356
  border: none;
353
357
  padding: var(--a-space-0-5) var(--timeline-item-toggle-px);
@@ -1,39 +1,32 @@
1
1
  /**
2
- * <toast-ui> — Notification popup wired through a shared top-layer
3
- * messaging channel.
2
+ * <toast-ui> — Thin facade over `<feed-ui>` / `AdiaFeed.post()`.
4
3
  *
5
- * All toasts declarative AND imperative route through one
6
- * lazily-mounted `[data-toast-container][data-toast-position]` per
7
- * position. Per-position singletons; consumers can post from anywhere
8
- * without holding a reference to the toast component:
4
+ * Phase 4 of `docs/specs/feed-channel.md` (SPEC-FEED-CHANNEL-001)
5
+ * toast-ui no longer owns its own per-position container. Both
6
+ * declarative `<toast-ui>` and imperative `AdiaToast.show()` paths
7
+ * route through `AdiaFeed`. The element exists for back-compat:
8
+ * authoring `<toast-ui text="…">` still produces a feed item.
9
9
  *
10
- * // Imperative API
10
+ * // Imperative API (delegates to AdiaFeed.post)
11
11
  * AdiaToast.show({ text: 'Saved!', variant: 'success' });
12
12
  *
13
- * // Global event channel — same shape, dispatched on `window`.
14
- * // Any code (other components, integration scripts) can post
15
- * // without importing AdiaToast.
13
+ * // Global event channel — same shape, same delegation.
16
14
  * window.dispatchEvent(new CustomEvent('toast', {
17
15
  * detail: { text: 'Saved!', variant: 'success' }
18
16
  * }));
19
17
  *
20
- * // Declarative — auto-routes to the per-position container on
21
- * // connect. No need to author <toast-ui> inside the container.
18
+ * // Declarative — auto-posts and removes self on connect.
22
19
  * <toast-ui text="Saved!" variant="success"></toast-ui>
23
20
  *
24
- * Events:
25
- * close fired after the toast finishes its exit animation
21
+ * The legacy `[data-toast-container]` per-position-Map plumbing was
22
+ * retired in this migration; the lane infrastructure now lives in
23
+ * `<feed-ui>` (see ../feed/feed.js).
26
24
  */
27
25
 
28
26
  import { AdiaElement, html } from '../../core/element.js';
27
+ import { AdiaFeed } from '../feed/feed.js';
29
28
 
30
29
  class AdiaToast extends AdiaElement {
31
- #timer = null;
32
- #removing = false;
33
- #closeTimer = null;
34
- #openRaf = null;
35
- #routed = false;
36
-
37
30
  static properties = {
38
31
  text: { type: String, default: '', reflect: true },
39
32
  variant: { type: String, default: 'info', reflect: true },
@@ -41,178 +34,55 @@ class AdiaToast extends AdiaElement {
41
34
  position: { type: String, default: 'bottom-right', reflect: true },
42
35
  };
43
36
 
44
- static parts = {
45
- message: '<div slot="message"></div>',
46
- close: '<button-ui slot="close" icon="x" variant="ghost" size="sm" aria-label="Dismiss"></button-ui>',
47
- };
48
-
49
37
  static template = () => html``;
50
38
 
51
- #onPress = (e) => {
52
- if (e.target.closest('[slot="close"]')) this.dismiss();
53
- };
54
-
55
39
  connected() {
56
- this.addEventListener('press', this.#onPress);
57
-
58
- // Route declarative <toast-ui> instances into the shared per-position
59
- // container so authored toasts share the same lane as imperatively-
60
- // posted ones (no overlap, consistent stacking). Skipped if we're
61
- // already inside a container (re-entrant connect after reparent).
62
- if (!this.#routed && !this.parentElement?.matches?.('[data-toast-container]')) {
63
- this.#routed = true;
64
- const container = AdiaToast.#getContainer(this.position || 'bottom-right');
65
- if (this.parentElement !== container) container.appendChild(this);
66
- }
67
- }
68
-
69
- #getDuration() {
70
- const raw = getComputedStyle(this).getPropertyValue('--toast-duration').trim();
71
- return parseFloat(raw) || 200;
72
- }
73
-
74
- render() {
75
- const message = this.ensure('message');
76
- message.textContent = this.text;
77
-
78
- const close = this.ensure('close');
79
- if (close.parentElement !== this) this.appendChild(close);
80
-
81
- this.setAttribute('role', 'status');
82
- this.setAttribute('aria-live', 'polite');
83
-
84
- // Schedule auto-open animation
85
- if (!this.hasAttribute('data-open') && !this.#removing) {
86
- this.#openRaf = requestAnimationFrame(() => {
87
- this.#openRaf = null;
88
- this.setAttribute('data-open', '');
89
- });
90
- }
91
-
92
- // Schedule auto-dismiss
93
- this.#scheduleAutoDismiss();
94
- }
95
-
96
- #scheduleAutoDismiss() {
97
- if (this.#timer) clearTimeout(this.#timer);
98
- if (this.duration > 0) {
99
- this.#timer = setTimeout(() => this.dismiss(), this.duration);
100
- }
101
- }
102
-
103
- dismiss() {
104
- if (this.#removing) return;
105
- this.#removing = true;
106
- if (this.#timer) { clearTimeout(this.#timer); this.#timer = null; }
107
-
108
- this.removeAttribute('data-open');
109
- this.setAttribute('data-closing', '');
110
-
111
- this.#closeTimer = setTimeout(() => {
112
- this.#closeTimer = null;
113
- this.removeAttribute('data-closing');
114
- const container = this.parentElement;
115
- this.dispatchEvent(new Event('close', { bubbles: true }));
116
- this.remove();
117
- /* If the lane is now empty, hide its popover and remove the
118
- container — keeps document.body free of leaked containers. */
119
- if (container?.matches?.('[data-toast-container]')) {
120
- AdiaToast.#releaseContainerIfEmpty(container);
121
- }
122
- }, this.#getDuration());
123
- }
124
-
125
- disconnected() {
126
- this.removeEventListener('press', this.#onPress);
127
- if (this.#timer) { clearTimeout(this.#timer); this.#timer = null; }
128
- if (this.#closeTimer) { clearTimeout(this.#closeTimer); this.#closeTimer = null; }
129
- if (this.#openRaf != null) { cancelAnimationFrame(this.#openRaf); this.#openRaf = null; }
40
+ /* Declarative path: post into AdiaFeed and remove self. The
41
+ element is fire-and-forget — its only job is to forward the
42
+ authored attributes to the feed, then dissolve. Re-entrant
43
+ guard keeps this safe under HMR / dev-mode re-attachment. */
44
+ if (this.__routedToFeed) return;
45
+ this.__routedToFeed = true;
46
+ AdiaFeed.post({
47
+ text: this.text,
48
+ variant: this.variant === 'error' ? 'danger' : this.variant,
49
+ duration: this.duration,
50
+ position: this.position,
51
+ });
52
+ /* Schedule removal so the calling code can read the attributes
53
+ if it inspected this element on the same microtask. */
54
+ queueMicrotask(() => { try { this.remove(); } catch { /* noop */ } });
130
55
  }
131
56
 
132
57
  /**
133
- * Static conveniencecreates a toast, appends to body, auto-removes.
58
+ * Static facadedelegates to AdiaFeed.post(). Kept for back-compat
59
+ * with consumer code shaped like `customElements.get('toast-ui').show(...)`
60
+ * or `AdiaToast.show(...)`. New code should call AdiaFeed.post()
61
+ * directly.
62
+ *
134
63
  * @param {Object} opts
135
64
  * @param {string} opts.text
136
- * @param {string} [opts.variant='info']
65
+ * @param {string} [opts.variant='info'] — `error` aliases to `danger`.
137
66
  * @param {number} [opts.duration=4000]
138
67
  * @param {string} [opts.position='bottom-right']
139
- * @returns {AdiaToast}
140
- */
141
- static #containers = new Map();
142
-
143
- /**
144
- * Get (or lazily create) the per-position lane. Each lane is a manual
145
- * Popover-API container — `[popover="manual"]` puts it in the browser's
146
- * top-layer, above ALL page content with no z-index wars, and the
147
- * native popover stack lets multiple lanes coexist (e.g. one toast in
148
- * top-right + another in bottom-center) without collision.
149
- *
150
- * `popover="manual"` (not `auto`) — toasts must NOT light-dismiss on
151
- * outside click; they auto-fade by their own duration timer.
152
- *
153
- * Falls back gracefully if the Popover API is unsupported (Safari < 17 /
154
- * Firefox < 125): the lane still renders as a `position: fixed` div via
155
- * the CSS `[data-toast-container]` rules. Browser baseline (Chromium
156
- * 125+, Safari 18.0+, Firefox 129+) all support `[popover]`.
68
+ * @returns {{id:string|null, dismiss:function, update:function}} FeedHandle.
157
69
  */
158
- static #getContainer(position) {
159
- let el = AdiaToast.#containers.get(position);
160
- if (el && el.isConnected) return el;
161
- el = document.createElement('div');
162
- el.setAttribute('data-toast-container', position);
163
- /* `manual` = no light-dismiss; container stays open until we
164
- explicitly hidePopover() it when its last toast leaves. */
165
- if ('popover' in HTMLElement.prototype) {
166
- el.setAttribute('popover', 'manual');
167
- }
168
- document.body.appendChild(el);
169
- /* Show the popover so the lane lifts into the top-layer. Wrapped in
170
- try/catch because some test rigs (happy-dom) don't ship the API. */
171
- try { el.showPopover?.(); } catch { /* graceful fallback to fixed */ }
172
- AdiaToast.#containers.set(position, el);
173
- return el;
70
+ static show(opts = {}) {
71
+ const { text, variant = 'info', duration = 4000, position = 'bottom-right' } = opts;
72
+ return AdiaFeed.post({
73
+ text,
74
+ variant: variant === 'error' ? 'danger' : variant,
75
+ duration,
76
+ position,
77
+ });
174
78
  }
175
-
176
- /**
177
- * Tear down the per-position lane when its last toast has been
178
- * dismissed. Keeps `document.body` clean — addresses the audit's L-B4
179
- * "container leak" finding (toasts permanently leaving DIVs in body).
180
- */
181
- static #releaseContainerIfEmpty(container) {
182
- if (!container) return;
183
- if (container.children.length > 0) return;
184
- try { container.hidePopover?.(); } catch { /* noop */ }
185
- container.remove();
186
- /* Clear from the singleton map so the next post() rebuilds. */
187
- for (const [pos, el] of AdiaToast.#containers) {
188
- if (el === container) AdiaToast.#containers.delete(pos);
189
- }
190
- }
191
-
192
- static show({ text, variant = 'info', duration = 4000, position = 'bottom-right' } = {}) {
193
- /* `error` is a documented alias of `danger` (Phase 6 variant table). */
194
- if (variant === 'error') variant = 'danger';
195
- const container = AdiaToast.#getContainer(position);
196
- const toast = document.createElement('toast-ui');
197
- toast.text = text;
198
- toast.variant = variant;
199
- toast.duration = duration;
200
- toast.position = position;
201
- container.appendChild(toast);
202
- return toast;
203
- }
204
-
205
79
  }
206
80
 
207
- /* Install the global 'toast' CustomEvent listener once, at module load,
208
- so any code can post into the channel without importing AdiaToast
209
- directly:
210
-
211
- window.dispatchEvent(new CustomEvent('toast', {
212
- detail: { text: 'Saved!', variant: 'success' }
213
- }));
214
-
215
- Idempotent — guarded by a window flag so HMR / re-imports are safe. */
81
+ /* Idempotent install of the global 'toast' CustomEvent listener.
82
+ Same shape as the historical channel code that posts via
83
+ `window.dispatchEvent(new CustomEvent('toast', {detail:{…}}))`
84
+ keeps working. The listener delegates to AdiaToast.show(), which
85
+ delegates to AdiaFeed.post(). */
216
86
  if (typeof window !== 'undefined' && !window.__adiaToastListenerInstalled) {
217
87
  window.__adiaToastListenerInstalled = true;
218
88
  window.addEventListener('toast', (e) => {
@@ -140,7 +140,7 @@
140
140
  width: var(--tooltip-indicator-size);
141
141
  height: var(--tooltip-indicator-size);
142
142
  border-radius: 50%;
143
- background: var(--tooltip-indicator-color, var(--chart-0));
143
+ background: var(--tooltip-indicator-color, var(--a-data-0));
144
144
  flex-shrink: 0;
145
145
  }
146
146
 
@@ -148,14 +148,14 @@
148
148
  display: inline-block;
149
149
  width: calc(var(--tooltip-indicator-size) * 1.6);
150
150
  height: 2px;
151
- background: var(--tooltip-indicator-color, var(--chart-0));
151
+ background: var(--tooltip-indicator-color, var(--a-data-0));
152
152
  flex-shrink: 0;
153
153
  }
154
154
 
155
155
  .tooltip-popup[data-follows="pointer"][data-indicator="dashed"] [data-indicator] {
156
156
  display: inline-block;
157
157
  width: calc(var(--tooltip-indicator-size) * 1.6);
158
- border-top: 2px dashed var(--tooltip-indicator-color, var(--chart-0));
158
+ border-top: 2px dashed var(--tooltip-indicator-color, var(--a-data-0));
159
159
  flex-shrink: 0;
160
160
  }
161
161
 
package/core/provider.js CHANGED
@@ -236,6 +236,7 @@ export class AdiaRouter extends AdiaProvider {
236
236
  }
237
237
 
238
238
  this.innerHTML = html;
239
+ this.scrollTo(0, 0);
239
240
  (this.closest('section') || this.parentElement)?.scrollTo(0, 0);
240
241
 
241
242
  if (route.title) document.title = route.title;
package/index.css CHANGED
@@ -7,8 +7,9 @@
7
7
  * + typography — via the colors tree) → component styles → global
8
8
  * resets.
9
9
  *
10
- * Pattern CSS (adia-chat, adia-editor, app-shell, etc.) is NOT
11
- * bundled here each page links its own patterns explicitly.
10
+ * Composite-element CSS (adia-chat, adia-editor, app-shell, etc.)
11
+ * lives in the sibling `@adia-ai/web-modules` package as of 0.0.29
12
+ * (see ADR-0012). Each page links its own cluster CSS explicitly.
12
13
  * Opinionated theme overrides live in `./styles/themes.css`; link
13
14
  * them separately when you want the 8 named themes.
14
15
  *
package/index.js CHANGED
@@ -2,17 +2,25 @@
2
2
  * @adia-ai/web-components — main entry.
3
3
  *
4
4
  * import '@adia-ai/web-components';
5
- * import { AdiaButton, AdiaAppShell } from '@adia-ai/web-components';
5
+ * import { AdiaButton } from '@adia-ai/web-components';
6
6
  *
7
- * Loading this file registers every component + pattern custom
8
- * element (side effect of each module's `customElements.define(...)`
9
- * call). Pair with `@adia-ai/web-components/css` (the all-in-one
10
- * stylesheet) or link tokens/components/resets individually.
7
+ * Loading this file registers every primitive (side effect of each
8
+ * module's `customElements.define(...)` call). Pair with
9
+ * `@adia-ai/web-components/css` (the all-in-one stylesheet) or link
10
+ * tokens/components/resets individually.
11
11
  *
12
12
  * If you only want a subset, use the subpath imports:
13
13
  * import '@adia-ai/web-components/components/button';
14
- * import { AdiaAppShell } from '@adia-ai/web-components/patterns';
14
+ *
15
+ * Composite elements (app-shell, app-nav, adia-chat, adia-editor,
16
+ * gen-ui, a2ui-root) shipped here as `patterns/` until 0.0.28 — they
17
+ * now live in `@adia-ai/web-modules` (see ADR-0012).
18
+ *
19
+ * import '@adia-ai/web-modules'; // every cluster
20
+ * import '@adia-ai/web-modules/shell'; // app-shell, app-nav*, section-nav*
21
+ * import '@adia-ai/web-modules/chat'; // adia-chat
22
+ * import '@adia-ai/web-modules/editor'; // adia-editor
23
+ * import '@adia-ai/web-modules/runtime'; // gen-ui, a2ui-root
15
24
  */
16
25
 
17
26
  export * from './components/index.js';
18
- export * from './patterns/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/web-components",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "AdiaUI web components — vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-utils.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,8 +11,6 @@
11
11
  "./core/*": "./core/*.js",
12
12
  "./components": "./components/index.js",
13
13
  "./components/*": "./components/*/*.js",
14
- "./patterns": "./patterns/index.js",
15
- "./patterns/*": "./patterns/*/*.js",
16
14
  "./styles/*": "./styles/*",
17
15
  "./traits": "./traits/index.js",
18
16
  "./traits/*": "./traits/*.js",
@@ -23,7 +21,6 @@
23
21
  "components/",
24
22
  "styles/",
25
23
  "traits/",
26
- "patterns/",
27
24
  "a2ui/",
28
25
  "index.js",
29
26
  "index.css"
@@ -32,7 +29,6 @@
32
29
  "*.css",
33
30
  "./index.js",
34
31
  "./components/**/*.js",
35
- "./patterns/**/*.js",
36
32
  "./core/provider.js"
37
33
  ],
38
34
  "dependencies": {
@@ -50,6 +50,7 @@
50
50
  @import "../components/alert/alert.css";
51
51
  @import "../components/kbd/kbd.css";
52
52
  @import "../components/tag/tag.css";
53
+ @import "../components/swatch/swatch.css";
53
54
  @import "../components/col/col.css";
54
55
  @import "../components/field/field.css";
55
56
  @import "../components/row/row.css";