@adia-ai/web-components 0.8.38 → 0.8.40

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 (101) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/MIGRATION.md +243 -2
  3. package/components/agent-artifact/agent-artifact.css +1 -1
  4. package/components/agent-reasoning/agent-reasoning.css +2 -2
  5. package/components/agent-trace/agent-trace.css +3 -3
  6. package/components/alert/alert.css +1 -1
  7. package/components/avatar/avatar.css +1 -1
  8. package/components/badge/badge.css +1 -1
  9. package/components/button/button.css +6 -5
  10. package/components/calendar-picker/calendar-picker.css +5 -2
  11. package/components/card/card.css +3 -3
  12. package/components/chart/chart.a2ui.json +5 -5
  13. package/components/chart/chart.class.js +4 -4
  14. package/components/chart/chart.css +6 -6
  15. package/components/chart/chart.d.ts +2 -2
  16. package/components/chart/chart.yaml +3 -2
  17. package/components/chat-thread/chat-thread.css +1 -1
  18. package/components/code/code.css +6 -6
  19. package/components/combobox/combobox.css +8 -2
  20. package/components/command/command.a2ui.json +3 -0
  21. package/components/command/command.class.js +28 -6
  22. package/components/command/command.css +17 -6
  23. package/components/command/command.yaml +5 -0
  24. package/components/date-range-picker/date-range-picker.css +7 -1
  25. package/components/datetime-picker/datetime-picker.css +5 -1
  26. package/components/description-list/description-list.css +2 -2
  27. package/components/display-field/display-field.css +3 -3
  28. package/components/divider/divider.css +1 -1
  29. package/components/drawer/drawer.css +2 -2
  30. package/components/drilldown/drilldown.a2ui.json +3 -1
  31. package/components/drilldown/drilldown.class.js +12 -4
  32. package/components/drilldown/drilldown.css +9 -10
  33. package/components/drilldown/drilldown.yaml +2 -0
  34. package/components/empty-state/empty-state.css +2 -2
  35. package/components/field/field.css +1 -1
  36. package/components/heatmap/heatmap.css +2 -2
  37. package/components/inline-message/inline-message.css +1 -1
  38. package/components/input/input.css +5 -4
  39. package/components/integration-card/integration-card.css +4 -4
  40. package/components/kbd/kbd.css +1 -1
  41. package/components/list/list.css +2 -2
  42. package/components/modal/modal.class.js +68 -4
  43. package/components/nav/nav.a2ui.json +5 -0
  44. package/components/nav/nav.class.js +24 -4
  45. package/components/nav/nav.css +2 -2
  46. package/components/nav/nav.d.ts +2 -0
  47. package/components/nav/nav.yaml +18 -0
  48. package/components/nav-group/nav-group.css +3 -3
  49. package/components/nav-item/nav-item.css +2 -2
  50. package/components/option-card/option-card.css +1 -1
  51. package/components/otp-input/otp-input.css +1 -1
  52. package/components/page/page.css +2 -2
  53. package/components/pagination/pagination.css +1 -1
  54. package/components/pane/pane.css +1 -1
  55. package/components/progress-row/progress-row.css +2 -2
  56. package/components/qr-code/qr-code.a2ui.json +10 -10
  57. package/components/qr-code/qr-code.class.js +3 -3
  58. package/components/qr-code/qr-code.d.ts +10 -7
  59. package/components/qr-code/qr-code.yaml +13 -9
  60. package/components/range/range.css +1 -1
  61. package/components/rating/rating.css +1 -1
  62. package/components/richtext/richtext.css +3 -3
  63. package/components/segment/segment.css +5 -4
  64. package/components/select/select.class.js +30 -12
  65. package/components/select/select.css +14 -5
  66. package/components/spinner/spinner.css +1 -1
  67. package/components/stat/stat.css +3 -3
  68. package/components/step-progress/step-progress.css +1 -1
  69. package/components/stepper/stepper.css +2 -2
  70. package/components/swatch/swatch.css +8 -6
  71. package/components/table/table.a2ui.json +0 -10
  72. package/components/table/table.class.js +4 -4
  73. package/components/table/table.css +6 -9
  74. package/components/table/table.d.ts +0 -2
  75. package/components/table/table.yaml +0 -9
  76. package/components/table-toolbar/table-toolbar.css +1 -1
  77. package/components/tabs/tabs.css +1 -1
  78. package/components/tag/tag.css +2 -2
  79. package/components/tags-input/tags-input.css +1 -1
  80. package/components/textarea/textarea.css +1 -1
  81. package/components/time-picker/time-picker.css +1 -1
  82. package/components/timeline/timeline.css +4 -4
  83. package/components/toc/toc.css +1 -1
  84. package/components/toggle-group/toggle-group.class.js +13 -11
  85. package/components/toggle-group/toggle-group.css +14 -8
  86. package/components/toggle-group/toggle-group.d.ts +5 -0
  87. package/components/toggle-group/toggle-group.yaml +7 -0
  88. package/components/toggle-group/toggle-option.a2ui.json +5 -0
  89. package/components/toggle-group/toggle-option.yaml +14 -2
  90. package/components/tooltip/tooltip.css +1 -1
  91. package/components/tour/tour.css +2 -2
  92. package/components/tree/tree.css +1 -1
  93. package/custom-elements.json +101 -89
  94. package/dist/host.min.css +1 -1
  95. package/dist/host.sheet.js +1 -1
  96. package/dist/theme-provider.min.js +3 -3
  97. package/dist/web-components.min.css +1 -1
  98. package/dist/web-components.min.js +97 -94
  99. package/dist/web-components.sheet.js +1 -1
  100. package/package.json +1 -1
  101. package/styles/type/scale.css +6 -7
