@adia-ai/web-components 0.8.42 → 0.8.44

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 (186) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/MIGRATION.md +130 -80
  3. package/USAGE.md +1 -1
  4. package/color/index.js +1 -1
  5. package/components/action-list/action-item.a2ui.json +3 -8
  6. package/components/action-list/action-item.yaml +10 -16
  7. package/components/action-list/action-list.class.js +5 -61
  8. package/components/action-list/action-list.d.ts +1 -3
  9. package/components/avatar/avatar.class.js +12 -1
  10. package/components/button/button.d.ts +4 -0
  11. package/components/button/button.yaml +1 -1
  12. package/components/calendar-picker/calendar-picker.a2ui.json +1 -1
  13. package/components/calendar-picker/calendar-picker.class.js +2 -3
  14. package/components/calendar-picker/calendar-picker.css +16 -18
  15. package/components/calendar-picker/calendar-picker.yaml +2 -2
  16. package/components/card/card.css +3 -3
  17. package/components/chart/chart.a2ui.json +29 -18
  18. package/components/chart/chart.class.js +1308 -266
  19. package/components/chart/chart.css +151 -1
  20. package/components/chart/chart.d.ts +9 -9
  21. package/components/chart/chart.yaml +63 -31
  22. package/components/chart-legend/chart-legend.a2ui.json +20 -14
  23. package/components/chart-legend/chart-legend.class.js +79 -58
  24. package/components/chart-legend/chart-legend.css +65 -1
  25. package/components/chart-legend/chart-legend.d.ts +5 -5
  26. package/components/chart-legend/chart-legend.examples.md +4 -4
  27. package/components/chart-legend/chart-legend.yaml +50 -20
  28. package/components/check/check.css +9 -0
  29. package/components/color-area/color-area.a2ui.json +1 -1
  30. package/components/color-area/color-area.class.js +2 -2
  31. package/components/color-area/color-area.css +4 -7
  32. package/components/color-area/color-area.d.ts +1 -1
  33. package/components/color-area/color-area.yaml +3 -3
  34. package/components/color-input/color-input.a2ui.json +1 -1
  35. package/components/color-input/color-input.class.js +1 -1
  36. package/components/color-input/color-input.yaml +2 -2
  37. package/components/combobox/combobox.a2ui.json +3 -0
  38. package/components/combobox/combobox.class.js +9 -8
  39. package/components/combobox/combobox.css +25 -4
  40. package/components/combobox/combobox.yaml +6 -0
  41. package/components/command/command.css +17 -1
  42. package/components/context-menu/context-menu.d.ts +2 -0
  43. package/components/drilldown/drilldown.a2ui.json +3 -0
  44. package/components/drilldown/drilldown.css +8 -1
  45. package/components/drilldown/drilldown.yaml +2 -0
  46. package/components/field/field.class.js +5 -5
  47. package/components/heatmap/heatmap.a2ui.json +5 -0
  48. package/components/heatmap/heatmap.d.ts +2 -0
  49. package/components/heatmap/heatmap.yaml +8 -0
  50. package/components/index.js +0 -4
  51. package/components/input/input.a2ui.json +4 -4
  52. package/components/input/input.class.js +20 -7
  53. package/components/input/input.css +6 -0
  54. package/components/input/input.yaml +15 -11
  55. package/components/integration-card/integration-card.d.ts +2 -0
  56. package/components/menu/menu-item.a2ui.json +3 -8
  57. package/components/menu/menu-item.yaml +13 -21
  58. package/components/menu/menu.class.js +5 -27
  59. package/components/menu/menu.d.ts +1 -3
  60. package/components/noodles/noodles.a2ui.json +0 -15
  61. package/components/noodles/noodles.yaml +0 -12
  62. package/components/number-format/number-format.class.js +10 -0
  63. package/components/pagination/pagination.class.js +88 -4
  64. package/components/pane/pane.a2ui.json +2 -12
  65. package/components/pane/pane.class.js +5 -30
  66. package/components/pane/pane.d.ts +3 -5
  67. package/components/pane/pane.yaml +7 -19
  68. package/components/popover/popover.d.ts +2 -0
  69. package/components/progress/progress.a2ui.json +1 -1
  70. package/components/progress/progress.class.js +13 -8
  71. package/components/progress/progress.d.ts +1 -1
  72. package/components/progress/progress.yaml +2 -2
  73. package/components/radio/radio.css +7 -0
  74. package/components/range/range.class.js +9 -1
  75. package/components/search/search.css +10 -1
  76. package/components/segment/segment.a2ui.json +1 -2
  77. package/components/segment/segment.css +10 -0
  78. package/components/segment/segment.yaml +1 -2
  79. package/components/segmented/segmented.a2ui.json +1 -3
  80. package/components/segmented/segmented.class.js +2 -2
  81. package/components/segmented/segmented.yaml +2 -4
  82. package/components/select/select.a2ui.json +5 -1
  83. package/components/select/select.class.js +14 -14
  84. package/components/select/select.css +20 -1
  85. package/components/select/select.yaml +7 -1
  86. package/components/step-progress/step-progress.yaml +1 -1
  87. package/components/stream/stream.d.ts +2 -0
  88. package/components/switch/switch.css +8 -0
  89. package/components/table/table.a2ui.json +6 -1
  90. package/components/table/table.class.js +18 -1
  91. package/components/table/table.css +31 -6
  92. package/components/table/table.d.ts +3 -1
  93. package/components/table/table.examples.md +2 -2
  94. package/components/table/table.yaml +9 -1
  95. package/components/table-toolbar/table-toolbar.a2ui.json +67 -2
  96. package/components/table-toolbar/table-toolbar.class.js +492 -17
  97. package/components/table-toolbar/table-toolbar.css +311 -0
  98. package/components/table-toolbar/table-toolbar.d.ts +17 -1
  99. package/components/table-toolbar/table-toolbar.yaml +220 -15
  100. package/components/tag/tag.class.js +13 -1
  101. package/components/text/text.a2ui.json +3 -3
  102. package/components/text/text.d.ts +5 -3
  103. package/components/text/text.yaml +3 -3
  104. package/components/textarea/textarea.class.js +9 -1
  105. package/components/textarea/textarea.css +4 -0
  106. package/components/time-picker/time-picker.yaml +3 -2
  107. package/components/tour/tour.d.ts +10 -0
  108. package/components/tree/tree.yaml +1 -1
  109. package/components/upload/upload.class.js +16 -0
  110. package/components/upload/upload.d.ts +7 -0
  111. package/components/upload/upload.yaml +7 -3
  112. package/core/a11y.d.ts +22 -0
  113. package/core/a11y.js +64 -0
  114. package/core/anchor.js +9 -5
  115. package/core/element.js +1 -1
  116. package/core/icons.js +2 -5
  117. package/custom-elements.json +142 -594
  118. package/dist/host.min.css +1 -1
  119. package/dist/host.sheet.js +1 -1
  120. package/dist/theme-provider.min.js +1 -1
  121. package/dist/web-components.min.css +1 -1
  122. package/dist/web-components.min.js +122 -119
  123. package/dist/web-components.sheet.js +1 -1
  124. package/index.d.ts +0 -15
  125. package/package.json +1 -1
  126. package/patterns/access-requests/access-requests.examples.html +1 -1
  127. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +7 -7
  128. package/patterns/agent-cost/agent-cost.examples.html +6 -6
  129. package/patterns/agent-memory/agent-memory.examples.html +3 -3
  130. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
  131. package/patterns/agent-tool-call/agent-tool-call.examples.html +1 -1
  132. package/patterns/approvals/approvals.examples.html +6 -6
  133. package/patterns/audit-log/audit-log.examples.html +1 -1
  134. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +4 -4
  135. package/patterns/chart-in-card/chart-in-card.examples.html +124 -10
  136. package/patterns/chart-in-card/chart-in-card.examples.js +37 -0
  137. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +5 -5
  138. package/patterns/conversion-funnel/conversion-funnel.html +2 -2
  139. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +2 -2
  140. package/patterns/diff-review/diff-review.examples.html +6 -6
  141. package/patterns/editor-shell/editor-shell.examples.html +3 -3
  142. package/patterns/export-flow/export-flow.examples.html +2 -2
  143. package/patterns/filter-bar/filter-bar.examples.html +2 -2
  144. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +2 -2
  145. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  146. package/patterns/marketing-engagement/marketing-engagement.examples.html +4 -4
  147. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
  148. package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
  149. package/patterns/permissions-sharing/permissions-sharing.examples.html +2 -2
  150. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +4 -4
  151. package/patterns/search-discovery/search-discovery.examples.html +2 -2
  152. package/styles/colors/semantics/features.css +8 -1
  153. package/styles/components.css +0 -4
  154. package/styles/type/roles.css +29 -9
  155. package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -1
  156. package/traits/resize-observer/resize-observer.js +1 -1
  157. package/components/color-picker/color-picker.a2ui.json +0 -148
  158. package/components/color-picker/color-picker.class.js +0 -46
  159. package/components/color-picker/color-picker.css +0 -14
  160. package/components/color-picker/color-picker.d.ts +0 -99
  161. package/components/color-picker/color-picker.examples.md +0 -19
  162. package/components/color-picker/color-picker.js +0 -17
  163. package/components/color-picker/color-picker.yaml +0 -175
  164. package/components/datetime-picker/datetime-picker.a2ui.json +0 -256
  165. package/components/datetime-picker/datetime-picker.class.js +0 -58
  166. package/components/datetime-picker/datetime-picker.css +0 -11
  167. package/components/datetime-picker/datetime-picker.d.ts +0 -87
  168. package/components/datetime-picker/datetime-picker.examples.md +0 -25
  169. package/components/datetime-picker/datetime-picker.js +0 -17
  170. package/components/datetime-picker/datetime-picker.yaml +0 -254
  171. package/components/progress-row/progress-row.a2ui.json +0 -107
  172. package/components/progress-row/progress-row.class.js +0 -118
  173. package/components/progress-row/progress-row.css +0 -60
  174. package/components/progress-row/progress-row.d.ts +0 -24
  175. package/components/progress-row/progress-row.examples.md +0 -7
  176. package/components/progress-row/progress-row.js +0 -17
  177. package/components/progress-row/progress-row.yaml +0 -85
  178. package/components/toggle-group/toggle-group.a2ui.json +0 -148
  179. package/components/toggle-group/toggle-group.class.js +0 -195
  180. package/components/toggle-group/toggle-group.css +0 -127
  181. package/components/toggle-group/toggle-group.d.ts +0 -50
  182. package/components/toggle-group/toggle-group.examples.md +0 -33
  183. package/components/toggle-group/toggle-group.js +0 -18
  184. package/components/toggle-group/toggle-group.yaml +0 -135
  185. package/components/toggle-group/toggle-option.a2ui.json +0 -86
  186. package/components/toggle-group/toggle-option.yaml +0 -75
