@adia-ai/web-modules 0.8.39 → 0.8.41

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 (120) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +6 -6
  3. package/agent-admin/admin-roster/admin-roster.a2ui.json +1 -0
  4. package/agent-admin/admin-roster/admin-roster.css +10 -2
  5. package/agent-admin/admin-roster/admin-roster.js +70 -22
  6. package/agent-admin/admin-settings/admin-settings.a2ui.json +1 -0
  7. package/agent-admin/agent-admin/agent-admin.a2ui.json +1 -0
  8. package/billing/billing-overview/billing-overview.a2ui.json +10 -1
  9. package/billing/billing-overview/billing-overview.class.js +142 -73
  10. package/billing/billing-overview/billing-overview.css +70 -57
  11. package/billing/billing-overview/billing-overview.yaml +5 -0
  12. package/billing/invoice-detail/invoice-detail.a2ui.json +9 -4
  13. package/billing/invoice-detail/invoice-detail.class.js +22 -5
  14. package/billing/invoice-detail/invoice-detail.yaml +9 -4
  15. package/billing/invoice-history/invoice-history.a2ui.json +7 -4
  16. package/billing/invoice-history/invoice-history.class.js +45 -12
  17. package/billing/invoice-history/invoice-history.css +18 -15
  18. package/billing/invoice-history/invoice-history.yaml +10 -4
  19. package/billing/payment-method-form/payment-method-form.a2ui.json +1 -0
  20. package/billing/payment-method-form/payment-method-form.class.js +3 -3
  21. package/billing/payment-method-form/payment-method-form.css +4 -4
  22. package/billing/payment-method-list/payment-method-list.a2ui.json +4 -0
  23. package/billing/payment-method-list/payment-method-list.class.js +31 -11
  24. package/billing/payment-method-list/payment-method-list.css +13 -10
  25. package/billing/payment-method-list/payment-method-list.yaml +3 -0
  26. package/billing/plan-picker/plan-picker.a2ui.json +6 -0
  27. package/billing/plan-picker/plan-picker.class.js +70 -22
  28. package/billing/plan-picker/plan-picker.css +21 -38
  29. package/billing/plan-picker/plan-picker.yaml +5 -0
  30. package/chat/chat-composer/chat-composer.a2ui.json +1 -0
  31. package/chat/chat-empty/chat-empty.a2ui.json +4 -0
  32. package/chat/chat-empty/chat-empty.yaml +2 -0
  33. package/chat/chat-header/chat-header.a2ui.json +5 -0
  34. package/chat/chat-header/chat-header.yaml +3 -0
  35. package/chat/chat-shell/chat-shell.a2ui.json +4 -0
  36. package/chat/chat-shell/chat-shell.yaml +2 -0
  37. package/chat/chat-shell/css/chat-shell.tokens.css +1 -1
  38. package/chat/chat-sidebar/chat-sidebar.a2ui.json +4 -0
  39. package/chat/chat-sidebar/chat-sidebar.yaml +2 -0
  40. package/chat/chat-status/chat-status.a2ui.json +4 -0
  41. package/chat/chat-status/chat-status.yaml +2 -0
  42. package/chat/chat-thread/chat-thread.a2ui.json +4 -0
  43. package/chat/chat-thread/chat-thread.yaml +2 -0
  44. package/dashboard/dashboard-layout/dashboard-layout.a2ui.json +8 -8
  45. package/dashboard/dashboard-layout/dashboard-layout.css +4 -4
  46. package/dashboard/dashboard-layout/dashboard-layout.js +10 -9
  47. package/dashboard/dashboard-layout/dashboard-layout.yaml +19 -7
  48. package/dashboard/date-range-selector/date-range-selector.a2ui.json +4 -3
  49. package/dashboard/date-range-selector/date-range-selector.yaml +6 -4
  50. package/dist/chat/chat-shell.min.css +1 -1
  51. package/dist/chat/chat-shell.min.js +25 -25
  52. package/dist/editor/editor-shell.min.js +3 -3
  53. package/dist/everything.min.js +118 -131
  54. package/dist/shell/admin-shell.min.css +1 -1
  55. package/dist/shell/admin-shell.min.js +6 -6
  56. package/dist/simple/simple-shell.min.js +5 -5
  57. package/dist/web-modules.min.css +1 -1
  58. package/dist/web-modules.sheet.js +1 -1
  59. package/editor/editor-canvas/editor-canvas.a2ui.json +4 -0
  60. package/editor/editor-canvas/editor-canvas.yaml +2 -0
  61. package/editor/editor-canvas-empty/editor-canvas-empty.a2ui.json +4 -0
  62. package/editor/editor-canvas-empty/editor-canvas-empty.yaml +2 -0
  63. package/editor/editor-canvas-toolbar/editor-canvas-toolbar.a2ui.json +4 -0
  64. package/editor/editor-canvas-toolbar/editor-canvas-toolbar.yaml +2 -0
  65. package/editor/editor-shell/editor-shell.a2ui.json +5 -0
  66. package/editor/editor-shell/editor-shell.yaml +3 -0
  67. package/editor/editor-sidebar/editor-sidebar.a2ui.json +4 -0
  68. package/editor/editor-sidebar/editor-sidebar.yaml +2 -0
  69. package/editor/editor-statusbar/editor-statusbar.a2ui.json +4 -0
  70. package/editor/editor-statusbar/editor-statusbar.yaml +2 -0
  71. package/editor/editor-toolbar/editor-toolbar.a2ui.json +4 -0
  72. package/editor/editor-toolbar/editor-toolbar.yaml +2 -0
  73. package/feedback/confirm-dialog/confirm-dialog.a2ui.json +1 -0
  74. package/form/form-popover/form-popover.a2ui.json +1 -0
  75. package/onboarding/onboarding-checklist/onboarding-checklist.a2ui.json +2 -1
  76. package/onboarding/onboarding-checklist/onboarding-checklist.js +2 -2
  77. package/onboarding/onboarding-checklist/onboarding-checklist.yaml +1 -1
  78. package/package.json +6 -6
  79. package/runtime/a2ui-root/a2ui-root.a2ui.json +6 -5
  80. package/runtime/a2ui-root/a2ui-root.css +75 -0
  81. package/runtime/a2ui-root/a2ui-root.js +118 -10
  82. package/runtime/a2ui-root/a2ui-root.yaml +7 -2
  83. package/runtime/gen-root/gen-root.a2ui.json +6 -5
  84. package/runtime/gen-root/gen-root.yaml +10 -2
  85. package/settings/integrations-page/integrations-page.a2ui.json +3 -2
  86. package/settings/integrations-page/integrations-page.js +8 -8
  87. package/settings/integrations-page/integrations-page.yaml +2 -2
  88. package/settings/notification-preferences/notification-preferences.a2ui.json +1 -0
  89. package/shell/admin-command/admin-command.a2ui.json +5 -1
  90. package/shell/admin-command/admin-command.yaml +3 -1
  91. package/shell/admin-content/admin-content.a2ui.json +4 -0
  92. package/shell/admin-content/admin-content.yaml +2 -0
  93. package/shell/admin-entity-item/admin-entity-item.a2ui.json +1 -0
  94. package/shell/admin-page/admin-page.a2ui.json +5 -0
  95. package/shell/admin-page/admin-page.yaml +3 -0
  96. package/shell/admin-page-body/admin-page-body.a2ui.json +4 -0
  97. package/shell/admin-page-body/admin-page-body.yaml +2 -0
  98. package/shell/admin-page-footer/admin-page-footer.a2ui.json +4 -0
  99. package/shell/admin-page-footer/admin-page-footer.yaml +2 -0
  100. package/shell/admin-page-header/admin-page-header.a2ui.json +4 -0
  101. package/shell/admin-page-header/admin-page-header.yaml +2 -0
  102. package/shell/admin-scroll/admin-scroll.a2ui.json +4 -0
  103. package/shell/admin-scroll/admin-scroll.yaml +2 -0
  104. package/shell/admin-shell/admin-shell.a2ui.json +7 -3
  105. package/shell/admin-shell/admin-shell.yaml +3 -1
  106. package/shell/admin-shell/css/admin-shell.sidebar.css +2 -2
  107. package/shell/admin-sidebar/admin-sidebar.a2ui.json +4 -0
  108. package/shell/admin-sidebar/admin-sidebar.yaml +2 -0
  109. package/shell/admin-statusbar/admin-statusbar.a2ui.json +6 -0
  110. package/shell/admin-statusbar/admin-statusbar.yaml +4 -0
  111. package/shell/admin-topbar/admin-topbar.a2ui.json +6 -0
  112. package/shell/admin-topbar/admin-topbar.yaml +4 -0
  113. package/shell/embed-shell/embed-shell.a2ui.json +1 -0
  114. package/simple/simple-content/simple-content.a2ui.json +4 -0
  115. package/simple/simple-content/simple-content.yaml +2 -0
  116. package/simple/simple-hero/simple-hero.a2ui.json +4 -0
  117. package/simple/simple-hero/simple-hero.yaml +2 -0
  118. package/simple/simple-shell/simple-shell.a2ui.json +4 -0
  119. package/simple/simple-shell/simple-shell.yaml +2 -0
  120. package/theme/theme-panel/theme-panel.a2ui.json +1 -0