@@ -76,10 +76,11 @@ props:
76
76
  type: boolean
77
77
  default: false
78
78
  attribute: hide-values
79
- radius:
80
- description: Bar corner radius (null = let CSS tokens decide)
79
+ cornerRadius:
80
+ description: Bar corner radius in px (null = let CSS tokens decide)
81
81
  type: number
82
82
  default: null
83
+ attribute: corner-radius
83
84
  size:
84
85
  description: Chart size
85
86
  type: string
@@ -50,7 +50,7 @@
50
50
  --chat-msg-avatar-size-font: var(--a-ui-sm);
51
51
  --chat-msg-avatar-weight: var(--a-weight-semibold);
52
52
  --chat-bubble-font-size: var(--a-body-size);
53
- --chat-bubble-line-height: var(--a-leading-normal);
53
+ --chat-bubble-line-height: var(--a-font-leading-relaxed);
54
54
  }
55
55
 
56
56
  :scope {
@@ -107,9 +107,9 @@
107
107
  }
108
108
 
109
109
  & > header [slot="label"] {
110
- font-weight: 500;
110
+ font-weight: var(--a-weight-medium);
111
111
  text-transform: uppercase;
112
- letter-spacing: 0.05em;
112
+ letter-spacing: var(--a-font-tracking-wide);
113
113
  }
114
114
 
115
115
  /* Copy button — ghost style */
@@ -141,7 +141,7 @@
141
141
  overflow-x: auto;
142
142
  font-family: var(--code-font);
143
143
  font-size: var(--code-font-size);
144
- line-height: 1.5;
144
+ line-height: var(--a-font-leading-relaxed);
145
145
  scrollbar-width: none;
146
146
  }
147
147
  & > pre::-webkit-scrollbar {
@@ -312,7 +312,7 @@
312
312
  color: var(--code-fg);
313
313
  font-family: var(--code-font);
314
314
  font-size: var(--code-font-size);
315
- line-height: 1.5;
315
+ line-height: var(--a-font-leading-relaxed);
316
316
  }
317
317
 
318
318
  :scope .cm-scroller {
@@ -377,7 +377,7 @@
377
377
 
378
378
  /* Syntax highlight — one rule per token role (see core/_cm-theme.js) */
379
379
  :scope .tok-comment { color: var(--code-tok-comment); font-style: italic; }
380
- :scope .tok-keyword { color: var(--code-tok-keyword); font-weight: 500; }
380
+ :scope .tok-keyword { color: var(--code-tok-keyword); font-weight: var(--a-weight-medium); }
381
381
  :scope .tok-string { color: var(--code-tok-string); }
382
382
  :scope .tok-number { color: var(--code-tok-number); }
383
383
  :scope .tok-boolean { color: var(--code-tok-boolean); }
@@ -385,7 +385,7 @@
385
385
  :scope .tok-punctuation { color: var(--code-tok-punctuation); }
386
386
  :scope .tok-function { color: var(--code-tok-function); }
387
387
  :scope .tok-variable { color: var(--code-tok-variable); }
388
- :scope .tok-type { color: var(--code-tok-type); font-weight: 500; }
388
+ :scope .tok-type { color: var(--code-tok-type); font-weight: var(--a-weight-medium); }
389
389
  :scope .tok-property { color: var(--code-tok-property); }
390
390
  :scope .tok-tag { color: var(--code-tok-tag); }
391
391
  :scope .tok-attribute { color: var(--code-tok-attribute); }
@@ -127,6 +127,12 @@
127
127
  cursor: pointer;
128
128
  }
