@adia-ai/web-components 0.8.32 → 0.8.33

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 (70) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/MIGRATION.md +136 -0
  3. package/components/accordion/accordion-item.a2ui.json +8 -0
  4. package/components/accordion/accordion-item.yaml +6 -0
  5. package/components/accordion/accordion.css +3 -1
  6. package/components/alert/alert.a2ui.json +3 -5
  7. package/components/alert/alert.class.js +3 -3
  8. package/components/alert/alert.css +5 -12
  9. package/components/alert/alert.d.ts +2 -2
  10. package/components/alert/alert.yaml +6 -5
  11. package/components/badge/badge.a2ui.json +6 -9
  12. package/components/badge/badge.class.js +4 -4
  13. package/components/badge/badge.css +105 -73
  14. package/components/badge/badge.d.ts +34 -12
  15. package/components/badge/badge.examples.md +1 -1
  16. package/components/badge/badge.yaml +37 -16
  17. package/components/button/button.a2ui.json +1 -1
  18. package/components/button/button.css +4 -2
  19. package/components/button/button.d.ts +2 -2
  20. package/components/button/button.yaml +1 -1
  21. package/components/card/card.yaml +1 -1
  22. package/components/chart/chart.class.js +8 -4
  23. package/components/integration-card/integration-card.class.js +11 -2
  24. package/components/mark/mark.a2ui.json +6 -7
  25. package/components/mark/mark.class.js +1 -1
  26. package/components/mark/mark.css +7 -4
  27. package/components/mark/mark.d.ts +2 -2
  28. package/components/mark/mark.examples.md +0 -4
  29. package/components/mark/mark.yaml +16 -6
  30. package/components/option-card/option-card.examples.md +1 -1
  31. package/components/popover/popover.a2ui.json +5 -0
  32. package/components/popover/popover.class.js +9 -4
  33. package/components/popover/popover.css +5 -2
  34. package/components/popover/popover.yaml +8 -0
  35. package/components/preview/preview.examples.md +1 -1
  36. package/components/table/cell-types.js +12 -1
  37. package/components/table-toolbar/table-toolbar.class.js +1 -1
  38. package/components/tag/tag.a2ui.json +5 -5
  39. package/components/tag/tag.class.js +1 -1
  40. package/components/tag/tag.css +86 -73
  41. package/components/tag/tag.d.ts +17 -11
  42. package/components/tag/tag.yaml +30 -19
  43. package/components/toast/toast.a2ui.json +2 -4
  44. package/components/toast/toast.css +0 -12
  45. package/components/toast/toast.yaml +3 -4
  46. package/dist/theme-provider.min.js +1 -1
  47. package/dist/web-components.min.css +1 -1
  48. package/dist/web-components.min.js +63 -63
  49. package/dist/web-components.sheet.js +1 -1
  50. package/package.json +1 -1
  51. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +1 -1
  52. package/patterns/agent-memory/agent-memory.examples.html +5 -5
  53. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +2 -2
  54. package/patterns/audit-log/audit-log.examples.js +12 -5
  55. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +4 -1
  56. package/patterns/changelog-feed/changelog-feed.examples.html +1 -1
  57. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +1 -1
  58. package/patterns/conversion-funnel/conversion-funnel.examples.html +1 -1
  59. package/patterns/diff-review/diff-review.examples.html +9 -9
  60. package/patterns/filter-bar/filter-bar.examples.html +12 -8
  61. package/patterns/filter-bar/filter-bar.examples.js +4 -1
  62. package/patterns/marketing-engagement/marketing-engagement.examples.html +1 -1
  63. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
  64. package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
  65. package/patterns/permissions-sharing/permissions-sharing.examples.html +1 -1
  66. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +2 -2
  67. package/patterns/record-detail-drawer/record-detail-drawer.examples.html +1 -1
  68. package/patterns/retention-cohort/retention-cohort.examples.html +1 -1
  69. package/patterns/retention-cohort/retention-cohort.examples.js +4 -1
  70. package/patterns/system-banners/system-banners.examples.html +3 -3
@@ -42,10 +42,6 @@
42
42
  <mark-ui variant="danger">danger</mark-ui>
43
43
  — removed line, conflict.
44
44
  </text-ui>
45
- <text-ui>
46
- <mark-ui variant="muted">muted</mark-ui>
47
- — neutral emphasis.
48
- </text-ui>
49
45
  </col-ui>
50
46
  ```
51
47
 
@@ -17,7 +17,14 @@ description: |
17
17
  background highlight behind the matched span.
18
18
  props:
19
19
  variant:
20
- description: Highlight color variant. Default `warning` is the conventional yellow-marker tone.
20
+ description: >-
21
+ Highlight color family — the only color axis mark exposes. Default
22
+ `warning` is the conventional yellow-marker tone and IS mark's
23
+ family-less identity, so there is no `default` member. For a
24
+ neutral (non-semantic) highlight, override the public tokens
25
+ instead of the variant: `--mark-bg: var(--a-bg-muted);
26
+ --mark-fg: var(--md-sys-color-neutral-on-surface)` — the successor
27
+ to the retired `variant="muted"` (gh#881).
21
28
  type: string
22
29
  default: warning
23
30
  enum:
@@ -25,7 +32,6 @@ props:
25
32
  - info
26
33
  - success
27
34
  - danger
28
- - muted
29
35
  reflect: true
30
36
  events: {}
31
37
  slots:
@@ -37,11 +43,15 @@ states:
37
43
  traits: []
38
44
  tokens:
39
45
  --mark-bg:
40
- description: Background color of the highlight.
41
- default: var(--a-warning-muted)
46
+ description: >-
47
+ Background color of the highlight. Override for a non-semantic
48
+ (e.g. neutral) highlight — see [variant].
49
+ default: var(--md-sys-color-warning-container)
42
50
  --mark-fg:
43
- description: Foreground (text) color inside the highlight.
44
- default: var(--a-warning-text)
51
+ description: >-
52
+ Foreground (text) color inside the highlight. Pair every [--mark-bg]
53
+ override with a matching fg so contrast holds in both schemes.
54
+ default: var(--md-sys-color-warning-on-surface)
45
55
  --mark-px:
46
56
  description: Horizontal padding around the highlighted text.
47
57
  default: var(--a-space-0-5)
@@ -24,7 +24,7 @@
24
24
  <span slot="heading">
25
25
  Pro
26
26
  <text-ui color="subtle" size="sm">· $49/mo</text-ui>
27
- <badge-ui text="14-day trial" variant="accent"></badge-ui>
27
+ <badge-ui text="14-day trial" variant="primary"></badge-ui>
28
28
  </span>
29
29
  </option-card-ui>
30
30
  <option-card-ui name="demo-plan" value="team" description="Everything in Pro · SSO · audit log · 1 TB storage">
@@ -21,6 +21,11 @@
21
21
  "type": "number",
22
22
  "default": 4
23
23
  },
24
+ "match-width": {
25
+ "description": "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.",
26
+ "type": "boolean",
27
+ "default": false
28
+ },
24
29
  "open": {
25
30
  "description": "Controls visibility via showPopover()/hidePopover()",
26
31
  "type": "boolean",
@@ -24,6 +24,9 @@
24
24
  * (see @core/anchor.js).
25
25
  *
26
26
  * Triggers: click | hover | manual. ESC closes click/manual popovers.
27
+ *
28
+ * Set [match-width] to size the panel to the trigger's width instead of
29
+ * max-content (opt-in — see @core/anchor.js's `matchWidth` option).
27
30
  */
28
31
 
29
32
  import { UIElement } from '../../core/element.js';
@@ -33,10 +36,11 @@ const HOVER_CLOSE_DELAY = 120;
33
36
 
34
37
  export class UIPopover extends UIElement {
35
38
  static properties = {
36
- placement: { type: String, default: 'bottom', reflect: true },
37
- gap: { type: Number, default: 4, reflect: true },
38
- open: { type: Boolean, default: false, reflect: true },
39
- trigger: { type: String, default: 'click', reflect: true },
39
+ placement: { type: String, default: 'bottom', reflect: true },
40
+ gap: { type: Number, default: 4, reflect: true },
41
+ open: { type: Boolean, default: false, reflect: true },
42
+ trigger: { type: String, default: 'click', reflect: true },
43
+ matchWidth: { type: Boolean, default: false, reflect: true, attribute: 'match-width' },
40
44
  };
41
45
 
42
46
  static template = () => null;
@@ -104,6 +108,7 @@ export class UIPopover extends UIElement {
104
108
  this.#anchorCleanup = anchorPopover(trigger, content, {
105
109
  placement: this.placement,
106
110
  gap: this.gap,
111
+ matchWidth: this.matchWidth,
107
112
  });
108
113
 
109
114
  if (this.trigger === 'click' || this.trigger === 'manual') {
@@ -12,9 +12,12 @@
12
12
  mode (dimmer = neutral-925, darker than the neutral-875 page it floats
13
13
  over — the panel read near-black). Matches select-ui's own dropdown
14
14
  surface exactly, so the two overlays on a shell's topbar (a select
15
- menu and a popover panel) sit on one plane. */
15
+ menu and a popover panel) sit on one plane. Border matches too
16
+ (gh#857) — `--a-ui-border` (→ outline), same token select-ui's
17
+ `[slot="listbox"]` uses, not outline-variant (that's for internal
18
+ dividers — separators, group rules — a different role). */
16
19
  --popover-bg: var(--md-sys-color-neutral-surface-bright);
17
- --popover-border: var(--md-sys-color-neutral-outline-variant);
20
+ --popover-border: var(--a-ui-border);
18
21
  --popover-shadow: var(--a-shadow-lg);
19
22
  }
20
23
 
@@ -13,6 +13,14 @@ props:
13
13
  description: Pixel offset between the anchor and the popover
14
14
  type: number
15
15
  default: 4
16
+ match-width:
17
+ description: >-
18
+ Size the content panel to the trigger's width instead of
19
+ max-content. Opt-in — the default (unset) keeps every existing
20
+ consumer's content-sized panel unchanged.
21
+ type: boolean
22
+ default: false
23
+ reflect: true
16
24
  open:
17
25
  description: Controls visibility via showPopover()/hidePopover()
18
26
  type: boolean
@@ -13,7 +13,7 @@
13
13
 
14
14
  ```html
15
15
  <preview-ui layout="split">
16
- <badge-ui text="New" variant="accent"></badge-ui>
16
+ <badge-ui text="New" variant="primary"></badge-ui>
17
17
  <badge-ui text="Beta" variant="warning"></badge-ui>
18
18
  <badge-ui text="Stable" variant="success"></badge-ui>
19
19
  </preview-ui>
@@ -173,7 +173,18 @@ registerCellType('badge', {
173
173
  }
174
174
  el.setAttribute('text', String(value ?? ''));
175
175
  const variants = meta?.variants || {};
176
- el.setAttribute('variant', variants[value] || 'neutral');
176
+ const variant = variants[value];
177
+ // Unmapped value → family-less badge, tone="muted" (quiet chrome) —
178
+ // `variant="neutral"` retired (variant/color/tone convention cut,
179
+ // gh#873/874). Element is reused across renders, so both attributes
180
+ // are explicitly set/cleared rather than only ever added.
181
+ if (variant) {
182
+ el.setAttribute('variant', variant);
183
+ el.removeAttribute('tone');
184
+ } else {
185
+ el.removeAttribute('variant');
186
+ el.setAttribute('tone', 'muted');
187
+ }
177
188
  },
178
189
  format(value) {
179
190
  return String(value ?? '');
@@ -272,7 +272,7 @@ export class UITableToolbar extends UIElement {
272
272
  const badge = document.createElement('badge-ui');
273
273
  badge.setAttribute('data-count-badge', '');
274
274
  badge.setAttribute('size', 'sm');
275
- badge.setAttribute('variant', 'muted');
275
+ badge.setAttribute('tone', 'muted');
276
276
  badge.hidden = true;
277
277
  title.appendChild(badge);
278
278
 
@@ -46,25 +46,25 @@
46
46
  "$ref": "common_types.json#/$defs/DynamicString"
47
47
  },
48
48
  "tone": {
49
- "description": "Fill style — orthogonal to [variant]. Three values:\n - `solid` (default for EVERY variant, including the family-less\n `default`, since gh#794) saturated bg + on-strong (near-white)\n text. The chip IS the state. A bare `<tag-ui text=\"…\">` renders\n this look with no attributes at all.\n - `muted` — tinted bg with scheme-paired text. Matches <badge-ui>'s\n default look, and is the pre-gh#794 look for the family-less\n `default` variant. Use on metadata / citation chips in dense\n lists or tables where the saturated default would compete for\n attention (gh#778's oversized-pill concern).\n - `outline` — transparent bg + family-colored border + family-colored\n text. The lightest visual weight; good in dense data tables or\n faceted filter rows where multiple chips would otherwise compete.\n`tone` is a declarative presentational attribute (not a reactive\nprop — see tag.class.js) so its schema `default` here is documentation\nof the rendered-by-default look, not a reflected attribute value.\n",
49
+ "description": "Fill style — orthogonal to [variant]. Three values:\n - `muted` (default for the family variants info/success/warning/\n danger/primary gh#864: tag and badge were swapped relative to\n their reported default formulas; this restores tag's own)\n — tinted bg with scheme-paired text. Matches <badge-ui>'s\n `[tone=\"muted\"]` look. Use on metadata / citation chips in dense\n lists or tables where a saturated fill would compete for\n attention (gh#778's oversized-pill concern). Does NOT apply to\n the family-less `default` variant, which stays solid\n unconditionally (gh#794, unaffected by gh#864) — a bare\n `<tag-ui text=\"…\">` still renders that solid look with no\n attributes at all.\n - `solid` — saturated bg + on-strong (near-white) text. The chip\n IS the state. Opt in explicitly for a family variant (gh#864),\n or it's already the unconditional look for the family-less\n `default` variant (gh#794).\n - `outline` — transparent bg + family-colored border + family-colored\n text. The lightest visual weight; good in dense data tables or\n faceted filter rows where multiple chips would otherwise compete.\n`tone` is a declarative presentational attribute (not a reactive\nprop — see tag.class.js) so its schema `default` here is documentation\nof the rendered-by-default look, not a reflected attribute value.\n",
50
50
  "type": "string",
51
51
  "enum": [
52
52
  "solid",
53
53
  "muted",
54
54
  "outline"
55
55
  ],
56
- "default": "solid"
56
+ "default": "muted"
57
57
  },
58
58
  "variant": {
59
- "description": "Semantic variant — `default | accent | info | success | warning | danger`. `accent` is brand-primary emphasis for non-semantic labels — a filter chip or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors <badge-ui>'s `accent` variant token-for-token.",
59
+ "description": "Semantic variant — `default | info | success | warning | danger | primary`. `primary` is brand emphasis for non-semantic labels — a filter chip or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors <badge-ui>'s `primary` variant token-for-token (`accent` retired, gh#874 — the capability survives renamed, sibling parity with badge preserved).",
60
60
  "type": "string",
61
61
  "enum": [
62
62
  "default",
63
- "accent",
64
63
  "info",
65
64
  "success",
66
65
  "warning",
67
- "danger"
66
+ "danger",
67
+ "primary"
68
68
  ],
69
69
  "default": "default"
70
70
  }
@@ -17,7 +17,7 @@
17
17
  * Inline tag / chip. Pill-shaped, text rendered via CSS attr().
18
18
  * Optional dismiss button dispatches a 'remove' CustomEvent.
19
19
  *
20
- * Variants: default, info, success, warning, danger
20
+ * Variants: default, info, success, warning, danger, primary
21
21
  * Sizes: sm, md (default)
22
22
  *
23
23
  * Events:
@@ -14,13 +14,17 @@ tag-ui[removable]:not([disabled]):hover {
14
14
  default at construction time. A bare `<tag-ui text="…">` therefore
15
15
  never gets a physical `variant="default"` attribute; these
16
16
  `:where(:scope)` zero-specificity tokens are what it actually
17
- renders. Solid neutral inverse (was `--a-bg-muted` quiet chrome
18
- pre-#794) — same pair the family variants and the redundant
17
+ renders. Solid neutral (was `--a-bg-muted` quiet chrome pre-#794)
18
+ — same pair the family variants and the redundant
19
19
  `:scope[variant="default"]` rule below carry, for the rare case
20
20
  `variant="default"` IS reflected explicitly (SSR/a2ui-producer
21
- markup). Opt out via `[tone="muted"]`. */
22
- --tag-bg: var(--md-sys-color-neutral-on-surface);
23
- --tag-fg: var(--md-sys-color-neutral-background);
21
+ markup). Opt out via `[tone="muted"]`. Uses the real
22
+ `--md-sys-color-neutral`/`-on-neutral` pair (operator ruling,
23
+ 2026-08-10) — the true parallel to `-primary`/`-on-primary` etc.,
24
+ not the `-on-surface`/`-background` ink/page tokens this rule
25
+ borrowed pre-#794's cross-check. */
26
+ --tag-bg: var(--md-sys-color-neutral);
27
+ --tag-fg: var(--md-sys-color-neutral-on-neutral);
24
28
  --tag-border: transparent;
25
29
  --tag-radius: var(--a-radius-full);
26
30
  --tag-px: var(--a-space-1-5);
@@ -122,85 +126,94 @@ tag-ui[removable]:not([disabled]):hover {
122
126
  }
123
127
 
124
128
  /* ── Variants ──
125
- Default tone is `solid` for the four family variants:
126
- `--a-{family}-bg` (saturated surface) + `--a-{family}-fg` (on-strong
127
- text, near-white in both schemes by design). Reads as a status pill
128
- where the chip IS the state. Opt out per-tag via [tone="muted"] for
129
- metadata-chip surfaces in dense lists. */
130
- /* `accent` is brand-primary emphasis for non-semantic labelsmirrors
131
- <badge-ui>'s `accent` variant token-for-token (--a-primary-bg /
132
- on-primary for the solid fill), applied to tag-ui's own solid-default
133
- tone shape. Not a status color no success/warning/danger implication. */
134
- :scope[variant="accent"] {
135
- --tag-bg: var(--a-primary-bg);
136
- --tag-fg: var(--md-sys-color-primary-on-primary);
129
+ Default tone is `muted` for the family variants (gh#864): the
130
+ tinted-container pair `--md-sys-color-{family}-container` (tinted
131
+ surface) + `-on-surface` (scheme-flipping text). Tag and badge had
132
+ been implementing each OTHER's reported default formula (gh#794
133
+ flipped tag's bare default to solid a day before gh#845 ratified
134
+ badge's register, with no cross-check between the two changes)this
135
+ restores tag's own. Opt into the saturated stamp per-tag via
136
+ [tone="solid"] below. This does NOT touch the family-less `default`
137
+ variant below, which stays solid unconditionally (gh#794, unrelated
138
+ to the gh#864 swap). */
139
+ /* `primary` is brand emphasis for non-semantic labels — mirrors
140
+ <badge-ui>'s `primary` variant token-for-token (--md-sys-color-primary-
141
+ container / -on-surface for the tinted fill; `accent` retired, gh#874).
142
+ Not a status color — no success/warning/danger implication. */
143
+ :scope[variant="primary"] {
144
+ --tag-bg: var(--md-sys-color-primary-container);
145
+ --tag-fg: var(--md-sys-color-primary-on-surface);
137
146
  }
138
147
 
139
148
  :scope[variant="info"] {
140
- --tag-bg: var(--a-info-bg);
141
- --tag-fg: var(--md-sys-color-info-on-info);
149
+ --tag-bg: var(--md-sys-color-info-container);
150
+ --tag-fg: var(--md-sys-color-info-on-surface);
142
151
  }
143
152
 
144
153
  :scope[variant="success"] {
145
- --tag-bg: var(--a-success-bg);
146
- --tag-fg: var(--md-sys-color-success-on-success);
154
+ --tag-bg: var(--md-sys-color-success-container);
155
+ --tag-fg: var(--md-sys-color-success-on-surface);
147
156
  }
148
157
 
149
- /* Same shape as the sibling families since the Material static-token
150
- migration: amber fill + the palette's own fixed-light on-color
151
- (`on-warning`, white in both schemes per Material's on-color law).
152
- The pre-migration dark-brown-text override is gone — its
153
- lower-than-siblings contrast is a known, operator-accepted
154
- consequence (TKT-0018, wontfix pending palette adjustment). */
155
158
  :scope[variant="warning"] {
156
- --tag-bg: var(--a-warning-bg);
157
- --tag-fg: var(--md-sys-color-warning-on-warning);
159
+ --tag-bg: var(--md-sys-color-warning-container);
160
+ --tag-fg: var(--md-sys-color-warning-on-surface);
158
161
  }
159
162
 
160
163
  :scope[variant="danger"] {
161
- --tag-bg: var(--a-danger-bg);
162
- --tag-fg: var(--md-sys-color-danger-on-danger);
164
+ --tag-bg: var(--md-sys-color-danger-container);
165
+ --tag-fg: var(--md-sys-color-danger-on-surface);
163
166
  }
164
167
 
165
168
  /* `default` (no family) is solid by default (gh#794) — the same
166
- high-contrast neutral inverse the family variants already carry.
167
- A bare `<tag-ui text="…">` is now a stamped pill, not quiet chrome.
168
- Opt OUT to the pre-#794 quiet-chrome look via `[tone="muted"]`
169
- (below) on metadata/citation chips in dense lists or tables where
170
- the saturated look competes for attention (gh#778's oversized-pill
171
- complaint) same escape hatch the family variants already use. */
169
+ high-contrast neutral inverse it has always carried. A bare
170
+ `<tag-ui text="…">` is a stamped pill, not quiet chrome. Unaffected by
171
+ the gh#864 family-variant swap above. Opt OUT to the pre-#794 quiet-
172
+ chrome look via `[tone="muted"]` (below) on metadata/citation chips
173
+ in dense lists or tables where the saturated look competes for
174
+ attention (gh#778's oversized-pill complaint). */
172
175
  :scope[variant="default"] {
173
- --tag-bg: var(--md-sys-color-neutral-on-surface);
174
- --tag-fg: var(--md-sys-color-neutral-background);
176
+ --tag-bg: var(--md-sys-color-neutral);
177
+ --tag-fg: var(--md-sys-color-neutral-on-neutral);
175
178
  }
176
179
 
177
180
  /* ── Tone modifier — orthogonal to [variant] ──
178
- `[tone="muted"]` opts each family variant OUT of the solid default
179
- into the canonical muted pair: `--a-{family}-muted` (tinted surface)
180
- + `--a-{family}-text` (scheme-flipping text). Same shape <badge-ui>
181
- uses as its default. Use on metadata chips in dense lists where the
182
- saturated default would compete for attention. */
183
- :scope[tone="muted"][variant="info"] {
184
- --tag-bg: var(--md-sys-color-info-container);
185
- --tag-fg: var(--md-sys-color-info-on-surface);
181
+ `[tone="solid"]` opts each family variant INTO the saturated-fill pair
182
+ (gh#864 this used to be the family variants' unconditional default;
183
+ see the Variants comment above): `--a-{family}-bg` (saturated surface)
184
+ + Material's on-color (`-on-{family}`, near-white by the fixed-light-
185
+ on-color law). Same shape <tag-ui>'s family-less `default` variant
186
+ still carries unconditionally. Use for a single hero tag that should
187
+ stamp its state.
188
+
189
+ Warning uses --a-warning-bg (semantics.css L3 redirect to the bright-
190
+ amber -20-tint) rather than the raw family token — see also
191
+ <badge-ui>'s identical workaround. */
192
+ :scope[tone="solid"][variant="info"] {
193
+ --tag-bg: var(--a-info-bg);
194
+ --tag-fg: var(--md-sys-color-info-on-info);
186
195
  }
187
- :scope[tone="muted"][variant="success"] {
188
- --tag-bg: var(--md-sys-color-success-container);
189
- --tag-fg: var(--md-sys-color-success-on-surface);
196
+ :scope[tone="solid"][variant="success"] {
197
+ --tag-bg: var(--a-success-bg);
198
+ --tag-fg: var(--md-sys-color-success-on-success);
190
199
  }
191
- :scope[tone="muted"][variant="warning"] {
192
- --tag-bg: var(--md-sys-color-warning-container);
193
- --tag-fg: var(--md-sys-color-warning-on-surface);
200
+ /* Same shape as the sibling families since the Material static-token
201
+ migration: amber fill + the palette's own fixed-light on-color
202
+ (`on-warning`, white in both schemes per Material's on-color law).
203
+ The pre-migration dark-brown-text override is gone — its
204
+ lower-than-siblings contrast is a known, operator-accepted
205
+ consequence (TKT-0018, wontfix pending palette adjustment). */
206
+ :scope[tone="solid"][variant="warning"] {
207
+ --tag-bg: var(--a-warning-bg);
208
+ --tag-fg: var(--md-sys-color-warning-on-warning);
194
209
  }
195
- :scope[tone="muted"][variant="danger"] {
196
- --tag-bg: var(--md-sys-color-danger-container);
197
- --tag-fg: var(--md-sys-color-danger-on-surface);
210
+ :scope[tone="solid"][variant="danger"] {
211
+ --tag-bg: var(--a-danger-bg);
212
+ --tag-fg: var(--md-sys-color-danger-on-danger);
198
213
  }
199
- /* Mirrors <badge-ui>'s default (muted) accent pair —
200
- --md-sys-color-primary-container / -on-surface. */
201
- :scope[tone="muted"][variant="accent"] {
202
- --tag-bg: var(--md-sys-color-primary-container);
203
- --tag-fg: var(--md-sys-color-primary-on-surface);
214
+ :scope[tone="solid"][variant="primary"] {
215
+ --tag-bg: var(--a-primary-bg);
216
+ --tag-fg: var(--md-sys-color-primary-on-primary);
204
217
  }
205
218
  /* gh#794: the pre-#794 quiet-chrome look for the variant-less default —
206
219
  same values the `:where(:scope)` base tokens carried before the
@@ -213,7 +226,7 @@ tag-ui[removable]:not([disabled]):hover {
213
226
  `installProps()` reflect() path only fires on a property SET) —
214
227
  the same reason the `[tone="solid"]` fallback below uses this same
215
228
  `:not()` shape instead of `[variant="default"]`. */
216
- :scope[tone="muted"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]) {
229
+ :scope[tone="muted"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="primary"]) {
217
230
  --tag-bg: var(--a-bg-muted);
218
231
  --tag-fg: var(--md-sys-color-neutral-on-surface);
219
232
  }
@@ -222,13 +235,13 @@ tag-ui[removable]:not([disabled]):hover {
222
235
  since gh#794 (the variant-less default is solid unconditionally
223
236
  above) but kept so `tone="solid"` stays a valid, harmless, explicit
224
237
  statement of intent for consumers who set it directly.
225
- [variant="accent"] is excluded — it already has an explicit solid
226
- pair above (the plain [variant="accent"] rule) that this higher-
227
- specificity fallback would otherwise clobber when tone="solid" is
228
- set explicitly alongside it. */
229
- :scope[tone="solid"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]) {
230
- --tag-bg: var(--md-sys-color-neutral-on-surface);
231
- --tag-fg: var(--md-sys-color-neutral-background);
238
+ [variant="primary"] is excluded — its solid pair is the explicit
239
+ `[tone="solid"][variant="primary"]` rule above (gh#864: the bare
240
+ `[variant="primary"]` rule is container-tinted now, not solid) — this
241
+ `:not()` keeps the neutral-only fallback from ever matching primary. */
242
+ :scope[tone="solid"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="primary"]) {
243
+ --tag-bg: var(--md-sys-color-neutral);
244
+ --tag-fg: var(--md-sys-color-neutral-on-neutral);
232
245
  }
233
246
 
234
247
  /* ── `[tone="outline"]` — transparent bg + family-colored border + text ──
@@ -255,15 +268,15 @@ tag-ui[removable]:not([disabled]):hover {
255
268
  --tag-fg: var(--md-sys-color-danger-on-surface);
256
269
  --tag-border: var(--md-sys-color-danger-outline);
257
270
  }
258
- /* Mirrors <badge-ui>'s outline accent pair —
271
+ /* Mirrors <badge-ui>'s outline primary pair —
259
272
  --md-sys-color-primary-on-surface / -primary-outline. */
260
- :scope[tone="outline"][variant="accent"] {
273
+ :scope[tone="outline"][variant="primary"] {
261
274
  --tag-fg: var(--md-sys-color-primary-on-surface);
262
275
  --tag-border: var(--md-sys-color-primary-outline);
263
276
  }
264
277
  /* Outline on neutral (no family) — fg-muted text + subtle border.
265
- [variant="accent"] excluded — see the [tone="solid"] fallback note above. */
266
- :scope[tone="outline"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]) {
278
+ [variant="primary"] excluded — see the [tone="solid"] fallback note above. */
279
+ :scope[tone="outline"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="primary"]) {
267
280
  --tag-fg: var(--a-fg-muted);
268
281
  --tag-border: var(--md-sys-color-neutral-outline);
269
282
  }
@@ -41,15 +41,21 @@ export class UITag extends UIElement {
41
41
  /** Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after. */
42
42
  textContent: string;
43
43
  /** Fill style — orthogonal to [variant]. Three values:
44
- - `solid` (default for EVERY variant, including the family-less
45
- `default`, since gh#794) saturated bg + on-strong (near-white)
46
- text. The chip IS the state. A bare `<tag-ui text="…">` renders
47
- this look with no attributes at all.
48
- - `muted` tinted bg with scheme-paired text. Matches <badge-ui>'s
49
- default look, and is the pre-gh#794 look for the family-less
50
- `default` variant. Use on metadata / citation chips in dense
51
- lists or tables where the saturated default would compete for
52
- attention (gh#778's oversized-pill concern).
44
+ - `muted` (default for the family variants info/success/warning/
45
+ danger/primary gh#864: tag and badge were swapped relative to
46
+ their reported default formulas; this restores tag's own)
47
+ tinted bg with scheme-paired text. Matches <badge-ui>'s
48
+ `[tone="muted"]` look. Use on metadata / citation chips in dense
49
+ lists or tables where a saturated fill would compete for
50
+ attention (gh#778's oversized-pill concern). Does NOT apply to
51
+ the family-less `default` variant, which stays solid
52
+ unconditionally (gh#794, unaffected by gh#864) — a bare
53
+ `<tag-ui text="…">` still renders that solid look with no
54
+ attributes at all.
55
+ - `solid` — saturated bg + on-strong (near-white) text. The chip
56
+ IS the state. Opt in explicitly for a family variant (gh#864),
57
+ or it's already the unconditional look for the family-less
58
+ `default` variant (gh#794).
53
59
  - `outline` — transparent bg + family-colored border + family-colored
54
60
  text. The lightest visual weight; good in dense data tables or
55
61
  faceted filter rows where multiple chips would otherwise compete.
@@ -58,8 +64,8 @@ prop — see tag.class.js) so its schema `default` here is documentation
58
64
  of the rendered-by-default look, not a reflected attribute value.
59
65
  */
60
66
  tone: 'solid' | 'muted' | 'outline';
61
- /** Semantic variant — `default | accent | info | success | warning | danger`. `accent` is brand-primary emphasis for non-semantic labels — a filter chip or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors <badge-ui>'s `accent` variant token-for-token. */
62
- variant: 'default' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
67
+ /** Semantic variant — `default | info | success | warning | danger | primary`. `primary` is brand emphasis for non-semantic labels — a filter chip or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors <badge-ui>'s `primary` variant token-for-token (`accent` retired, gh#874 — the capability survives renamed, sibling parity with badge preserved). */
68
+ variant: 'default' | 'info' | 'success' | 'warning' | 'danger' | 'primary';
63
69
 
64
70
  addEventListener(type: 'remove', listener: (ev: TagRemoveEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
65
71
  addEventListener<K extends keyof HTMLElementEventMap>(
@@ -46,31 +46,38 @@ props:
46
46
  type: string
47
47
  dynamic: true
48
48
  variant:
49
- description: Semantic variant — `default | accent | info | success | warning | danger`.
50
- `accent` is brand-primary emphasis for non-semantic labels — a filter chip
49
+ description: Semantic variant — `default | info | success | warning | danger | primary`.
50
+ `primary` is brand emphasis for non-semantic labels — a filter chip
51
51
  or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors
52
- <badge-ui>'s `accent` variant token-for-token.
52
+ <badge-ui>'s `primary` variant token-for-token (`accent` retired, gh#874 —
53
+ the capability survives renamed, sibling parity with badge preserved).
53
54
  type: string
54
55
  default: default
55
56
  enum:
56
57
  - default
57
- - accent
58
58
  - info
59
59
  - success
60
60
  - warning
61
61
  - danger
62
+ - primary
62
63
  tone:
63
64
  description: |
64
65
  Fill style — orthogonal to [variant]. Three values:
65
- - `solid` (default for EVERY variant, including the family-less
66
- `default`, since gh#794) saturated bg + on-strong (near-white)
67
- text. The chip IS the state. A bare `<tag-ui text="…">` renders
68
- this look with no attributes at all.
69
- - `muted` tinted bg with scheme-paired text. Matches <badge-ui>'s
70
- default look, and is the pre-gh#794 look for the family-less
71
- `default` variant. Use on metadata / citation chips in dense
72
- lists or tables where the saturated default would compete for
73
- attention (gh#778's oversized-pill concern).
66
+ - `muted` (default for the family variants info/success/warning/
67
+ danger/primary gh#864: tag and badge were swapped relative to
68
+ their reported default formulas; this restores tag's own)
69
+ tinted bg with scheme-paired text. Matches <badge-ui>'s
70
+ `[tone="muted"]` look. Use on metadata / citation chips in dense
71
+ lists or tables where a saturated fill would compete for
72
+ attention (gh#778's oversized-pill concern). Does NOT apply to
73
+ the family-less `default` variant, which stays solid
74
+ unconditionally (gh#794, unaffected by gh#864) — a bare
75
+ `<tag-ui text="…">` still renders that solid look with no
76
+ attributes at all.
77
+ - `solid` — saturated bg + on-strong (near-white) text. The chip
78
+ IS the state. Opt in explicitly for a family variant (gh#864),
79
+ or it's already the unconditional look for the family-less
80
+ `default` variant (gh#794).
74
81
  - `outline` — transparent bg + family-colored border + family-colored
75
82
  text. The lightest visual weight; good in dense data tables or
76
83
  faceted filter rows where multiple chips would otherwise compete.
@@ -78,7 +85,7 @@ props:
78
85
  prop — see tag.class.js) so its schema `default` here is documentation
79
86
  of the rendered-by-default look, not a reflected attribute value.
80
87
  type: string
81
- default: solid
88
+ default: muted
82
89
  enum:
83
90
  - solid
84
91
  - muted
@@ -132,12 +139,16 @@ a2ui:
132
139
  vertically; vertical lists of dismissable items are an
133
140
  <action-list-ui> use case, not <tag-ui>.
134
141
  - >-
135
- Bare <tag-ui text="…"> (no [tone]) renders the high-contrast
136
- solid pill by default (gh#794). In dense tables, tight metadata
137
- rows, or citation/footnote strips where many tags sit close
138
- together, set [tone="muted"] to keep the quieter tinted look
139
- instead — a wall of solid pills reads as visual noise there
142
+ A family-less <tag-ui text="…"> (no [variant], no [tone]) renders
143
+ the high-contrast solid pill by default (gh#794). In dense tables,
144
+ tight metadata rows, or citation/footnote strips where many tags
145
+ sit close together, set [tone="muted"] to keep the quieter tinted
146
+ look instead — a wall of solid pills reads as visual noise there
140
147
  (gh#778).
148
+ - >-
149
+ A family [variant] (info/success/warning/danger/primary) with no
150
+ [tone] renders the tinted-container look by default (gh#864). Set
151
+ [tone="solid"] for a saturated status stamp instead.
141
152
  anti_patterns: []
142
153
  examples:
143
154
  - name: basic-tag
@@ -40,7 +40,7 @@
40
40
  "default": ""
41
41
  },
42
42
  "variant": {
43
- "description": "Semantic variant — `default | info | success | warning | danger`. `primary` and `muted` are style hints; canonical \"neutral but interesting\" tone is `info`.",
43
+ "description": "Semantic variant — `default | info | success | warning | danger | primary`. `primary` is the brand-emphasis fill (mirrors badge-ui/button-ui's `primary`); canonical \"neutral but interesting\" tone is `info`.",
44
44
  "type": "string",
45
45
  "enum": [
46
46
  "default",
@@ -48,9 +48,7 @@
48
48
  "success",
49
49
  "warning",
50
50
  "danger",
51
- "primary",
52
- "muted",
53
- "neutral"
51
+ "primary"
54
52
  ],
55
53
  "default": "info"
56
54
  }