@adia-ai/web-components 0.8.9 → 0.8.11

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 (89) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/MIGRATION.md +58 -0
  3. package/USAGE.md +5 -7
  4. package/components/adia-mark/adia-mark.a2ui.json +6 -6
  5. package/components/adia-mark/adia-mark.class.js +1 -1
  6. package/components/adia-mark/adia-mark.css +3 -4
  7. package/components/adia-mark/adia-mark.d.ts +1 -1
  8. package/components/adia-mark/adia-mark.examples.md +0 -2
  9. package/components/adia-mark/adia-mark.test.js +3 -3
  10. package/components/adia-mark/adia-mark.yaml +5 -4
  11. package/components/adia-wordmark/adia-wordmark.a2ui.json +108 -0
  12. package/components/adia-wordmark/adia-wordmark.class.js +60 -0
  13. package/components/adia-wordmark/adia-wordmark.css +45 -0
  14. package/components/adia-wordmark/adia-wordmark.d.ts +20 -0
  15. package/components/adia-wordmark/adia-wordmark.examples.md +23 -0
  16. package/components/adia-wordmark/adia-wordmark.js +17 -0
  17. package/components/adia-wordmark/adia-wordmark.test.js +69 -0
  18. package/components/adia-wordmark/adia-wordmark.yaml +102 -0
  19. package/components/avatar/avatar-group.a2ui.json +1 -1
  20. package/components/avatar/avatar-group.yaml +1 -1
  21. package/components/avatar/avatar.a2ui.json +2 -4
  22. package/components/avatar/avatar.css +16 -12
  23. package/components/avatar/avatar.d.ts +3 -3
  24. package/components/avatar/avatar.examples.md +1 -1
  25. package/components/avatar/avatar.yaml +1 -3
  26. package/components/badge/badge.a2ui.json +2 -4
  27. package/components/badge/badge.d.ts +2 -2
  28. package/components/badge/badge.yaml +1 -3
  29. package/components/button/button.a2ui.json +2 -4
  30. package/components/button/button.d.ts +2 -2
  31. package/components/button/button.yaml +1 -3
  32. package/components/calendar-grid/calendar-grid.class.js +44 -27
  33. package/components/calendar-grid/calendar-grid.css +1 -1
  34. package/components/calendar-picker/calendar-picker.class.js +2 -2
  35. package/components/calendar-picker/calendar-picker.css +1 -1
  36. package/components/card/card.css +1 -1
  37. package/components/chat-thread/chat-input.css +1 -1
  38. package/components/combobox/combobox.class.js +1 -1
  39. package/components/combobox/combobox.css +1 -1
  40. package/components/icon/icon.a2ui.json +1 -1
  41. package/components/icon/icon.class.js +5 -5
  42. package/components/icon/icon.css +7 -15
  43. package/components/icon/icon.d.ts +1 -1
  44. package/components/icon/icon.examples.md +1 -1
  45. package/components/icon/icon.yaml +10 -10
  46. package/components/index.js +1 -0
  47. package/components/input/input.class.js +2 -2
  48. package/components/modal/modal.a2ui.json +2 -3
  49. package/components/modal/modal.d.ts +2 -2
  50. package/components/modal/modal.yaml +1 -2
  51. package/components/select/select.class.js +4 -4
  52. package/components/select/select.css +12 -3
  53. package/components/swatch/swatch.css +1 -1
  54. package/components/switch/switch.a2ui.json +2 -4
  55. package/components/switch/switch.yaml +1 -3
  56. package/components/table/table.yaml +9 -3
  57. package/components/tag/tag.a2ui.json +2 -1
  58. package/components/tag/tag.class.js +1 -1
  59. package/components/tag/tag.css +31 -5
  60. package/components/tag/tag.d.ts +2 -2
  61. package/components/tag/tag.yaml +5 -1
  62. package/components/theme-provider/theme-provider.a2ui.json +11 -1
  63. package/components/theme-provider/theme-provider.class.js +27 -7
  64. package/components/theme-provider/theme-provider.d.ts +2 -2
  65. package/components/theme-provider/theme-provider.yaml +10 -1
  66. package/components/timeline/timeline.css +1 -1
  67. package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -4
  68. package/components/toggle-scheme/toggle-scheme.d.ts +2 -2
  69. package/components/toggle-scheme/toggle-scheme.yaml +1 -3
  70. package/dist/host.min.css +1 -1
  71. package/dist/host.sheet.js +1 -1
  72. package/dist/scale.min.css +1 -0
  73. package/dist/scale.sheet.js +11 -0
  74. package/dist/theme-provider.min.js +8 -8
  75. package/dist/web-components.min.css +1 -1
  76. package/dist/web-components.min.js +94 -86
  77. package/dist/web-components.sheet.js +1 -1
  78. package/package.json +1 -1
  79. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +4 -4
  80. package/patterns/kanban-board/kanban-board.examples.html +8 -8
  81. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +2 -2
  82. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +1 -1
  83. package/patterns/search-discovery/search-discovery.examples.html +4 -4
  84. package/styles/colors/semantics/aliases.css +16 -3
  85. package/styles/colors/semantics/features.css +10 -0
  86. package/styles/components.css +1 -0
  87. package/styles/prose.css +4 -0
  88. package/styles/scale.css +683 -0
  89. package/styles/verse.css +4 -0