129
129
  [data-suffix] icon-ui[name="caret-down"] {
130
+ /* Universal caret size (gh#1314 sweep) — overrides the shared
131
+ [data-prefix]/[data-suffix] --a-icon-size (font-size) above so the
132
+ default caret matches select-ui's trigger caret instead of riding
133
+ the field's text size. Name-guarded: a consumer-slotted non-caret
134
+ suffix glyph keeps the font-size default. */
135
+ --a-icon-size: var(--a-caret-size);
130
136
  transition: rotate var(--a-duration-fast) var(--a-easing);
131
137
  }
132
138
  /* Clear OPEN state: the default caret flips while the listbox is open.
@@ -143,7 +149,7 @@
143
149
  color: var(--combobox-fg);
144
150
  font: inherit;
145
151
  font-size: var(--combobox-font-size);
146
- line-height: 1.4;
152
+ line-height: var(--a-font-leading-normal);
147
153
  white-space: nowrap;
148
154
  overflow: hidden;
149
155
  /* Positioning context for the [data-empty]::before placeholder pseudo
@@ -316,7 +322,7 @@ combobox-ui [data-listbox] [role="group"] [data-group-label] {
316
322
  font-weight: var(--a-ui-weight);
317
323
  color: var(--a-ui-text-muted);
318
324
  text-transform: uppercase;
319
- letter-spacing: 0.05em;
325
+ letter-spacing: var(--a-font-tracking-wide);
320
326
  white-space: nowrap;
321
327
  }
322
328
 
@@ -105,6 +105,9 @@
105
105
  "footer": {
106
106
  "description": "Keyboard hint bar"
107
107
  },
108
+ "input": {
109
+ "description": "The auto-stamped search field — a contenteditable=\"plaintext-only\" span carrying role=\"combobox\" (per ADR-0025/ADR-0055; no native <input>). Internal only; not consumer-slottable."
110
+ },
108
111
  "list": {
109
112
  "description": "Container for command items and groups"
110
113
  }
@@ -14,6 +14,12 @@
14
14
  import { UIElement } from '../../core/element.js';
15
15
  import { logicalSlotted } from '../../core/logical-children.js';
16
16
 
17
+ function escapeHTML(s) {
18
+ return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
19
+ }
20
+
21
+ let cmdInstanceSeq = 0;
22
+
17
23
  /**
18
24
  * <command-ui> — Searchable command palette.
19
25
  *
@@ -58,6 +64,7 @@ export class UICommand extends UIElement {
58
64
  #bound = false;
59
65
  #itemByEl = new WeakMap();
60
66
  #emptyNodes = [];
67
+ #instanceId = `command-${++cmdInstanceSeq}`;
61
68
 
62
69
  static #RECENTS_MAX = 3;
63
70
 
@@ -96,12 +103,22 @@ export class UICommand extends UIElement {
96
103
  }
97
104
  this.#emptyNodes = logicalSlotted(this, 'empty');
98
105
 
106
+ const listId = `${this.#instanceId}-list`;
107
+
108
+ // No native <input> wrap (per ADR-0055 / ADR-0025): the search field
109
+ // is a `contenteditable="plaintext-only"` surface carrying
110
+ // `role="combobox"`, matching combobox-ui's editable-surface pattern.
111
+ // Placeholder text renders via the [data-empty]::before pseudo (see
112
+ // command.css), same mechanism as input-ui / combobox-ui.
99
113
  this.innerHTML = `
100
114
  <header>
101
115
  <icon-ui name="magnifying-glass" slot="icon"></icon-ui>
102
- <input type="text" placeholder="${this.placeholder}" slot="input" />
116
+ <span contenteditable="plaintext-only" role="combobox" tabindex="0"
117
+ aria-autocomplete="list" aria-expanded="false" aria-controls="${listId}"
118
+ data-placeholder="${escapeHTML(this.placeholder)}" data-empty
119
+ slot="input"></span>
103
120
  </header>
104
- <section slot="list"></section>
121
+ <section slot="list" id="${listId}"></section>
105
122
  <footer>
106
123
  <span data-hint><kbd>↑</kbd><kbd>↓</kbd> Navigate</span>
107
124
  <span data-hint><kbd>↵</kbd> Select</span>
@@ -109,7 +126,7 @@ export class UICommand extends UIElement {
109
126
  </footer>
110
127
  `;
111
128
 
112
- this.#inputEl = this.querySelector('input');
129
+ this.#inputEl = this.querySelector('[slot="input"]');
113
130
  this.#listEl = this.querySelector('[slot="list"]');
114
131
  this.#footerEl = this.querySelector('footer');
115
132
 
@@ -120,6 +137,8 @@ export class UICommand extends UIElement {
120
137
  this.#renderItems();
121
138
  }
122
139
 
140
+ if (this.#inputEl) this.#inputEl.setAttribute('aria-expanded', String(this.open));
141
+
123
142
  if (this.open) {
124
143
  this.#focusRaf = requestAnimationFrame(() => {
125
144
  this.#focusRaf = null;
@@ -130,11 +149,12 @@ export class UICommand extends UIElement {
130
149
 
131
150
  // ── Public API ──
132
151
 
133
- get value() { return this.#inputEl?.value || ''; }
152
+ get value() { return this.#inputEl?.textContent || ''; }
134
153
  set value(v) {
135
154
  if (!this.#inputEl) return;
136
155
  const next = v ?? '';
137
- this.#inputEl.value = next;
156
+ this.#inputEl.textContent = next;
157
+ this.#inputEl.toggleAttribute('data-empty', !next);
138
158
  // Keep the rendered list in sync with the visible input — the host
139
159
  // commonly clears value on (re)open, and consumers expect to see the
140
160
  // full list (plus recents) rather than the previous filter's residue.
@@ -421,7 +441,9 @@ export class UICommand extends UIElement {
421
441
  // ── Events ──
422
442
 
423
443
  #onInput = () => {
424
- this.#renderItems(this.#inputEl.value);
444
+ const text = this.#inputEl.textContent || '';
445
+ this.#inputEl.toggleAttribute('data-empty', !text);
446
+ this.#renderItems(text);
425
447
  };
426
448
 
427
449
  #onKeydown = (e) => {
@@ -102,7 +102,7 @@
102
102
  --a-icon-size: 1rem;
103
103
  }
104
104
 
105
- & > header input {
105
+ & > header [slot="input"] {
106
106
  flex: 1;
107
107
  min-width: 0;
108
108
  border: none;
@@ -111,16 +111,27 @@
111
111
  color: var(--command-fg);
112
112
  font-family: var(--command-font-family, var(--a-font-family-ui));
113
113
  font-size: var(--command-input-font-size);
114
- line-height: 1.4;
114
+ line-height: var(--a-font-leading-normal);
115
115
  padding: 0;
116
+ white-space: nowrap;
117
+ overflow: hidden;
118
+ /* Positioning context for the [data-empty]::before placeholder pseudo
119
+ below — out-of-flow, same rationale as input-ui/combobox-ui: an
120
+ in-flow pseudo would render the caret after the placeholder text
121
+ instead of at content-start. */
122
+ position: relative;
116
123
  }
