@adia-ai/web-components 0.6.50 → 0.7.1

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 (106) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/components/action-list/action-list.css +1 -1
  3. package/components/agent-artifact/agent-artifact.class.js +10 -10
  4. package/components/agent-artifact/agent-artifact.css +1 -1
  5. package/components/agent-reasoning/agent-reasoning.class.js +51 -0
  6. package/components/agent-reasoning/agent-reasoning.css +49 -22
  7. package/components/alert/alert.class.js +8 -1
  8. package/components/alert/alert.css +13 -1
  9. package/components/avatar/avatar.a2ui.json +2 -14
  10. package/components/avatar/avatar.class.js +3 -15
  11. package/components/avatar/avatar.d.ts +2 -4
  12. package/components/avatar/avatar.yaml +1 -18
  13. package/components/breadcrumb/breadcrumb.css +4 -1
  14. package/components/button/button.a2ui.json +3 -0
  15. package/components/button/button.css +14 -3
  16. package/components/button/button.yaml +5 -0
  17. package/components/calendar-grid/calendar-grid.css +1 -1
  18. package/components/calendar-picker/calendar-picker.css +5 -2
  19. package/components/chart/chart.a2ui.json +0 -18
  20. package/components/chart/chart.class.js +8 -50
  21. package/components/chart/chart.css +1 -15
  22. package/components/chart/chart.d.ts +0 -4
  23. package/components/chart/chart.yaml +0 -24
  24. package/components/color-input/color-input.css +4 -1
  25. package/components/combobox/combobox.class.js +11 -0
  26. package/components/combobox/combobox.css +8 -0
  27. package/components/date-range-picker/date-range-picker.class.js +5 -1
  28. package/components/date-range-picker/date-range-picker.css +12 -2
  29. package/components/datetime-picker/datetime-picker.class.js +3 -0
  30. package/components/datetime-picker/datetime-picker.css +16 -2
  31. package/components/empty-state/empty-state.css +11 -4
  32. package/components/field/field.css +17 -6
  33. package/components/grid/grid.a2ui.json +5 -0
  34. package/components/grid/grid.class.js +16 -6
  35. package/components/grid/grid.css +17 -3
  36. package/components/grid/grid.d.ts +2 -0
  37. package/components/grid/grid.yaml +9 -0
  38. package/components/heatmap/heatmap.class.js +9 -3
  39. package/components/heatmap/heatmap.css +19 -2
  40. package/components/image/image.css +4 -1
  41. package/components/input/input.class.js +38 -0
  42. package/components/input/input.css +9 -5
  43. package/components/input/input.test.js +57 -0
  44. package/components/integration-card/integration-card.class.js +31 -7
  45. package/components/integration-card/integration-card.test.js +12 -1
  46. package/components/kbd/kbd.a2ui.json +3 -2
  47. package/components/kbd/kbd.css +7 -4
  48. package/components/kbd/kbd.d.ts +2 -2
  49. package/components/kbd/kbd.yaml +2 -1
  50. package/components/list/list.class.js +8 -1
  51. package/components/menu/menu.class.js +12 -3
  52. package/components/menu/menu.css +4 -1
  53. package/components/menu/menu.test.js +130 -0
  54. package/components/modal/modal.class.js +10 -1
  55. package/components/modal/modal.css +9 -0
  56. package/components/option-card/option-card.a2ui.json +3 -0
  57. package/components/option-card/option-card.css +44 -19
  58. package/components/option-card/option-card.yaml +5 -0
  59. package/components/otp-input/otp-input.css +25 -10
  60. package/components/page/page.css +64 -11
  61. package/components/pagination/pagination.class.js +1 -1
  62. package/components/pagination/pagination.css +9 -1
  63. package/components/pipeline-status/pipeline-status.css +6 -0
  64. package/components/popover/popover.css +12 -1
  65. package/components/preview/preview.css +30 -3
  66. package/components/progress-row/progress-row.css +3 -1
  67. package/components/qr-code/qr-code.css +4 -1
  68. package/components/segmented/segmented.css +4 -1
  69. package/components/select/select.a2ui.json +1 -1
  70. package/components/select/select.class.js +63 -7
  71. package/components/select/select.css +18 -0
  72. package/components/select/select.yaml +9 -2
  73. package/components/stack/stack.a2ui.json +12 -1
  74. package/components/stack/stack.d.ts +2 -2
  75. package/components/stack/stack.yaml +13 -1
  76. package/components/stat/stat.a2ui.json +5 -0
  77. package/components/stat/stat.css +55 -0
  78. package/components/stat/stat.d.ts +2 -0
  79. package/components/stat/stat.js +4 -0
  80. package/components/stat/stat.yaml +9 -0
  81. package/components/swiper/swiper.class.js +14 -6
  82. package/components/switch/switch.css +13 -0
  83. package/components/table/table.a2ui.json +2 -2
  84. package/components/table/table.css +13 -1
  85. package/components/table/table.yaml +2 -2
  86. package/components/time-picker/time-picker.css +4 -1
  87. package/components/timeline/timeline.class.js +3 -3
  88. package/components/timeline/timeline.css +23 -5
  89. package/components/toggle-group/toggle-group.css +4 -1
  90. package/components/toggle-scheme/toggle-scheme.css +4 -1
  91. package/components/tree/tree.class.js +24 -4
  92. package/components/tree/tree.test.js +108 -0
  93. package/dist/web-components.min.css +1 -1
  94. package/dist/web-components.min.js +83 -83
  95. package/package.json +3 -3
  96. package/styles/api/layout.css +7 -0
  97. package/styles/api/text.css +9 -5
  98. package/styles/index.css +11 -2
  99. package/styles/prose.css +8 -0
  100. package/styles/resets.css +5 -5
  101. package/styles/themes.css +8 -1
  102. package/styles/tokens.css +3 -3
  103. package/styles/type/elements.css +73 -0
  104. package/styles/type/roles.css +14 -49
  105. package/styles/type/scale.css +0 -5
  106. package/styles/typography.css +3 -3
@@ -25,12 +25,15 @@
25
25
 
26
26
  :scope {
27
27
  box-sizing: border-box;
28
- display: inline-flex;
28
+ display: flex;
29
29
  align-items: center;
30
30
  gap: var(--breadcrumb-gap, var(--breadcrumb-gap-default));
31
31
  font-size: var(--breadcrumb-font-size, var(--breadcrumb-font-size-default));
32
32
  }
33
33
 
34
+ /* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
35
+ :scope[inline] { display: inline-flex; }
36
+
34
37
  /* Separator — standalone span, never inside <a> */
35
38
  [data-sep] {
36
39
  color: var(--breadcrumb-separator-fg, var(--breadcrumb-separator-fg-default));
@@ -131,6 +131,9 @@
131
131
  "Link"
132
132
  ],
133
133
  "slots": {
134
+ "icon-trailing": {
135
+ "description": "Trailing icon, after the label. Stamped from the `icon-trailing` prop, or slot a custom `<icon-ui slot=\"icon-trailing\">` directly (the consumer's element wins over the prop-stamped one). Sized to --content-height."
136
+ },
134
137
  "leading": {
135
138
  "description": "Icon container (start), sized to --content-height"
136
139
  },
@@ -72,15 +72,19 @@ button-ui[color="danger"]:not([disabled]):hover {
72
72
 
73
73
  /* ── Trailing slot ── */
74
74
  --button-trailing-font-size-default: var(--a-ui-sm);
75
- --button-trailing-fg-default: var(--a-fg-muted);
76
- --button-trailing-border-default: var(--a-border-subtle);
75
+ /* kbd-pill tracks the button's OWN text color (currentColor) so it reads
76
+ on any variant fill — on a primary button the fixed --a-fg-muted gray
77
+ was nearly invisible against the white label. Border is a translucent
78
+ slice of the same color so the pill outline adapts too. */
79
+ --button-trailing-fg-default: currentColor;
80
+ --button-trailing-border-default: color-mix(in oklab, currentColor 28%, transparent);
77
81
  --button-trailing-radius-default: var(--a-radius-sm);
78
82
  --button-trailing-px-default: var(--a-space-0-5);
79
83
  }
80
84
 
81
85
  :scope {
82
86
  box-sizing: border-box;
83
- display: inline-flex;
87
+ display: flex;
84
88
  align-items: center;
85
89
  justify-content: center;
86
90
  gap: var(--button-gap, var(--button-gap-default));
@@ -113,6 +117,13 @@ button-ui[color="danger"]:not([disabled]):hover {
113
117
  min-width: 0;
114
118
  }
115
119
 
120
+ /* Display convention (ADR-0037): block-level by default — a text button used
121
+ directly in block flow fills its container. Icon-only buttons (no [text])
122
+ stay inline-level, and [inline] forces inline for any button. Inside
123
+ row-ui/col-ui/grid-ui this is moot (flex/grid items are blockified). */
124
+ :scope:not([text]) { display: inline-flex; }
125
+ :scope[inline] { display: inline-flex; }
126
+
116
127
  /* Trailing icon slot — for forward-affordance carets ("Next →"), distinct
117
128
  from `[slot="trailing"]` which is styled as a kbd-pill for shortcut
118
129
  indicators. Auto-stamped when `[icon-trailing]` is set. */
@@ -103,6 +103,11 @@ slots:
103
103
  description: Icon container (start), sized to --content-height
104
104
  trailing:
105
105
  description: Icon container (end), sized to --content-height
106
+ icon-trailing:
107
+ description: >-
108
+ Trailing icon, after the label. Stamped from the `icon-trailing` prop, or
109
+ slot a custom `<icon-ui slot="icon-trailing">` directly (the consumer's
110
+ element wins over the prop-stamped one). Sized to --content-height.
106
111
  states:
107
112
  - name: idle
108
113
  description: Default, ready for interaction.
@@ -31,7 +31,7 @@
31
31
 
32
32
  /* Nav buttons (prev/next) — secondary chrome at one notch below the
33
33
  control height (mirrors select's `calc(height - gap)` idiom); icon
34
- is a directional chevron sized from the universal --a-caret-size. */
34
+ is a directional caret sized from the universal --a-caret-size. */
35
35
  --calendar-grid-nav-size-default: calc(var(--a-size) - var(--a-space-2));
36
36
  --calendar-grid-nav-radius-default: var(--a-radius-sm);
37
37
  --calendar-grid-nav-bg-default: transparent;
@@ -16,7 +16,10 @@
16
16
  --calendar-picker-trigger-radius-default: var(--a-radius);
17
17
  --calendar-picker-trigger-bg-default: var(--a-ui-bg);
18
18
  --calendar-picker-trigger-bg-hover-default: var(--a-ui-bg-hover);
19
- --calendar-picker-trigger-fg-default: var(--a-ui-text-subtle);
19
+ /* Committed value reads at full text strength (matches input-ui / select-ui
20
+ value color); the placeholder state drops to -placeholder below via the
21
+ :not([value]) override. Was -subtle, which muted the committed date. (bug-15/16) */
22
+ --calendar-picker-trigger-fg-default: var(--a-ui-text);
20
23
  --calendar-picker-trigger-border-default: var(--a-ui-border);
21
24
  --calendar-picker-trigger-border-hover-default: var(--a-ui-border-hover);
22
25
  --calendar-picker-trigger-focus-ring-default: var(--a-focus-ring);
@@ -45,7 +48,7 @@
45
48
 
46
49
  /* Nav buttons (prev/next) — secondary chrome at one notch below the
47
50
  control height (mirrors select's `calc(height - gap)` idiom); icon
48
- is a directional chevron sized from the universal --a-caret-size. */
51
+ is a directional caret sized from the universal --a-caret-size. */
49
52
  --calendar-picker-nav-size-default: calc(var(--a-size) - var(--a-space-2));
50
53
  --calendar-picker-nav-radius-default: var(--a-radius-sm);
51
54
  --calendar-picker-nav-bg-default: transparent;
@@ -38,18 +38,6 @@
38
38
  ],
39
39
  "default": "bar"
40
40
  },
41
- "aspect": {
42
- "description": "DEPRECATED (OD-CHART-02). Parents should size the chart directly (width/height on the enclosing card or container). Still honored for back-compat; emits a one-shot console.warn per instance when set.",
43
- "type": "string",
44
- "enum": [
45
- "std",
46
- "wide",
47
- "square",
48
- "tall"
49
- ],
50
- "default": "std",
51
- "deprecated": true
52
- },
53
41
  "color": {
54
42
  "description": "Color scheme",
55
43
  "type": "string",
@@ -81,12 +69,6 @@
81
69
  ],
82
70
  "default": "abbr"
83
71
  },
84
- "heading": {
85
- "description": "DEPRECATED (OD-CHART-02). Place chart titles in an enclosing card-ui's `<header><span slot=\"heading\">...</span></header>` instead. Still honored for back-compat; emits a one-shot console.warn per instance when set. Used as the chart's `aria-label` when no explicit label is provided.",
86
- "type": "string",
87
- "default": "",
88
- "deprecated": true
89
- },
90
72
  "hideAverage": {
91
73
  "description": "When true, suppress the overlaid average line",
92
74
  "type": "boolean",
@@ -12,14 +12,13 @@
12
12
  */
13
13
 
14
14
  /**
15
- * <chart-ui type="bar" x="month" y="revenue" heading="Monthly Revenue"></chart-ui>
15
+ * <chart-ui type="bar" x="month" y="revenue"></chart-ui>
16
16
  *
17
17
  * Declarative chart component supporting bar, line, pie, donut, radar,
18
18
  * sparkline, stacked-bar, grouped-bar, and multi-line chart types.
19
19
  *
20
20
  * Attributes:
21
21
  * type — chart type (default: 'bar')
22
- * heading — chart heading text
23
22
  * x — key for X-axis data
24
23
  * y — key(s) for Y-axis, comma-separated for multi-series
25
24
  * hide-average — suppress the overlaid average line on bar/line (default: false — line shown)
@@ -202,19 +201,16 @@ function topRoundedBarPath(x, y, w, h, r = 0) {
202
201
 
203
202
  /* ── Aspect ratios ─────────────────────────────────────────────── */
204
203
 
205
- const ASPECTS = {
206
- std: { ratio: 4 / 3 }, // default balanced dataviz proportion
207
- wide: { ratio: 16 / 9 }, // landscape / video (sparkline, timeline)
208
- square: { ratio: 1 }, // pie / donut / radar
209
- tall: { ratio: 3 / 4 }, // vertical column
210
- };
204
+ // Implicit aspect ratio — a chart derives its height from width ÷ this ratio when
205
+ // no explicit height is set. The per-chart [aspect] attribute (std/wide/square/tall)
206
+ // was retired (OD-CHART-02); parents size charts directly now.
207
+ const ASPECTS = { std: { ratio: 4 / 3 } };
211
208
 
212
209
  /* ── Component ──────────────────────────────────────────────────── */
213
210
 
214
211
  export class UIChart extends UIElement {
215
212
  static properties = {
216
213
  type: { type: String, default: 'bar', reflect: true },
217
- heading: { type: String, default: '', reflect: true },
218
214
  x: { type: String, default: '', reflect: true },
219
215
  y: { type: String, default: '', reflect: true },
220
216
  hideAverage: { type: Boolean, default: false, reflect: true, attribute: 'hide-average' },
@@ -223,7 +219,6 @@ export class UIChart extends UIElement {
223
219
  hideValues: { type: Boolean, default: false, reflect: true, attribute: 'hide-values' },
224
220
  radius: { type: Number, default: null, reflect: true },
225
221
  smooth: { type: Number, default: 0.4, reflect: true },
226
- aspect: { type: String, default: 'std', reflect: true },
227
222
  size: { type: String, default: '', reflect: true },
228
223
  format: { type: String, default: 'abbr', reflect: true },
229
224
  loading: { type: Boolean, default: false, reflect: true },
@@ -304,7 +299,7 @@ export class UIChart extends UIElement {
304
299
 
305
300
  connected() {
306
301
  if (!this.hasAttribute('role')) this.setAttribute('role', 'img');
307
- if (!this.hasAttribute('aria-label')) this.setAttribute('aria-label', this.heading || `${this.type} chart`);
302
+ if (!this.hasAttribute('aria-label')) this.setAttribute('aria-label', `${this.type} chart`);
308
303
 
309
304
  /* Hydrate from inline `data="[…]"` HTML attribute. The canonical
310
305
  entry point is the `.data` property (set programmatically), but
@@ -332,9 +327,7 @@ export class UIChart extends UIElement {
332
327
  move a virtual focus across datums in DOM order, Enter/Space fires
333
328
  chart-select, Escape clears focus. Per-datum focus dispatches the
334
329
  same chart-hover event the pointer path uses, so tooltip-ui[for]
335
- tracks keyboard focus transparently.
336
- Deprecation warnings for `aspect=` and `heading=` also fire here
337
- per OD-CHART-02 — one-shot per instance to keep the console clean. */
330
+ tracks keyboard focus transparently. */
338
331
  if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0');
339
332
  this.addEventListener('keydown', this.#onKeydown);
340
333
  this.addEventListener('focus', this.#onFocus);
@@ -347,7 +340,6 @@ export class UIChart extends UIElement {
347
340
  this.addEventListener('pointerleave', this.#onPointerLeave);
348
341
  this.addEventListener('pointerdown', this.#onPointerDown);
349
342
  this.addEventListener('click', this.#onClick);
350
- this.#warnDeprecatedAttrs();
351
343
 
352
344
  this.#resizeObs = new ResizeObserver((entries) => {
353
345
  const { inlineSize: w, blockSize: h } = entries[0].contentBoxSize[0];
@@ -394,7 +386,7 @@ export class UIChart extends UIElement {
394
386
  #dims() {
395
387
  const containerW = this.clientWidth || 300;
396
388
  const containerH = this.clientHeight || 0;
397
- const aspect = ASPECTS[this.aspect] || ASPECTS.std;
389
+ const aspect = ASPECTS.std;
398
390
  const n = this.#data.length || 1;
399
391
 
400
392
  const width = Math.max(containerW, 120);
@@ -470,13 +462,6 @@ export class UIChart extends UIElement {
470
462
 
471
463
  this.#injectSeriesColors();
472
464
 
473
- if (this.heading) {
474
- const headingEl = document.createElement('div');
475
- headingEl.setAttribute('data-chart-heading', '');
476
- headingEl.textContent = this.heading;
477
- this.appendChild(headingEl);
478
- }
479
-
480
465
  const svgWrap = document.createElement('div');
481
466
  if (this.type === 'sparkline') svgWrap.setAttribute('data-sparkline', '');
482
467
  this.appendChild(svgWrap);
@@ -609,33 +594,6 @@ export class UIChart extends UIElement {
609
594
  return !!key && this.#hiddenSeriesKeys.has(key);
610
595
  }
611
596
 
612
- /* ── Deprecation warnings (OD-CHART-02) ─────────────────────────
613
- `aspect=` and `heading=` were part of the pre-composition model —
614
- `aspect` is stale because parents now size the chart; `heading`
615
- because card headers are the semantic location for chart titles.
616
- Warn once per instance so the console stays readable. Attrs still
617
- honored; removal planned for the next major. */
618
- #deprecationWarned = false;
619
- #warnDeprecatedAttrs() {
620
- if (this.#deprecationWarned) return;
621
- if (this.aspect && this.aspect !== 'std') {
622
- console.warn(
623
- `[chart-ui] aspect="${this.aspect}" is deprecated. ` +
624
- `Parents should size the chart directly (width/height on the card ` +
625
- `or container). The attribute will be removed in a future major.`
626
- );
627
- this.#deprecationWarned = true;
628
- }
629
- if (this.heading) {
630
- console.warn(
631
- `[chart-ui] heading="${this.heading}" is deprecated. ` +
632
- `Place the title in an enclosing card-ui <header><span slot="heading"> ` +
633
- `instead. The attribute will be removed in a future major.`
634
- );
635
- this.#deprecationWarned = true;
636
- }
637
- }
638
-
639
597
  /* ── Number formatting (OD-CHART-03) ────────────────────────────
640
598
  `format` attribute selects how datum values are displayed on axis
641
599
  labels, bar/line value overlays, donut centers, etc. Falls back to
@@ -42,10 +42,6 @@
42
42
  --chart-segments-gap-default: 2px;
43
43
  --chart-pie-gap-default: 1.25px;
44
44
 
45
- /* Heading */
46
- --chart-heading-size-default: var(--a-ui-size);
47
- --chart-heading-weight-default: var(--a-weight-medium);
48
-
49
45
  /* Transitions */
50
46
  --chart-duration-default: var(--a-duration-fast);
51
47
  --chart-easing-default: var(--a-easing);
@@ -106,7 +102,6 @@
106
102
  /* Title + legend are fixed-height siblings; SVG gets the remaining
107
103
  vertical budget. min-height:0 lets the SVG wrapper shrink to fit
108
104
  inside the max-height envelope instead of pushing the legend out. */
109
- [data-chart-heading] { flex: 0 0 auto; }
110
105
  [data-legend] { flex: 0 0 auto; }
111
106
 
112
107
  /* Empty-state slot — author places <empty-state-ui slot="empty"> inside
@@ -121,7 +116,7 @@
121
116
  min-height: 0;
122
117
  }
123
118
 
124
- :scope > div:not([data-chart-heading]):not([data-legend]) {
119
+ :scope > div:not([data-legend]) {
125
120
  flex: 1 1 auto;
126
121
  min-height: 0;
127
122
  }
@@ -150,15 +145,6 @@
150
145
  overflow: visible;
151
146
  }
152
147
 
153
- /* ── Heading ── */
154
-
155
- [data-chart-heading] {
156
- font-size: var(--chart-heading-size, var(--chart-heading-size-default));
157
- font-weight: var(--chart-heading-weight, var(--chart-heading-weight-default));
158
- color: var(--chart-fg, var(--chart-fg-default));
159
- margin-bottom: var(--chart-space-md, var(--chart-space-md-default));
160
- }
161
-
162
148
  /* ── Grid lines ── */
163
149
 
164
150
  [data-grid] {
@@ -20,16 +20,12 @@ export type ChartLegendUpdateEvent = CustomEvent<unknown>;
20
20
  export class UIChart extends UIElement {
21
21
  /** Chart type. All 18 enum values have dedicated render paths in chart.js. */
22
22
  type: 'bar' | 'line' | 'pie' | 'donut' | 'radar' | 'sparkline' | 'segments' | 'area' | 'scatter' | 'radial-bar' | 'gauge' | 'stacked-bar' | 'grouped-bar' | 'multi-line' | 'funnel' | 'treemap' | 'sankey' | 'composed';
23
- /** DEPRECATED (OD-CHART-02). Parents should size the chart directly (width/height on the enclosing card or container). Still honored for back-compat; emits a one-shot console.warn per instance when set. */
24
- aspect: 'std' | 'wide' | 'square' | 'tall';
25
23
  /** Color scheme */
26
24
  color: 'accent' | 'success' | 'warning' | 'danger' | 'info';
27
25
  /** JS property (set programmatically — `el.data = [...]`). An array of plain objects; each object's keys are named by the `x` and `y` attributes — e.g. `<chart-ui x="month" y="revenue">` consumes `[{month:'Jan', revenue:3200}, {month:'Feb', revenue:4100}]`. The Chart.js `{labels, datasets}` envelope is NOT chart-ui's API — passing it (or any non-array value) renders an empty chart. May also be supplied declaratively as a JSON-array `data="[…]"` attribute, hydrated once at connect. Custom accessor on the element class, not a reflected attribute. */
28
26
  data: unknown[];
29
27
  /** Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default "$"); `percent` multiplies × 100 and adds a % suffix. */
30
28
  format: 'abbr' | 'decimal' | 'currency' | 'percent';
31
- /** DEPRECATED (OD-CHART-02). Place chart titles in an enclosing card-ui's `<header><span slot="heading">...</span></header>` instead. Still honored for back-compat; emits a one-shot console.warn per instance when set. Used as the chart's `aria-label` when no explicit label is provided. */
32
- heading: string;
33
29
  /** When true, suppress the overlaid average line */
34
30
  hideAverage: boolean;
35
31
  /** Hide gridlines */
@@ -36,19 +36,6 @@ props:
36
36
  - treemap
37
37
  - sankey
38
38
  - composed
39
- aspect:
40
- description: >-
41
- DEPRECATED (OD-CHART-02). Parents should size the chart directly
42
- (width/height on the enclosing card or container). Still honored for
43
- back-compat; emits a one-shot console.warn per instance when set.
44
- type: string
45
- default: std
46
- enum:
47
- - std
48
- - wide
49
- - square
50
- - tall
51
- deprecated: true
52
39
  format:
53
40
  description: >-
54
41
  Number-format mode applied to axis labels + value overlays + donut
@@ -115,17 +102,6 @@ props:
115
102
  type: boolean
116
103
  default: false
117
104
  reflect: true
118
- heading:
119
- description: >-
120
- DEPRECATED (OD-CHART-02). Place chart titles in an enclosing
121
- card-ui's `<header><span slot="heading">...</span></header>`
122
- instead. Still honored for back-compat; emits a one-shot
123
- console.warn per instance when set. Used as the chart's
124
- `aria-label` when no explicit label is provided.
125
- type: string
126
- default: ""
127
- reflect: true
128
- deprecated: true
129
105
  x:
130
106
  description: Data key for x-axis (category) values
131
107
  type: string
@@ -11,10 +11,13 @@
11
11
  :scope {
12
12
  --color-input-swatch-size: 1em;
13
13
 
14
- display: inline-flex;
14
+ display: flex;
15
15
  vertical-align: middle;
16
16
  }
17
17
 
18
+ /* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
19
+ :scope[inline] { display: inline-flex; }
20
+
18
21
  :scope[disabled] {
19
22
  opacity: 0.55;
20
23
  pointer-events: none;
@@ -481,6 +481,10 @@ export class UICombobox extends UIFormElement {
481
481
  if (this.#suppressInput) return;
482
482
  const text = this.#inputEl.textContent || '';
483
483
  this.#query = text.trim();
484
+ // Hide the placeholder pseudo as soon as anything is typed — it's keyed
485
+ // off [data-empty], which the programmatic text-setter toggles but the
486
+ // typing path did not, so the placeholder bled THROUGH the typed text.
487
+ this.#inputEl.toggleAttribute('data-empty', !text);
484
488
 
485
489
  if (!this.open) {
486
490
  this.open = true;
@@ -489,6 +493,13 @@ export class UICombobox extends UIFormElement {
489
493
 
490
494
  this.#renderOptions();
491
495
 
496
+ // WAI-APG list-autocomplete: pre-activate the first match while typing so
497
+ // pressing Enter commits it (and the user sees which option Enter will
498
+ // pick). #renderOptions() reset the active index; only activate when a
499
+ // query is present and there is something to match.
500
+ const opts = this.#renderedOptions();
501
+ if (this.#query && opts.length) this.#setActiveIndex(0);
502
+
492
503
  this.dispatchEvent(new CustomEvent('input', {
493
504
  bubbles: true,
494
505
  detail: { value: text, query: this.#query.toLowerCase() },
@@ -166,6 +166,14 @@
166
166
  }
167
167
  }
168
168
 
169
+ /* Higher-specificity guard: the editable [data-input] picked up 8px block
170
+ padding from an outer source that out-cascaded the @scope rule above, pinning
171
+ the field to ~36px at every [size]. This wins the cascade so the field height
172
+ tracks --a-size (sm/md/lg) like input-ui. */
173
+ combobox-ui [data-field] [data-input] {
174
+ padding-block: 0;
175
+ }
176
+
169
177
  /* ── Top-layer popover: cannot inherit @scope component tokens ── */
170
178
 
171
179
  combobox-ui [data-listbox] {
@@ -435,7 +435,11 @@ export class UIDateRangePicker extends UIFormElement {
435
435
  // Mirror reactive props onto the part nodes — runs in the element's
436
436
  // effect every time a tracked prop changes.
437
437
  if (!this.#triggerRef) return;
438
- this.#triggerRef.setAttribute('text', this.#displayText());
438
+ const display = this.#displayText();
439
+ this.#triggerRef.setAttribute('text', display);
440
+ // Filled vs placeholder color (matches input/select) — #displayText()
441
+ // returns the placeholder verbatim only when no range is committed.
442
+ this.#triggerRef.toggleAttribute('data-has-value', display !== this.placeholder);
439
443
  this.#triggerRef.toggleAttribute('disabled', this.disabled);
440
444
  this.#triggerRef.setAttribute('aria-haspopup', 'dialog');
441
445
  this.#triggerRef.setAttribute('aria-expanded', this.open ? 'true' : 'false');
@@ -48,7 +48,9 @@
48
48
  --date-range-picker-trigger-radius-default: var(--a-radius);
49
49
  --date-range-picker-trigger-bg-default: var(--a-ui-bg);
50
50
  --date-range-picker-trigger-bg-hover-default: var(--a-ui-bg-hover);
51
- --date-range-picker-trigger-fg-default: var(--a-ui-text-subtle);
51
+ /* Placeholder state by default; a committed value bumps to --a-ui-text
52
+ via [data-has-value] (matches input-ui / select-ui value vs placeholder). */
53
+ --date-range-picker-trigger-fg-default: var(--a-ui-text-placeholder);
52
54
  --date-range-picker-trigger-border-default: var(--a-ui-border);
53
55
  --date-range-picker-trigger-border-hover-default: var(--a-ui-border-hover);
54
56
  --date-range-picker-trigger-focus-ring-default: var(--a-focus-ring);
@@ -72,11 +74,14 @@
72
74
  :scope {
73
75
  box-sizing: border-box;
74
76
  position: relative;
75
- display: inline-block;
77
+ display: block;
76
78
  color: var(--date-range-picker-fg, var(--date-range-picker-fg-default));
77
79
  font-size: var(--a-ui-size);
78
80
  }
79
81
 
82
+ /* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
83
+ :scope[inline] { display: inline-block; }
84
+
80
85
  /* ── Trigger ──
81
86
  Canonical trigger surface matching <select-ui> + <calendar-picker-ui>:
82
87
  flex row, --a-size min-height, --a-ui-px padding, --a-radius corner,
@@ -108,6 +113,11 @@
108
113
  border-color: var(--date-range-picker-trigger-border-hover, var(--date-range-picker-trigger-border-hover-default));
109
114
  background: var(--date-range-picker-trigger-bg-hover, var(--date-range-picker-trigger-bg-hover-default));
110
115
  }
116
+ /* Committed value reads as filled content (matches input-ui/select-ui),
117
+ not as the muted placeholder. Marked by the class when a range is set. */
118
+ :scope [slot="trigger"][data-has-value] {
119
+ color: var(--a-ui-text);
120
+ }
111
121
  :scope:focus-visible { outline: none; }
112
122
  :scope:focus-visible [slot="trigger"] {
113
123
  box-shadow: var(--date-range-picker-trigger-focus-ring, var(--date-range-picker-trigger-focus-ring-default));
@@ -381,6 +381,9 @@ export class UIDatetimePicker extends UIFormElement {
381
381
 
382
382
  // Trigger reflection — text, disabled, ARIA expansion.
383
383
  this.#triggerRef.setAttribute('text', this.#displayText());
384
+ // Mark a committed value so the trigger brightens to --a-ui-text (the
385
+ // empty placeholder stays muted) — mirrors date-range-picker.
386
+ this.#triggerRef.toggleAttribute('data-has-value', this.#displayText() !== this.placeholder);
384
387
  this.#triggerRef.toggleAttribute('disabled', this.disabled);
385
388
  this.#triggerRef.setAttribute('aria-haspopup', 'dialog');
386
389
  this.#triggerRef.setAttribute('aria-expanded', this.open ? 'true' : 'false');
@@ -48,15 +48,29 @@
48
48
  :scope {
49
49
  box-sizing: border-box;
50
50
  position: relative;
51
- display: inline-block;
51
+ display: block;
52
52
  color: var(--datetime-picker-fg, var(--datetime-picker-fg-default));
53
53
  font-size: var(--a-ui-size);
54
54
  }
55
55
 
56
+ /* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
57
+ :scope[inline] { display: inline-block; }
58
+
56
59
  /* Default trigger sizing — composes button-ui's surface; just
57
- stretches the min-width so "Jan 1, 2026 14:30" fits. */
60
+ stretches the min-width so "Jan 1, 2026 14:30" fits. Normalize to the
61
+ picker-family field shape (mirrors date-range-picker): value text
62
+ left-aligned with the caret pushed to the trailing edge, not centered
63
+ like a default button. */
58
64
  :scope [slot="trigger"] {
59
65
  min-width: var(--datetime-picker-trigger-min-width, var(--datetime-picker-trigger-min-width-default));
66
+ justify-content: space-between;
67
+ line-height: 1;
68
+ }
69
+ /* A committed value bumps to --a-ui-text (bright), matching input-ui /
70
+ select-ui / time-picker value color; the empty placeholder keeps
71
+ button-ui's muted outline fg. */
72
+ :scope [slot="trigger"][data-has-value] {
73
+ color: var(--a-ui-text);
60
74
  }
61
75
 
62
76
  /* States */
@@ -12,8 +12,12 @@
12
12
  --empty-state-heading-fg-default: var(--a-fg);
13
13
  --empty-state-desc-fg-default: var(--a-fg-muted);
14
14
 
15
- /* ── Typography ── */
16
- --empty-state-heading-size-default: var(--a-ui-lg);
15
+ /* ── Typography ──
16
+ Heading uses the dedicated heading ramp (16px), NOT --a-ui-lg (15px,
17
+ the top of the control-label ramp) — at 15px the heading was only 1.07×
18
+ the 14px description, a hierarchy too weak to read as a title. 17px
19
+ lifts the ratio to ~1.21 (heading-medium weight adds further contrast). */
20
+ --empty-state-heading-size-default: var(--a-heading-md);
17
21
  --empty-state-heading-weight-default: var(--a-weight-medium);
18
22
  --empty-state-desc-size-default: var(--a-ui-size);
19
23
  }
@@ -91,8 +95,11 @@
91
95
  }
92
96
  :scope[minimal] [slot="heading"] {
93
97
  font-size: inherit;
94
- font-weight: var(--a-weight-normal);
95
- color: inherit;
98
+ /* Keep the heading bolder + non-muted so it stays distinct from the
99
+ muted inline description on the same baseline (otherwise '[icon]
100
+ heading description' reads as one run-on phrase). */
101
+ font-weight: var(--empty-state-heading-weight, var(--empty-state-heading-weight-default));
102
+ color: var(--empty-state-heading-fg, var(--empty-state-heading-fg-default));
96
103
  line-height: inherit;
97
104
  }
98
105
  :scope[minimal] [slot="description"] {
@@ -36,6 +36,13 @@
36
36
  align-items: center;
37
37
  }
38
38
 
39
+ /* A stacked field is a full-width form row — fill the container (form column,
40
+ grid cell, or flex parent) rather than sizing to content. Inline fields stay
41
+ intrinsic so compact filter bars keep their side-by-side layout. (bug-34) */
42
+ :scope:not([inline]) {
43
+ width: 100%;
44
+ }
45
+
39
46
  /* Gate `row-gap` on actual message presence — otherwise the grid
40
47
  reserves --field-gap (~8px) between the control row and a
41
48
  zero-content message row, making field-ui[inline] visibly taller
@@ -125,11 +132,15 @@
125
132
  "label control"
126
133
  ". message";
127
134
  }
135
+ /* Trailing sits at the control's trailing edge (after the input), not between
136
+ label and control — inline trailing is a control affordance (⌘K hint,
137
+ result count), so it reads at the row's end, mirroring input-ui's own
138
+ trailing slot. (bug-18) */
128
139
  :scope[inline]:has([slot="trailing"]):not(:has([slot="action"])) {
129
- grid-template-columns: minmax(var(--field-label-inline-min, var(--field-label-inline-min-default)), auto) auto minmax(0, 1fr);
140
+ grid-template-columns: minmax(var(--field-label-inline-min, var(--field-label-inline-min-default)), auto) minmax(0, 1fr) auto;
130
141
  grid-template-areas:
131
- "label trailing control"
132
- ". . message";
142
+ "label control trailing"
143
+ ". message message";
133
144
  }
134
145
  :scope[inline]:not(:has([slot="trailing"])):has([slot="action"]) {
135
146
  grid-template-columns: minmax(var(--field-label-inline-min, var(--field-label-inline-min-default)), auto) minmax(0, 1fr) auto;
@@ -138,10 +149,10 @@
138
149
  ". message message";
139
150
  }
140
151
  :scope[inline]:has([slot="trailing"]):has([slot="action"]) {
141
- grid-template-columns: minmax(var(--field-label-inline-min, var(--field-label-inline-min-default)), auto) auto minmax(0, 1fr) auto;
152
+ grid-template-columns: minmax(var(--field-label-inline-min, var(--field-label-inline-min-default)), auto) minmax(0, 1fr) auto auto;
142
153
  grid-template-areas:
143
- "label trailing control action"
144
- ". . message message";
154
+ "label control trailing action"
155
+ ". message message message";
145
156
  }
146
157
  :scope[inline]:not([label]):not(:has([slot="trailing"])):not(:has([slot="action"])) {
147
158
  grid-template-columns: minmax(0, 1fr);
@@ -31,6 +31,11 @@
31
31
  "type": "string",
32
32
  "default": "md"
33
33
  },
34
+ "minColumnWidth": {
35
+ "description": "Minimum track width for columns=\"auto-fit\"/\"auto-fill\" (any CSS length, e.g. \"240px\", \"16rem\"). Sets the minmax() floor so cards don't shrink below it before wrapping; unset uses the 12rem default. No effect on numeric columns.",
36
+ "type": "string",
37
+ "default": ""
38
+ },
34
39
  "rowGap": {
35
40
  "description": "Row gap override",
36
41
  "type": "string",