@@ -18,19 +18,11 @@
18
18
  height: 100%;
19
19
  }
20
20
 
21
- /* ── Named size scale ─────────────────────────────────────────────
22
- sm/md/lg are also driven by the universal `[size]` token system
23
- on ancestors (tokens.css §SIZE PRESETS) these rules let an
24
- icon-ui set its own size locally. xs / xl / 2xl / 3xl / 4xl
25
- extend the scale beyond the universal range for hero placeholder
26
- contexts. `fill` matches the parent box. */
27
- :scope[size="xs"] { --icon-size: 0.75rem; } /* 12px */
28
- :scope[size="sm"] { --icon-size: 0.875rem; } /* 14px */
29
- :scope[size="md"] { --icon-size: 1rem; } /* 16px */
30
- :scope[size="lg"] { --icon-size: 1.25rem; } /* 20px */
31
- :scope[size="xl"] { --icon-size: 2rem; } /* 32px */
32
- :scope[size="2xl"] { --icon-size: 3rem; } /* 48px */
33
- :scope[size="3xl"] { --icon-size: 4rem; } /* 64px */
34
- :scope[size="4xl"] { --icon-size: 6rem; } /* 96px */
35
- :scope[size="fill"] { --icon-size: 100%; }
21
+ /* ── Size ─────────────────────────────────────────────────────────
22
+ Grid-native: sm/md/lg come from the universal `[size]` token
23
+ system (--a-icon-size), which the ancestor [scale] tiers re-table
24
+ no per-size rules of icon's own. Values beyond the row (hero
25
+ placeholders, fill-the-parent) use the free-form string prop
26
+ (size="48", size="3rem", size="100%"), which sets --icon-size
27
+ inline from icon.class.js. */
36
28
  }
@@ -17,7 +17,7 @@ export class UIIcon extends UIElement {
17
17
  label: string;
18
18
  /** Icon name from registry */
19
19
  name: string;
20
- /** Icon size. Accepts the named scale (`xs` 12px / `sm` 14px / `md` 16px / `lg` 20px / `xl` 32px / `2xl` 48px / `3xl` 64px / `4xl` 96px / `fill` 100% of parent) or a free-form pixel / rem / em value as a string ("48", "3rem", "1.25em"). Overrides the inherited `--a-icon-size` from the universal `[size]` system on ancestors. */
20
+ /** Icon size. Named tiers `sm` 14px / `md` 16px / `lg` 20px ride the universal `[size]` system (`--a-icon-size`), which the ancestor `[scale]` tiers re-table. Anything beyond the row is a free-form pixel / rem / em / percent string ("48", "3rem", "1.25em", "100%" fills the parent box). */
21
21
  size: string;
22
22
  /** Icon weight — selects the Phosphor weight variant (thin/light/regular/bold/fill/duotone). */
23
23
  weight: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
@@ -9,7 +9,7 @@
9
9
  ## size
10
10
 
11
11
  ```html
12
- <icon-ui name="star" size="xs"></icon-ui>
12
+ <icon-ui name="star" size="12"></icon-ui>
13
13
  ```
14
14
 
15
15
  ## label
@@ -24,12 +24,11 @@ props:
24
24
  default: ""
25
25
  size:
26
26
  description: >-
27
- Icon size. Accepts the named scale
28
- (`xs` 12px / `sm` 14px / `md` 16px / `lg` 20px / `xl` 32px /
29
- `2xl` 48px / `3xl` 64px / `4xl` 96px / `fill` 100% of parent)
30
- or a free-form pixel / rem / em value as a string ("48", "3rem",
31
- "1.25em"). Overrides the inherited `--a-icon-size` from the
32
- universal `[size]` system on ancestors.
27
+ Icon size. Named tiers `sm` 14px / `md` 16px / `lg` 20px ride the
28
+ universal `[size]` system (`--a-icon-size`), which the ancestor
29
+ `[scale]` tiers re-table. Anything beyond the row is a free-form
30
+ pixel / rem / em / percent string ("48", "3rem", "1.25em",
31
+ "100%" fills the parent box).
33
32
  type: string
34
33
  default: ""
35
34
  weight:
@@ -58,10 +57,11 @@ a2ui:
58
57
  beside a text label. The host stamps role="img" + aria-label
59
58
  when [label] is set.
60
59
  - >-
61
- Use named [size] tokens (sm | md | lg | xl) — px / rem values
62
- only when matching a strict design spec. [size="xl"] is
63
- conventional for empty-state hero icons; [size="md"] is the
64
- default for inline use.
60
+ Use named [size] tokens (sm | md | lg) — free-form px / rem
61
+ values ("32", "48") for anything beyond the row, e.g.
62
+ empty-state hero icons; [size="md"] is the default for inline
63
+ use. A denser or larger register comes from an ancestor [scale]
64
+ tier, which the named tokens track automatically.
65
65
  - >-
66
66
  Use slot="icon" on parent primitives (<button-ui>, <badge-ui>,
67
67
  <alert-ui>, <list-item-ui>, <input-ui>, <nav-item-ui>, every
@@ -59,6 +59,7 @@ export { UIUpload } from './upload/upload.js';
59
59
  export { UICard } from './card/card.js';
60
60
  export { UIAvatar, UIAvatarGroup } from './avatar/avatar.js';
61
61
  export { UIAdiaMark } from './adia-mark/adia-mark.js';
62
+ export { UIAdiaWordmark } from './adia-wordmark/adia-wordmark.js';
62
63
  export { UIProgress } from './progress/progress.js';
63
64
  export { UIStepProgress } from './step-progress/step-progress.js';
64
65
  export { UISkeleton } from './skeleton/skeleton.js';
@@ -223,9 +223,9 @@ export class UIInput extends UIFormElement {
223
223
 
224
224
  const controls = this.#isNumberMode ? `
225
225
  <span slot="controls" data-controls aria-hidden="true">
226
- <button-ui type="button" tabindex="-1" variant="ghost" size="xs"
226
+ <button-ui type="button" tabindex="-1" variant="ghost" size="sm"
227
227
  icon="caret-up" data-step="up" aria-label="Increase"></button-ui>
228
- <button-ui type="button" tabindex="-1" variant="ghost" size="xs"
228
+ <button-ui type="button" tabindex="-1" variant="ghost" size="sm"
229
229
  icon="caret-down" data-step="down" aria-label="Decrease"></button-ui>
230
230
  </span>` : '';
231
231
 
@@ -27,13 +27,12 @@
27
27
  "default": false
28
28
  },
29
29
  "size": {
30
- "description": "Width preset. sm=24rem, md=32rem, lg=48rem, full=95vw.",
30
+ "description": "Width preset. sm=24rem, md=32rem, lg=48rem (each capped at 90vw).",
31
31
  "type": "string",
32
32
  "enum": [
33
33
  "sm",
34
34
  "md",
35
- "lg",
36
- "xl"
35
+ "lg"
37
36
  ],
38
37
  "default": "md"
39
38
  },
@@ -28,8 +28,8 @@ export class UIModal extends UIElement {
28
28
  open: boolean;
29
29
  /** When true, suppress backdrop click and Escape key dismissal of the overlay */
30
30
  permanent: boolean;
31
- /** Width preset. sm=24rem, md=32rem, lg=48rem, full=95vw. */
32
- size: 'sm' | 'md' | 'lg' | 'xl';
31
+ /** Width preset. sm=24rem, md=32rem, lg=48rem (each capped at 90vw). */
32
+ size: 'sm' | 'md' | 'lg';
33
33
  /** Aria label applied to the surface element for accessibility */
34
34
  text: string;
35
35
 
@@ -26,14 +26,13 @@ props:
26
26
  type: boolean
27
27
  default: false
28
28
  size:
29
- description: Width preset. sm=24rem, md=32rem, lg=48rem, full=95vw.
29
+ description: Width preset. sm=24rem, md=32rem, lg=48rem (each capped at 90vw).
30
30
  type: string
31
31
  default: md
32
32
  enum:
33
33
  - sm
34
34
  - md
35
35
  - lg
36
- - xl
37
36
  text:
38
37
  description: Aria label applied to the surface element for accessibility
39
38
  type: string
@@ -423,7 +423,7 @@ export class UISelect extends UIFormElement {
423
423
  // render. The `data-select-leading` marker scopes that reconciliation to
424
424
  // our element. mark wins over avatar, which wins over icon (gh#339).
425
425
  const leading = this.mark
426
- ? `<adia-mark-ui slot="leading" data-select-leading size="xs"></adia-mark-ui>`
426
+ ? `<adia-mark-ui slot="leading" data-select-leading size="sm"></adia-mark-ui>`
427
427
  : this.avatar
428
428
  ? `<img slot="leading" data-select-leading src="${escapeHTML(this.avatar)}" alt="" />`
429
429
  : this.icon
@@ -447,7 +447,7 @@ export class UISelect extends UIFormElement {
447
447
  ${leading}
448
448
  <span data-chips></span>
449
449
  ${displayMarkup}
450
- <button-ui variant="ghost" size="xs" icon="x" aria-label="Clear all" data-clear-all hidden></button-ui>
450
+ <button-ui variant="ghost" size="sm" icon="x" aria-label="Clear all" data-clear-all hidden></button-ui>
451
451
  <icon-ui name="caret-down" slot="caret"></icon-ui>
452
452
  </span>
453
453
  ${hintMarkup}
@@ -683,7 +683,7 @@ export class UISelect extends UIFormElement {
683
683
  // (resolved against the selected option).
684
684
  static #optionLeadHTML(opt) {
685
685
  if (!opt) return '';
686
- if (opt.mark) return `<adia-mark-ui size="xs"></adia-mark-ui>`;
686
+ if (opt.mark) return `<adia-mark-ui data-select-mark size="sm"></adia-mark-ui>`;
687
687
  if (opt.avatar) return `<img data-option-avatar src="${escapeHTML(opt.avatar)}" alt="" />`;
688
688
  if (opt.icon) return `<icon-ui name="${escapeHTML(opt.icon)}"></icon-ui>`;
689
689
  return '';
@@ -708,7 +708,7 @@ export class UISelect extends UIFormElement {
708
708
  const icon = (sel && sel.icon) || this.icon || '';
709
709
  const existing = trigger.querySelector(':scope > [data-select-leading]');
710
710
  let html = '';
711
- if (mark) html = `<adia-mark-ui slot="leading" data-select-leading size="xs"></adia-mark-ui>`;
711
+ if (mark) html = `<adia-mark-ui slot="leading" data-select-leading size="sm"></adia-mark-ui>`;
712
712
  else if (avatar) html = `<img slot="leading" data-select-leading src="${escapeHTML(avatar)}" alt="" />`;
713
713
  else if (icon) html = `<icon-ui slot="leading" data-select-leading name="${escapeHTML(icon)}"></icon-ui>`;
714
714
  if (!html) { existing?.remove(); return; }
@@ -225,7 +225,7 @@
225
225
  /* Chip styling tracks the active variant via tag-ui's own tokens. */
226
226
  --tag-size: var(--a-ui-tiny);
227
227
  }
228
- /* "+N more" overflow pill — a stamped <button-ui variant="ghost" size="xs">
228
+ /* "+N more" overflow pill — a stamped <button-ui variant="ghost" size="sm">
229
229
  (gh issue 276: no native <button> in stamped DOM); pill shape + chip-row
230
230
  height via button token re-points, chrome stays button-ui's own. */
231
231
  :scope[data-multi-chips] [data-chips] [data-more] {
@@ -236,7 +236,7 @@
236
236
  flex-shrink: 0;
237
237
  }
238
238
 
239
- /* Clear-all `x` affordance — stamped <button-ui variant="ghost" size="xs"
239
+ /* Clear-all `x` affordance — stamped <button-ui variant="ghost" size="sm"
240
240
  icon="x"> (gh issue 276). Visible only when [clearable] AND chips. */
241
241
  :scope[data-multi-chips] [data-clear-all] {
242
242
  --button-radius: var(--a-radius-full);
@@ -426,7 +426,7 @@ select-ui [slot="listbox"] [data-select-all] {
426
426
  border-bottom: 1px solid var(--md-sys-color-neutral-outline-variant);
427
427
  margin-bottom: var(--a-space-1);
428
428
  }
429
- /* Select-all / Clear — stamped <button-ui variant="ghost" size="xs">
429
+ /* Select-all / Clear — stamped <button-ui variant="ghost" size="sm">
430
430
  (gh issue 276); link-colored via the button fg token, chrome is button-ui's. */
431
431
  select-ui [slot="listbox"] [data-select-all-btn] {
432
432
  --button-fg: var(--md-sys-color-primary);
@@ -495,3 +495,12 @@ select-ui [slot="listbox"] [data-empty] {
495
495
  text-align: center;
496
496
  font-size: var(--a-ui-xs);
497
497
  }
498
+
499
+ /* Stamped leading marks (trigger + option rows) stay at the compact
500
+ 1.25rem diameter the removed xs tier gave them — a select row is
501
+ denser than the mark's own sm (1.75rem). The extra [size] attr
502
+ out-specifies adia-mark's own :scope[size] variant rule. */
503
+ select-ui adia-mark-ui[data-select-leading][size],
504
+ select-ui adia-mark-ui[data-select-mark][size] {
505
+ --adia-mark-size: 1.25rem;
506
+ }
@@ -288,7 +288,7 @@
288
288
  color: color-mix(in oklab, var(--a-chrome-dark, #111) 70%, transparent);
289
289
  }
290
290
 
291
- /* ═══════ Copy button — a stamped <button-ui variant="ghost" size="xs">
291
+ /* ═══════ Copy button — a stamped <button-ui variant="ghost" size="sm">
292
292
  (gh issue 276: no native <button> in stamped DOM). Geometry/colors
293
293
  ride button token re-points; focus ring is button-ui's own. ═══════ */
294
294
  :scope > [data-copy] {
@@ -47,14 +47,12 @@
47
47
  "default": ""
48
48
  },
49
49
  "size": {
50
- "description": "Sizing scale (full tier — xs / sm / md / lg / xl).",
50
+ "description": "Sizing scale (sm / md / lg). For a denser or larger register, set [scale] on an ancestor.",
51
51
  "type": "string",
52
52
  "enum": [
53
- "xs",
54
53
  "sm",
55
54
  "md",
56
- "lg",
57
- "xl"
55
+ "lg"
58
56
  ],
59
57
  "default": ""
60
58
  },
@@ -42,15 +42,13 @@ props:
42
42
  type: string
43
43
  default: ''
44
44
  size:
45
- description: Sizing scale (full tier — xs / sm / md / lg / xl).
45
+ description: Sizing scale (sm / md / lg). For a denser or larger register, set [scale] on an ancestor.
46
46
  type: string
47
47
  default: ''
48
48
  enum:
49
- - xs
50
49
  - sm
51
50
  - md
52
51
  - lg
53
- - xl
54
52
  reflect: true
55
53
  value:
56
54
  description: Form value (submitted as 'on' when checked)
@@ -269,9 +269,15 @@ a2ui:
269
269
  multiline, or per-cell with [data-wrap] on a single column /
270
270
  cell.
271
271
  - >-
272
- Use [raw] in production app consumers it disables the demo
273
- seed data so the table renders only consumer-provided rows /
274
- columns / data props.
272
+ [raw] is a visual-and-lifecycle chrome reset for consumer-owned
273
+ body markup render()'s early return (`if (this.raw) return;`)
274
+ is unconditional: no header injection, no .data/.columns
275
+ reconciliation, no empty/loading overlays, no aggregation or
276
+ pagination footers, even if .columns and .data are set. Reach
277
+ for it only when the consumer authors 100% of the body
278
+ (spreadsheet / inline-edit style patterns wrapping a native
279
+ <table>) — never to "keep the data lifecycle but skip demo
280
+ seeding."
275
281
  - >-
276
282
  Listen for the `sort` event with detail.key + detail.dir (NOT
277
283
  .column / .direction). `cell-click` detail carries {key, row,
@@ -55,10 +55,11 @@
55
55
  "default": "solid"
56
56
  },
57
57
  "variant": {
58
- "description": "Semantic variant — `default | info | success | warning | danger`.",
58
+ "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
59
  "type": "string",
60
60
  "enum": [
61
61
  "default",
62
+ "accent",
62
63
  "info",
63
64
  "success",
64
65
  "warning",
@@ -57,7 +57,7 @@ export class UITag extends UIElement {
57
57
  static parts = {
58
58
  // button-ui, not a native <button> (gh issue 276) — the icon slots in
59
59
  // explicitly to keep its bold weight (the icon= prop stamps regular).
60
- dismiss: '<button-ui slot="dismiss" variant="ghost" size="xs" aria-label="Remove"><icon-ui slot="icon" name="x" weight="bold"></icon-ui></button-ui>',
60
+ dismiss: '<button-ui slot="dismiss" variant="ghost" size="sm" aria-label="Remove"><icon-ui slot="icon" name="x" weight="bold"></icon-ui></button-ui>',
61
61
  };
62
62
 
63
63
  static template = () => null;
@@ -93,6 +93,15 @@ tag-ui[removable]:not([disabled]):hover {
93
93
  text, near-white in both schemes by design). Reads as a status pill
94
94
  where the chip IS the state. Opt out per-tag via [tone="muted"] for
95
95
  metadata-chip surfaces in dense lists. */
96
+ /* `accent` is brand-primary emphasis for non-semantic labels — mirrors
97
+ <badge-ui>'s `accent` variant token-for-token (--a-primary-bg /
98
+ on-primary for the solid fill), applied to tag-ui's own solid-default
99
+ tone shape. Not a status color — no success/warning/danger implication. */
100
+ :scope[variant="accent"] {
101
+ --tag-bg: var(--a-primary-bg);
102
+ --tag-fg: var(--md-sys-color-primary-on-primary);
103
+ }
104
+
96
105
  :scope[variant="info"] {
97
106
  --tag-bg: var(--a-info-bg);
98
107
  --tag-fg: var(--md-sys-color-info-on-info);
@@ -149,11 +158,21 @@ tag-ui[removable]:not([disabled]):hover {
149
158
  --tag-bg: var(--md-sys-color-danger-container);
150
159
  --tag-fg: var(--md-sys-color-danger-on-surface);
151
160
  }
161
+ /* Mirrors <badge-ui>'s default (muted) accent pair —
162
+ --md-sys-color-primary-container / -on-surface. */
163
+ :scope[tone="muted"][variant="accent"] {
164
+ --tag-bg: var(--md-sys-color-primary-container);
165
+ --tag-fg: var(--md-sys-color-primary-on-surface);
166
+ }
152
167
 
153
168
  /* `[tone="solid"]` on the neutral default (or no variant) inverts the
154
169
  chrome — solid fg-color bg with bg-color text. High-contrast neutral
155
- stamp. Explicit opt-in; the variant-less default stays quiet chrome. */
156
- :scope[tone="solid"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]) {
170
+ stamp. Explicit opt-in; the variant-less default stays quiet chrome.
171
+ [variant="accent"] is excluded — it already has an explicit solid
172
+ pair above (the plain [variant="accent"] rule) that this higher-
173
+ specificity fallback would otherwise clobber when tone="solid" is
174
+ set explicitly alongside it. */
175
+ :scope[tone="solid"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]) {
157
176
  --tag-bg: var(--md-sys-color-neutral-on-surface);
158
177
  --tag-fg: var(--md-sys-color-neutral-background);
159
178
  }
@@ -182,8 +201,15 @@ tag-ui[removable]:not([disabled]):hover {
182
201
  --tag-fg: var(--md-sys-color-danger-on-surface);
183
202
  --tag-border: var(--md-sys-color-danger-outline);
184
203
  }
185
- /* Outline on neutral (no family) fg-muted text + subtle border. */
186
- :scope[tone="outline"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]) {
204
+ /* Mirrors <badge-ui>'s outline accent pair
205
+ --md-sys-color-primary-on-surface / -primary-outline. */
206
+ :scope[tone="outline"][variant="accent"] {
207
+ --tag-fg: var(--md-sys-color-primary-on-surface);
208
+ --tag-border: var(--md-sys-color-primary-outline);
209
+ }
210
+ /* Outline on neutral (no family) — fg-muted text + subtle border.
211
+ [variant="accent"] excluded — see the [tone="solid"] fallback note above. */
212
+ :scope[tone="outline"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]) {
187
213
  --tag-fg: var(--a-fg-muted);
188
214
  --tag-border: var(--md-sys-color-neutral-outline);
189
215
  }
@@ -223,7 +249,7 @@ tag-ui[removable]:not([disabled]):hover {
223
249
  gap: var(--tag-gap-icon, 0.2em);
224
250
  }
225
251
 
226
- /* ── Dismiss button — a stamped <button-ui variant="ghost" size="xs">
252
+ /* ── Dismiss button — a stamped <button-ui variant="ghost" size="sm">
227
253
  (gh issue 276: no native <button> in stamped DOM); geometry + hover
228
254
  ride button token re-points, chrome is button-ui's own. */
229
255
  [slot="dismiss"] {
@@ -54,8 +54,8 @@ tone unless `tone="solid"` is set explicitly (high-contrast neutral
54
54
  inverse), or `tone="outline"` (fg-muted text + subtle border).
55
55
  */
56
56
  tone: 'solid' | 'muted' | 'outline';
57
- /** Semantic variant — `default | info | success | warning | danger`. */
58
- variant: 'default' | 'info' | 'success' | 'warning' | 'danger';
57
+ /** 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. */
58
+ variant: 'default' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
59
59
 
60
60
  addEventListener<K extends keyof HTMLElementEventMap>(
61
61
  type: K,
@@ -45,11 +45,15 @@ props:
45
45
  type: string
46
46
  dynamic: true
47
47
  variant:
48
- description: Semantic variant — `default | info | success | warning | danger`.
48
+ description: Semantic variant — `default | accent | info | success | warning | danger`.
49
+ `accent` is brand-primary emphasis for non-semantic labels — a filter chip
50
+ or taxonomy tag that shouldn't imply a success/warning/danger state. Mirrors
51
+ <badge-ui>'s `accent` variant token-for-token.
49
52
  type: string
50
53
  default: default
51
54
  enum:
52
55
  - default
56
+ - accent
53
57
  - info
54
58
  - success
55
59
  - warning
@@ -22,8 +22,18 @@
22
22
  "const": "ThemeProvider"
23
23
  },
24
24
  "scale": {
25
- "description": "Typographic / density register for the subtree — \"verse\" (compact) or \"prose\" (long-form). Adopts the matching register layer on demand; maps onto the [verse]/[prose] attribute (additive).",
25
+ "description": "Sizing register for the subtree — one of the six [scale] tiers: ui-sm (dense product UI), ui-md (base), ui-lg (touch/presentation), content-sm (compact article), content-md (long-form), content-lg (hero/marketing). Adopts the scale layer on demand; the reflected attribute is the [scale=\"…\"] CSS hook. Deprecated aliases \"verse\" (→ ui-sm) and \"prose\" (→ content-md) still map onto the legacy [verse]/[prose] attributes; removed at v1.0.",
26
26
  "type": "string",
27
+ "enum": [
28
+ "ui-sm",
29
+ "ui-md",
30
+ "ui-lg",
31
+ "content-sm",
32
+ "content-md",
33
+ "content-lg",
34
+ "verse",
35
+ "prose"
36
+ ],
27
37
  "default": ""
28
38
  }
29
39
  },
@@ -64,10 +64,11 @@ function provideFoundation() {
64
64
  // the first time a provider needs one, deduped by sheet identity. Dynamic-imported
65
65
  // (static paths, so bundlers can code-split) so the element stays lean — a provider
66
66
  // that does no theming never pulls these in.
67
- const TWIN_LOADED = { themes: false, verse: false, prose: false };
67
+ const TWIN_LOADED = { themes: false, verse: false, prose: false, scale: false };
68
68
  function loadTwin(name) {
69
69
  switch (name) {
70
70
  case 'themes': return import('../../dist/themes.sheet.js');
71
+ case 'scale': return import('../../dist/scale.sheet.js');
71
72
  case 'verse': return import('../../dist/verse.sheet.js');
72
73
  case 'prose': return import('../../dist/prose.sheet.js');
73
74
  default: return null;
@@ -96,10 +97,11 @@ export class UIThemeProvider extends UIElement {
96
97
  // Named theme preset (ocean / forest / slate / …). Reflected, so the attribute
97
98
  // — which IS the `[theme="…"]` CSS hook in themes.css — tracks the property.
98
99
  theme: { type: String, reflect: true },
99
- // Typographic/density register: "verse" (compact) | "prose" (long-form).
100
- // Mapped onto the existing `[verse]` / `[prose]` attribute below (additive —
101
- // the register CSS is untouched), so every register rule incl. `[size]`
102
- // sub-tiers applies for free.
100
+ // Sizing register one of the six [scale] tiers (ui-sm | ui-md | ui-lg |
101
+ // content-sm | content-md | content-lg). Reflected, so the attribute IS the
102
+ // `[scale="…"]` CSS hook in scale.css (the `theme` prop's mechanism).
103
+ // DEPRECATED aliases: "verse" (→ ui-sm) and "prose" (→ content-md) still
104
+ // map onto the legacy [verse]/[prose] attributes; removed at v1.0.
103
105
  scale: { type: String, reflect: true },
104
106
  };
105
107
  static template = () => null;
@@ -128,7 +130,25 @@ export class UIThemeProvider extends UIElement {
128
130
  const scale = this.scale;
129
131
  this.toggleAttribute('verse', scale === 'verse');
130
132
  this.toggleAttribute('prose', scale === 'prose');
131
- if (scale === 'verse') ensureTwin('verse');
132
- else if (scale === 'prose') ensureTwin('prose');
133
+ if (scale === 'verse' || scale === 'prose') {
134
+ // Legacy register aliases — the reflected scale="verse|prose" attribute
135
+ // matches no scale.css tier selector, so only the toggled [verse]/[prose]
136
+ // attribute has CSS effect. Removed at v1.0.
137
+ warnDeprecatedScaleAlias(scale);
138
+ ensureTwin(scale);
139
+ } else if (SCALE_TIERS.has(scale)) {
140
+ // Tier names match [scale="…"] in scale.css directly via reflection.
141
+ ensureTwin('scale');
142
+ }
133
143
  }
134
144
  }
145
+
146
+ const SCALE_TIERS = new Set(['ui-sm', 'ui-md', 'ui-lg', 'content-sm', 'content-md', 'content-lg']);
147
+
148
+ const warnedAliases = new Set();
149
+ function warnDeprecatedScaleAlias(alias) {
150
+ if (warnedAliases.has(alias)) return;
151
+ warnedAliases.add(alias);
152
+ const tier = alias === 'verse' ? 'ui-sm' : 'content-md';
153
+ console.warn(`[theme-provider] scale="${alias}" is deprecated — use scale="${tier}" (removed at v1.0).`);
154
+ }
@@ -40,6 +40,6 @@ import { UIElement } from '../../core/element.js';
40
40
  export class UIThemeProvider extends UIElement {
41
41
  /** Named theme preset for the wrapped subtree (default, ocean, forest, sunset, lavender, rose, slate, midnight). Adopts the themes layer on demand + matches the [theme="…"] hook. */
42
42
  theme: string;
43
- /** Typographic / density register for the subtree — "verse" (compact) or "prose" (long-form). Adopts the matching register layer on demand; maps onto the [verse]/[prose] attribute (additive). */
44
- scale: string;
43
+ /** Sizing register for the subtree — one of the six [scale] tiers: ui-sm (dense product UI), ui-md (base), ui-lg (touch/presentation), content-sm (compact article), content-md (long-form), content-lg (hero/marketing). Adopts the scale layer on demand; the reflected attribute is the [scale="…"] CSS hook. Deprecated aliases "verse" (→ ui-sm) and "prose" (→ content-md) still map onto the legacy [verse]/[prose] attributes; removed at v1.0. */
44
+ scale: 'ui-sm' | 'ui-md' | 'ui-lg' | 'content-sm' | 'content-md' | 'content-lg' | 'verse' | 'prose';
45
45
  }
@@ -39,9 +39,18 @@ props:
39
39
  default: ""
40
40
  reflect: true
41
41
  scale:
42
- description: 'Typographic / density register for the subtree — "verse" (compact) or "prose" (long-form). Adopts the matching register layer on demand; maps onto the [verse]/[prose] attribute (additive).'
42
+ description: 'Sizing register for the subtree — one of the six [scale] tiers: ui-sm (dense product UI), ui-md (base), ui-lg (touch/presentation), content-sm (compact article), content-md (long-form), content-lg (hero/marketing). Adopts the scale layer on demand; the reflected attribute is the [scale="…"] CSS hook. Deprecated aliases "verse" (→ ui-sm) and "prose" (→ content-md) still map onto the legacy [verse]/[prose] attributes; removed at v1.0.'
43
43
  type: string
44
44
  default: ""
45
+ enum:
46
+ - ui-sm
47
+ - ui-md
48
+ - ui-lg
49
+ - content-sm
50
+ - content-md
51
+ - content-lg
52
+ - verse
53
+ - prose
45
54
  reflect: true
46
55
  events: {}
47
56
  slots: {}
@@ -362,7 +362,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
362
362
 
363
363
  /* ═══════ Toggle caret (outcomes) ═══════ */
364
364
 
365
- /* A stamped <button-ui variant="ghost" size="xs" icon="caret-*">
365
+ /* A stamped <button-ui variant="ghost" size="sm" icon="caret-*">
366
366
  (gh issue 276: no native <button> in stamped DOM). Geometry/colors
367
367
  ride button token re-points; focus ring + hover are button-ui's own. */
368
368
  :scope > [data-timeline-toggle] {
@@ -81,14 +81,12 @@
81
81
  "default": "auto"
82
82
  },
83
83
  "size": {
84
- "description": "Sizing scale forwarded to the internal <button-ui>.",
84
+ "description": "Sizing scale (sm/md/lg) forwarded to the internal <button-ui>.",
85
85
  "type": "string",
86
86
  "enum": [
87
- "xs",
88
87
  "sm",
89
88
  "md",
90
- "lg",
91
- "xl"
89
+ "lg"
92
90
  ],
93
91
  "default": "md"
94
92
  },
@@ -40,8 +40,8 @@ export class UIToggleScheme extends UIElement {
40
40
  persist: boolean;
41
41
  /** Initial scheme — "auto" follows prefers-color-scheme; "light" / "dark" force. */
42
42
  scheme: 'auto' | 'light' | 'dark';
43
- /** Sizing scale forwarded to the internal <button-ui>. */
44
- size: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
43
+ /** Sizing scale (sm/md/lg) forwarded to the internal <button-ui>. */
44
+ size: 'sm' | 'md' | 'lg';
45
45
  /** LocalStorage key prefix; default matches <theme-panel> for cross-element interop. */
46
46
  storagePrefix: string;
47
47
  /** CSS selector for the element receiving `color-scheme`. ":root" → <html>. */
@@ -69,15 +69,13 @@ props:
69
69
  attribute: label-dark
70
70
  reflect: true
71
71
  size:
72
- description: Sizing scale forwarded to the internal <button-ui>.
72
+ description: Sizing scale (sm/md/lg) forwarded to the internal <button-ui>.
73
73
  type: string
74
74
  default: md
75
75
  enum:
76
- - xs
77
76
  - sm
78
77
  - md
79
78
  - lg
80
- - xl
81
79
  reflect: true
82
80
  variant:
83
81
  description: Visual style forwarded to the internal <button-ui>. Defaults to "ghost" (matches app practice).