@@ -5,15 +5,25 @@
5
5
  * marketing pricing page (SPEC-012). Each plan card is composed from
6
6
  * <option-card-ui> (radio semantics) decorated with a price block,
7
7
  * feature list, and CTA button derived from the plan record. The
8
- * optional cycle toggle is a <segmented-ui> that swaps monthly /
9
- * annual prices in place across every card.
8
+ * optional cycle toggle is a <field-ui label="Billing interval">
9
+ * wrapping a <segmented-ui> the canonical billing-interval chain
10
+ * from apps/saas/app/billing/billing.contents.html — that swaps
11
+ * monthly / annual prices in place across every card.
12
+ *
13
+ * Internal layout composes the framework layout primitives (gh#1519):
14
+ * the plans host is a <grid-ui columns="auto-fit">, each card body is
15
+ * a <col-ui> of <row-ui data-price-row> + <divider-ui> + a
16
+ * <col-ui data-features> of <row-ui> feature lines — mirroring the
17
+ * canonical's col-ui/row-ui feature-list grammar instead of raw
18
+ * div/ul/li.
10
19
  *
11
20
  * SPEC: .claude/docs/specs/implementation-ready/SPEC-011-plan-picker-in-app-upgrade.md
12
21
  * WAI-APG: https://www.w3.org/WAI/ARIA/apg/patterns/radio/
13
22
  *
14
23
  * Architecture (light-DOM, ADR-0033):
15
- * This composite stamps a four-region skeleton once on first connect:
16
- * [data-toggle] · [data-plans] · [data-skeleton] · [data-empty]
24
+ * This composite stamps a region skeleton once on first connect:
25
+ * [data-toggle] · [data-toggle-divider] · [data-plans] ·
26
+ * [data-skeleton] · [data-empty]
17
27
  * Then mutates per-card DOM by id-keyed in-place diff on every
18
28
  * `plans` / `value` / `current` / `cycle` change. The diff preserves
19
29
  * focus-within during re-render (replacing children would break the
@@ -116,8 +126,10 @@ export class PlanPicker extends UIFormElement {
116
126
  #stamped = false;
117
127
  #cleanups = [];
118
128
  #toggleHost = null; // <div data-toggle> wrapper
119
- #toggleSegmented = null; // <segmented-ui> inside toggle host
120
- #plansHost = null; // <div data-plans role=radiogroup>
129
+ #toggleField = null; // <field-ui> inside toggle host (canonical chain)
130
+ #toggleSegmented = null; // <segmented-ui> inside the field
131
+ #toggleDivider = null; // <divider-ui data-toggle-divider> after the toggle
132
+ #plansHost = null; // <grid-ui data-plans role=presentation>
121
133
  #skeletonHost = null; // <div data-skeleton>
122
134
  #emptyHost = null; // <empty-state-ui data-empty>
123
135
  #cardsById = new Map(); // id → <option-card-ui>
@@ -285,10 +297,11 @@ export class PlanPicker extends UIFormElement {
285
297
  this.removeAttribute('empty');
286
298
  }
287
299
 
288
- // Toggle visibility / contents.
300
+ // Toggle visibility / contents (divider tracks the toggle).
289
301
  if (this.#toggleHost) {
290
302
  const show = this.cycleToggle && plans.length > 0;
291
303
  this.#toggleHost.hidden = !show;
304
+ if (this.#toggleDivider) this.#toggleDivider.hidden = !show;
292
305
  if (show) this.#renderToggle();
293
306
  }
294
307
 
@@ -321,12 +334,24 @@ export class PlanPicker extends UIFormElement {
321
334
  this.appendChild(toggle);
322
335
  this.#toggleHost = toggle;
323
336
 
324
- // Plans host the radiogroup container the option-card-ui kids
325
- // live in. We give it role="presentation" because the OUTER host
326
- // already carries role="radiogroup" and nesting two radiogroups
327
- // would confuse AT.
328
- const plansHost = document.createElement('div');
337
+ // Divider between the interval toggle and the plan list — the
338
+ // canonical change-plan grammar separates the two groups with a
339
+ // <divider-ui> (billing.contents.html drawer). Visible only when
340
+ // the toggle is.
341
+ const toggleDivider = document.createElement('divider-ui');
342
+ toggleDivider.setAttribute('data-toggle-divider', '');
343
+ toggleDivider.hidden = true;
344
+ this.appendChild(toggleDivider);
345
+ this.#toggleDivider = toggleDivider;
346
+
347
+ // Plans host — a <grid-ui> (the framework grid primitive; the
348
+ // [layout] mode overrides its columns via plan-picker.css) that
349
+ // the option-card-ui kids live in as DIRECT children. We give it
350
+ // role="presentation" because the OUTER host already carries
351
+ // role="radiogroup" and nesting two radiogroups would confuse AT.
352
+ const plansHost = document.createElement('grid-ui');
329
353
  plansHost.setAttribute('data-plans', '');
354
+ plansHost.setAttribute('columns', 'auto-fit');
330
355
  plansHost.setAttribute('role', 'presentation');
331
356
  this.appendChild(plansHost);
332
357
  this.#plansHost = plansHost;
@@ -354,9 +379,16 @@ export class PlanPicker extends UIFormElement {
354
379
  if (!this.#toggleHost) return;
355
380
  let seg = this.#toggleSegmented;
356
381
  if (!seg) {
382
+ // Canonical billing-interval chain: <field-ui label="Billing
383
+ // interval"> wrapping the <segmented-ui> (billing.contents.html
384
+ // "Current plan" region).
385
+ const field = document.createElement('field-ui');
386
+ field.setAttribute('label', 'Billing interval');
357
387
  seg = document.createElement('segmented-ui');
358
388
  seg.setAttribute('aria-label', 'Billing cycle');
359
- this.#toggleHost.appendChild(seg);
389
+ field.appendChild(seg);
390
+ this.#toggleHost.appendChild(field);
391
+ this.#toggleField = field;
360
392
  this.#toggleSegmented = seg;
361
393
  // Stamp segments — known cycles in display order.
362
394
  for (const cycleKey of ['monthly', 'annual']) {
@@ -443,8 +475,9 @@ export class PlanPicker extends UIFormElement {
443
475
  // bodies show always.
444
476
  let body = card.querySelector(':scope > [data-plan-body]');
445
477
  if (!body) {
446
- body = document.createElement('div');
478
+ body = document.createElement('col-ui');
447
479
  body.setAttribute('data-plan-body', '');
480
+ body.setAttribute('gap', '3');
448
481
  card.appendChild(body);
449
482
  }
450
483
  this.#decorateBody(body, plan);
@@ -478,9 +511,11 @@ export class PlanPicker extends UIFormElement {
478
511
  // Wipe + restamp body (small DOM; cycle / feature-list / cta).
479
512
  body.replaceChildren();
480
513
 
481
- // Price row.
482
- const priceRow = document.createElement('div');
514
+ // Price row — <row-ui> per the canonical inline-cluster grammar.
515
+ const priceRow = document.createElement('row-ui');
483
516
  priceRow.setAttribute('data-price-row', '');
517
+ priceRow.setAttribute('gap', '1');
518
+ priceRow.setAttribute('align', 'baseline');
484
519
  const cycle = KNOWN_CYCLES.has(this.cycle) ? this.cycle : 'monthly';
485
520
  const prices = plan.prices || {};
486
521
  const priceRec = prices[cycle] || prices.monthly || null;
@@ -513,20 +548,33 @@ export class PlanPicker extends UIFormElement {
513
548
  body.appendChild(note);
514
549
  }
515
550
 
516
- // Feature list.
551
+ // Feature list — the canonical feature-line grammar:
552
+ // <col-ui gap="1"> of <row-ui gap="2"><icon-ui/><span/></row-ui>
553
+ // (billing.contents.html trial-banner / what's-included blocks),
554
+ // separated from the price block by a <divider-ui>.
517
555
  if (Array.isArray(plan.features) && plan.features.length) {
518
- const list = document.createElement('ul');
556
+ const divider = document.createElement('divider-ui');
557
+ divider.setAttribute('data-body-divider', '');
558
+ body.appendChild(divider);
559
+
560
+ const list = document.createElement('col-ui');
519
561
  list.setAttribute('data-features', '');
562
+ list.setAttribute('gap', '1');
563
+ list.setAttribute('role', 'list');
520
564
  for (const feature of plan.features) {
521
- const li = document.createElement('li');
565
+ const line = document.createElement('row-ui');
566
+ line.setAttribute('data-feature', '');
567
+ line.setAttribute('gap', '2');
568
+ line.setAttribute('align', 'start');
569
+ line.setAttribute('role', 'listitem');
522
570
  const icon = document.createElement('icon-ui');
523
571
  icon.setAttribute('name', 'check');
524
572
  icon.setAttribute('aria-hidden', 'true');
525
- li.appendChild(icon);
573
+ line.appendChild(icon);
526
574
  const label = document.createElement('span');
527
575
  label.textContent = String(feature);
528
- li.appendChild(label);
529
- list.appendChild(li);
576
+ line.appendChild(label);
577
+ list.appendChild(line);
530
578
  }
531
579
  body.appendChild(list);
532
580
  }
@@ -53,7 +53,8 @@ plan-picker-ui {
53
53
  background: var(--plan-picker-bg);
54
54
  }
55
55
 
56
- /* ── Toggle row ── */
56
+ /* ── Toggle row <field-ui label="Billing interval"> wrapping the
57
+ <segmented-ui> (canonical billing-interval chain). ── */
57
58
  :scope > [data-toggle] {
58
59
  display: flex;
59
60
  justify-content: var(--plan-picker-toggle-justify);
@@ -61,19 +62,21 @@ plan-picker-ui {
61
62
  :scope > [data-toggle][hidden] {
62
63
  display: none;
63
64
  }
65
+ :scope > [data-toggle-divider][hidden] {
66
+ display: none;
67
+ }
64
68
 
65
- /* ── Plans grid ── */
69
+ /* ── Plans grid a <grid-ui columns="auto-fit"> primitive; we only
70
+ forward this composite's min/gap tokens into grid-ui's own
71
+ contract (--grid-min-col / --grid-gap). ── */
66
72
  :scope > [data-plans] {
67
- display: grid;
68
- grid-template-columns: repeat(
69
- auto-fit,
70
- minmax(var(--plan-picker-grid-min), 1fr)
71
- );
72
- gap: var(--plan-picker-grid-gap);
73
+ --grid-min-col: var(--plan-picker-grid-min);
74
+ --grid-gap: var(--plan-picker-grid-gap);
73
75
  align-items: stretch;
74
76
  }
75
77
 
76
- /* List layout — single-column rows for in-app settings. */
78
+ /* List layout — single-column rows for in-app settings (mode
79
+ attribute; overrides grid-ui's auto-fit template). */
77
80
  :scope[layout="list"] > [data-plans] {
78
81
  grid-template-columns: 1fr;
79
82
  }
@@ -131,12 +134,8 @@ plan-picker-ui {
131
134
  display: none;
132
135
  }
133
136
 
134
- /* ── Price row ── */
135
- :scope [data-price-row] {
136
- display: flex;
137
- align-items: baseline;
138
- gap: var(--a-space-1);
139
- }
137
+ /* ── Price row a <row-ui gap="1" align="baseline">; the primitive
138
+ owns the flex geometry, we style only the text chrome. ── */
140
139
  :scope [data-price] {
141
140
  font-size: var(--plan-picker-price-size);
142
141
  color: var(--plan-picker-price-fg);
@@ -152,39 +151,23 @@ plan-picker-ui {
152
151
  color: var(--plan-picker-cycle-fg);
153
152
  }
154
153
 
155
- /* ── Features list ── */
156
- :scope ul[data-features] {
157
- list-style: none;
158
- margin: 0;
159
- padding: 0;
160
- display: flex;
161
- flex-direction: column;
162
- gap: var(--plan-picker-features-gap);
154
+ /* ── Features list <col-ui data-features> of <row-ui data-feature>
155
+ lines (canonical feature-line grammar); the layout primitives own
156
+ the stack/row geometry, we forward gap + text/icon chrome. ── */
157
+ :scope [data-features] {
158
+ --col-gap: var(--plan-picker-features-gap);
163
159
  }
164
- :scope ul[data-features] > li {
165
- display: flex;
166
- align-items: flex-start;
167
- gap: var(--a-space-2);
168
- /* Override the docs feature-list indent (site.css adds
169
- `padding-left: 24px` + a ::before checkmark to ul[data-features] li);
170
- the slotted <icon-ui> IS our bullet, so the row aligns flush-left. */
171
- padding-inline-start: 0;
160
+ :scope [data-features] > [data-feature] {
172
161
  color: var(--md-sys-color-neutral-on-surface);
173
162
  font-size: var(--a-text-sm, 0.875rem);
174
163
  line-height: 1.4;
175
164
  }
176
- :scope ul[data-features] > li > icon-ui {
165
+ :scope [data-features] > [data-feature] > icon-ui {
177
166
  flex-shrink: 0;
178
167
  color: var(--plan-picker-feature-icon-fg);
179
168
  --a-icon-size: 1rem;
180
169
  margin-block-start: 0.125rem;
181
170
  }
182
- /* The feature check is the slotted <icon-ui>. Suppress any inherited
183
- ::before checkmark (the docs admin-page feature-list style adds a green
184
- "✓" to every ul[data-features] li) so the bullet doesn't double up. */
185
- :scope ul[data-features] > li::before {
186
- content: none;
187
- }
188
171
 
189
172
  /* ── CTA button — full-width, anchored to the body's bottom edge so a
190
173
  row of cards keeps their CTAs aligned regardless of feature count. ── */
@@ -34,6 +34,11 @@ composes:
34
34
  - option-card-ui
35
35
  - segmented-ui
36
36
  - segment-ui
37
+ - field-ui
38
+ - grid-ui
39
+ - col-ui
40
+ - row-ui
41
+ - divider-ui
37
42
  - button-ui
38
43
  - icon-ui
39
44
  - text-ui
@@ -48,6 +48,7 @@
48
48
  "conversation-input"
49
49
  ],
50
50
  "name": "ChatComposer",
51
+ "parts": {},
51
52
  "related": [
52
53
  "ChatShell",
53
54
  "ChatThread",
@@ -22,6 +22,9 @@
22
22
  ],
23
23
  "unevaluatedProperties": false,
24
24
  "x-adiaui": {
25
+ "allowedParents": [
26
+ "ChatThread"
27
+ ],
25
28
  "anti_patterns": [],
26
29
  "category": "feedback",
27
30
  "composes": [],
@@ -34,6 +37,7 @@
34
37
  "no-messages"
35
38
  ],
36
39
  "name": "ChatEmpty",
40
+ "parts": {},
37
41
  "related": [
38
42
  "ChatShell",
39
43
  "ChatThread",
@@ -39,6 +39,8 @@ states:
39
39
  traits: []
40
40
 
41
41
  a2ui:
42
+ allowedParents:
43
+ - ChatThread
42
44
  rules:
43
45
  - >-
44
46
  chat-empty is the bespoke replacement for legacy
@@ -22,6 +22,10 @@
22
22
  ],
23
23
  "unevaluatedProperties": false,
24
24
  "x-adiaui": {
25
+ "allowedParents": [
26
+ "ChatShell",
27
+ "ChatSidebar"
28
+ ],
25
29
  "anti_patterns": [],
26
30
  "category": "layout",
27
31
  "composes": [],
@@ -34,6 +38,7 @@
34
38
  "app-header"
35
39
  ],
36
40
  "name": "ChatHeader",
41
+ "parts": {},
37
42
  "related": [
38
43
  "ChatShell",
39
44
  "ChatStatus",
@@ -47,6 +47,9 @@ states:
47
47
  traits: []
48
48
 
49
49
  a2ui:
50
+ allowedParents:
51
+ - ChatShell
52
+ - ChatSidebar
50
53
  rules:
51
54
  - >-
52
55
  chat-header replaces the legacy <header> chrome bar inside
@@ -52,6 +52,9 @@
52
52
  ],
53
53
  "unevaluatedProperties": false,
54
54
  "x-adiaui": {
55
+ "allowedParents": [
56
+ "Surface"
57
+ ],
55
58
  "anti_patterns": [],
56
59
  "category": "container",
57
60
  "composes": [
@@ -118,6 +121,7 @@
118
121
  "assistant"
119
122
  ],
120
123
  "name": "ChatShell",
124
+ "parts": {},
121
125
  "related": [
122
126
  "ChatThread",
123
127
  "ChatComposer",
@@ -126,6 +126,8 @@ states:
126
126
  traits: []
127
127
 
128
128
  a2ui:
129
+ allowedParents:
130
+ - Surface
129
131
  rules:
130
132
  - >-
131
133
  chat-shell takes bespoke chat-* children only. The canonical
@@ -61,7 +61,7 @@
61
61
 
62
62
  /* Typography */
63
63
  --chat-font-size: var(--a-ui-size);
64
- --chat-line-height: var(--a-leading-normal);
64
+ --chat-line-height: var(--a-font-leading-relaxed);
65
65
  --chat-weight-semibold: var(--a-weight-semibold);
66
66
 
67
67
  /* Header typography */
@@ -52,6 +52,9 @@
52
52
  ],
53
53
  "unevaluatedProperties": false,
54
54
  "x-adiaui": {
55
+ "allowedParents": [
56
+ "ChatShell"
57
+ ],
55
58
  "anti_patterns": [],
56
59
  "category": "layout",
57
60
  "composes": [],
@@ -83,6 +86,7 @@
83
86
  "inspector"
84
87
  ],
85
88
  "name": "ChatSidebar",
89
+ "parts": {},
86
90
  "related": [
87
91
  "ChatShell",
88
92
  "ChatComposer",
@@ -108,6 +108,8 @@ states:
108
108
  traits: []
109
109
 
110
110
  a2ui:
111
+ allowedParents:
112
+ - ChatShell
111
113
  rules:
112
114
  - >-
113
115
  chat-sidebar is the bespoke replacement for legacy
@@ -22,6 +22,9 @@
22
22
  ],
23
23
  "unevaluatedProperties": false,
24
24
  "x-adiaui": {
25
+ "allowedParents": [
26
+ "ChatHeader"
27
+ ],
25
28
  "anti_patterns": [],
26
29
  "category": "feedback",
27
30
  "composes": [],
@@ -34,6 +37,7 @@
34
37
  "streaming-indicator"
35
38
  ],
36
39
  "name": "ChatStatus",
40
+ "parts": {},
37
41
  "related": [
38
42
  "ChatShell",
39
43
  "ChatHeader",
@@ -32,6 +32,8 @@ states:
32
32
  traits: []
33
33
 
34
34
  a2ui:
35
+ allowedParents:
36
+ - ChatHeader
35
37
  rules:
36
38
  - >-
37
39
  chat-status replaces legacy <span data-chat-status> for the
@@ -32,6 +32,9 @@
32
32
  ],
33
33
  "unevaluatedProperties": false,
34
34
  "x-adiaui": {
35
+ "allowedParents": [
36
+ "ChatShell"
37
+ ],
35
38
  "anti_patterns": [],
36
39
  "category": "container",
37
40
  "composes": [],
@@ -45,6 +48,7 @@
45
48
  "scroll-surface"
46
49
  ],
47
50
  "name": "ChatThread",
51
+ "parts": {},
48
52
  "related": [
49
53
  "ChatShell",
50
54
  "ChatEmpty",
@@ -58,6 +58,8 @@ states:
58
58
  description: Zero message children — empty state visible.
59
59
  traits: []
60
60
  a2ui:
61
+ allowedParents:
62
+ - ChatShell
61
63
  rules:
62
64
  - chat-thread is the bespoke replacement for legacy <section data-chat-messages> inside <chat-shell>. Use it for the message
63
65
  scroll surface; the host appends dynamic message divs as children.
@@ -13,6 +13,11 @@
13
13
  }
14
14
  ],
15
15
  "properties": {
16
+ "bandGap": {
17
+ "description": "Override band-to-band vertical gap. Empty string = the\ndensity-modulated default. Numeric `1`..`6` selects the\ncorresponding --a-space-N step. Renamed from `[gap]` (gh#1335) —\nthis attribute set the component-local `--dashboard-layout-gap`\ntoken directly, never composing with the ambient\n`[size]`→`--a-gap` cascade the global Scale-grammar `[gap]`\nattribute uses, and covers a narrower numeric range (1-6 vs. the\nglobal 0-16) — a genuinely distinct, band-scoped concept kept\nunder its own namespaced name rather than converged.\n",
18
+ "type": "string",
19
+ "default": ""
20
+ },
16
21
  "chart-split": {
17
22
  "description": "Chart-band column split. Empty string = single full-width chart;\n`2` = two equal columns; `2:1` / `3:2` / `3:1` = asymmetric\nratios. Collapses to single column at narrow widths (≤48em).\n",
18
23
  "type": "string",
@@ -29,21 +34,15 @@
29
34
  "const": "DashboardLayout"
30
35
  },
31
36
  "density": {
32
- "description": "Spacing scale — propagates --a-density to descendant primitives\nvia CSS custom-property cascade. Empty string inherits whatever\ndensity is in effect on an ancestor (the default — respects an\napp-level density theme). `compact` / `comfortable` / `spacious`\nexplicitly override.\n",
37
+ "description": "Spacing scale — propagates --a-density to descendant primitives\nvia CSS custom-property cascade. Empty string inherits whatever\ndensity is in effect on an ancestor (the default — respects an\napp-level density theme). `compact` / `spacious` explicitly\noverride. `comfortable` retired (gh#1335) — verified dead code:\nit set `--a-density: 1` with no gap-token override, functionally\nidentical to the \"\" (unset/ambient) state, not to `spacious`\n(`--a-density: 1.15` + wider gap tokens) — so it converges onto\n\"\" (the closest matching real behavior) rather than a\n`comfortable`→`spacious` rename, which would have silently\nchanged behavior for any existing consumer.\n",
33
38
  "type": "string",
34
39
  "enum": [
35
40
  "",
36
- "comfortable",
37
41
  "compact",
38
42
  "spacious"
39
43
  ],
40
44
  "default": ""
41
45
  },
42
- "gap": {
43
- "description": "Override band-to-band vertical gap. Empty string = the\ndensity-modulated default (--a-space-4 at comfortable). Numeric\n`1`..`6` selects the corresponding --a-space-N step.\n",
44
- "type": "string",
45
- "default": ""
46
- },
47
46
  "kpi-columns": {
48
47
  "description": "Target column count for the KPI band at desktop width. Range 2-6;\nout-of-range values fall back to 4. Container-query collapse\nreduces this at narrower widths (≤48em → 2; ≤32em → 1).\n",
49
48
  "type": "string",
@@ -101,7 +100,7 @@
101
100
  "description": "Fired when [density] changes (programmatic or via setDensity()).\nBubbles; detail.density carries the new value.\n",
102
101
  "detail": {
103
102
  "density": {
104
- "description": "The new density value (comfortable / compact / spacious).",
103
+ "description": "The new density value (\"\" / compact / spacious).",
105
104
  "type": "string"
106
105
  }
107
106
  }
@@ -146,6 +145,7 @@
146
145
  "layout-container"
147
146
  ],
148
147
  "name": "UIDashboardLayout",
148
+ "parts": {},
149
149
  "related": [
150
150
  "AdminPageBody",
151
151
  "AdminPage",
@@ -119,10 +119,10 @@ dashboard-layout-ui {
119
119
 
120
120
  /* ── Density variants — override TOKEN values only ──
121
121
  Per the contract: variants change tokens; modes change layout.
122
- Density is a token-override, not a layout-shape change. */
123
- :scope[density="comfortable"] {
124
- --a-density: 1;
125
- }
122
+ Density is a token-override, not a layout-shape change.
123
+ `comfortable` retired (gh#1335) — verified dead code: it set only
124
+ --a-density:1 with no gap-token override, functionally identical
125
+ to the unset/"" state below (no selector needed), not to `spacious`. */
126
126
  :scope[density="compact"] {
127
127
  --dashboard-layout-gap: var(--dashboard-layout-gap-compact);
128
128
  --dashboard-layout-kpi-gap: var(--dashboard-layout-kpi-gap-compact);
@@ -30,7 +30,7 @@ import { untracked } from '@adia-ai/web-components/core/signals';
30
30
 
31
31
  // ── Validation tables ────────────────────────────────────────────
32
32
 
33
- const VALID_DENSITIES = new Set(['', 'comfortable', 'compact', 'spacious']);
33
+ const VALID_DENSITIES = new Set(['', 'compact', 'spacious']);
34
34
  const VALID_KPI_COLUMNS = new Set(['2', '3', '4', '5', '6']);
35
35
  const VALID_CHART_SPLIT = new Set(['', '2', '2:1', '3:2', '3:1']);
36
36
  const REGION_SLOTS = ['toolbar', 'kpis', 'charts', 'table', 'aside'];
@@ -44,7 +44,7 @@ export class UIDashboardLayout extends UIElement {
44
44
  'kpi-columns': { type: String, default: '4', reflect: true, attribute: 'kpi-columns' },
45
45
  'chart-split': { type: String, default: '', reflect: true, attribute: 'chart-split' },
46
46
  loading: { type: Boolean, default: false, reflect: true },
47
- gap: { type: String, default: '', reflect: true },
47
+ bandGap: { type: String, default: '', reflect: true, attribute: 'band-gap' },
48
48
  };
49
49
  }
50
50
 
@@ -76,7 +76,7 @@ export class UIDashboardLayout extends UIElement {
76
76
  * Programmatic equivalent of setting the [density] attribute.
77
77
  * Fires `density-change` once with the new value.
78
78
  *
79
- * @param {string} value — '' | 'comfortable' | 'compact' | 'spacious'
79
+ * @param {string} value — '' | 'compact' | 'spacious'
80
80
  */
81
81
  setDensity(value) {
82
82
  const next = VALID_DENSITIES.has(value) ? value : '';
@@ -118,7 +118,7 @@ export class UIDashboardLayout extends UIElement {
118
118
  // changes flow through attributeChangedCallback below.
119
119
  this.#syncAriaBusy();
120
120
 
121
- // Apply the [gap] override → public token if set.
121
+ // Apply the [band-gap] override → public token if set.
122
122
  this.#applyGapAttr();
123
123
 
124
124
  // Watch for region-empty transitions. Children are arbitrary
@@ -195,7 +195,7 @@ export class UIDashboardLayout extends UIElement {
195
195
  return;
196
196
  }
197
197
 
198
- if (name === 'gap' && oldVal !== newVal) {
198
+ if (name === 'band-gap' && oldVal !== newVal) {
199
199
  this.#applyGapAttr();
200
200
  return;
201
201
  }
@@ -237,12 +237,13 @@ export class UIDashboardLayout extends UIElement {
237
237
  }
238
238
 
239
239
  /**
240
- * Map the [gap="N"] attribute to the public --dashboard-layout-gap
241
- * custom property. The CSS reads `var(--dashboard-layout-gap, …)`
242
- * so empty / unset falls back to the density-modulated default.
240
+ * Map the [band-gap="N"] attribute (renamed from [gap], gh#1335) to the
241
+ * public --dashboard-layout-gap custom property. The CSS reads
242
+ * `var(--dashboard-layout-gap, …)` so empty / unset falls back to the
243
+ * density-modulated default.
243
244
  */
244
245
  #applyGapAttr() {
245
- const g = (this.gap || '').trim();
246
+ const g = (this.bandGap || '').trim();
246
247
  if (g === '') {
247
248
  this.style.removeProperty('--dashboard-layout-gap');
248
249
  return;
@@ -40,13 +40,18 @@ props:
40
40
  Spacing scale — propagates --a-density to descendant primitives
41
41
  via CSS custom-property cascade. Empty string inherits whatever
42
42
  density is in effect on an ancestor (the default — respects an
43
- app-level density theme). `compact` / `comfortable` / `spacious`
44
- explicitly override.
43
+ app-level density theme). `compact` / `spacious` explicitly
44
+ override. `comfortable` retired (gh#1335) — verified dead code:
45
+ it set `--a-density: 1` with no gap-token override, functionally
46
+ identical to the "" (unset/ambient) state, not to `spacious`
47
+ (`--a-density: 1.15` + wider gap tokens) — so it converges onto
48
+ "" (the closest matching real behavior) rather than a
49
+ `comfortable`→`spacious` rename, which would have silently
50
+ changed behavior for any existing consumer.
45
51
  type: string
46
52
  default: ""
47
53
  enum:
48
54
  - ""
49
- - comfortable
50
55
  - compact
51
56
  - spacious
52
57
  reflect: true
@@ -91,13 +96,20 @@ props:
91
96
  default: false
92
97
  reflect: true
93
98
 
94
- gap:
99
+ bandGap:
95
100
  description: |
96
101
  Override band-to-band vertical gap. Empty string = the
97
- density-modulated default (--a-space-4 at comfortable). Numeric
98
- `1`..`6` selects the corresponding --a-space-N step.
102
+ density-modulated default. Numeric `1`..`6` selects the
103
+ corresponding --a-space-N step. Renamed from `[gap]` (gh#1335) —
104
+ this attribute set the component-local `--dashboard-layout-gap`
105
+ token directly, never composing with the ambient
106
+ `[size]`→`--a-gap` cascade the global Scale-grammar `[gap]`
107
+ attribute uses, and covers a narrower numeric range (1-6 vs. the
108
+ global 0-16) — a genuinely distinct, band-scoped concept kept
109
+ under its own namespaced name rather than converged.
99
110
  type: string
100
111
  default: ""
112
+ attribute: band-gap
101
113
  reflect: true
102
114
 
103
115
  events:
@@ -108,7 +120,7 @@ events:
108
120
  detail:
109
121
  density:
110
122
  type: string
111
- description: The new density value (comfortable / compact / spacious).
123
+ description: The new density value ("" / compact / spacious).
112
124
 
113
125
  region-empty:
114
126
  description: |