@adia-ai/web-components 0.6.35 → 0.6.37

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 (126) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/components/badge/badge.a2ui.json +10 -0
  3. package/components/badge/badge.css +70 -0
  4. package/components/badge/badge.yaml +20 -0
  5. package/components/blockquote/blockquote.a2ui.json +121 -0
  6. package/components/blockquote/blockquote.class.js +68 -0
  7. package/components/blockquote/blockquote.css +46 -0
  8. package/components/blockquote/blockquote.d.ts +31 -0
  9. package/components/blockquote/blockquote.js +17 -0
  10. package/components/blockquote/blockquote.yaml +124 -0
  11. package/components/button/button.css +11 -3
  12. package/components/calendar-picker/calendar-picker.a2ui.json +15 -0
  13. package/components/calendar-picker/calendar-picker.class.js +7 -1
  14. package/components/calendar-picker/calendar-picker.yaml +14 -0
  15. package/components/color-input/color-input.a2ui.json +2 -2
  16. package/components/color-input/color-input.class.js +9 -2
  17. package/components/color-input/color-input.yaml +2 -2
  18. package/components/combobox/combobox.class.js +4 -0
  19. package/components/combobox/combobox.css +12 -0
  20. package/components/context-menu/context-menu.a2ui.json +159 -0
  21. package/components/context-menu/context-menu.class.js +275 -0
  22. package/components/context-menu/context-menu.css +56 -0
  23. package/components/context-menu/context-menu.d.ts +70 -0
  24. package/components/context-menu/context-menu.js +17 -0
  25. package/components/context-menu/context-menu.yaml +136 -0
  26. package/components/date-range-picker/date-range-picker.a2ui.json +15 -0
  27. package/components/date-range-picker/date-range-picker.class.js +3 -1
  28. package/components/date-range-picker/date-range-picker.css +4 -1
  29. package/components/date-range-picker/date-range-picker.yaml +14 -0
  30. package/components/datetime-picker/datetime-picker.a2ui.json +15 -0
  31. package/components/datetime-picker/datetime-picker.class.js +3 -1
  32. package/components/datetime-picker/datetime-picker.css +7 -1
  33. package/components/datetime-picker/datetime-picker.d.ts +2 -0
  34. package/components/datetime-picker/datetime-picker.yaml +14 -0
  35. package/components/empty-state/empty-state.class.js +2 -0
  36. package/components/feed/feed.class.js +13 -5
  37. package/components/feed/feed.css +14 -0
  38. package/components/index.js +9 -0
  39. package/components/input/input.css +15 -1
  40. package/components/input/input.test.js +40 -0
  41. package/components/integration-card/integration-card.class.js +9 -0
  42. package/components/integration-card/integration-card.test.js +4 -3
  43. package/components/nav-group/nav-group.css +7 -1
  44. package/components/number-format/number-format.a2ui.json +180 -0
  45. package/components/number-format/number-format.class.js +96 -0
  46. package/components/number-format/number-format.css +18 -0
  47. package/components/number-format/number-format.d.ts +68 -0
  48. package/components/number-format/number-format.js +17 -0
  49. package/components/number-format/number-format.yaml +204 -0
  50. package/components/pagination/pagination.a2ui.json +19 -2
  51. package/components/pagination/pagination.class.js +90 -37
  52. package/components/pagination/pagination.css +32 -127
  53. package/components/pagination/pagination.d.ts +8 -2
  54. package/components/pagination/pagination.test.js +195 -0
  55. package/components/pagination/pagination.yaml +22 -1
  56. package/components/password-strength/password-strength.a2ui.json +152 -0
  57. package/components/password-strength/password-strength.class.js +157 -0
  58. package/components/password-strength/password-strength.css +80 -0
  59. package/components/password-strength/password-strength.d.ts +59 -0
  60. package/components/password-strength/password-strength.js +17 -0
  61. package/components/password-strength/password-strength.yaml +153 -0
  62. package/components/popover/popover.css +43 -23
  63. package/components/popover/popover.yaml +8 -4
  64. package/components/qr-code/QR-TEST.svg +4 -0
  65. package/components/qr-code/qr-code.a2ui.json +154 -0
  66. package/components/qr-code/qr-code.class.js +129 -0
  67. package/components/qr-code/qr-code.css +41 -0
  68. package/components/qr-code/qr-code.d.ts +83 -0
  69. package/components/qr-code/qr-code.js +17 -0
  70. package/components/qr-code/qr-code.yaml +203 -0
  71. package/components/qr-code/qr-encoder.js +633 -0
  72. package/components/relative-time/relative-time.a2ui.json +120 -0
  73. package/components/relative-time/relative-time.class.js +136 -0
  74. package/components/relative-time/relative-time.css +22 -0
  75. package/components/relative-time/relative-time.d.ts +51 -0
  76. package/components/relative-time/relative-time.js +17 -0
  77. package/components/relative-time/relative-time.yaml +133 -0
  78. package/components/search/search.class.js +2 -0
  79. package/components/segmented/segmented.class.js +5 -1
  80. package/components/select/select.class.js +4 -0
  81. package/components/skip-nav/skip-nav.a2ui.json +92 -0
  82. package/components/skip-nav/skip-nav.class.js +45 -0
  83. package/components/skip-nav/skip-nav.css +54 -0
  84. package/components/skip-nav/skip-nav.d.ts +27 -0
  85. package/components/skip-nav/skip-nav.js +12 -0
  86. package/components/skip-nav/skip-nav.yaml +68 -0
  87. package/components/slider/slider.a2ui.json +16 -1
  88. package/components/slider/slider.class.js +264 -122
  89. package/components/slider/slider.css +82 -2
  90. package/components/slider/slider.d.ts +19 -3
  91. package/components/slider/slider.test.js +55 -0
  92. package/components/slider/slider.yaml +28 -6
  93. package/components/table/table.class.js +29 -6
  94. package/components/table/table.css +31 -4
  95. package/components/table-toolbar/table-toolbar.class.js +4 -1
  96. package/components/tag/tag.a2ui.json +10 -0
  97. package/components/tag/tag.class.js +8 -1
  98. package/components/tag/tag.css +108 -20
  99. package/components/tag/tag.d.ts +14 -0
  100. package/components/tag/tag.test.js +99 -1
  101. package/components/tag/tag.yaml +20 -0
  102. package/components/tags-input/tags-input.class.js +10 -3
  103. package/components/tags-input/tags-input.css +12 -3
  104. package/components/textarea/textarea.css +10 -1
  105. package/components/toast/toast.class.js +12 -4
  106. package/components/toc/toc.a2ui.json +159 -0
  107. package/components/toc/toc.class.js +222 -0
  108. package/components/toc/toc.css +92 -0
  109. package/components/toc/toc.d.ts +61 -0
  110. package/components/toc/toc.js +17 -0
  111. package/components/toc/toc.yaml +180 -0
  112. package/components/toolbar/toolbar.class.js +3 -0
  113. package/components/visually-hidden/visually-hidden.a2ui.json +71 -0
  114. package/components/visually-hidden/visually-hidden.class.js +14 -0
  115. package/components/visually-hidden/visually-hidden.css +25 -0
  116. package/components/visually-hidden/visually-hidden.d.ts +26 -0
  117. package/components/visually-hidden/visually-hidden.js +12 -0
  118. package/components/visually-hidden/visually-hidden.yaml +54 -0
  119. package/core/anchor.js +19 -3
  120. package/core/provider.js +19 -2
  121. package/dist/web-components.min.css +1 -1
  122. package/dist/web-components.min.js +101 -89
  123. package/package.json +1 -1
  124. package/styles/colors/semantics.css +11 -2
  125. package/styles/components.css +9 -0
  126. package/styles/resets.css +10 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.6.37] — 2026-05-25
4
+
5
+ ### Changed — `--a-warning-bg` redirected from `-strong` to `-20-tint` (bright caution-tape amber, scheme-independent)
6
+
7
+ - **Token-system fix for the muddy warning surface class.** Previously `--a-warning-bg` was an alias for `--a-warning-strong` (= `-50`, mid-tone amber). Paired with `--a-warning-fg` (= `-text-strong` = `-10-shade`, dark brown — per `semantics.css:309` "warning is light-colored — text on warning fills should be dark"), the pair collapsed to brown-on-brown chips. The local fix shipped in `<tag-ui>` / `<badge-ui>` (literal `--a-warning-20-tint` override) is now hoisted to the L3 token layer so every consumer benefits: progress-row, rating, password-strength, agent-artifact, text[color=warning], timeline. `<button-ui color="warning">` updated to read `--a-warning-bg` (was `-strong`) so it joins the fix. Local tag/badge `-20-tint` overrides removed — they now read the canonical `-bg` token cleanly.
8
+ - **`-strong` unchanged** — still the L2 saturated mid-tone, used as a foreground/icon color by alert / chart / code / empty-state / agent-trace (those use it AS a color, not as a surface to put text on, so the `light-dark` swap stays appropriate).
9
+ - **Why `-20-tint` is bright in both schemes**: the lightness math `l-max - 0.2*(l-max - l-min)` is scheme-independent (no `light-dark()` swap), so warning surfaces keep the caution-tape look in dark mode too. Other family `-bg` tokens stay scheme-flipping because they pair with `-fg` (= `-05-tint` near-white) which has enough contrast either way.
10
+ - Files: `styles/colors/semantics.css`, `components/button/button.css`, `components/tag/tag.{css,test.js}`, `components/badge/badge.css`.
11
+
12
+ ### Added — `<tag-ui>` + `<badge-ui>` gain `[tone="outline"]` third chip style
13
+
14
+ - **Outline tone**: transparent bg + family-colored 1px border + family-colored text. The lightest visual weight; good in dense data tables or faceted filter rows where multiple chips would otherwise compete. Family variants resolve to `--a-{family}-text` + `--a-{family}-border`; neutral default resolves to `--a-fg-muted` + `--a-border`.
15
+ - **Vocabulary mirror across the two primitives**: tag-ui defaults to `solid` tone (filter chip / status pill identity); badge-ui defaults to `muted` (quiet metadata identity). Both accept all three values (`solid` | `muted` | `outline`) so authors can swap shape without learning a new prop. Badge-ui's existing `primary` variant remains as a shortcut for `<badge-ui variant="accent" tone="solid">`.
16
+ - New regression guards: 6 source-grep tests on tag-ui for outline-tone rules.
17
+ - Files: `components/tag/tag.{css,yaml,test.js,examples.html}`, `components/badge/badge.{css,yaml,examples.html}`, regenerated `.a2ui.json` sidecars.
18
+
19
+ ## [0.6.36] — 2026-05-24
20
+
21
+ ### Changed — `<pagination-ui>` composes `<button-ui>` for every cell + adds universal `[size]` thread-through
22
+
23
+ - **Native-primitive leak closed.** `pagination.class.js:128` previously stamped raw `<button>` for every page / prev / next cell — the exact failure mode `dogfood-sweep` mode 4 audits for, and the same shape that produced the FB-55 silent-failure trap on `<admin-shell>`. Substrate authors reading pagination as the canonical numbered-button pattern would carry the leak into downstream components. Substrate now stamps `<button-ui>` for every cell so chrome / hover / focus-ring / disabled-state / active-fill come from button-ui's token chain (the canonical surface matrix), not a pagination-tier re-impl.
24
+ - **`[size]` prop added** — reflected enum (`sm` | `md` | `lg`, default `md` — aligned with `<button-ui>`'s default since pagination is now a button-ui composite). Threads through to every nested `<button-ui size=…>` so pagination honors the substrate's 24/30/36 px universal size system (with `[density]` modifier). Previously pagination hardcoded `--a-size-sm` (24 px), so consumers on md/lg surfaces had no escape hatch.
25
+ - **Active state now `variant="primary"`** instead of a pagination-tier `[data-active]` + custom-bg-token chain. The filled-accent state inherits from button-ui's primary surface matrix — one token chain, one source of truth.
26
+ - **Prev / Next now use Phosphor `caret-left` / `caret-right`** via `<button-ui icon=…>` (was: `‹` / `›` Unicode glyphs). Declared in `static requiredIcons` so the audit picks them up.
27
+ - **`variant="button"` mode** swaps each non-active cell to `variant="outline"` (the bordered 1×1 mode). `pagination.css` shrunk from 165 → 71 lines — the 94 lines of button styling rules collapsed into button-ui composition.
28
+ - **Constant-width compact-mode layout** — `#buildRange` redesigned around an invariant `W = 2*siblings + 5` (= 7 cells at siblings=1; 9 at siblings=2). Three layouts (near-start / middle / near-end) each yield exactly W cells so the row width stays stable when the current page advances. When `total ≤ W`, every page renders (no ellipsis — compressing wouldn't save horizontal slots). Replaces the "bridge if only 1 is skipped" heuristic from an earlier draft, which produced asymmetric cell counts under page advances (page 3 → 6 cells, page 4 → 7 cells — visibly jumpy).
29
+ - **17 new DOM + source-grep regression tests** (`pagination.test.js`, NEW). Guards: no raw `<button>` in source; `requiredIcons` declared; size threads to every nested button-ui; active page is `variant="primary"`; rest variant tracks the host's `variant=` (ghost/outline); **width invariance under all page positions for total=10 siblings=1 (always 7 cells) and total=20 siblings=2 (always 9 cells)**.
30
+ - Files: `components/pagination/pagination.{class.js,yaml,css,test.js}`, regenerated sidecar + corpus.
31
+
32
+ ### Fixed — `<tag-ui>` dismiss X + slotted icons now inherit the variant text color
33
+
34
+ - **Visible after the solid-default flip**: the dismiss X (`[slot="dismiss"]`) was hardcoded to `--a-fg-muted` (a neutral grey) regardless of the host's variant, so the X disappeared against saturated solid pills — a near-invisible grey X on the Info/Success/Warning/Error bgs. Same trap on any slotted leading icon: tag had no `currentColor` inheritance rule, so `<icon-ui>` children rendered in their own foreground color rather than the variant's.
35
+ - **Fix**: dismiss `color` token now defaults to `currentColor` at `opacity: 0.85` (quieter than the label, but tracks every variant — near-white X on saturated bg, dark X on warning amber, fg-muted X on quiet chrome). Hover restores `opacity: 1` and overlays a `color-mix(in oklch, currentColor 18%, transparent)` bg highlight — same color family as the host, not a stark neutral wash. The dismiss `<icon-ui>` now stamps with `weight="bold"` so the X reads crisply at small size on every variant (was implicit regular — too thin against bright bgs like warning amber). NEW `:scope > icon-ui { color: currentColor; flex-shrink: 0 }` rule mirrors `<badge-ui>`'s convention so leading-icon legends/status chips read as a single color-coded unit.
36
+ - Two new component tokens for the dismiss opacity (`--tag-dismiss-opacity`, `--tag-dismiss-opacity-hover`) replace the prior color-swap tokens (`--tag-dismiss-fg-hover` removed — opacity-driven hover instead). Files: `components/tag/tag.css`.
37
+
38
+ ### Fixed — `<tag-ui variant="warning">` solid pill: bright amber bg instead of muddy mid-brown
39
+
40
+ - **Visible after the solid-default flip**: the canonical `--a-warning-bg` + `--a-warning-fg` pair collapses for warning. `--a-warning-fg` resolves to `--a-warning-10-shade` (a dark brown — per `semantics.css:309` "warning is light-colored — text on warning fills should be dark"), but `--a-warning-bg` (= `--a-warning-strong` = `-50`) is a mid-tone amber. Dark text on mid-tone amber gives the muddy brown-on-brown look the user reported. The other family variants (info/success/danger) all have `-text-strong = -05-tint` (near-white) which contrasts cleanly against their `-50` saturated bg, so they don't hit this trap.
41
+ - **Fix at the tag layer**: `:scope[variant="warning"]` now uses the literal `--a-warning-20-tint` step (bright caution-tape amber, scheme-independent) as bg + keeps `--a-warning-fg` as dark text. Restores the bright-amber-with-dark-text shape `semantics.css` intends. Other family variants unchanged. Regression guard added that hard-fails any revert to `--a-warning-bg` for the warning solid bg.
42
+ - **Token-system follow-up flagged (not shipped)**: this is a symptom of `--a-warning-bg` pointing at the wrong step. Same muddy contrast likely surfaces wherever `--a-warning-bg` + `--a-warning-fg` is paired (`button-ui variant="warning"`, `chart-ui` warning bars, `rating-ui` filled fg, `progress-row variant="warning"`). A token-side fix that redirects `--a-warning-bg` to `--a-warning-20-tint` would resolve all consumers in one stroke but needs a visual sweep across those components first. Files: `components/tag/tag.{css,test.js}`.
43
+
44
+ ### Changed — `<tag-ui>` family variants default to **solid** fill (BREAKING-visual)
45
+
46
+ - **`<tag-ui variant="info|success|warning|danger">` now renders as a saturated bg + on-strong (near-white) text** — the chip IS the state, not a tinted metadata label. Aligns the chip vocabulary so consumers can read tag-ui as a status pill at a glance. Previously: muted tinted bg with `--a-{family}-bg` (saturated solid) text — an off-canonical pair that read as "passive metadata with bold color" and diverged from `<badge-ui>`'s canonical muted pair.
47
+ - **Opt-out**: NEW `[tone="muted"]` attribute drops a family variant back to the canonical muted pair `--a-{family}-muted` + `--a-{family}-text` (scheme-flipping text — the same pair `<badge-ui>` uses as its default). Use on metadata chips in dense lists where the saturated default would compete for attention.
48
+ - **The `default` variant (no family) is unchanged** — it stays as quiet `--a-bg-muted` + `--a-fg` chrome. Opt in to a high-contrast inverse stamp via `<tag-ui tone="solid">` (no variant); resolves to `--a-fg` bg + `--a-bg` fg.
49
+ - **Author migration**: existing `<tag-ui variant="info|success|warning|danger">` markup auto-flips to the new saturated default — every existing tag in the codebase becomes louder. If any specific surface needs the prior look, append `tone="muted"`. 75 occurrences across 30 substrate/app/playground files identified; review per surface.
50
+ - Source-grep regression guards added: 4 family variants verified to use the solid pair as default; 4 `[tone="muted"][variant=…]` rules verified to use the canonical muted pair; `[variant="default"]` verified unchanged; `[tone="solid"]` neutral inverse verified. Files: `components/tag/tag.{css,yaml,test.js,examples.html,a2ui.json}` + regenerated corpus catalog.
51
+
52
+ ### Fixed — placeholder pseudo no longer pushes the caret to its right after type-then-delete
53
+
54
+ - **Bug report**: with `<input-ui placeholder="Select country…">`, typing text then deleting it left the caret visually at the END of the placeholder text instead of at position 0. Same trap on `<textarea-ui>`, `<combobox-ui>`, and `<tags-input-ui>`. Root cause: the empty-state placeholder is implemented via `[data-empty]::before { content: attr(data-placeholder); }`, rendered as an **inline** pseudo box. When the contenteditable is empty, the caret IS at offset 0 of the empty text node — but the in-flow `::before` pseudo precedes the text content, occupying inline space, so the caret renders to the right of the pseudo's box. (Only happens after type-then-delete because that path leaves the contenteditable focused, making the caret visible at its true position-0 location.)
55
+ - **Fix**: pseudo is now `position: absolute; inset: 0; padding: inherit` — fills the host's content-box without occupying inline-flow space, so the caret renders at the actual content-start where it belongs. Host elements gain `position: relative` as the positioning anchor. For `<tags-input-ui>` + `<combobox-ui>` the pseudo also uses `display: flex; align-items: center` so the placeholder text vertically aligns with the host's flex-centered line-box.
56
+ - Regression guards added to `input.test.js` — three source-grep assertions (`:scope` declares `position: relative`, pseudo declares `position: absolute`, pseudo carries `inset: 0` + `padding: inherit`) that hard-fail if the in-flow shape ever re-appears.
57
+ - Files: `components/input/input.{css,test.js}`, `components/textarea/textarea.css`, `components/tags-input/tags-input.css`, `components/combobox/combobox.css`.
58
+
3
59
  ## [0.6.35] — 2026-05-24
4
60
 
5
61
  ### Fixed — `<popover-ui>` + `<menu-ui>` yaml `slots:` blocks declare the canonical `trigger` / `content` vocabulary (FB-62)
@@ -54,6 +54,16 @@
54
54
  "description": "Badge display text. Renderer routes this to the `text` attribute via CSS attr(text) on ::after.",
55
55
  "$ref": "common_types.json#/$defs/DynamicString"
56
56
  },
57
+ "tone": {
58
+ "description": "Fill style — orthogonal to [variant]. Badge defaults to `muted`\n(quiet metadata is the primitive's identity — counts, IDs, status\npills in dense rows). Three values:\n - `muted` (default) — tinted bg + scheme-paired text. Same as\n the existing family-variant rules.\n - `solid` — saturated bg + on-strong text. Use for hero badges\n where the badge IS the state (e.g. a single inline error). The\n existing `primary` variant is a shortcut for accent + solid.\n - `outline` — transparent bg + family-colored border + family-\n colored text. Lightest visual weight; good in dense data rows.\nVocabulary mirrors `<tag-ui>` (which defaults to solid, given its\ndifferent role as filter / autocomplete chip).\n",
59
+ "type": "string",
60
+ "enum": [
61
+ "muted",
62
+ "solid",
63
+ "outline"
64
+ ],
65
+ "default": "muted"
66
+ },
57
67
  "variant": {
58
68
  "description": "Semantic color variant.",
59
69
  "type": "string",
@@ -100,5 +100,75 @@
100
100
  --badge-fg-default: var(--a-fg);
101
101
  }
102
102
 
103
+ /* ── Tone modifier — orthogonal to [variant] ──
104
+ Badge's default tone is `muted` (the rules above) — quiet metadata is
105
+ the primitive's identity. `[tone="solid"]` opts into the saturated-fill
106
+ pair (same shape <tag-ui>'s solid default uses); `[tone="outline"]`
107
+ into the transparent-fill + colored-ring shape. Same vocabulary as
108
+ <tag-ui>; different defaults reflecting each primitive's role.
109
+
110
+ Warning uses --a-warning-20-tint as bg (a bright amber, scheme-
111
+ independent) instead of --a-warning-bg — the latter pair collapses
112
+ to muddy brown-on-brown (-text-strong is dark, -bg is mid-tone).
113
+ See <tag-ui>'s identical workaround. Token-system follow-up planned. */
114
+ :scope[tone="solid"][variant="info"] {
115
+ --badge-bg-default: var(--a-info-bg);
116
+ --badge-fg-default: var(--a-info-fg);
117
+ }
118
+ :scope[tone="solid"][variant="success"] {
119
+ --badge-bg-default: var(--a-success-bg);
120
+ --badge-fg-default: var(--a-success-fg);
121
+ }
122
+ :scope[tone="solid"][variant="warning"] {
123
+ /* --a-warning-bg is the bright-amber step (semantics.css L3 redirect
124
+ to -20-tint) — see also <tag-ui>'s warning solid pair. */
125
+ --badge-bg-default: var(--a-warning-bg);
126
+ --badge-fg-default: var(--a-warning-fg);
127
+ }
128
+ :scope[tone="solid"][variant="danger"] {
129
+ --badge-bg-default: var(--a-danger-bg);
130
+ --badge-fg-default: var(--a-danger-fg);
131
+ }
132
+ :scope[tone="solid"][variant="accent"] {
133
+ --badge-bg-default: var(--a-accent-bg);
134
+ --badge-fg-default: var(--a-accent-fg);
135
+ }
136
+ /* Solid on neutral default → high-contrast inverse stamp. */
137
+ :scope[tone="solid"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]):not([variant="primary"]) {
138
+ --badge-bg-default: var(--a-fg);
139
+ --badge-fg-default: var(--a-bg);
140
+ }
141
+
142
+ /* ── `[tone="outline"]` — transparent bg + family-colored border + text ── */
143
+ :scope[tone="outline"] {
144
+ --badge-bg-default: transparent;
145
+ border: 1px solid var(--badge-border, var(--badge-border-default, transparent));
146
+ }
147
+ :scope[tone="outline"][variant="info"] {
148
+ --badge-fg-default: var(--a-info-text);
149
+ --badge-border-default: var(--a-info-border);
150
+ }
151
+ :scope[tone="outline"][variant="success"] {
152
+ --badge-fg-default: var(--a-success-text);
153
+ --badge-border-default: var(--a-success-border);
154
+ }
155
+ :scope[tone="outline"][variant="warning"] {
156
+ --badge-fg-default: var(--a-warning-text);
157
+ --badge-border-default: var(--a-warning-border);
158
+ }
159
+ :scope[tone="outline"][variant="danger"] {
160
+ --badge-fg-default: var(--a-danger-text);
161
+ --badge-border-default: var(--a-danger-border);
162
+ }
163
+ :scope[tone="outline"][variant="accent"] {
164
+ --badge-fg-default: var(--a-accent-text);
165
+ --badge-border-default: var(--a-accent-border);
166
+ }
167
+ /* Outline on neutral — fg-muted text + subtle ring. */
168
+ :scope[tone="outline"]:not([variant="info"]):not([variant="success"]):not([variant="warning"]):not([variant="danger"]):not([variant="accent"]):not([variant="primary"]) {
169
+ --badge-fg-default: var(--a-fg-muted);
170
+ --badge-border-default: var(--a-border);
171
+ }
172
+
103
173
  /* Size handled by universal [size] attribute system. */
104
174
  }
@@ -70,6 +70,26 @@ props:
70
70
  - primary
71
71
  - muted
72
72
  - neutral
73
+ tone:
74
+ description: |
75
+ Fill style — orthogonal to [variant]. Badge defaults to `muted`
76
+ (quiet metadata is the primitive's identity — counts, IDs, status
77
+ pills in dense rows). Three values:
78
+ - `muted` (default) — tinted bg + scheme-paired text. Same as
79
+ the existing family-variant rules.
80
+ - `solid` — saturated bg + on-strong text. Use for hero badges
81
+ where the badge IS the state (e.g. a single inline error). The
82
+ existing `primary` variant is a shortcut for accent + solid.
83
+ - `outline` — transparent bg + family-colored border + family-
84
+ colored text. Lightest visual weight; good in dense data rows.
85
+ Vocabulary mirrors `<tag-ui>` (which defaults to solid, given its
86
+ different role as filter / autocomplete chip).
87
+ type: string
88
+ default: muted
89
+ enum:
90
+ - muted
91
+ - solid
92
+ - outline
73
93
  events: {}
74
94
  slots: {}
75
95
  states:
@@ -0,0 +1,121 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/Blockquote.json",
4
+ "title": "Blockquote",
5
+ "description": "Styled quotation block with a left visual indicator (border rule) +\nitalic body text + optional `cite` attribution line. Use for pull-quotes,\ntestimonials, or inline citations within prose. The default visual\nfollows the prose typography family — pair with `<text-ui>` body\nvariants inside, or pass raw text in the default slot. The optional\n[cite] attribute (or [slot=cite]) renders a small attribution line\nbelow the quote prefixed with an em-dash. Semantic blockquote element\nwith `role=\"blockquote\"` implied via tag name (do NOT wrap in a native\n`<blockquote>` — that produces nested-blockquote semantics).\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "cite": {
17
+ "description": "Source attribution shown beneath the quote (small, muted, em-dash\nprefix). For richer attribution (links, multi-line), use the\n`[slot=\"cite\"]` content slot instead — when both are set, the slot\ncontent wins. Plain-string convenience prop for the common case.\n",
18
+ "type": "string",
19
+ "default": ""
20
+ },
21
+ "component": {
22
+ "const": "Blockquote"
23
+ }
24
+ },
25
+ "required": [
26
+ "component"
27
+ ],
28
+ "unevaluatedProperties": false,
29
+ "x-adiaui": {
30
+ "anti_patterns": [],
31
+ "category": "display",
32
+ "composes": [],
33
+ "events": {},
34
+ "examples": [
35
+ {
36
+ "description": "Pull-quote with em-dash attribution.",
37
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"Blockquote\",\n \"cite\": \"Steve Jobs, Stanford Commencement, 2005\",\n \"content\": \"Stay hungry. Stay foolish.\"\n }\n]\n",
38
+ "name": "default"
39
+ },
40
+ {
41
+ "description": "Blockquote with a linked citation via slot.",
42
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"Blockquote\",\n \"children\": [\"body\", \"src\"]\n },\n {\n \"id\": \"body\",\n \"component\": \"Text\",\n \"textContent\": \"The best way to predict the future is to invent it.\"\n },\n {\n \"id\": \"src\",\n \"component\": \"Link\",\n \"slot\": \"cite\",\n \"href\": \"https://en.wikipedia.org/wiki/Alan_Kay\",\n \"text\": \"Alan Kay (1971)\"\n }\n]\n",
43
+ "name": "rich-attribution"
44
+ }
45
+ ],
46
+ "keywords": [
47
+ "blockquote",
48
+ "quote",
49
+ "pull-quote",
50
+ "quotation",
51
+ "testimonial",
52
+ "citation",
53
+ "cite"
54
+ ],
55
+ "name": "UIBlockquote",
56
+ "related": [
57
+ "text",
58
+ "link",
59
+ "card"
60
+ ],
61
+ "slots": {
62
+ "default": {
63
+ "description": "The quote body. Plain text or composed `<text-ui>` / inline elements."
64
+ },
65
+ "cite": {
66
+ "description": "Optional citation override. Use for rich attribution (linked source,\nperson + role pairing) where [cite] string is insufficient.\n"
67
+ }
68
+ },
69
+ "states": [
70
+ {
71
+ "description": "Default, ready for reading.",
72
+ "name": "idle"
73
+ }
74
+ ],
75
+ "status": "stable",
76
+ "synonyms": {
77
+ "quote": [
78
+ "blockquote",
79
+ "quotation",
80
+ "pull-quote"
81
+ ],
82
+ "testimonial": [
83
+ "blockquote",
84
+ "quote"
85
+ ]
86
+ },
87
+ "tag": "blockquote-ui",
88
+ "tokens": {
89
+ "--blockquote-cite-fg": {
90
+ "description": "Citation text color (muted).",
91
+ "default": "var(--a-fg-muted)"
92
+ },
93
+ "--blockquote-cite-size": {
94
+ "description": "Citation font size.",
95
+ "default": "var(--a-ui-sm)"
96
+ },
97
+ "--blockquote-fg": {
98
+ "description": "Quote text color.",
99
+ "default": "var(--a-fg-subtle)"
100
+ },
101
+ "--blockquote-pad-block": {
102
+ "description": "Vertical padding inside the blockquote.",
103
+ "default": "var(--a-space-2)"
104
+ },
105
+ "--blockquote-pad-inline": {
106
+ "description": "Inline padding between the rule and the quote text.",
107
+ "default": "var(--a-space-3)"
108
+ },
109
+ "--blockquote-rule-color": {
110
+ "description": "Color of the left indicator rule.",
111
+ "default": "var(--a-border-strong)"
112
+ },
113
+ "--blockquote-rule-width": {
114
+ "description": "Width of the left indicator rule.",
115
+ "default": "2px"
116
+ }
117
+ },
118
+ "traits": [],
119
+ "version": 1
120
+ }
121
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Non-side-effect class export for `<blockquote-ui>`.
3
+ *
4
+ * Importing this file gives you the class without auto-registering the
5
+ * tag. Useful for test isolation, subclassing with tag-name override,
6
+ * or selective composition.
7
+ *
8
+ * The auto-register path stays at `@adia-ai/web-components/components/blockquote`
9
+ * (which imports this file + calls `defineIfFree()`).
10
+ *
11
+ * @see ../../USAGE.md#registration--auto-vs-explicit
12
+ */
13
+
14
+ /**
15
+ * <blockquote-ui cite="Alan Kay">
16
+ * The best way to predict the future is to invent it.
17
+ * </blockquote-ui>
18
+ *
19
+ * Layout:
20
+ * │ italic quote body ← left rule indicator
21
+ * │ — citation line ← em-dash prefix
22
+ *
23
+ * Two attribution paths:
24
+ * • [cite="..."] attribute → renders a small em-dashed line below
25
+ * • <span slot="cite">...</span> slot → richer attribution (links, etc.)
26
+ * Slot content overrides the attribute when both are present.
27
+ */
28
+
29
+ import { UIElement } from '../../core/element.js';
30
+
31
+ export class UIBlockquote extends UIElement {
32
+ static properties = {
33
+ cite: { type: String, default: '', reflect: true },
34
+ };
35
+
36
+ static template = () => null;
37
+
38
+ connected() {
39
+ // Implicit semantic role — the tag name carries blockquote meaning,
40
+ // but assistive tech doesn't infer from custom-element tag names.
41
+ if (!this.hasAttribute('role')) this.setAttribute('role', 'blockquote');
42
+ }
43
+
44
+ render() {
45
+ // Stamp the citation line from [cite] only when no [slot="cite"]
46
+ // content is provided. Slot wins on conflict (per the contract).
47
+ const slotted = this.querySelector('[slot="cite"]:not([data-cite-stamped])');
48
+ const stamped = this.querySelector('[slot="cite"][data-cite-stamped]');
49
+ if (slotted) {
50
+ // Author supplied richer attribution — drop any stamped version.
51
+ stamped?.remove();
52
+ return;
53
+ }
54
+ if (this.cite) {
55
+ if (stamped) {
56
+ stamped.textContent = this.cite;
57
+ } else {
58
+ const el = document.createElement('span');
59
+ el.setAttribute('slot', 'cite');
60
+ el.setAttribute('data-cite-stamped', '');
61
+ el.textContent = this.cite;
62
+ this.appendChild(el);
63
+ }
64
+ } else if (stamped) {
65
+ stamped.remove();
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,46 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ BLOCKQUOTE-UI — Styled quotation block with left rule + cite line.
3
+ ═══════════════════════════════════════════════════════════════ */
4
+
5
+ @scope (blockquote-ui) {
6
+ :where(:scope) {
7
+ /* ── Tokens ── */
8
+ --blockquote-rule-color-default: var(--a-border-strong);
9
+ --blockquote-rule-width-default: 2px;
10
+ --blockquote-pad-inline-default: var(--a-space-3);
11
+ --blockquote-pad-block-default: var(--a-space-2);
12
+ --blockquote-fg-default: var(--a-fg-subtle);
13
+ --blockquote-cite-fg-default: var(--a-fg-muted);
14
+ --blockquote-cite-size-default: var(--a-ui-sm);
15
+ --blockquote-cite-mt-default: var(--a-space-2);
16
+ }
17
+
18
+ :scope {
19
+ box-sizing: border-box;
20
+ display: block;
21
+ padding-inline-start: var(--blockquote-pad-inline, var(--blockquote-pad-inline-default));
22
+ padding-block: var(--blockquote-pad-block, var(--blockquote-pad-block-default));
23
+ border-inline-start: var(--blockquote-rule-width, var(--blockquote-rule-width-default))
24
+ solid
25
+ var(--blockquote-rule-color, var(--blockquote-rule-color-default));
26
+ color: var(--blockquote-fg, var(--blockquote-fg-default));
27
+ font-style: italic;
28
+ /* Reset native margin if a consumer wraps in a native <blockquote>
29
+ (not recommended — see yaml a2ui rule #3) so nesting renders
30
+ reasonably. */
31
+ margin: 0;
32
+ }
33
+
34
+ /* Cite line — em-dash prefix + small + muted + non-italic */
35
+ [slot="cite"] {
36
+ display: block;
37
+ margin-top: var(--blockquote-cite-mt, var(--blockquote-cite-mt-default));
38
+ font-style: normal;
39
+ font-size: var(--blockquote-cite-size, var(--blockquote-cite-size-default));
40
+ color: var(--blockquote-cite-fg, var(--blockquote-cite-fg-default));
41
+ }
42
+
43
+ [slot="cite"]::before {
44
+ content: "— ";
45
+ }
46
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `<blockquote-ui>` — Styled quotation block with a left visual indicator (border rule) +
3
+ italic body text + optional `cite` attribution line. Use for pull-quotes,
4
+ testimonials, or inline citations within prose. The default visual
5
+ follows the prose typography family — pair with `<text-ui>` body
6
+ variants inside, or pass raw text in the default slot. The optional
7
+ [cite] attribute (or [slot=cite]) renders a small attribution line
8
+ below the quote prefixed with an em-dash. Semantic blockquote element
9
+ with `role="blockquote"` implied via tag name (do NOT wrap in a native
10
+ `<blockquote>` — that produces nested-blockquote semantics).
11
+
12
+ *
13
+ * @see https://ui-kit.exe.xyz/site/components/blockquote
14
+ *
15
+ * Type declarations generated by scripts/build/dts-codegen.mjs from
16
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
17
+ * run `npm run build:components`, then `npm run codegen:dts` to
18
+ * regenerate; or hand-author this file fully if rich event types are
19
+ * needed beyond what the yaml `events:` block can express.
20
+ */
21
+
22
+ import { UIElement } from '../../core/element.js';
23
+
24
+ export class UIBlockquote extends UIElement {
25
+ /** Source attribution shown beneath the quote (small, muted, em-dash
26
+ prefix). For richer attribution (links, multi-line), use the
27
+ `[slot="cite"]` content slot instead — when both are set, the slot
28
+ content wins. Plain-string convenience prop for the common case.
29
+ */
30
+ cite: string;
31
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `<blockquote-ui>` — auto-registers the tag on import.
3
+ *
4
+ * For non-side-effect class import (test isolation, tag override), use
5
+ * the `class` subpath:
6
+ *
7
+ * import { UIBlockquote } from '@adia-ai/web-components/components/blockquote/class';
8
+ *
9
+ * @see ../../USAGE.md#registration--auto-vs-explicit
10
+ */
11
+
12
+ import { defineIfFree } from '../../core/register.js';
13
+ import { UIBlockquote } from './blockquote.class.js';
14
+
15
+ defineIfFree('blockquote-ui', UIBlockquote);
16
+
17
+ export { UIBlockquote };
@@ -0,0 +1,124 @@
1
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
+ name: UIBlockquote
3
+ tag: blockquote-ui
4
+ status: stable
5
+ component: Blockquote
6
+ category: display
7
+ version: 1
8
+ description: |
9
+ Styled quotation block with a left visual indicator (border rule) +
10
+ italic body text + optional `cite` attribution line. Use for pull-quotes,
11
+ testimonials, or inline citations within prose. The default visual
12
+ follows the prose typography family — pair with `<text-ui>` body
13
+ variants inside, or pass raw text in the default slot. The optional
14
+ [cite] attribute (or [slot=cite]) renders a small attribution line
15
+ below the quote prefixed with an em-dash. Semantic blockquote element
16
+ with `role="blockquote"` implied via tag name (do NOT wrap in a native
17
+ `<blockquote>` — that produces nested-blockquote semantics).
18
+ props:
19
+ cite:
20
+ description: |
21
+ Source attribution shown beneath the quote (small, muted, em-dash
22
+ prefix). For richer attribution (links, multi-line), use the
23
+ `[slot="cite"]` content slot instead — when both are set, the slot
24
+ content wins. Plain-string convenience prop for the common case.
25
+ type: string
26
+ default: ""
27
+ reflect: true
28
+ events: {}
29
+ slots:
30
+ default:
31
+ description: The quote body. Plain text or composed `<text-ui>` / inline elements.
32
+ cite:
33
+ description: |
34
+ Optional citation override. Use for rich attribution (linked source,
35
+ person + role pairing) where [cite] string is insufficient.
36
+ states:
37
+ - name: idle
38
+ description: Default, ready for reading.
39
+ traits: []
40
+ tokens:
41
+ --blockquote-rule-color:
42
+ description: Color of the left indicator rule.
43
+ default: var(--a-border-strong)
44
+ --blockquote-rule-width:
45
+ description: Width of the left indicator rule.
46
+ default: 2px
47
+ --blockquote-pad-inline:
48
+ description: Inline padding between the rule and the quote text.
49
+ default: var(--a-space-3)
50
+ --blockquote-pad-block:
51
+ description: Vertical padding inside the blockquote.
52
+ default: var(--a-space-2)
53
+ --blockquote-fg:
54
+ description: Quote text color.
55
+ default: var(--a-fg-subtle)
56
+ --blockquote-cite-fg:
57
+ description: Citation text color (muted).
58
+ default: var(--a-fg-muted)
59
+ --blockquote-cite-size:
60
+ description: Citation font size.
61
+ default: var(--a-ui-sm)
62
+ a2ui:
63
+ rules:
64
+ - rule: "Use for pull-quotes, testimonials, or inline citations. Renders italic body text with a left rule indicator + optional em-dash attribution line."
65
+ reason: "Quote-display primitive with semantic chrome."
66
+ - rule: "Set [cite] for plain-string attribution; use [slot=\"cite\"] for rich attribution (linked source, role pairing). Slot content overrides the [cite] prop when both are set."
67
+ reason: "Two attribution paths — string for the common case, slot for richness."
68
+ - rule: "Do NOT wrap blockquote-ui in a native <blockquote> element — that produces nested-blockquote semantics. The tag IS the blockquote."
69
+ reason: "Avoid double-wrapping."
70
+ anti_patterns: []
71
+ examples:
72
+ - name: default
73
+ description: Pull-quote with em-dash attribution.
74
+ a2ui: |
75
+ [
76
+ {
77
+ "id": "q",
78
+ "component": "Blockquote",
79
+ "cite": "Steve Jobs, Stanford Commencement, 2005",
80
+ "content": "Stay hungry. Stay foolish."
81
+ }
82
+ ]
83
+ - name: rich-attribution
84
+ description: Blockquote with a linked citation via slot.
85
+ a2ui: |
86
+ [
87
+ {
88
+ "id": "q",
89
+ "component": "Blockquote",
90
+ "children": ["body", "src"]
91
+ },
92
+ {
93
+ "id": "body",
94
+ "component": "Text",
95
+ "textContent": "The best way to predict the future is to invent it."
96
+ },
97
+ {
98
+ "id": "src",
99
+ "component": "Link",
100
+ "slot": "cite",
101
+ "href": "https://en.wikipedia.org/wiki/Alan_Kay",
102
+ "text": "Alan Kay (1971)"
103
+ }
104
+ ]
105
+ keywords:
106
+ - blockquote
107
+ - quote
108
+ - pull-quote
109
+ - quotation
110
+ - testimonial
111
+ - citation
112
+ - cite
113
+ synonyms:
114
+ quote:
115
+ - blockquote
116
+ - quotation
117
+ - pull-quote
118
+ testimonial:
119
+ - blockquote
120
+ - quote
121
+ related:
122
+ - text
123
+ - link
124
+ - card
@@ -161,15 +161,23 @@ button-ui[color="danger"]:not([disabled]):hover {
161
161
  --button-fg-default: var(--button-fg-danger, var(--button-fg-danger-default));
162
162
  }
163
163
  :scope[color="success"] {
164
- --button-bg-default: var(--a-success-strong);
164
+ /* Consume the L3 `-bg` alias, not the L2 `-strong` step. Currently
165
+ resolves identically (both = `-50`), but consuming `-bg` future-
166
+ proofs if the surface-step ever redirects (as -warning-bg did
167
+ in v0.6.36 to fix muddy contrast). */
168
+ --button-bg-default: var(--a-success-bg);
165
169
  --button-fg-default: var(--a-success-fg);
166
170
  }
167
171
  :scope[color="info"] {
168
- --button-bg-default: var(--a-info-strong);
172
+ --button-bg-default: var(--a-info-bg);
169
173
  --button-fg-default: var(--a-info-fg);
170
174
  }
171
175
  :scope[color="warning"] {
172
- --button-bg-default: var(--a-warning-strong);
176
+ /* `--a-warning-bg` (bright amber, scheme-independent) not
177
+ `-strong` (mid-tone). The pair `-strong` + `-fg` gives muddy
178
+ brown-on-brown — the L3 `-bg` is the canonical solid-warning
179
+ surface paired with `-fg` (dark text). */
180
+ --button-bg-default: var(--a-warning-bg);
173
181
  --button-fg-default: var(--a-warning-fg);
174
182
  }
175
183
 
@@ -66,6 +66,21 @@
66
66
  "type": "string",
67
67
  "default": "Select date..."
68
68
  },
69
+ "placement": {
70
+ "description": "Popover placement relative to the trigger. Default `bottom` centers the calendar panel under the trigger (ADR-0034 Rule 2 — calendar panel wider than trigger).",
71
+ "type": "string",
72
+ "enum": [
73
+ "top",
74
+ "bottom",
75
+ "left",
76
+ "right",
77
+ "top-start",
78
+ "top-end",
79
+ "bottom-start",
80
+ "bottom-end"
81
+ ],
82
+ "default": "bottom"
83
+ },
69
84
  "value": {
70
85
  "description": "Selected date (ISO string)",
71
86
  "type": "string",