@adia-ai/web-components 0.8.33 → 0.8.35

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 (118) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/components/agent-questions/agent-questions.class.js +0 -1
  3. package/components/agent-reasoning/agent-reasoning.a2ui.json +1 -1
  4. package/components/agent-reasoning/agent-reasoning.yaml +3 -3
  5. package/components/badge/badge.css +33 -7
  6. package/components/badge/badge.examples.md +4 -4
  7. package/components/button/button.css +12 -0
  8. package/components/card/card.css +44 -1
  9. package/components/check/check.a2ui.json +25 -11
  10. package/components/check/check.class.js +5 -0
  11. package/components/check/check.css +21 -0
  12. package/components/check/check.d.ts +2 -0
  13. package/components/check/check.examples.md +4 -4
  14. package/components/check/check.yaml +26 -7
  15. package/components/combobox/combobox.a2ui.json +1 -1
  16. package/components/combobox/combobox.yaml +3 -0
  17. package/components/command/command.a2ui.json +4 -0
  18. package/components/command/command.class.js +54 -4
  19. package/components/command/command.d.ts +2 -0
  20. package/components/command/command.yaml +25 -3
  21. package/components/date-range-picker/date-range-picker.a2ui.json +1 -1
  22. package/components/date-range-picker/date-range-picker.class.js +42 -43
  23. package/components/date-range-picker/date-range-picker.css +11 -0
  24. package/components/date-range-picker/date-range-picker.yaml +6 -3
  25. package/components/demo-toggle/demo-toggle.css +4 -0
  26. package/components/demo-toggle/demo-toggle.examples.md +4 -4
  27. package/components/description-list/description-list.css +16 -4
  28. package/components/feed/feed-item.a2ui.json +3 -2
  29. package/components/feed/feed-item.yaml +7 -1
  30. package/components/feed/feed.css +28 -5
  31. package/components/field/field.examples.md +4 -4
  32. package/components/image/image.class.js +8 -0
  33. package/components/modal/modal.class.js +43 -2
  34. package/components/modal/modal.css +23 -0
  35. package/components/nav-group/nav-group.css +27 -5
  36. package/components/nav-item/nav-item.css +11 -3
  37. package/components/option-card/option-card.a2ui.json +10 -10
  38. package/components/option-card/option-card.css +32 -16
  39. package/components/option-card/option-card.yaml +19 -15
  40. package/components/radio/radio.examples.md +4 -4
  41. package/components/range/range.css +8 -4
  42. package/components/richtext/richtext.css +5 -1
  43. package/components/segment/segment.css +10 -0
  44. package/components/slider/slider.a2ui.json +6 -3
  45. package/components/slider/slider.css +28 -12
  46. package/components/slider/slider.yaml +11 -3
  47. package/components/stat/stat.examples.md +4 -4
  48. package/components/step-progress/step-progress.css +16 -3
  49. package/components/swatch/swatch.css +14 -6
  50. package/components/switch/switch.examples.md +4 -4
  51. package/components/table/cell-types.js +8 -0
  52. package/components/table/table.a2ui.json +1 -1
  53. package/components/table/table.class.js +11 -0
  54. package/components/table/table.css +9 -0
  55. package/components/table/table.d.ts +1 -1
  56. package/components/table/table.yaml +1 -1
  57. package/components/table-toolbar/table-toolbar.css +10 -1
  58. package/components/tabs/tabs.css +13 -5
  59. package/components/tag/tag.class.js +14 -1
  60. package/components/tag/tag.css +70 -9
  61. package/components/text/text.examples.md +4 -4
  62. package/components/timeline/timeline-item.a2ui.json +2 -2
  63. package/components/timeline/timeline-item.yaml +2 -2
  64. package/components/timeline/timeline.css +33 -5
  65. package/components/timeline/timeline.d.ts +2 -2
  66. package/components/toast/toast.css +28 -5
  67. package/core/element.js +31 -0
  68. package/core/signals.js +3 -1
  69. package/custom-elements.json +469 -46
  70. package/dist/theme-provider.min.js +2 -2
  71. package/dist/web-components.min.css +1 -1
  72. package/dist/web-components.min.js +41 -41
  73. package/dist/web-components.sheet.js +1 -1
  74. package/package.json +1 -1
  75. package/patterns/access-requests/access-requests.examples.html +3 -3
  76. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +3 -3
  77. package/patterns/admin-shell/admin-shell.examples.html +3 -4
  78. package/patterns/agent-cost/agent-cost.examples.html +3 -3
  79. package/patterns/agent-memory/agent-memory.examples.html +3 -3
  80. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +3 -3
  81. package/patterns/agent-tool-call/agent-tool-call.examples.html +3 -3
  82. package/patterns/alert-dialog/alert-dialog.examples.html +3 -3
  83. package/patterns/app-nav/app-nav.examples.html +4 -4
  84. package/patterns/approvals/approvals.examples.html +3 -3
  85. package/patterns/audit-log/audit-log.examples.html +3 -3
  86. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +19 -9
  87. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +2 -2
  88. package/patterns/changelog-feed/changelog-feed.examples.html +3 -3
  89. package/patterns/chart-in-card/chart-in-card.examples.html +37 -3
  90. package/patterns/chart-in-card/chart-in-card.examples.js +12 -0
  91. package/patterns/chart-in-card/chart-in-card.html +6 -0
  92. package/patterns/chat-shell/chat-shell.examples.html +3 -4
  93. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +3 -3
  94. package/patterns/conversion-funnel/conversion-funnel.examples.html +3 -3
  95. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +3 -3
  96. package/patterns/diff-review/diff-review.examples.html +3 -3
  97. package/patterns/editor-shell/editor-shell.examples.html +3 -4
  98. package/patterns/export-flow/export-flow.examples.html +3 -3
  99. package/patterns/filter-bar/filter-bar.examples.html +3 -3
  100. package/patterns/form-drawer/form-drawer.examples.html +3 -3
  101. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +3 -3
  102. package/patterns/inline-dialog/inline-dialog.examples.html +3 -3
  103. package/patterns/kanban-board/kanban-board.examples.html +3 -3
  104. package/patterns/layout/layout.examples.html +4 -7
  105. package/patterns/marketing-engagement/marketing-engagement.examples.html +3 -3
  106. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +3 -3
  107. package/patterns/permissions-matrix/permissions-matrix.examples.html +3 -3
  108. package/patterns/permissions-role-picker/permissions-role-picker.examples.html +3 -3
  109. package/patterns/permissions-sharing/permissions-sharing.examples.html +3 -3
  110. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +3 -3
  111. package/patterns/record-detail-drawer/record-detail-drawer.examples.html +3 -3
  112. package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.examples.html +135 -147
  113. package/patterns/retention-cohort/retention-cohort.examples.html +3 -3
  114. package/patterns/search-discovery/search-discovery.examples.html +3 -3
  115. package/patterns/system-banners/system-banners.examples.html +3 -3
  116. package/patterns/timezone-selector/timezone-selector.examples.html +3 -3
  117. package/patterns/wizard-drawer/wizard-drawer.examples.html +3 -3
  118. package/styles/colors/semantics/core.css +22 -2