117
124
 
118
- & > header input::placeholder {
125
+ & > header [slot="input"][data-empty]::before {
126
+ content: attr(data-placeholder);
119
127
  color: var(--command-fg-muted);
128
+ pointer-events: none;
129
+ position: absolute;
130
+ inset: 0;
120
131
  }
121
132
 
122
133
  /* Suppress focus ring on the input — the palette itself is the focused surface */
123
- & > header input:focus-visible {
134
+ & > header [slot="input"]:focus-visible {
124
135
  outline: none;
125
136
  box-shadow: none;
126
137
  }
@@ -205,7 +216,7 @@
205
216
  font-weight: var(--command-group-font-weight);
206
217
  color: var(--command-group-fg);
207
218
  text-transform: uppercase;
208
- letter-spacing: 0.05em;
219
+ letter-spacing: var(--a-font-tracking-wide);
209
220
  white-space: nowrap;
210
221
  }
211
222
 
@@ -244,7 +255,7 @@
244
255
  border-radius: var(--command-kbd-radius);
245
256
  font-family: inherit;
246
257
  font-size: inherit;
247
- line-height: 1.6;
258
+ line-height: var(--a-font-leading-loose);
248
259
  color: var(--command-kbd-fg);
249
260
  background: var(--command-kbd-bg);
250
261
  }
@@ -67,6 +67,11 @@ slots:
67
67
  description: Empty state shown when no items match
68
68
  footer:
69
69
  description: Keyboard hint bar
70
+ input:
71
+ description: >-
72
+ The auto-stamped search field — a contenteditable="plaintext-only"
73
+ span carrying role="combobox" (per ADR-0025/ADR-0055; no native
74
+ <input>). Internal only; not consumer-slottable.
70
75
  list:
71
76
  description: Container for command items and groups
72
77
  states:
@@ -90,6 +90,12 @@
90
90
  equal specificity so the picker trigger reads as part of the
91
91
  input/picker family rather than a generic button. */
92
92
  :scope [slot="trigger"] icon-ui[name="caret-down"] {
93
+ /* Universal caret size (gh#1314) — without this the caret rides the
94
+ ambient icon size instead of the shared --a-caret-size token that
95
+ select-ui's trigger caret already reads, so mixed control rows
96
+ (select-ui next to date-range-picker-ui) showed visibly different
97
+ chevron sizes. */
98
+ --a-icon-size: var(--a-caret-size);
93
99
  transition: rotate var(--a-duration-fast) var(--a-easing);
94
100
  }
95
101
  /* Clear OPEN state: the default trigger's trailing caret flips while the
@@ -113,7 +119,7 @@
113
119
  slot triplet. button-ui's natural alignment is `center`; our
114
120
  leading+text+trailing layout reads better as space-between. */
115
121
  justify-content: space-between;
116
- line-height: 1;
122
+ line-height: var(--a-font-leading-none);
117
123
  transition:
118
124
  border-color var(--date-range-picker-duration) var(--date-range-picker-easing),
119
125
  background var(--date-range-picker-duration) var(--date-range-picker-easing);
@@ -62,6 +62,10 @@
62
62
  left-aligned with the caret pushed to the trailing edge, not centered
63
63
  like a default button. */
64
64
  :scope [slot="trigger"] icon-ui[name="caret-down"] {
65
+ /* Universal caret size (gh#1314 sweep) — mirrors select-ui's trigger
66
+ caret so mixed control rows read as one family instead of showing
67
+ the ambient (larger) icon size. */
68
+ --a-icon-size: var(--a-caret-size);
65
69
  transition: rotate var(--a-duration-fast) var(--a-easing);
66
70
  }
67
71
  /* Clear OPEN state: the default trigger's trailing caret flips while the
@@ -73,7 +77,7 @@
73
77
  :scope [slot="trigger"] {
74
78
  min-width: var(--datetime-picker-trigger-min-width);
75
79
  justify-content: space-between;
76
- line-height: 1;
80
+ line-height: var(--a-font-leading-none);
77
81
  }
78
82
  /* A committed value bumps to --a-ui-text (bright), matching input-ui /
79
83
  select-ui / time-picker value color; the empty placeholder keeps
@@ -44,7 +44,7 @@
44
44
  font-size: var(--description-list-term-font-size);
45
45
  font-weight: var(--description-list-term-weight);
46
46
  color: var(--description-list-term-fg);
47
- line-height: 1.3;
47
+ line-height: var(--a-font-leading-normal);
48
48
  }
49
49
 
50
50
  [data-dl-desc],
@@ -53,7 +53,7 @@
53
53
  font-size: var(--description-list-desc-font-size);
54
54
  font-weight: var(--description-list-desc-weight);
55
55
  color: var(--description-list-desc-fg);
56
- line-height: 1.4;
56
+ line-height: var(--a-font-leading-relaxed);
57
57
  }
58
58
 
59
59
  /* Pair separator: extra margin under each non-last dd so DD→DT (between
@@ -50,7 +50,7 @@
50
50
  color: var(--display-field-label-color);
51
51
  font-size: var(--display-field-label-size);
52
52
  font-weight: var(--display-field-label-weight);
53
- line-height: 1.3;
53
+ line-height: var(--a-font-leading-normal);
54
54
  min-width: 0;
55
55
  }
56
56
 
@@ -67,7 +67,7 @@
67
67
  color: var(--display-field-value-color);
68
68
  font-size: var(--display-field-value-size);
69
69
  font-weight: var(--display-field-value-weight);
70
- line-height: 1.3;
70
+ line-height: var(--a-font-leading-normal);
71
71
  min-width: 0;
72
72
  }
73
73
 
@@ -75,7 +75,7 @@
75
75
  grid-area: hint;
76
76
  color: var(--display-field-hint-color);
77
77
  font-size: var(--display-field-hint-size);
78
- line-height: 1.3;
78
+ line-height: var(--a-font-leading-normal);
79
79
  min-width: 0;
80
80
  }
81
81
 
@@ -52,7 +52,7 @@
52
52
  font-size: var(--divider-label-font);
53
53
  color: var(--divider-label-fg);
54
54
  white-space: nowrap;
55
- line-height: 1;
55
+ line-height: var(--a-font-leading-none);
56
56
  }
57
57
 
58
58
  /* ── Vertical ── */