@@ -37,8 +37,9 @@
37
37
  * four-sided border is suppressed, only the inner-edge
38
38
  * border is drawn, the resize grabber moves to that
39
39
  * inner edge, and the resize-drag direction flips so
40
- * trailing panes grow when dragged leftward. `side` is a
41
- * deprecated dual-read alias (ADR-0063, gh#1563).
40
+ * trailing panes grow when dragged leftward. The
41
+ * deprecated `side` dual-read alias was cut in 0.8.43
42
+ * (gh#1617, ADR-0063).
42
43
  *
43
44
  * JS API:
44
45
  * pane.collapsed = true/false
@@ -59,20 +60,13 @@ export class UIPane extends UIElement {
59
60
  resizable: { type: Boolean, default: false, reflect: true },
60
61
  minWidth: { type: Number, default: 200, attribute: 'min-width', reflect: true },
61
62
  maxWidth: { type: Number, default: 9999, attribute: 'max-width', reflect: true },
62
- // ADR-0063 (gh#1563) — `side` is DEPRECATED; `edge` is the canonical
63
- // spelling (same type/default/enum). `side` stays declared (dual-read
64
- // compat, 0.8.42); `#resolveEdge()` (called from connected()) mirrors
65
- // an old-only value onto `edge` + warns once. Internal usage below
66
- // reads `edge` exclusively.
67
- side: { type: String, default: '', reflect: true },
63
+ // ADR-0063 (gh#1563) — `edge` is the canonical spelling; the deprecated
64
+ // `side` dual-read alias was cut in 0.8.43 (gh#1617).
68
65
  edge: { type: String, default: '', reflect: true },
69
66
  };
70
67
 
71
68
  static template = () => null;
72
69
 
73
- // ADR-0063 (gh#1563) one-shot-per-class deprecation warn for [side].
74
- static #warnedSide = false;
75
-
76
70
  #resizeEl = null;
77
71
  #dragging = false;
78
72
  #startX = 0;
@@ -82,25 +76,6 @@ export class UIPane extends UIElement {
82
76
  #bound = false;
83
77
 
84
78
  connected() {
85
- // ADR-0063 (gh#1563) compat shim — resolve BEFORE the first render so
86
- // there's no wrong-then-right flash. New-name precedence: [edge] wins
87
- // outright when present; only fall back to (and mirror) [side] when
88
- // [edge] is absent from markup. `edge` defaults `''` (not a
89
- // true-default Boolean), so a live hasAttribute() check here is
90
- // reliable — no gh#961 self-stamp interference (see chart-legend.class.js
91
- // for that failure mode with a true-default Boolean).
92
- if (!this.hasAttribute('edge') && this.hasAttribute('side')) {
93
- this.edge = this.side;
94
- if (!UIPane.#warnedSide) {
95
- UIPane.#warnedSide = true;
96
- // eslint-disable-next-line no-console
97
- console.warn(
98
- '[AdiaUI] <pane-ui [side]> is deprecated — use [edge] instead ' +
99
- '(ADR-0063, gh#1563). Kept working as-is; no behavior change.',
100
- );
101
- }
102
- }
103
-
104
79
  if (!this.#bound) {
105
80
  this.#bound = true;
106
81
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `<pane-ui>` — Collapsible, resizable content panel — drag-resize handle on the
3
- inner edge when [side="leading"] / [side="trailing"], [resizable]
3
+ inner edge when [edge="leading"] / [edge="trailing"], [resizable]
4
4
  opt-in. Used standalone for resizable two-pane layouts, or wrapped
5
5
  by <editor-sidebar> / <admin-sidebar> which DELEGATE drag to the
6
6
  inner pane-ui rather than reimplementing it. See pane.yaml's
@@ -28,8 +28,8 @@ four-sided border and moves the resize grabber to the inner edge
28
28
  (right edge for `leading`, left edge for `trailing`). Also flips the
29
29
  resize-drag direction so `trailing` panes grow when dragged leftward.
30
30
  Unset keeps the pane-intrinsic chrome (full border, right-edge
31
- grabber when resizable). Canonical spelling (ADR-0063, gh#1563)
32
- replacing `side`.
31
+ grabber when resizable). Canonical spelling (ADR-0063, gh#1563) — the
32
+ deprecated `side` dual-read alias was cut in 0.8.43 (gh#1617).
33
33
  */
34
34
  edge: '' | 'leading' | 'trailing';
35
35
  /** Component property: maxWidth. */
@@ -38,8 +38,6 @@ replacing `side`.
38
38
  minWidth: number;
39
39
  /** Component property: resizable. */
40
40
  resizable: boolean;
41
- /** DEPRECATED (ADR-0063, gh#1563) — use `edge` instead. Same type/default/enum; kept working as a dual-read compat shim (one-time console.warn when it's the name that resolves). Removed in 0.9.0. */
42
- side: '' | 'leading' | 'trailing';
43
41
 
44
42
  addEventListener(type: 'toggle', listener: (ev: PaneToggleEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
45
43
  addEventListener<K extends keyof HTMLElementEventMap>(
@@ -7,7 +7,7 @@ category: layout
7
7
  version: 1
8
8
  description: |
9
9
  Collapsible, resizable content panel — drag-resize handle on the
10
- inner edge when [side="leading"] / [side="trailing"], [resizable]
10
+ inner edge when [edge="leading"] / [edge="trailing"], [resizable]
11
11
  opt-in. Used standalone for resizable two-pane layouts, or wrapped
12
12
  by <editor-sidebar> / <admin-sidebar> which DELEGATE drag to the
13
13
  inner pane-ui rather than reimplementing it. See pane.yaml's
@@ -35,18 +35,6 @@ props:
35
35
  description: 'Component property: resizable.'
36
36
  type: boolean
37
37
  default: false
38
- side:
39
- description: >-
40
- DEPRECATED (ADR-0063, gh#1563) — use `edge` instead. Same
41
- type/default/enum; kept working as a dual-read compat shim (one-time
42
- console.warn when it's the name that resolves). Removed in 0.9.0.
43
- type: string
44
- default: ''
45
- enum:
46
- - ''
47
- - leading
48
- - trailing
49
- reflect: true
50
38
  edge:
51
39
  description: 'Opts a pane into horizontal-sibling chrome: suppresses the default
52
40
 
@@ -58,9 +46,9 @@ props:
58
46
 
59
47
  Unset keeps the pane-intrinsic chrome (full border, right-edge
60
48
 
61
- grabber when resizable). Canonical spelling (ADR-0063, gh#1563)
49
+ grabber when resizable). Canonical spelling (ADR-0063, gh#1563) — the
62
50
 
63
- replacing `side`.
51
+ deprecated `side` dual-read alias was cut in 0.8.43 (gh#1617).
64
52
 
65
53
  '
66
54
  type: string
@@ -96,10 +84,10 @@ a2ui:
96
84
  rules:
97
85
  - >-
98
86
  pane-ui is a resizable / collapsible content panel. As a standalone
99
- primitive (no [side] attribute), it carries its own four-sided
87
+ primitive (no [edge] attribute), it carries its own four-sided
100
88
  chrome and a right-edge resize grabber. As a horizontal-sibling
101
- child of a layout container (set [side="leading"] or
102
- [side="trailing"]), the chrome and grabber move to the inner
89
+ child of a layout container (set [edge="leading"] or
90
+ [edge="trailing"]), the chrome and grabber move to the inner
103
91
  edge so adjacent panes share a single seam.
104
92
  - >-
105
93
  Wrapped by <editor-sidebar slot="leading|trailing"> inside
@@ -115,7 +103,7 @@ a2ui:
115
103
  navigator tree, inspector form rows, or other primary content.
116
104
  - >-
117
105
  For a standalone resizable two-pane layout (no shell), nest panes
118
- directly inside a flex row — both with [side]-typed chrome —
106
+ directly inside a flex row — both with [edge]-typed chrome —
119
107
  and the resize handle will live on the seam between them. For
120
108
  a non-resizable summary pane (a fixed-width detail rail), drop
121
109
  [resizable] and pane-ui collapses to a static container.
@@ -13,6 +13,8 @@
13
13
  import { UIElement } from '../../core/element.js';
14
14
 
15
15
  export class UIPopover extends UIElement {
16
+ /** Size the content panel to the trigger's width instead of max-content. Opt-in — the default (unset) keeps every existing consumer's content-sized panel unchanged. */
17
+ matchWidth: boolean;
16
18
  /** Pixel offset between the anchor and the popover. Renamed from `[gap]` (gh#1335) — a raw-px number can't share a name with the global Scale-grammar `[gap]` attribute (ADR-0053). */
17
19
  offset: number;
18
20
  /** Controls visibility via showPopover()/hidePopover() */
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://adiaui.dev/a2ui/v0_9/components/Progress.json",
4
4
  "title": "Progress",
5
- "description": "Linear progress bar indicator. Value < 0 marks indeterminate state showing animated activity instead of a fill. Bar-only — for circular loading indicators use <spinner-ui> instead (the former `variant=\"spinner\"` render mode was retired; spinner-ui owns circular). Set `label` for a labeled task-list row (label + bar + optional `meta` text in one row, e.g. storage quotas, capacity breakdowns) — absorbed <progress-row-ui>'s row layout directly; that component is now a deprecated alias. Omit `label` for a standalone bar (global loading indicators); for percent-complete inline displays use <stat-ui> instead.",
5
+ "description": "Linear progress bar indicator. Value < 0 marks indeterminate state showing animated activity instead of a fill. Bar-only — for circular loading indicators use <spinner-ui> instead (the former `variant=\"spinner\"` render mode was retired; spinner-ui owns circular). Set `label` for a labeled task-list row (label + bar + optional `meta` text in one row, e.g. storage quotas, capacity breakdowns) — absorbed <progress-row-ui>'s row layout directly; that component was cut in 0.8.43 (gh#1617). Omit `label` for a standalone bar (global loading indicators); for percent-complete inline displays use <stat-ui> instead.",
6
6
  "type": "object",
7
7
  "allOf": [
8
8
  {
@@ -23,11 +23,12 @@
23
23
  * (Legacy `value="-1"` is still treated as indeterminate for back-compat.)
24
24
  *
25
25
  * `label` (non-empty) activates the labeled row layout — label + bar +
26
- * optional `meta` text in one row (absorbed from the now-deprecated
27
- * <progress-row-ui>, gh#1363 C4). Omit `label` for a plain standalone bar.
26
+ * optional `meta` text in one row (absorbed from <progress-row-ui>,
27
+ * gh#1363 C4, cut in 0.8.43, gh#1617). Omit `label` for a plain standalone bar.
28
28
  */
29
29
 
30
30
  import { UIElement } from '../../core/element.js';
31
+ import { syncAutoAriaLabel } from '../../core/a11y.js';
31
32
 
32
33
  export class UIProgress extends UIElement {
33
34
  static properties = {
@@ -42,6 +43,10 @@ export class UIProgress extends UIElement {
42
43
  #fill = null;
43
44
  #labelEl = null;
44
45
  #metaEl = null;
46
+ // gh#1647: tracks the aria-label VALUE this element itself last derived
47
+ // from `label`/`meta` (undefined when none) — value-tracking guard
48
+ // ported from tag.class.js/select.class.js (gh#1644/#1646).
49
+ #lastAutoAriaLabel = undefined;
45
50
 
46
51
  connected() {
47
52
  this.setAttribute('role', 'progressbar');
@@ -111,12 +116,12 @@ export class UIProgress extends UIElement {
111
116
  }
112
117
  }
113
118
 
114
- // ARIA: label the control so screen readers announce "CPU, 42 percent".
115
- if (this.label) {
116
- this.setAttribute('aria-label', this.meta ? `${this.label}, ${this.meta}` : this.label);
117
- } else {
118
- this.removeAttribute('aria-label');
119
- }
119
+ // ARIA: label the control so screen readers announce "CPU, 42 percent"
120
+ // — never clobbering a consumer's own aria-label (gh#1647,
121
+ // value-tracking guard ported from tag.class.js/select.class.js,
122
+ // gh#1644/#1646).
123
+ const ariaSource = this.label ? (this.meta ? `${this.label}, ${this.meta}` : this.label) : '';
124
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, ariaSource);
120
125
  }
121
126
 
122
127
  disconnected() {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `<progress-ui>` — Linear progress bar indicator. Value < 0 marks indeterminate state showing animated activity instead of a fill. Bar-only — for circular loading indicators use <spinner-ui> instead (the former `variant="spinner"` render mode was retired; spinner-ui owns circular). Set `label` for a labeled task-list row (label + bar + optional `meta` text in one row, e.g. storage quotas, capacity breakdowns) — absorbed <progress-row-ui>'s row layout directly; that component is now a deprecated alias. Omit `label` for a standalone bar (global loading indicators); for percent-complete inline displays use <stat-ui> instead.
2
+ * `<progress-ui>` — Linear progress bar indicator. Value < 0 marks indeterminate state showing animated activity instead of a fill. Bar-only — for circular loading indicators use <spinner-ui> instead (the former `variant="spinner"` render mode was retired; spinner-ui owns circular). Set `label` for a labeled task-list row (label + bar + optional `meta` text in one row, e.g. storage quotas, capacity breakdowns) — absorbed <progress-row-ui>'s row layout directly; that component was cut in 0.8.43 (gh#1617). Omit `label` for a standalone bar (global loading indicators); for percent-complete inline displays use <stat-ui> instead.
3
3
  *
4
4
  * @see https://ui-kit.exe.xyz/site/components/progress
5
5
  *
@@ -12,8 +12,8 @@ description: >-
12
12
  `variant="spinner"` render mode was retired; spinner-ui owns circular).
13
13
  Set `label` for a labeled task-list row (label + bar + optional `meta`
14
14
  text in one row, e.g. storage quotas, capacity breakdowns) — absorbed
15
- <progress-row-ui>'s row layout directly; that component is now
16
- a deprecated alias. Omit `label` for a standalone bar (global loading
15
+ <progress-row-ui>'s row layout directly; that component was cut in
16
+ 0.8.43 (gh#1617). Omit `label` for a standalone bar (global loading
17
17
  indicators); for percent-complete inline displays use <stat-ui> instead.
18
18
  props:
19
19
  value:
@@ -14,6 +14,12 @@ radio-ui[checked] [slot="dot"] {
14
14
  background: var(--radio-bg-checked);
15
15
  border-color: var(--radio-border-checked);
16
16
  }
17
+ /* gh#1596 — a checked dot kept its full primary fill when disabled; higher
18
+ specificity (2 attrs) than the rule above wins without reordering. */
19
+ radio-ui[checked][disabled] [slot="dot"] {
20
+ background: var(--radio-bg-checked-disabled);
21
+ border-color: var(--radio-bg-checked-disabled);
22
+ }
17
23
  radio-ui[checked] [slot="dot"]::after {
18
24
  width: calc(var(--radio-size) * 0.6);
19
25
  height: calc(var(--radio-size) * 0.6);
@@ -40,6 +46,7 @@ radio-ui[checked] [slot="dot"]::after {
40
46
 
41
47
  /* ── State: disabled ── */
42
48
  --radio-fg-disabled: var(--a-ui-text-disabled);
49
+ --radio-bg-checked-disabled: var(--a-ui-bg-disabled);
43
50
 
44
51
  /* ── State: focus ── */
45
52
  --radio-focus-ring: var(--a-focus-ring);
@@ -25,6 +25,7 @@
25
25
  */
26
26
 
27
27
  import { UIFormElement } from '../../core/form.js';
28
+ import { syncAutoAriaLabel } from '../../core/a11y.js';
28
29
 
29
30
  export class UIRange extends UIFormElement {
30
31
  // Opt out of UIFormElement's per-control `label` deprecation warning.
@@ -52,6 +53,10 @@ export class UIRange extends UIFormElement {
52
53
  #dragging = false;
53
54
  #startX = 0;
54
55
  #startVal = 0;
56
+ // gh#1647: tracks the aria-label VALUE this element itself last derived
57
+ // from `label` (undefined when none) — value-tracking guard ported from
58
+ // tag.class.js/select.class.js (gh#1644/#1646).
59
+ #lastAutoAriaLabel = undefined;
55
60
 
56
61
  connected() {
57
62
  super.connected();
@@ -96,7 +101,10 @@ export class UIRange extends UIFormElement {
96
101
  this.setAttribute('aria-valuemax', this.max);
97
102
  this.setAttribute('aria-valuenow', this.value);
98
103
  this.setAttribute('aria-valuetext', `${this.value}${this.suffix ? ' ' + this.suffix : ''}`);
99
- this.setAttribute('aria-label', this.label || '');
104
+
105
+ // A11y (gh#1647): never clobber a consumer's own aria-label
106
+ // (value-tracking guard, gh#1644/#1646).
107
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, this.label || '');
100
108
 
101
109
  this.syncValue(String(this.value));
102
110
  }
@@ -18,7 +18,16 @@
18
18
  pointer-events: none;
19
19
  }
20
20
 
21
- [slot="suffix"] {
21
+ /* input-ui's suffix slot is decorative-only by default (input.css's own
22
+ @scope (input-ui) sets pointer-events: none on [slot="prefix"|"suffix"]).
23
+ search-ui repurposes it as the clickable clear (x-circle) affordance, so
24
+ it must opt back into pointer events. A same-specificity `[slot="suffix"]`
25
+ here loses to input.css's rule on scoping proximity — @scope(input-ui) is
26
+ the CLOSER scope root to the suffix span than @scope(search-ui), and
27
+ proximity is only a tiebreak AFTER specificity. Add `input-ui` to the
28
+ selector so specificity itself decides the override (gh#1593). */
29
+ input-ui [slot="suffix"] {
30
+ pointer-events: auto;
22
31
  transition: opacity var(--search-duration) var(--search-easing);
23
32
  }
24
33
 
@@ -90,8 +90,7 @@
90
90
  "name": "UISegment",
91
91
  "parts": {},
92
92
  "related": [
93
- "segmented-control",
94
- "ToggleOption"
93
+ "segmented-control"
95
94
  ],
96
95
  "slots": {},
97
96
  "states": [
@@ -17,6 +17,15 @@ segment-ui[selected] {
17
17
  segmented-ui[multiple] > segment-ui[selected] {
18
18
  background: var(--segment-bg-selected);
19
19
  }
20
+ /* gh#1596 — a selected segment in [multiple] mode kept its full
21
+ primary-container fill when disabled (only the label fg dimmed); 2-attr
22
+ selector outweighs the 1-attr rule above regardless of source order.
23
+ Neutralizes to the same shared disabled-bg role button-ui's colored
24
+ variants already reset to, rather than a color-family container-low
25
+ (disabled drops color semantics entirely, same convention as button). */
26
+ segmented-ui[multiple] > segment-ui[selected][disabled] {
27
+ background: var(--segment-bg-selected-disabled);
28
+ }
20
29
 
21
30
  @scope (segment-ui) {
22
31
  :where(:scope) {
@@ -43,6 +52,7 @@ segmented-ui[multiple] > segment-ui[selected] {
43
52
  --segment-fg-hover: var(--a-ui-text-hover);
44
53
  --segment-fg-selected: var(--a-chrome-dark);
45
54
  --segment-fg-disabled: var(--a-ui-text-disabled);
55
+ --segment-bg-selected-disabled: var(--a-ui-bg-disabled);
46
56
  /* [multiple] only — see the moved-out selector above (Safari 17.x bug
47
57
  note at top of file). Same default the deprecated
48
58
  toggle-option-ui[selected] background used, for visual continuity
@@ -61,7 +61,7 @@ a2ui:
61
61
  rules:
62
62
  - rule: 'Child of <segmented-ui> — one selectable option button; the parent''s [multiple] axis decides single- or multi-select, segment-ui itself is unchanged either way.'
63
63
  reason: 'Cluster contract.'
64
- - rule: '<toggle-option-ui> (deprecated, gh#1369) is the same concept — use segment-ui inside <segmented-ui multiple> instead.'
64
+ - rule: '<toggle-option-ui> (cut in 0.8.43, gh#1617, gh#1369) was the same concept — use segment-ui inside <segmented-ui multiple> instead.'
65
65
  reason: 'Deprecation redirect.'
66
66
  - rule: 'Selected state managed by the parent <segmented-ui> — it syncs the selected attribute onto every child whose value is in its own value (single value, or the [multiple] comma-separated set); do not set selected directly on segment.'
67
67
  reason: 'Parent owns selection state.'
@@ -243,4 +243,3 @@ synonyms:
243
243
  segment: [segment-button, segmented-option, option-button, toggle-option]
244
244
  related:
245
245
  - segmented-control
246
- - ToggleOption
@@ -22,7 +22,7 @@
22
22
  "const": "Segmented"
23
23
  },
24
24
  "multiple": {
25
- "description": "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the deprecated <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1). Unlike <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set).",
25
+ "description": "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1) — those components were cut in 0.8.43 (gh#1617). Unlike the former <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set).",
26
26
  "type": "boolean",
27
27
  "default": false
28
28
  },
@@ -81,8 +81,6 @@
81
81
  },
82
82
  "related": [
83
83
  "Segment",
84
- "ToggleGroup",
85
- "ToggleOption",
86
84
  "Tabs",
87
85
  "Radio"
88
86
  ],
@@ -29,8 +29,8 @@
29
29
  * [multiple] (gh#1369, #1363 C1): multi-select mode — `value` is a
30
30
  * comma-separated set, no sliding indicator (each selected segment carries
31
31
  * its own background instead), Space/Enter toggles instead of arrow-move.
32
- * Absorbs <toggle-group-ui>/<toggle-option-ui>'s role, which are deprecated
33
- * in favor of this axis.
32
+ * Absorbs <toggle-group-ui>/<toggle-option-ui>'s role; those components
33
+ * were cut in 0.8.43 (gh#1617) in favor of this axis.
34
34
  */
35
35
 
36
36
  import { UIFormElement } from '../../core/form.js';
@@ -12,7 +12,7 @@ props:
12
12
  type: string
13
13
  default: ''
14
14
  multiple:
15
- description: "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the deprecated <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1). Unlike <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set)."
15
+ description: "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1) — those components were cut in 0.8.43 (gh#1617). Unlike the former <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set)."
16
16
  type: boolean
17
17
  default: false
18
18
  reflect: true
@@ -45,7 +45,7 @@ a2ui:
45
45
  rules:
46
46
  - rule: 'Single-select by default. Hosts <segment-ui> children; exactly one selected at a time.'
47
47
  reason: 'Single-select cluster contract.'
48
- - rule: 'For multi-select (filter chips, multi-flag toggles, day-of-week pickers), set [multiple] instead of using a separate component — value becomes a comma-separated set of selected segment values. <toggle-group-ui>/<toggle-option-ui> are deprecated; use <segmented-ui multiple> + <segment-ui> instead (gh#1369, #1363 C1).'
48
+ - rule: 'For multi-select (filter chips, multi-flag toggles, day-of-week pickers), set [multiple] instead of using a separate component — value becomes a comma-separated set of selected segment values. <toggle-group-ui>/<toggle-option-ui> were cut in 0.8.43 (gh#1617); use <segmented-ui multiple> + <segment-ui> instead (gh#1369, #1363 C1).'
49
49
  reason: 'Selection model axis — multiple absorbs the deprecated multi-select pair.'
50
50
  - rule: 'Use for view-mode switches (grid/list, light/dark) or short filter sets (3-5 options); for longer sets use <tabs-ui> or <select-ui multiple>.'
51
51
  reason: 'Capacity guidance.'
@@ -201,7 +201,5 @@ synonyms:
201
201
  - Segmented
202
202
  related:
203
203
  - Segment
204
- - ToggleGroup
205
- - ToggleOption
206
204
  - Tabs
207
205
  - Radio
@@ -301,7 +301,11 @@
301
301
  ]
302
302
  },
303
303
  "tag": "select-ui",
304
- "tokens": {},
304
+ "tokens": {
305
+ "--select-min-width": {
306
+ "description": "Intrinsic min-width floor on the host (default `20ch`, matching input-ui's own `--input-min-width` UA-baseline derivation) so a select in a shrinking flex/grid cell doesn't crush to unusable width. Set to `0` to opt back into full collapse (gh#1633)."
307
+ }
308
+ },
305
309
  "traits": [],
306
310
  "version": 1
307
311
  }
@@ -14,6 +14,7 @@
14
14
  import { UIFormElement } from '../../core/form.js';
15
15
  import { anchorPopover } from '../../core/anchor.js';
16
16
  import { untracked } from '../../core/signals.js';
17
+ import { syncAutoAriaLabel } from '../../core/a11y.js';
17
18
 
18
19
  function escapeHTML(s) {
19
20
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
@@ -337,17 +338,22 @@ export class UISelect extends UIFormElement {
337
338
  else this.selectAllOptions();
338
339
  };
339
340
 
340
- // FB-88: tracks whether the host's current aria-label was derived from
341
- // `placeholder` (vs author-supplied), so re-renders refresh/clear OUR name
342
- // without ever clobbering an author's aria-label.
343
- #placeholderNamed = false;
341
+ // FB-88: tracks the aria-label VALUE this element itself last derived from
342
+ // `placeholder` (undefined when none), so re-renders refresh/clear OUR name
343
+ // without ever clobbering a consumer's own aria-label (gh#1646: a boolean
344
+ // flag couldn't detect a consumer's setAttribute between batched renders).
345
+ // The compare-against-what-we-last-wrote guard lives in core/a11y.js's
346
+ // `syncAutoAriaLabel` (gh#1647 / gh#1651); this field is its state.
347
+ #lastAutoAriaLabel = undefined;
344
348
 
345
349
  /**
346
350
  * Derive an accessible name from `placeholder` when the select is otherwise
347
351
  * unnamed — mirrors input-ui so a placeholder-only select (the idiomatic
348
352
  * filter-bar shape) still has a name for assistive tech (WCAG 4.1.2, FB-88).
349
353
  *
350
- * Guards (a placeholder-only fix must NOT clobber a real label):
354
+ * Guards (a placeholder-only fix must NOT clobber a real label) — the
355
+ * per-component policy stays HERE, resolved into the source string
356
+ * (`''` = no auto name this render); the helper only reconciles it:
351
357
  * • an author `aria-label`, a visible `label`, or an `aria-labelledby` wins;
352
358
  * • the default 'Select...' prompt is NOT used as a name — otherwise every
353
359
  * field-ui-wrapped select (named by a sibling `<label for>`, which aria-label
@@ -355,17 +361,11 @@ export class UISelect extends UIFormElement {
355
361
  */
356
362
  #syncAccessibleName() {
357
363
  const DEFAULT_PLACEHOLDER = 'Select...'; // matches static properties.placeholder.default
358
- const authoredAria = this.hasAttribute('aria-label') && !this.#placeholderNamed;
359
364
  const labeledElsewhere = !!this.label || this.hasAttribute('aria-labelledby');
360
- const namable = !authoredAria && !labeledElsewhere
365
+ const namable = !labeledElsewhere
361
366
  && this.placeholder && this.placeholder !== DEFAULT_PLACEHOLDER;
362
- if (namable) {
363
- this.setAttribute('aria-label', this.placeholder);
364
- this.#placeholderNamed = true;
365
- } else if (this.#placeholderNamed) {
366
- this.removeAttribute('aria-label');
367
- this.#placeholderNamed = false;
368
- }
367
+ const source = namable ? this.placeholder : '';
368
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, source);
369
369
  }
370
370
 
371
371
  connected() {
@@ -7,6 +7,15 @@
7
7
  --select-px: var(--a-ui-px);
8
8
  --select-radius: var(--a-radius);
9
9
  --select-leading-radius: var(--a-radius-full);
10
+ /* gh#1633 / ADIA2-9136 (adiav2#12791) — the host's own `min-width: 0`
11
+ below (the ellipsis-reset trick, kept for the trigger/display text
12
+ inside this floor) had no intrinsic lower bound, so a select in a
13
+ shrinking flex/grid cell crushed to unusable width — the same gap
14
+ already fixed on --input-min-width (this family's reference; see
15
+ input.css, gh#781). Same ch-based UA-baseline derivation, applied
16
+ to select-ui's own trigger surface. Override to 0 to opt back into
17
+ full collapse. */
18
+ --select-min-width: 20ch;
10
19
 
11
20
  /* ── Typography ── */
12
21
  --select-font-size: var(--a-ui-size);
@@ -21,6 +30,11 @@
21
30
  --select-bg-selected to re-enable a tinted selected row. */
22
31
  --select-bg-selected: transparent;
23
32
  --select-bg-hover: var(--a-ui-bg-hover);
33
+ /* gh#1596 — the trigger kept its full field bg when disabled (no
34
+ swap existed at all, unlike input-ui/textarea-ui's own
35
+ --<component>-bg-disabled indirection); wired to the same shared
36
+ role those already alias to. */
37
+ --select-bg-disabled: var(--a-ui-bg-disabled);
24
38
  --select-border: var(--a-ui-border);
25
39
  --select-border-hover: var(--a-ui-border-hover);
26
40
  --select-focus-ring: var(--a-focus-ring);
@@ -57,7 +71,11 @@
57
71
  display: flex;
58
72
  flex-direction: column;
59
73
  gap: var(--select-gap);
60
- min-width: 0;
74
+ /* Floored, not zeroed — see --select-min-width above (gh#1633). The
75
+ trigger's own `min-width: 0` further down stays 0: that one exists
76
+ so the display text can ellipsis-truncate INSIDE this floor, not to
77
+ guard the host's own collapse. */
78
+ min-width: var(--select-min-width);
61
79
  /* font-family floor on the host — trigger/native-select/options inherit it. */
62
80
  font-family: var(--select-font-family, var(--a-font-family-ui));
63
81
  font-size: var(--select-font-size);
@@ -69,6 +87,7 @@
69
87
  align-items: center;
70
88
  }
71
89
  :scope[disabled] { pointer-events: none; color: var(--select-fg-disabled); }
90
+ :scope[disabled] [slot="trigger"] { background: var(--select-bg-disabled); }
72
91
 
73
92
  /* Label */
74
93
  :scope::before {
@@ -280,7 +280,13 @@ states:
280
280
  description: Non-interactive; dimmed.
281
281
  attribute: disabled
282
282
  traits: []
283
- tokens: {}
283
+ tokens:
284
+ --select-min-width:
285
+ description: >-
286
+ Intrinsic min-width floor on the host (default `20ch`, matching
287
+ input-ui's own `--input-min-width` UA-baseline derivation) so a
288
+ select in a shrinking flex/grid cell doesn't crush to unusable
289
+ width. Set to `0` to opt back into full collapse (gh#1633).
284
290
  requiredIcons:
285
291
  - caret-down
286
292
  - check # checkbox indicator on each option in [multiple] mode
@@ -51,7 +51,7 @@ a2ui:
51
51
  reason: 'Minimal stepper visualization.'
52
52
  - rule: 'Different from <stepper-ui> (labeled, expanded) — step-progress is dense and label-free.'
53
53
  reason: 'Density boundary.'
54
- - rule: 'For multi-task progress bars (multiple labeled rows) use a stack of <progress-ui> with `label` set (absorbed the row layout from the now-deprecated progress-row-ui).'
54
+ - rule: 'For multi-task progress bars (multiple labeled rows) use a stack of <progress-ui> with `label` set (absorbed the row layout from progress-row-ui, which was cut in 0.8.43, gh#1617).'
55
55
  reason: 'Different layout.'
56
56
  anti_patterns: []
57
57
 
@@ -22,6 +22,8 @@ export type StreamErrorEvent = CustomEvent<StreamErrorEventDetail>;
22
22
  export type StreamStartEvent = CustomEvent<unknown>;
23
23
 
24
24
  export class UIStream extends UIElement {
25
+ /** When true, suppress the blinking cursor during active streaming */
26
+ hideCursor: boolean;
25
27
  /** Milliseconds between character renders. 0 = real-time. */
26
28
  pace: number;
27
29
  /** Read-only reflected state, true while stream is active */
@@ -14,6 +14,13 @@ switch-ui[checked] {
14
14
  --switch-track-border: var(--switch-track-border-checked);
15
15
  --switch-thumb-bg: var(--switch-thumb-bg-checked);
16
16
  }
17
+ /* gh#1596 — a checked track kept its full primary fill when disabled
18
+ (only the label fg dimmed); 2-attr selector outweighs the 1-attr rule
19
+ above regardless of source order. */
20
+ switch-ui[checked][disabled] {
21
+ --switch-track-bg: var(--switch-track-bg-checked-disabled);
22
+ --switch-track-border: var(--switch-track-bg-checked-disabled);
23
+ }
17
24
  switch-ui[checked] [slot="thumb"] {
18
25
  transform: translateX(var(--switch-thumb-travel));
19
26
  }
@@ -60,6 +67,7 @@ switch-ui[checked] [slot="thumb"] {
60
67
 
61
68
  /* ── State: disabled ── */
62
69
  --switch-fg-disabled: var(--a-ui-text-disabled);
70
+ --switch-track-bg-checked-disabled: var(--a-ui-bg-disabled);
63
71
  text-align: start; /* §text-align-reset — blocks inheritance from centered ancestors */
64
72
  }
65
73
 
@@ -13,8 +13,13 @@
13
13
  }
14
14
  ],
15
15
  "properties": {
16
+ "clickable-rows": {
17
+ "description": "Renders body rows with `cursor: pointer`. `row-click` fires unconditionally whether or not a listener is attached, so the cursor can't be inferred from listener presence — set this explicitly when row-click behavior is wired up (master-detail, open-flyout, navigation) so rows read as actionable.",
18
+ "type": "boolean",
19
+ "default": false
20
+ },
16
21
  "columns": {
17
- "description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, wrap?, valign?, accessor?, format?, render?, sortFn?, filterType?, meta?}. `valign` ('top'|'center') overrides the host [valign] for that column's body cells only — header cells always stay centered. Alternative to declarative <col-def> children (<col-def valign=\"top\">); col-def also accepts `meta` as a JSON attribute (gh#925) — e.g. <col-def type=\"badge\" meta='{\"variants\":{\"Online\":\"success\"}}'> — so cell-type meta (badge variant maps, currency codes) is expressible in static HTML.",
22
+ "description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, wrap?, valign?, accessor?, format?, render?, sortFn?, filterType?, meta?}. `valign` ('top'|'center') overrides the host [valign] for that column's body cells only — header cells always stay centered. Alternative to declarative <col-def> children (<col-def valign=\"top\">); col-def also accepts `meta` as a JSON attribute (gh#925) — e.g. <col-def type=\"badge\" meta='{\"variants\":{\"Online\":\"success\"}}'> — so cell-type meta (badge variant maps, currency codes) is expressible in static HTML. Truncation contract for `render` cells (gh#1681) — a `render(value, row, cell, dataIndex)` function's returned markup isn't guaranteed to be a bare <span>/<a> the way built-in cell types are, so single-line ellipsis truncation isn't automatic; set `data-truncate` on whichever rendered element (any tag, including a custom element) should single-line-ellipsis to opt it into the same contract built-in cells get for free. `[wrap]` (host) / `[data-wrap]` (per-column) override it back to multi-line, matching built-in cells.",
18
23
  "$ref": "common_types.json#/$defs/DynamicStringList"
19
24
  },
20
25
  "component": {