@@ -30,26 +30,38 @@ option-card-ui[checked] [slot="icon"] {
30
30
 
31
31
  @scope (option-card-ui) {
32
32
  :where(:scope) {
33
- /* ── Container ── */
33
+ /* ── Container (gh#1018: tonal surface, not a bordered box on page
34
+ bg) ── */
34
35
  --option-card-padding-block: var(--a-space-3);
35
36
  --option-card-padding-inline: var(--a-space-4);
36
37
  --option-card-radius: var(--a-radius-md);
37
- --option-card-bg: var(--md-sys-color-neutral-background);
38
- --option-card-border: var(--md-sys-color-neutral-outline);
38
+ --option-card-bg: var(--md-sys-color-neutral-container-low);
39
+ /* No outline as the primary boundary — the tonal bg IS the
40
+ boundary. Transparent (not removed) so a consumer override that
41
+ sets a real color doesn't cause a layout reflow. */
42
+ --option-card-border: transparent;
39
43
  --option-card-gap-x: var(--a-space-3);
40
44
  --option-card-gap-y: var(--a-space-1);
41
45
 
42
46
  /* ── State: hover ── */
43
- --option-card-bg-hover: var(--a-bg-muted);
44
- --option-card-border-hover: var(--md-sys-color-neutral-on-surface-variant);
47
+ /* One step up from the container-low base (--a-bg-muted resolves to
48
+ the SAME role as the base bg now, gh#1018) so hover stays visibly
49
+ distinct instead of collapsing to a no-op. */
50
+ --option-card-bg-hover: var(--md-sys-color-neutral-container);
51
+ --option-card-border-hover: transparent;
45
52
 
46
53
  /* ── State: checked ── */
54
+ /* Kept as the accent border+fill (design decision, gh#1018): the
55
+ checked state is the one state that must stay unmistakable, so it
56
+ keeps the token-ladder rung idle/hover gave up. */
47
57
  --option-card-bg-checked: var(--md-sys-color-primary-container);
48
58
  --option-card-border-checked: var(--md-sys-color-primary);
49
59
 
50
60
  /* ── Indicator (CSS radio circle, same size + recipe as <radio-ui>). */
51
61
  --option-card-radio-size: var(--a-toggle-size);
52
- --option-card-radio-bg: var(--md-sys-color-neutral-background);
62
+ /* Matches the card bg (gh#1018) so the ring reads flush with the new
63
+ tonal surface instead of floating as a mismatched lighter cutout. */
64
+ --option-card-radio-bg: var(--md-sys-color-neutral-container-low);
53
65
  --option-card-radio-border: var(--md-sys-color-neutral-outline);
54
66
  --option-card-radio-fill: var(--md-sys-color-primary);
55
67
  /* Mirror radio.css's --radio-fg-checked recipe: an always-light
@@ -82,7 +94,8 @@ option-card-ui[checked] [slot="icon"] {
82
94
  }
83
95
 
84
96
  /* ── Base — grid: indicator | (heading + description). Optional icon
85
- sits between indicator and heading via :has() rules below. ── */
97
+ sits at the trailing end of the header row via :has() rules below
98
+ (gh#1018: was a leading column between indicator and heading). ── */
86
99
  :scope {
87
100
  box-sizing: border-box;
88
101
  display: grid;
@@ -105,17 +118,19 @@ option-card-ui[checked] [slot="icon"] {
105
118
  box-shadow var(--option-card-duration) var(--option-card-easing);
106
119
  }
107
120
 
108
- /* When an icon slot is present, insert a third column for it
109
- between indicator and heading. */
121
+ /* When an icon slot is present, insert a trailing column for it
122
+ alongside the heading only — description still spans the full
123
+ content width beneath (gh#1018). */
110
124
  :scope:has([slot="icon"]) {
111
- grid-template-columns: auto auto minmax(0, 1fr);
125
+ grid-template-columns: auto minmax(0, 1fr) auto;
112
126
  grid-template-areas:
113
- "indicator icon heading"
114
- "indicator icon description";
127
+ "indicator heading icon"
128
+ "indicator description description";
115
129
  }
116
130
  :scope [slot="icon"] {
117
131
  grid-area: icon;
118
- align-self: start;
132
+ align-self: center;
133
+ justify-self: end;
119
134
  color: var(--option-card-icon-color);
120
135
  --a-icon-size: var(--option-card-icon-size);
121
136
  transition: color var(--option-card-duration) var(--option-card-easing);
@@ -158,13 +173,14 @@ option-card-ui[checked] [slot="icon"] {
158
173
  gutter). Common pattern: an "Other" option with a free-text
159
174
  textarea, conditional follow-up fields, etc. ── */
160
175
  :scope > :not([slot]) {
176
+ /* 2/-1 spans every content column (heading/description, plus the
177
+ trailing icon column when present, gh#1018) — the icon column now
178
+ sits at the END, so this span already covers it without a
179
+ separate :has() override. */
161
180
  grid-column: 2 / -1;
162
181
  margin-block-start: var(--a-space-3);
163
182
  display: none;
164
183
  }
165
- :scope:has([slot="icon"]) > :not([slot]) {
166
- grid-column: 3 / -1;
167
- }
168
184
  /* hover + [checked] state rules moved outside @scope — see Safari 17.x bug note at top.
169
185
  The :scope[checked]::before recipe lives at top-of-file: an accent disc
170
186
  with a centered dot via radial-gradient, mirroring radio-ui's recipe. */
@@ -9,9 +9,12 @@ version: 1
9
9
  description: >-
10
10
  Selectable card with radio semantics. A "rich radio" — single-select
11
11
  one of N where each option carries a heading, optional description,
12
- and optional leading icon. Siblings sharing a `name` form a
13
- radiogroup. The whole card is the click target; a CSS-rendered radio
14
- circle in the top-left signals state. Form-associated, so `name=value`
12
+ and an optional icon at the trailing end of the header row. Siblings
13
+ sharing a `name` form a radiogroup. The whole card is the click
14
+ target; a CSS-rendered radio circle in the top-left signals state.
15
+ Renders on a container-low tonal surface (no outline as the primary
16
+ boundary); the checked state keeps an accent border + fill so
17
+ selection stays unmistakable. Form-associated, so `name=value`
15
18
  submits with the parent form when checked.
16
19
  # Per ADR-0027 — primitives that programmatically create other primitives
17
20
  # do NOT auto-import them. Consumer (or demo shell) must explicitly import.
@@ -52,16 +55,17 @@ props:
52
55
  default: ""
53
56
  reflect: true
54
57
  icon:
55
- description: Optional Phosphor icon name. Stamped as a leading <icon-ui slot="icon"> when set.
58
+ description: Optional Phosphor icon name. Stamped as a trailing <icon-ui slot="icon"> when set.
56
59
  type: string
57
60
  default: ""
58
61
  reflect: true
59
62
  layout:
60
63
  description: >-
61
- Internal layout. `default` puts the indicator on the left and the icon
62
- adjacent. `tile` stacks vertically icon top-left, indicator top-right,
63
- heading + description belowfor hero pickers (source / role / plan
64
- tiles) where the icon is a primary brand cue.
64
+ Internal layout. `default` puts the indicator on the left and, when
65
+ [icon] is set, the icon at the trailing end of the header row
66
+ alongside the heading. `tile` stacks verticallyicon top-left,
67
+ indicator top-right, heading + description below for hero pickers
68
+ (source / role / plan tiles) where the icon is a primary brand cue.
65
69
  type: string
66
70
  default: default
67
71
  enum: [default, tile]
@@ -112,17 +116,17 @@ tokens:
112
116
  --option-card-radius:
113
117
  description: Card corner radius.
114
118
  --option-card-bg:
115
- description: Default background.
119
+ description: Default background (container-low tonal surface, gh#1018).
116
120
  --option-card-border:
117
- description: Default border color.
121
+ description: Default border color (transparent — the tonal bg is the primary boundary, not an outline; gh#1018).
118
122
  --option-card-gap-x:
119
123
  description: Horizontal gap between indicator (and icon) and content.
120
124
  --option-card-gap-y:
121
125
  description: Vertical gap between heading and description.
122
126
  --option-card-bg-hover:
123
- description: Hover background (non-checked).
127
+ description: Hover background (non-checked) — one tonal step up from --option-card-bg so hover stays visibly distinct.
124
128
  --option-card-border-hover:
125
- description: Hover border color (non-checked).
129
+ description: Hover border color (non-checked; transparent by default, matching the no-outline base).
126
130
  --option-card-bg-checked:
127
131
  description: Background when checked.
128
132
  --option-card-border-checked:
@@ -152,11 +156,11 @@ tokens:
152
156
  --option-card-desc-line-height:
153
157
  description: Description line height.
154
158
  --option-card-icon-color:
155
- description: Leading icon color when the card is not checked.
159
+ description: Trailing icon color when the card is not checked.
156
160
  --option-card-icon-color-checked:
157
- description: Leading icon color when the card is checked.
161
+ description: Trailing icon color when the card is checked.
158
162
  --option-card-icon-size:
159
- description: Leading icon size (sets `--a-icon-size` on the slotted icon-ui).
163
+ description: Trailing icon size (sets `--a-icon-size` on the slotted icon-ui).
160
164
  --option-card-disabled-opacity:
161
165
  description: Opacity multiplier when disabled.
162
166
  --option-card-focus-ring:
@@ -11,8 +11,8 @@
11
11
  ```html
12
12
  <row-ui gap="6" align="start" wrap>
13
13
  <col-ui gap="2">
14
- <text-ui variant="caption" color="muted">verse</text-ui>
15
- <div verse>
14
+ <text-ui variant="caption" color="muted">scale="ui-sm"</text-ui>
15
+ <div scale="ui-sm">
16
16
  <radio-ui label="Standard" name="reg-verse" checked></radio-ui>
17
17
  </div>
18
18
  </col-ui>
@@ -23,8 +23,8 @@
23
23
  </div>
24
24
  </col-ui>
25
25
  <col-ui gap="2">
26
- <text-ui variant="caption" color="muted">prose</text-ui>
27
- <div prose>
26
+ <text-ui variant="caption" color="muted">scale="content-md"</text-ui>
27
+ <div scale="content-md">
28
28
  <radio-ui label="Standard" name="reg-prose" checked></radio-ui>
29
29
  </div>
30
30
  </col-ui>
@@ -9,11 +9,15 @@ range-ui:not([disabled]) [slot="field"]:hover [data-layer="fill"] {
9
9
  :where(:scope) {
10
10
  /* ── Tokens (wired to --a-ui-*) ── */
11
11
  --range-bg: var(--a-ui-bg);
12
- --range-fill-bg: var(--a-ui-bg);
13
- --range-fill-bg-hover: var(--a-ui-bg-hover);
14
- --range-fill-bg-active: var(--a-ui-bg-active);
12
+ /* Brand-primary fill (gh#1080): the neutral --a-ui-bg fill read as
13
+ near-invisible against the track at partial values; slider-ui's
14
+ --slider-fill-bg already uses the primary family — same convention
15
+ here, with the on-primary ink pair for the clipped fill-layer text. */
16
+ --range-fill-bg: var(--a-primary-bg);
17
+ --range-fill-bg-hover: var(--a-primary-bg-hover);
18
+ --range-fill-bg-active: var(--a-primary-bg-active);
15
19
  --range-fill-bg-disabled: var(--a-canvas-muted);
16
- --range-fill-fg: var(--md-sys-color-neutral-on-surface);
20
+ --range-fill-fg: var(--md-sys-color-primary-on-primary);
17
21
  --range-fill-fg-disabled: var(--a-ui-text-disabled);
18
22
  --range-fill-label-fg: var(--a-ui-text-subtle);
19
23
  --range-border: var(--a-ui-border);
@@ -15,7 +15,11 @@
15
15
  --richtext-fg: var(--md-sys-color-neutral-on-surface);
16
16
  --richtext-fg-muted: var(--a-fg-muted);
17
17
  --richtext-fg-subtle: var(--md-sys-color-neutral-on-surface-variant);
18
- --richtext-code-bg: var(--a-canvas-2);
18
+ /* Container-low (10% alpha), not an opaque canvas tier (gh#972): the
19
+ inline chip must RECEDE behind prose and composite consistently on
20
+ any stacked surface — an opaque canvas-2 chip read heavy on the
21
+ page and inverted inside cards. Same tier as --a-bg-muted/hover. */
22
+ --richtext-code-bg: var(--md-sys-color-neutral-container-low);
19
23
  --richtext-border: var(--md-sys-color-neutral-outline-variant);
20
24
  --richtext-link: var(--a-primary-bg);
21
25
  --richtext-link-hover: var(--md-sys-color-primary);
@@ -19,6 +19,13 @@ segment-ui[selected] {
19
19
  --segment-font-size: var(--a-ui-size);
20
20
  --segment-font-weight: var(--a-ui-weight);
21
21
  --segment-font-family: var(--a-font-family-ui);
22
+ /* Leading for the [text] label box ONLY — never the host. The host's
23
+ `line-height: 1` is deliberate, but the label's ::after clips to its
24
+ own line box, so inheriting 1 makes half-leading negative and shears
25
+ descenders (g/j/p/q/y, parentheses) by ~0.93px at the default size —
26
+ gh#906. Snug (1.3) contains the font's content box at every [size];
27
+ mirrors --button-label-line-height. */
28
+ --segment-label-line-height: var(--a-leading-snug);
22
29
 
23
30
  /* ── Colors ── */
24
31
  --segment-fg: var(--a-ui-text-subtle);
@@ -92,6 +99,9 @@ segment-ui[selected] {
92
99
  overflow: hidden;
93
100
  text-overflow: ellipsis;
94
101
  white-space: nowrap;
102
+ /* `overflow: hidden` (needed for the ellipsis) makes this line box the
103
+ clip box — give it leading tall enough to contain the descenders. */
104
+ line-height: var(--segment-label-line-height);
95
105
  }
96
106
 
97
107
  /* States — hover + [selected] rules moved outside @scope; see Safari 17.x bug note at top. */
@@ -175,16 +175,19 @@
175
175
  "description": "Filled portion / progress color (was mixed accent, now primary)"
176
176
  },
177
177
  "--slider-thumb-height": {
178
- "description": "Thumb pill height (track-height − 2× inset)"
178
+ "description": "Thumb pill height (--slider-thumb-size − 2× inset)"
179
+ },
180
+ "--slider-thumb-size": {
181
+ "description": "Thumb (grab handle) control size — scales via the universal [size] attribute (16 sm / 20 md / 24 lg at density=1). Independent of --slider-track-height (gh#1012); the thumb overhangs the thin rail."
179
182
  },
180
183
  "--slider-thumb-width": {
181
- "description": "Thumb pill width (2× thumb-height, driven by track-height)"
184
+ "description": "Thumb pill width (2× thumb-visual-height, driven by --slider-thumb-size)"
182
185
  },
183
186
  "--slider-track": {
184
187
  "description": "Unfilled track background color"
185
188
  },
186
189
  "--slider-track-height": {
187
- "description": "Full track height (scales via universal [size] attribute)"
190
+ "description": "Rail thickness — a slim strip (a few px, house space scale), NOT control height (gh#1012 re-baseline; was --a-toggle-size, making the whole track read as a toggle-height progress bar)."
188
191
  }
189
192
  },
190
193
  "traits": [],
@@ -7,13 +7,19 @@
7
7
  Variables
8
8
  W = track width (100% of the track element)
9
9
  t = thumb width (full outer width including internal padding)
10
- h = track height (var(--slider-track-height))
10
+ h = thumb height (var(--slider-thumb-size) — control size,
11
+ gh#1012: DECOUPLED from track height. The
12
+ rail (var(--slider-track-height)) is a thin
13
+ conventional-slider strip; the thumb
14
+ overhangs it above and below, centered via
15
+ top:50% + translate(-50%,-50%) on the track.)
11
16
  pad = internal padding on the thumb (var(--slider-thumb-padding))
12
17
  p = progress (0.0 → 1.0, written by JS as --slider-pct)
13
18
 
14
19
  The thumb consists of two layers:
15
20
  • Container: the geometry element that the fill aligns to.
16
- Sized to t × h. Provides the full-height grab area.
21
+ Sized to t × h. Provides the full grab area,
22
+ independent of the (thin) rail it overhangs.
17
23
  • Visual: the white pill rendered inside the container via
18
24
  ::before. Sized to (t−2·pad) × (h−2·pad), centered
19
25
  by inset = pad on all sides.
@@ -64,17 +70,26 @@
64
70
  --slider-readout-gap: var(--a-space-0-5);
65
71
  --slider-radius: var(--a-radius-full);
66
72
 
67
- /* Track height scales with the universal [size] attribute
68
- via --a-toggle-size: 16 sm / 20 md / 24 lg at density=1.
69
- Override --slider-track-height directly for custom sizes. */
70
- --slider-track-height: var(--a-toggle-size);
73
+ /* Rail thickness (gh#1012 re-baseline) conventional slider anatomy:
74
+ a slim strip, not control height. Was var(--a-toggle-size) (16/20/24px),
75
+ making the whole track read as a toggle-height progress bar. Now a
76
+ few px from the house space scale; the thumb (below) keeps the
77
+ control size independently. */
78
+ --slider-track-height: var(--a-space-1-5);
79
+
80
+ /* Thumb size: the universal [size] attribute's control dimension —
81
+ 16 sm / 20 md / 24 lg at density=1, same scale the rail used to
82
+ carry directly. Decoupled from --slider-track-height so resizing
83
+ the rail never resizes the grab target, and vice versa. */
84
+ --slider-thumb-size: var(--a-toggle-size);
71
85
 
72
86
  /* Thumb padding: internal breathing room on all sides.
73
87
  The visual pill sits pad px away from the container edge. */
74
88
  --slider-thumb-padding: 2px;
75
89
 
76
- /* Visual thumb height: track height minus top and bottom padding. */
77
- --slider-thumb-visual-h: calc(var(--slider-track-height) - 2 * var(--slider-thumb-padding));
90
+ /* Visual thumb height: thumb (control) size minus top/bottom padding
91
+ NOT track height (gh#1012); the thumb overhangs the thin rail. */
92
+ --slider-thumb-visual-h: calc(var(--slider-thumb-size) - 2 * var(--slider-thumb-padding));
78
93
 
79
94
  /* Visual thumb width: 2×1 pill ratio. */
80
95
  --slider-thumb-visual-w: calc(var(--slider-thumb-visual-h) * 2);
@@ -213,16 +228,17 @@
213
228
  * (100% - 2 * var(--slider-thumb-width)));
214
229
  }
215
230
 
216
- /* Thumb CONTAINER: full track height, geometry width.
217
- Transparent background; the white pill is rendered by ::before.
218
- This element provides a generous vertical grab area. */
231
+ /* Thumb CONTAINER: control-size height (independent of the thin rail —
232
+ gh#1012), geometry width. Transparent background; the white pill is
233
+ rendered by ::before. Centered on the rail via top:50% + the
234
+ translate(-50%,-50%) below, so it overhangs above and below. */
219
235
  [slot="thumb"] {
220
236
  position: absolute;
221
237
  top: 50%;
222
238
  left: calc(var(--slider-thumb-width) / 2
223
239
  + var(--slider-pct) * (100% - var(--slider-thumb-width)));
224
240
  width: var(--slider-thumb-width);
225
- height: var(--slider-track-height);
241
+ height: var(--slider-thumb-size);
226
242
  border-radius: var(--slider-radius);
227
243
  background: transparent;
228
244
  transform: translate(-50%, -50%);
@@ -115,13 +115,21 @@ tokens:
115
115
  --slider-fill:
116
116
  description: Filled portion / progress color (was mixed accent, now primary)
117
117
  --slider-thumb-width:
118
- description: Thumb pill width (2× thumb-height, driven by track-height)
118
+ description: Thumb pill width (2× thumb-visual-height, driven by --slider-thumb-size)
119
119
  --slider-thumb-height:
120
- description: Thumb pill height (track-height − 2× inset)
120
+ description: Thumb pill height (--slider-thumb-size − 2× inset)
121
+ --slider-thumb-size:
122
+ description: >-
123
+ Thumb (grab handle) control size — scales via the universal [size]
124
+ attribute (16 sm / 20 md / 24 lg at density=1). Independent of
125
+ --slider-track-height (gh#1012); the thumb overhangs the thin rail.
121
126
  --slider-track:
122
127
  description: Unfilled track background color
123
128
  --slider-track-height:
124
- description: Full track height (scales via universal [size] attribute)
129
+ description: >-
130
+ Rail thickness — a slim strip (a few px, house space scale), NOT
131
+ control height (gh#1012 re-baseline; was --a-toggle-size, making
132
+ the whole track read as a toggle-height progress bar).
125
133
  a2ui:
126
134
  rules:
127
135
  - rule: 'Default mode is single-handle. Form-associated; emits numeric change events with detail.value.'
@@ -11,8 +11,8 @@
11
11
  ```html
12
12
  <row-ui gap="6" align="start" wrap>
13
13
  <col-ui gap="2">
14
- <text-ui variant="caption" color="muted">verse</text-ui>
15
- <div verse style="width:180px">
14
+ <text-ui variant="caption" color="muted">scale="ui-sm"</text-ui>
15
+ <div scale="ui-sm" style="width:180px">
16
16
  <stat-ui value="$48.2k" label="Revenue" change="+12.5%" trend="up"></stat-ui>
17
17
  </div>
18
18
  </col-ui>
@@ -23,8 +23,8 @@
23
23
  </div>
24
24
  </col-ui>
25
25
  <col-ui gap="2">
26
- <text-ui variant="caption" color="muted">prose</text-ui>
27
- <div prose style="width:180px">
26
+ <text-ui variant="caption" color="muted">scale="content-md"</text-ui>
27
+ <div scale="content-md" style="width:180px">
28
28
  <stat-ui value="$48.2k" label="Revenue" change="+12.5%" trend="up"></stat-ui>
29
29
  </div>
30
30
  </col-ui>
@@ -14,9 +14,15 @@
14
14
  --step-progress-caption-fg: var(--a-fg-muted);
15
15
  --step-progress-caption-size: var(--a-ui-sm);
16
16
 
17
- /* Sizing — match the bespoke flex shape in registration + onboarding
18
- (flex:0 1 18rem; min-width:10rem). Consumers can override. */
19
- --step-progress-flex: 0 1 18rem;
17
+ /* Sizing — 18rem of track width, shrinkable to 10rem, matching the
18
+ bespoke shape in registration + onboarding. Expressed as inline-size
19
+ rather than flex-basis (gh#942): a flex-basis of 18rem is
20
+ direction-fragile — inside a COLUMN-direction flex parent (col-ui,
21
+ any stacked wizard) the same basis constrains HEIGHT, inflating the
22
+ ~30px component to 288px. inline-size constrains width in both flex
23
+ directions. Consumers can override. */
24
+ --step-progress-flex: 0 1 auto;
25
+ --step-progress-inline-size: 18rem;
20
26
  --step-progress-min-width: 10rem;
21
27
  }
22
28
 
@@ -25,6 +31,13 @@
25
31
  flex-direction: column;
26
32
  gap: var(--step-progress-gap);
27
33
  flex: var(--step-progress-flex);
34
+ /* Deliberate SCOPE-EXTENT exception: this component has always shipped
35
+ a default extent (previously flex-basis 18rem + min-width 10rem —
36
+ extent by another name, just direction-fragile). Both remain
37
+ token-overridable; going fully size-agnostic would silently reflow
38
+ the registration/onboarding row-header consumers. */
39
+ inline-size: var(--step-progress-inline-size);
40
+ max-inline-size: 100%;
28
41
  min-width: var(--step-progress-min-width);
29
42
  }
30
43
 
@@ -217,8 +217,10 @@
217
217
  each pip is a positioned child with semantic color. */
218
218
  :scope > [data-badge] {
219
219
  position: absolute;
220
- top: -4px;
221
- right: -4px;
220
+ /* Inside the tile's corner (gh#1086) — the old -4px offsets hung the
221
+ pips outside the host box, reading as misplaced chrome. */
222
+ top: 2px;
223
+ right: 2px;
222
224
  display: inline-flex;
223
225
  align-items: center;
224
226
  gap: 2px;
@@ -316,13 +318,19 @@
316
318
  transition: box-shadow var(--a-duration-fast) var(--a-easing-out);
317
319
  }
318
320
  :scope[selectable]:focus { outline: none; }
321
+ /* Focus keeps an OUTER host ring — a11y wants focus visible beyond the
322
+ element's own silhouette. */
319
323
  :scope[selectable]:focus-visible {
320
324
  box-shadow: 0 0 0 var(--swatch-select-ring-width) var(--swatch-select-ring);
321
325
  }
322
- :scope[selected] {
323
- box-shadow: 0 0 0 var(--swatch-select-ring-width) var(--swatch-select-ring);
326
+ /* Selection + hover rings draw INSET on the tile itself (gh#1086): the
327
+ ring follows the tile's real shape (round for dots, square radius for
328
+ tiles) and the outer silhouette stays identical selected vs not — the
329
+ old outer host ring visually inflated dot swatches by 2px. */
330
+ :scope[selected] > [data-tile] {
331
+ box-shadow: inset 0 0 0 var(--swatch-select-ring-width) var(--swatch-select-ring);
324
332
  }
325
- :scope[selectable]:hover:not([selected]) {
326
- box-shadow: 0 0 0 1px color-mix(in oklab, var(--swatch-select-ring) 50%, transparent);
333
+ :scope[selectable]:hover:not([selected]) > [data-tile] {
334
+ box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--swatch-select-ring) 50%, transparent);
327
335
  }
328
336
  }
@@ -11,8 +11,8 @@
11
11
  ```html
12
12
  <row-ui gap="6" align="start" wrap>
13
13
  <col-ui gap="2">
14
- <text-ui variant="caption" color="muted">verse</text-ui>
15
- <div verse>
14
+ <text-ui variant="caption" color="muted">scale="ui-sm"</text-ui>
15
+ <div scale="ui-sm">
16
16
  <switch-ui label="Enabled" checked></switch-ui>
17
17
  </div>
18
18
  </col-ui>
@@ -23,8 +23,8 @@
23
23
  </div>
24
24
  </col-ui>
25
25
  <col-ui gap="2">
26
- <text-ui variant="caption" color="muted">prose</text-ui>
27
- <div prose>
26
+ <text-ui variant="caption" color="muted">scale="content-md"</text-ui>
27
+ <div scale="content-md">
28
28
  <switch-ui label="Enabled" checked></switch-ui>
29
29
  </div>
30
30
  </col-ui>
@@ -282,10 +282,18 @@ registerCellType('progress', {
282
282
  wrapper = document.createElement('row-ui');
283
283
  wrapper.setAttribute('gap', '2');
284
284
  wrapper.setAttribute('align', 'center');
285
+ // The gridcell is a flex container; without an explicit flex the
286
+ // wrapper shrinks to content — and a progress bar has no intrinsic
287
+ // width, so the whole cell collapsed to ~33px and the value span
288
+ // ellipsized to "7.." (gh#940). Fill the cell; keep the numeric
289
+ // label un-shrinkable so the BAR absorbs the flexing instead.
290
+ wrapper.style.flex = '1';
291
+ wrapper.style.minWidth = '0';
285
292
  const prog = document.createElement('progress-ui');
286
293
  prog.setAttribute('size', 'sm');
287
294
  prog.style.flex = '1';
288
295
  const span = document.createElement('span');
296
+ span.style.flexShrink = '0';
289
297
  wrapper.appendChild(prog);
290
298
  wrapper.appendChild(span);
291
299
  cell.appendChild(wrapper);
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "properties": {
16
16
  "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\">).",
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.",
18
18
  "$ref": "common_types.json#/$defs/DynamicStringList"
19
19
  },
20
20
  "component": {
@@ -432,6 +432,17 @@ export class UITable extends UIElement {
432
432
  const flex = el.getAttribute('flex');
433
433
  if (flex) col.flex = Number(flex);
434
434
 
435
+ /* gh#925 — cell-type meta (e.g. the badge type's per-value variant
436
+ map, currency's currency code) had no declarative form: columns[]
437
+ carries `meta` but col-def never parsed it, so a static-HTML badge
438
+ column was structurally stuck at the unmapped tone="muted"
439
+ fallback. JSON attribute, same silent-on-malformed discipline as
440
+ the host's `data` attribute (gh#288). */
441
+ const meta = el.getAttribute('meta');
442
+ if (meta) {
443
+ try { col.meta = JSON.parse(meta); } catch (_) { /* malformed JSON — ignored */ }
444
+ }
445
+
435
446
  cols.push(col);
436
447
  el.remove();
437
448
  }
@@ -313,8 +313,17 @@
313
313
  white-space: nowrap;
314
314
  }
315
315
 
316
+ /* Must match the span/a rule above: without flex:1, row-ui (a flex
317
+ child with default flex:0 1 auto) sizes to its own shrink-to-fit
318
+ content instead of filling the cell — avatar/progress composite
319
+ types then split that tiny intrinsic width between their
320
+ progress-ui/avatar-ui and label span, clipping the label (gh#940:
321
+ stock "71%" rendered as "7.."). Generalizes the per-renderer inline
322
+ flex fix from PR #945 to every composite cell type; adopted from
323
+ PR #943's analysis. */
316
324
  [data-body] [role="gridcell"] > row-ui {
317
325
  min-width: 0;
326
+ flex: 1;
318
327
  overflow: hidden;
319
328
  }
320
329
 
@@ -86,7 +86,7 @@ export interface TableSortEventDetail {
86
86
  export type TableSortEvent = CustomEvent<TableSortEventDetail>;
87
87
 
88
88
  export class UITable extends UIElement {
89
- /** 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">). */
89
+ /** 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. */
90
90
  columns: string;
91
91
  /** JS property (set programmatically — `el.data = [...]`) — row records, an array of plain objects keyed to columns[].key. May also be supplied declaratively as a JSON-array `data="[…]"` attribute, hydrated once at connect (gh#288) — the same pattern chart-ui's `data` attribute uses. Custom accessor on the element class, not a reflected attribute. */
92
92
  data: string;
@@ -20,7 +20,7 @@ composes:
20
20
  - badge-ui
21
21
  props:
22
22
  columns:
23
- 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">).
23
+ 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.
24
24
  type: array
25
25
  default: []
26
26
  dynamic: true # JS-set collection prop with a custom setter — deliberately not in static properties
@@ -39,6 +39,13 @@
39
39
  [data-toolbar] {
40
40
  display: flex;
41
41
  flex-direction: row;
42
+ /* gh#1076 — narrow containers WRAP the clusters to a new row instead of
43
+ crushing them into each other: the fixed-size control clusters
44
+ (flex 0 0 auto) never shrink, so without wrap all pressure landed on
45
+ [data-search] (min-width:0 → collapsed to 0px, measured live) while
46
+ neighbors painted over the gap. */
47
+ flex-wrap: wrap;
48
+ row-gap: var(--table-toolbar-cluster-gap);
42
49
  align-items: center;
43
50
  gap: var(--table-toolbar-gap);
44
51
  padding: var(--table-toolbar-py) var(--table-toolbar-px);
@@ -95,7 +102,9 @@
95
102
 
96
103
  [data-search] {
97
104
  flex: 1 1 var(--table-toolbar-search-min);
98
- min-width: 0;
105
+ /* gh#1076 — never collapse to 0: floor at a usable width and let the
106
+ flex-wrap above move it to its own row when the container is tight. */
107
+ min-width: min(10rem, 100%);
99
108
  max-width: var(--table-toolbar-search-max);
100
109
  margin-inline-start: auto;
101
110
  }