@@ -244,7 +244,7 @@ drawer-ui [slot="panel"] > [slot="header"]:has(> :is([slot="description"], p, sm
244
244
  drawer-ui [slot="panel"] > [slot="header"] > :is([slot="heading"], h1, h2, h3, h4, h5, h6),
245
245
  drawer-ui [slot="panel"] > [slot="header"] > [slot="heading"] :is(h1, h2, h3, h4, h5, h6) {
246
246
  grid-row: 1;
247
- line-height: 1.3;
247
+ line-height: var(--a-font-leading-normal);
248
248
  margin: 0;
249
249
  font-size: var(--drawer-heading-size);
250
250
  font-weight: var(--drawer-heading-weight);
@@ -266,7 +266,7 @@ drawer-ui [slot="panel"] > [slot="header"]:not(:has(> [slot="icon"])) > :is([slo
266
266
  drawer-ui [slot="panel"] > [slot="header"] > :is([slot="description"], p, small) {
267
267
  grid-row: 2;
268
268
  grid-column: 1 / -1;
269
- line-height: 1.4;
269
+ line-height: var(--a-font-leading-relaxed);
270
270
  margin: 0;
271
271
  font-size: var(--drawer-description-size);
272
272
  color: var(--drawer-description-fg);
@@ -60,7 +60,9 @@
60
60
  "composes": [
61
61
  "icon-ui",
62
62
  "skeleton-ui",
63
- "empty-state-ui"
63
+ "empty-state-ui",
64
+ "input-ui",
65
+ "button-ui"
64
66
  ],
65
67
  "events": {
66
68
  "navigate": {
@@ -181,6 +181,10 @@ export class UIDrilldown extends UIElement {
181
181
  // ── Structural stamp (once) ──
182
182
 
183
183
  #stamp() {
184
+ // No native <input> wrap (per ADR-0055 / ADR-0025): the filter field
185
+ // composes <input-ui> — the search-ui precedent — instead of stamping
186
+ // a raw <input>. `raw` strips input-ui's own chrome so it blends into
187
+ // this row's own icon + border-bottom (drilldown.css owns the layout).
184
188
  this.innerHTML = `
185
189
  <div slot="header">
186
190
  <button-ui slot="back" icon="caret-left" variant="ghost" size="sm" hidden>
@@ -194,7 +198,7 @@ export class UIDrilldown extends UIElement {
194
198
  </div>
195
199
  <div slot="filter" hidden>
196
200
  <icon-ui name="magnifying-glass"></icon-ui>
197
- <input type="text" />
201
+ <input-ui raw></input-ui>
198
202
  </div>
199
203
  <div slot="viewport">
200
204
  <div slot="panel" role="listbox"></div>
@@ -207,7 +211,7 @@ export class UIDrilldown extends UIElement {
207
211
  this.#titleEl = this.querySelector('[data-level-title]');
208
212
  this.#countEl = this.querySelector('[data-level-count]');
209
213
  this.#filterRowEl = this.querySelector('[slot="filter"]');
210
- this.#filterInputEl = this.querySelector('[slot="filter"] input');
214
+ this.#filterInputEl = this.querySelector('[slot="filter"] input-ui');
211
215
  this.#panelEl = this.querySelector('[slot="panel"]');
212
216
  this.#liveEl = this.querySelector('[slot="live"]');
213
217
  this.#breadcrumbEl = this.querySelector('[slot="breadcrumb"]');
@@ -233,7 +237,7 @@ export class UIDrilldown extends UIElement {
233
237
 
234
238
  #syncChrome() {
235
239
  this.#filterRowEl.hidden = !this.filterable;
236
- this.#filterInputEl.placeholder = this.placeholder;
240
+ this.#filterInputEl.setAttribute('placeholder', this.placeholder);
237
241
  }
238
242
 
239
243
  // ── Tree walking ──
@@ -524,7 +528,11 @@ export class UIDrilldown extends UIElement {
524
528
  }
525
529
  case 'ArrowLeft':
526
530
  case 'Backspace':
527
- if (e.key === 'Backspace' && e.target === this.#filterInputEl) break;
531
+ // input-ui's editable surface is a light-DOM contenteditable span
532
+ // INSIDE the composed <input-ui> — e.target on a keydown fired while
533
+ // typing is that inner span, not the <input-ui> host itself (unlike
534
+ // the former native <input>, where target === the field element).
535
+ if (e.key === 'Backspace' && this.#filterInputEl?.contains(e.target)) break;
528
536
  e.preventDefault();
529
537
  this.back();
530
538
  break;
@@ -144,18 +144,17 @@
144
144
  color: var(--drilldown-fg-muted);
145
145
  flex-shrink: 0;
146
146
  }
147
- [slot="filter"] input {
147
+ /* Composed <input-ui raw> (per ADR-0055 / ADR-0025 — no native <input>
148
+ wrap; the search-ui precedent). `raw` already strips input-ui's own
149
+ border/background/padding (input.css); re-point its own tokens so the
150
+ text inherits this row's chrome instead of input-ui's defaults. */
151
+ [slot="filter"] input-ui {
148
152
  flex: 1;
149
153
  min-width: 0;
150
- border: none;
151
- outline: none;
152
- background: transparent;
153
- color: var(--drilldown-fg);
154
+ --input-fg: var(--drilldown-fg);
155
+ --input-placeholder-fg: var(--drilldown-fg-muted);
154
156
  font: inherit;
155
157
  }
156
- [slot="filter"] input::placeholder {
157
- color: var(--drilldown-fg-muted);
158
- }
159
158
 
160
159
  /* ── Viewport / panel ── */
161
160
  [slot="viewport"] {
@@ -231,7 +230,7 @@
231
230
  flex-direction: column;
232
231
  min-width: 0;
233
232
  flex: 1;
234
- line-height: 1.3;
233
+ line-height: var(--a-font-leading-normal);
235
234
  }
236
235
  [slot="label"] {
237
236
  overflow: hidden;
@@ -257,7 +256,7 @@
257
256
  border-radius: var(--drilldown-count-chip-radius);
258
257
  font-size: var(--drilldown-count-chip-font-size);
259
258
  font-variant-numeric: tabular-nums;
260
- line-height: 1;
259
+ line-height: var(--a-font-leading-none);
261
260
  background: var(--drilldown-count-chip-bg);
262
261
  color: var(--drilldown-count-chip-fg);
263
262
  white-space: nowrap;
@@ -27,6 +27,8 @@ composes:
27
27
  - icon-ui
28
28
  - skeleton-ui
29
29
  - empty-state-ui
30
+ - input-ui # filter row's text field (ADR-0055 — no native <input> in stamped DOM)
31
+ - button-ui # back-navigation affordance
30
32
  props:
31
33
  items:
32
34
  description: >-
@@ -44,14 +44,14 @@
44
44
  font-size: var(--empty-state-heading-size);
45
45
  font-weight: var(--empty-state-heading-weight);
46
46
  color: var(--empty-state-heading-fg);
47
- line-height: 1.3;
47
+ line-height: var(--a-font-leading-normal);
48
48
  }
49
49
 
50
50
  /* ── Description ── */
51
51
  [slot="description"] {
52
52
  font-size: var(--empty-state-desc-size);
53
53
  color: var(--empty-state-desc-fg);
54
- line-height: 1.5;
54
+ line-height: var(--a-font-leading-relaxed);
55
55
  max-width: 36ch;
56
56
  }
57
57
 
@@ -133,7 +133,7 @@
133
133
  :scope [slot="hint"],
134
134
  :scope [slot="error"] {
135
135
  grid-area: message;
136
- line-height: 1.3;
136
+ line-height: var(--a-font-leading-normal);
137
137
  }
138
138
  :scope [slot="hint"] {
139
139
  color: var(--field-hint-color);
@@ -53,7 +53,7 @@
53
53
 
54
54
  /* Title slot */
55
55
  :scope [slot="title"] {
56
- font-weight: 600;
56
+ font-weight: var(--a-weight-semibold);
57
57
  margin: 0;
58
58
  }
59
59
 
@@ -66,7 +66,7 @@
66
66
  }
67
67
 
68
68
  :scope [data-month-label] {
69
- line-height: 1;
69
+ line-height: var(--a-font-leading-none);
70
70
  }
71
71
 
72
72
  /* Grid of cells */
@@ -14,7 +14,7 @@
14
14
 
15
15
  /* ── Typography ── */
16
16
  --inline-message-font-size: var(--a-ui-sm);
17
- --inline-message-line-height: var(--a-leading-snug);
17
+ --inline-message-line-height: var(--a-font-leading-normal);
18
18
  }
19
19
 
20
20
  :scope {
@@ -106,13 +106,14 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
106
106
  /* font-family floor — see segment.css rationale. */
107
107
  font-family: var(--input-font-family);
108
108
  font-size: var(--input-font-size);
109
- /* line-height: 1.4 (not 1) so descender-bearing glyphs (g, j, p, q, y)
110
- have room inside [slot="text"]'s line box. With line-height: 1 the
109
+ /* line-height: normal (1.35, not 1) so descender-bearing glyphs
110
+ (g, j, p, q, y) have room inside [slot="text"]'s line box. With
111
+ line-height: 1 the
111
112
  line box equals the em-square and descenders extend below it; the
112
113
  overflow: hidden on [slot="text"] then clips them. The min-height
113
114
  still controls overall chrome height — align-items: center keeps the
114
115
  baseline centered regardless of line-height. */
115
- line-height: 1.4;
116
+ line-height: var(--a-font-leading-normal);
116
117
  cursor: text;
117
118
  /* Cover every property the hover / focus / invalid states change so
118
119
  the field doesn't half-snap (border slides, but bg/colour/ring snap). */
@@ -306,7 +307,7 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
306
307
  flex-shrink: 0;
307
308
  color: var(--input-affix-fg);
308
309
  font-size: var(--input-font-size);
309
- line-height: 1;
310
+ line-height: var(--a-font-leading-none);
310
311
  user-select: none;
311
312
  pointer-events: none;
312
313
  }
@@ -97,7 +97,7 @@
97
97
  color: var(--integration-card-heading-fg);
98
98
  font-size: var(--integration-card-heading-size);
99
99
  font-weight: var(--integration-card-heading-weight);
100
- line-height: 1.3;
100
+ line-height: var(--a-font-leading-normal);
101
101
  min-width: 0;
102
102
  overflow: hidden;
103
103
  text-overflow: ellipsis;
@@ -118,7 +118,7 @@
118
118
  margin: 0;
119
119
  color: var(--integration-card-description-fg);
120
120
  font-size: var(--integration-card-description-size);
121
- line-height: 1.4;
121
+ line-height: var(--a-font-leading-relaxed);
122
122
  }
123
123
  :scope > [data-integration-card-description][hidden] {
124
124
  display: none;
@@ -131,7 +131,7 @@
131
131
  margin: 0;
132
132
  color: var(--integration-card-description-fg);
133
133
  font-size: var(--integration-card-description-size);
134
- line-height: 1.4;
134
+ line-height: var(--a-font-leading-relaxed);
135
135
  }
136
136
 
137
137
  /* ── Error message ── */
@@ -139,7 +139,7 @@
139
139
  margin: 0;
140
140
  color: var(--integration-card-error-fg);
141
141
  font-size: var(--integration-card-error-size);
142
- line-height: 1.4;
142
+ line-height: var(--a-font-leading-relaxed);
143
143
  }
144
144
  :scope > [data-integration-card-error][hidden] {
145
145
  display: none;
@@ -43,7 +43,7 @@
43
43
  font-family: var(--kbd-font);
44
44
  font-size: var(--kbd-font-size);
45
45
  font-weight: var(--kbd-weight);
46
- line-height: 1;
46
+ line-height: var(--a-font-leading-none);
47
47
  color: var(--kbd-fg);
48
48
  background: var(--kbd-bg);
49
49
  border: 1px solid var(--kbd-border);
@@ -125,7 +125,7 @@
125
125
  row-gap: var(--list-item-gap-row);
126
126
  font-size: var(--list-item-font-size);
127
127
  color: var(--list-item-text-color);
128
- line-height: 1.4;
128
+ line-height: var(--a-font-leading-normal);
129
129
  /* Defensive floor: empty list-item-ui (no text/icon/children) collapses
130
130
  to 0 height and disappears. Keep a visible row instead. */
131
131
  min-height: var(--a-space-6);
@@ -175,7 +175,7 @@
175
175
  grid-row: 2;
176
176
  color: var(--list-item-desc-color);
177
177
  font-size: var(--list-item-desc-font-size);
178
- line-height: 1.3;
178
+ line-height: var(--a-font-leading-normal);
179
179
  }
180
180
 
181
181
  /* When a [slot="action"] child is present, the grid becomes 3-column: