@adia-ai/a2ui-corpus 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.
@@ -2829,6 +2829,16 @@
2829
2829
  "description": "Badge display text. Renderer routes this to the `text` attribute via CSS attr(text) on ::after.",
2830
2830
  "$ref": "#/$defs/DynamicString"
2831
2831
  },
2832
+ "tone": {
2833
+ "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",
2834
+ "type": "string",
2835
+ "enum": [
2836
+ "muted",
2837
+ "solid",
2838
+ "outline"
2839
+ ],
2840
+ "default": "muted"
2841
+ },
2832
2842
  "variant": {
2833
2843
  "description": "Semantic color variant.",
2834
2844
  "type": "string",
@@ -3368,6 +3378,125 @@
3368
3378
  "version": 1
3369
3379
  }
3370
3380
  },
3381
+ "Blockquote": {
3382
+ "title": "Blockquote",
3383
+ "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",
3384
+ "type": "object",
3385
+ "allOf": [
3386
+ {
3387
+ "$ref": "#/$defs/ComponentCommon"
3388
+ },
3389
+ {
3390
+ "$ref": "#/$defs/CatalogComponentCommon"
3391
+ }
3392
+ ],
3393
+ "properties": {
3394
+ "cite": {
3395
+ "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",
3396
+ "type": "string",
3397
+ "default": ""
3398
+ },
3399
+ "component": {
3400
+ "const": "Blockquote"
3401
+ }
3402
+ },
3403
+ "required": [
3404
+ "component"
3405
+ ],
3406
+ "unevaluatedProperties": false,
3407
+ "x-adiaui": {
3408
+ "anti_patterns": [],
3409
+ "category": "display",
3410
+ "composes": [],
3411
+ "events": {},
3412
+ "examples": [
3413
+ {
3414
+ "description": "Pull-quote with em-dash attribution.",
3415
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"Blockquote\",\n \"cite\": \"Steve Jobs, Stanford Commencement, 2005\",\n \"content\": \"Stay hungry. Stay foolish.\"\n }\n]\n",
3416
+ "name": "default"
3417
+ },
3418
+ {
3419
+ "description": "Blockquote with a linked citation via slot.",
3420
+ "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",
3421
+ "name": "rich-attribution"
3422
+ }
3423
+ ],
3424
+ "keywords": [
3425
+ "blockquote",
3426
+ "quote",
3427
+ "pull-quote",
3428
+ "quotation",
3429
+ "testimonial",
3430
+ "citation",
3431
+ "cite"
3432
+ ],
3433
+ "name": "UIBlockquote",
3434
+ "related": [
3435
+ "text",
3436
+ "link",
3437
+ "card"
3438
+ ],
3439
+ "slots": {
3440
+ "default": {
3441
+ "description": "The quote body. Plain text or composed `<text-ui>` / inline elements."
3442
+ },
3443
+ "cite": {
3444
+ "description": "Optional citation override. Use for rich attribution (linked source,\nperson + role pairing) where [cite] string is insufficient.\n"
3445
+ }
3446
+ },
3447
+ "states": [
3448
+ {
3449
+ "description": "Default, ready for reading.",
3450
+ "name": "idle"
3451
+ }
3452
+ ],
3453
+ "status": "stable",
3454
+ "synonyms": {
3455
+ "quote": [
3456
+ "blockquote",
3457
+ "quotation",
3458
+ "pull-quote"
3459
+ ],
3460
+ "testimonial": [
3461
+ "blockquote",
3462
+ "quote"
3463
+ ]
3464
+ },
3465
+ "tag": "blockquote-ui",
3466
+ "tokens": {
3467
+ "--blockquote-cite-fg": {
3468
+ "description": "Citation text color (muted).",
3469
+ "default": "var(--a-fg-muted)"
3470
+ },
3471
+ "--blockquote-cite-size": {
3472
+ "description": "Citation font size.",
3473
+ "default": "var(--a-ui-sm)"
3474
+ },
3475
+ "--blockquote-fg": {
3476
+ "description": "Quote text color.",
3477
+ "default": "var(--a-fg-subtle)"
3478
+ },
3479
+ "--blockquote-pad-block": {
3480
+ "description": "Vertical padding inside the blockquote.",
3481
+ "default": "var(--a-space-2)"
3482
+ },
3483
+ "--blockquote-pad-inline": {
3484
+ "description": "Inline padding between the rule and the quote text.",
3485
+ "default": "var(--a-space-3)"
3486
+ },
3487
+ "--blockquote-rule-color": {
3488
+ "description": "Color of the left indicator rule.",
3489
+ "default": "var(--a-border-strong)"
3490
+ },
3491
+ "--blockquote-rule-width": {
3492
+ "description": "Width of the left indicator rule.",
3493
+ "default": "2px"
3494
+ }
3495
+ },
3496
+ "traits": [],
3497
+ "version": 1
3498
+ }
3499
+ },
3371
3500
  "Breadcrumb": {
3372
3501
  "title": "Breadcrumb",
3373
3502
  "description": "Breadcrumb trail with auto-inserted separators. Supports a leading icon (first child) and an overflow popover that collapses middle crumbs into a `…` menu.",
@@ -3899,6 +4028,21 @@
3899
4028
  "type": "string",
3900
4029
  "default": "Select date..."
3901
4030
  },
4031
+ "placement": {
4032
+ "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).",
4033
+ "type": "string",
4034
+ "enum": [
4035
+ "top",
4036
+ "bottom",
4037
+ "left",
4038
+ "right",
4039
+ "top-start",
4040
+ "top-end",
4041
+ "bottom-start",
4042
+ "bottom-end"
4043
+ ],
4044
+ "default": "bottom"
4045
+ },
3902
4046
  "value": {
3903
4047
  "description": "Selected date (ISO string)",
3904
4048
  "type": "string",
@@ -6220,7 +6364,7 @@
6220
6364
  "default": false
6221
6365
  },
6222
6366
  "placement": {
6223
- "description": "Popover placement relative to the trigger.",
6367
+ "description": "Popover placement relative to the trigger. Default `bottom` centers the color-picker panel under the swatch button (ADR-0034 Rule 2 — panel wider than trigger).",
6224
6368
  "type": "string",
6225
6369
  "enum": [
6226
6370
  "top",
@@ -6232,7 +6376,7 @@
6232
6376
  "bottom-start",
6233
6377
  "bottom-end"
6234
6378
  ],
6235
- "default": "bottom-start"
6379
+ "default": "bottom"
6236
6380
  },
6237
6381
  "value": {
6238
6382
  "description": "Current color as a string in the active [format].",
@@ -7306,6 +7450,163 @@
7306
7450
  "version": 1
7307
7451
  }
7308
7452
  },
7453
+ "ContextMenu": {
7454
+ "title": "ContextMenu",
7455
+ "description": "Right-click activated menu — the OS-native context-menu pattern as a\nweb component. Distinct from `menu-ui` (which is button-triggered):\nsame item shape (`menu-item-ui` children), different trigger surface\n(`contextmenu` event), and pointer-anchored positioning instead of\nelement-anchored. Pattern: WAI-APG Menu.\n\nTwo binding modes:\n **A. Wrap.** Default-slot child becomes the target:\n `<context-menu-ui><my-table>...</my-table>...items</context-menu-ui>`.\n **B. Selector.** Point at one or more existing elements via [for]:\n `<context-menu-ui for=\"#my-table\">...items</context-menu-ui>`.\n\nOn `contextmenu` event on a target: `preventDefault()`, position the\nmenu at the pointer coords, show via Popover API. Touch long-press\n(configurable via [long-press-ms]) does the same. Shift+F10 / Menu\nkey opens at the focused target's center for keyboard users.\n",
7456
+ "type": "object",
7457
+ "allOf": [
7458
+ {
7459
+ "$ref": "#/$defs/ComponentCommon"
7460
+ },
7461
+ {
7462
+ "$ref": "#/$defs/CatalogComponentCommon"
7463
+ }
7464
+ ],
7465
+ "properties": {
7466
+ "component": {
7467
+ "const": "ContextMenu"
7468
+ },
7469
+ "for": {
7470
+ "description": "CSS selector(s) for target element(s). Empty = use default-slot child.",
7471
+ "type": "string",
7472
+ "default": ""
7473
+ },
7474
+ "long-press-ms": {
7475
+ "description": "Long-press duration (ms) on touch devices to open the menu.",
7476
+ "type": "number",
7477
+ "default": 500
7478
+ },
7479
+ "open": {
7480
+ "description": "Programmatic open state. Set true to open at target center.",
7481
+ "type": "boolean",
7482
+ "default": false
7483
+ }
7484
+ },
7485
+ "required": [
7486
+ "component"
7487
+ ],
7488
+ "unevaluatedProperties": false,
7489
+ "x-adiaui": {
7490
+ "anti_patterns": [
7491
+ {
7492
+ "fix": "Wrap a target: `<context-menu-ui><my-target></my-target>...items</context-menu-ui>` OR point at one: `<context-menu-ui for=\"#my-target\">...items</context-menu-ui>`.",
7493
+ "why": "No target binding — the menu never opens.",
7494
+ "wrong": "<context-menu-ui>...just items...</context-menu-ui>"
7495
+ }
7496
+ ],
7497
+ "category": "container",
7498
+ "composes": [
7499
+ "menu-item-ui"
7500
+ ],
7501
+ "events": {
7502
+ "context-menu-close": {
7503
+ "description": "Fired when the menu closes (item-select / outside-click / Escape).",
7504
+ "detail": {
7505
+ "reason": {
7506
+ "description": "\"select\" | \"outside\" | \"escape\"",
7507
+ "type": "string"
7508
+ }
7509
+ }
7510
+ },
7511
+ "context-menu-open": {
7512
+ "description": "Fired when the menu opens (right-click / long-press / keyboard).",
7513
+ "detail": {
7514
+ "target": {
7515
+ "description": "The target element the menu was opened on.",
7516
+ "type": "Element"
7517
+ },
7518
+ "x": {
7519
+ "description": "Pointer x coord (viewport-relative); null for keyboard activation.",
7520
+ "type": "number"
7521
+ },
7522
+ "y": {
7523
+ "description": "Pointer y coord; null for keyboard activation.",
7524
+ "type": "number"
7525
+ }
7526
+ }
7527
+ },
7528
+ "context-menu-select": {
7529
+ "description": "Fired when an item is activated. Same shape as menu-ui's `action` event.",
7530
+ "detail": {
7531
+ "text": {
7532
+ "description": "Selected item's text.",
7533
+ "type": "string"
7534
+ },
7535
+ "value": {
7536
+ "description": "Selected item's value.",
7537
+ "type": "string"
7538
+ }
7539
+ }
7540
+ }
7541
+ },
7542
+ "examples": [
7543
+ {
7544
+ "description": "Right-click a file row for Open / Rename / Delete.",
7545
+ "a2ui": "[\n { \"id\": \"root\", \"component\": \"ContextMenu\", \"children\": [\"target\", \"item-open\", \"item-rename\", \"div\", \"item-delete\"] },\n { \"id\": \"target\", \"component\": \"Text\", \"textContent\": \"Right-click me\" },\n { \"id\": \"item-open\", \"component\": \"MenuItem\", \"value\": \"open\", \"text\": \"Open\" },\n { \"id\": \"item-rename\", \"component\": \"MenuItem\", \"value\": \"rename\", \"text\": \"Rename\" },\n { \"id\": \"div\", \"component\": \"MenuDivider\" },\n { \"id\": \"item-delete\", \"component\": \"MenuItem\", \"value\": \"delete\", \"text\": \"Delete\", \"variant\": \"danger\" }\n]\n",
7546
+ "name": "file-actions"
7547
+ }
7548
+ ],
7549
+ "keywords": [
7550
+ "context-menu",
7551
+ "right-click",
7552
+ "menu",
7553
+ "popup-menu"
7554
+ ],
7555
+ "name": "UIContextMenu",
7556
+ "related": [
7557
+ "menu",
7558
+ "menu-item",
7559
+ "popover"
7560
+ ],
7561
+ "slots": {
7562
+ "default": {
7563
+ "description": "Two-purpose slot: the wrapped target element (mode A — first\nnon-menu-item-ui child) AND the menu-item-ui items. Items are\npromoted to the popover surface on open.\n"
7564
+ }
7565
+ },
7566
+ "states": [
7567
+ {
7568
+ "description": "Default. Menu closed; trigger listeners attached.",
7569
+ "name": "idle"
7570
+ },
7571
+ {
7572
+ "description": "Menu visible at pointer position; focus inside.",
7573
+ "attribute": "open",
7574
+ "name": "open"
7575
+ }
7576
+ ],
7577
+ "status": "stable",
7578
+ "synonyms": {
7579
+ "popup-menu": [
7580
+ "menu",
7581
+ "context-menu"
7582
+ ],
7583
+ "right-click": [
7584
+ "context-menu"
7585
+ ]
7586
+ },
7587
+ "tag": "context-menu-ui",
7588
+ "tokens": {
7589
+ "--context-menu-bg": {
7590
+ "description": "Menu surface background color.",
7591
+ "default": "var(--a-bg-subtle)"
7592
+ },
7593
+ "--context-menu-border": {
7594
+ "description": "Menu surface border color.",
7595
+ "default": "var(--a-border-subtle)"
7596
+ },
7597
+ "--context-menu-radius": {
7598
+ "description": "Menu surface border radius.",
7599
+ "default": "var(--a-radius-md)"
7600
+ },
7601
+ "--context-menu-shadow": {
7602
+ "description": "Menu surface shadow.",
7603
+ "default": "var(--a-shadow-lg)"
7604
+ }
7605
+ },
7606
+ "traits": [],
7607
+ "version": 1
7608
+ }
7609
+ },
7309
7610
  "DashboardLayout": {
7310
7611
  "title": "DashboardLayout",
7311
7612
  "description": "Module-tier dashboard-body composite. Crystallizes the recurring\n\"toolbar + KPI grid + chart area + table\" dashboard layout into a\nsingle primitive with four named regions (toolbar / kpis / charts /\ntable) plus an optional aside column. Each region is filled by\nconsumer-supplied <card-ui>s; the composite owns band sizing,\nresponsive breakpoints, and a [density] knob that propagates to\nevery descendant primitive via the parametric --a-density cascade.\n\nSits inside an <admin-page-body>; replaces the hand-rolled\n<col-ui gap=\"4\"> + nested <grid-ui> + <card-ui> chains every\nanalytics consumer reinvents today. Per ADR-0033 (Light-DOM\nsubstrate) — slot= attributes are decorative metadata; CSS rules\nmatch `:scope > [slot=\"X\"]` to position bands in DOM order.\n\nSpec: docs/specs/implementation-ready/SPEC-018-dashboard-layout.md.\n",
@@ -7387,7 +7688,7 @@
7387
7688
  "wrong": "<dashboard-layout-ui>\n <dashboard-layout-ui slot=\"charts\">...</dashboard-layout-ui>\n</dashboard-layout-ui>\n"
7388
7689
  },
7389
7690
  {
7390
- "description": "kpi-columns out of range. Eight cards in a row produces KPI\ncards narrower than --dashboard-layout-kpi-min (16em); the\ncontainer-query collapse misfires.\n",
7691
+ "description": "kpi-columns out of range. Eight cards in a row is too narrow\nto be legible at typical container widths; the container-query\ncollapse (≤48em → 2 cols, ≤32em → 1 col) won't help when N is\nalready that large at desktop.\n",
7391
7692
  "right": "<dashboard-layout-ui kpi-columns=\"4\">...</dashboard-layout-ui>\n",
7392
7693
  "rule": "kpi-columns ∈ {2,3,4,5,6}. Split into 2 rows of 4 by composing\n2 DashboardLayouts vertically if 8 cards are truly necessary.\n",
7393
7694
  "wrong": "<dashboard-layout-ui kpi-columns=\"8\">...</dashboard-layout-ui>\n"
@@ -7541,10 +7842,6 @@
7541
7842
  "description": "Inter-card gap inside the chart band.",
7542
7843
  "default": "var(--a-space-4)"
7543
7844
  },
7544
- "--dashboard-layout-chart-min": {
7545
- "description": "Minimum chart card inline-size.",
7546
- "default": "22em"
7547
- },
7548
7845
  "--dashboard-layout-gap": {
7549
7846
  "description": "Band-to-band vertical gap.",
7550
7847
  "default": "var(--a-space-4)"
@@ -7553,10 +7850,6 @@
7553
7850
  "description": "Inter-card gap inside the KPI band.",
7554
7851
  "default": "var(--a-space-2)"
7555
7852
  },
7556
- "--dashboard-layout-kpi-min": {
7557
- "description": "Minimum KPI card inline-size before container-query collapse.",
7558
- "default": "16em"
7559
- },
7560
7853
  "--dashboard-layout-padding": {
7561
7854
  "description": "Outer padding around the composite.",
7562
7855
  "default": "0"
@@ -7641,6 +7934,21 @@
7641
7934
  "type": "string",
7642
7935
  "default": "Select range"
7643
7936
  },
7937
+ "placement": {
7938
+ "description": "Popover placement relative to the trigger. Default `bottom` centers the two-calendar panel under the trigger (ADR-0034 Rule 2 — ~800px panel >> trigger).",
7939
+ "type": "string",
7940
+ "enum": [
7941
+ "top",
7942
+ "bottom",
7943
+ "left",
7944
+ "right",
7945
+ "top-start",
7946
+ "top-end",
7947
+ "bottom-start",
7948
+ "bottom-end"
7949
+ ],
7950
+ "default": "bottom"
7951
+ },
7644
7952
  "readonly": {
7645
7953
  "description": "Block edits; allow keyboard navigation for screen-reader inspection.",
7646
7954
  "type": "boolean",
@@ -8164,6 +8472,21 @@
8164
8472
  "type": "string",
8165
8473
  "default": "Select date and time"
8166
8474
  },
8475
+ "placement": {
8476
+ "description": "Popover placement relative to the trigger. Default `bottom` centers the calendar+time panel under the trigger (ADR-0034 Rule 2 — ~600px panel >> trigger).",
8477
+ "type": "string",
8478
+ "enum": [
8479
+ "top",
8480
+ "bottom",
8481
+ "left",
8482
+ "right",
8483
+ "top-start",
8484
+ "top-end",
8485
+ "bottom-start",
8486
+ "bottom-end"
8487
+ ],
8488
+ "default": "bottom"
8489
+ },
8167
8490
  "precision": {
8168
8491
  "description": "Time-pane precision. `minute` (default) emits `HH:mm`; `second` exposes the seconds segment and emits `HH:mm:ss`.",
8169
8492
  "type": "string",
@@ -15153,9 +15476,9 @@
15153
15476
  "version": 1
15154
15477
  }
15155
15478
  },
15156
- "OnboardingChecklist": {
15157
- "title": "OnboardingChecklist",
15158
- "description": "Module-tier onboarding checklist a progressive setup-step widget\n(\"Getting started\" card seen in Stripe / Linear / Vercel dashboards).\nComposes <progress-ui> (top fill bar), <list-ui> + <list-item-ui>\n(the step rows), <check-ui> (per-item completion checkbox), and\noptional <button-ui> (per-item action CTA).\n\nOwns the data model (items: array of {id, label, description, href,\ndone}), the persistence contract (storage-key writes a JSON blob to\nlocalStorage / sessionStorage), the auto-computed progress display,\nand the dismiss-on-complete behavior. Items are data, not slotted\nmarkup — host wiring uses stable per-item ids, not DOM positions.\n\nUse for the \"card of optional setup tasks\" case; use <step-progress-ui>\nfor horizontal multi-screen wizards where the user is locked into\nlinear progression.\n",
15479
+ "NumberFormat": {
15480
+ "title": "NumberFormat",
15481
+ "description": "Display a numeric value with locale-aware formatting currency,\npercentage, compact (1.2K / 3.4M), unit, or plain decimal. Wraps\n`Intl.NumberFormat`. Distinct from `<input-ui type=\"number\">`\n(an INPUT primitive); this is a DISPLAY primitive read-only, no\nform participation, no keyboard handling. Pair with `<stat-ui>` for\nKPI surfaces or use standalone inline within prose.\n",
15159
15482
  "type": "object",
15160
15483
  "allOf": [
15161
15484
  {
@@ -15166,28 +15489,206 @@
15166
15489
  }
15167
15490
  ],
15168
15491
  "properties": {
15169
- "title": {
15170
- "description": "Header label above the progress bar. Defaults to \"Get started\".",
15492
+ "compactDisplay": {
15493
+ "description": "When [notation=\"compact\"], controls the compact-form length.\n`short` = \"1.2M\" (default); `long` = \"1.2 million\".\n",
15171
15494
  "type": "string",
15172
- "default": "Get started"
15173
- },
15174
- "items": {
15175
- "description": "Step list — each item is { id, label, description?, href?, done? }. Required, non-empty.",
15176
- "$ref": "#/$defs/DynamicStringList"
15177
- },
15178
- "collapsed": {
15179
- "description": "Initial / current collapsed state — hides the item list, keeps progress + header visible.",
15180
- "$ref": "#/$defs/DynamicBoolean"
15181
- },
15182
- "collapsible": {
15183
- "description": "Show a top-right collapse toggle.",
15184
- "type": "boolean",
15185
- "default": true
15495
+ "enum": [
15496
+ "short",
15497
+ "long"
15498
+ ],
15499
+ "default": "short"
15186
15500
  },
15187
15501
  "component": {
15188
- "const": "OnboardingChecklist"
15502
+ "const": "NumberFormat"
15189
15503
  },
15190
- "dismiss-on-complete": {
15504
+ "currency": {
15505
+ "description": "ISO 4217 currency code (e.g. \"USD\", \"EUR\", \"JPY\"). Required when\n[number-style=\"currency\"]; ignored otherwise.\n",
15506
+ "type": "string",
15507
+ "default": ""
15508
+ },
15509
+ "locale": {
15510
+ "description": "BCP-47 locale tag for the formatter. Empty defaults to the\ndocument locale (`<html lang>`) then to browser default.\n",
15511
+ "type": "string",
15512
+ "default": ""
15513
+ },
15514
+ "maximumFractionDigits": {
15515
+ "description": "Maximum fractional digits (0–20). Default `2` for decimal/\ncurrency/percent, `1` for compact notation.\n",
15516
+ "type": "number",
15517
+ "default": 2
15518
+ },
15519
+ "minimumFractionDigits": {
15520
+ "description": "Minimum fractional digits (0–20). Padded with trailing zeros.\nUseful for currency display to force \".00\" suffix.\n",
15521
+ "type": "number",
15522
+ "default": 0
15523
+ },
15524
+ "notation": {
15525
+ "description": "`Intl.NumberFormat` `notation` option. `standard` is the\nthousands-grouped form (1,234,567); `compact` is the abbreviated\nform (1.2M); `scientific` and `engineering` are the exponent\nforms. Defaults to `standard`.\n",
15526
+ "type": "string",
15527
+ "enum": [
15528
+ "standard",
15529
+ "compact",
15530
+ "scientific",
15531
+ "engineering"
15532
+ ],
15533
+ "default": "standard"
15534
+ },
15535
+ "numberStyle": {
15536
+ "description": "`Intl.NumberFormat` `style` option. `decimal` (default) renders a\nplain number with locale-aware grouping. `currency` requires\n[currency] to be set. `percent` formats 0–1 as 0%–100%. `unit`\nrequires [unit] to be set (e.g. \"kilobyte\", \"celsius\").\n",
15537
+ "type": "string",
15538
+ "enum": [
15539
+ "decimal",
15540
+ "currency",
15541
+ "percent",
15542
+ "unit"
15543
+ ],
15544
+ "default": "decimal"
15545
+ },
15546
+ "signDisplay": {
15547
+ "description": "`Intl.NumberFormat` `signDisplay` option. `auto` (default) shows\n\"−\" for negatives only; `always` shows \"+\" / \"−\"; `exceptZero`\nshows sign for non-zero only; `never` hides signs.\n",
15548
+ "type": "string",
15549
+ "enum": [
15550
+ "auto",
15551
+ "always",
15552
+ "exceptZero",
15553
+ "never"
15554
+ ],
15555
+ "default": "auto"
15556
+ },
15557
+ "unit": {
15558
+ "description": "`Intl.NumberFormat` unit identifier (e.g. \"kilometer-per-hour\",\n\"celsius\", \"byte\"). Required when [number-style=\"unit\"]; ignored\notherwise. See MDN's NumberFormat docs for the valid set.\n",
15559
+ "type": "string",
15560
+ "default": ""
15561
+ },
15562
+ "value": {
15563
+ "description": "The numeric value to format. Empty string or non-numeric value\nrenders nothing.\n",
15564
+ "type": "number",
15565
+ "default": 0
15566
+ }
15567
+ },
15568
+ "required": [
15569
+ "component"
15570
+ ],
15571
+ "unevaluatedProperties": false,
15572
+ "x-adiaui": {
15573
+ "anti_patterns": [
15574
+ {
15575
+ "fix": "<number-format-ui value=\"0.5\" number-style=\"percent\"></number-format-ui>\n",
15576
+ "why": "Renders \"5,000%\" — Intl.NumberFormat percent style multiplies the\ninput by 100. value=50 means \"5000%\".\n",
15577
+ "wrong": "<number-format-ui value=\"50\" number-style=\"percent\"></number-format-ui>\n"
15578
+ },
15579
+ {
15580
+ "fix": "<number-format-ui value=\"9.99\" number-style=\"currency\" currency=\"USD\"></number-format-ui>\n",
15581
+ "why": "Missing [currency] code. Renders nothing rather than producing\nmalformed currency output.\n",
15582
+ "wrong": "<number-format-ui value=\"9.99\" number-style=\"currency\"></number-format-ui>\n"
15583
+ }
15584
+ ],
15585
+ "category": "display",
15586
+ "composes": [],
15587
+ "events": {},
15588
+ "examples": [
15589
+ {
15590
+ "description": "Plain locale-grouped number — default style.",
15591
+ "a2ui": "[\n {\n \"id\": \"n\",\n \"component\": \"NumberFormat\",\n \"value\": 1234567.89\n }\n]\n",
15592
+ "name": "decimal"
15593
+ },
15594
+ {
15595
+ "description": "USD currency display.",
15596
+ "a2ui": "[\n {\n \"id\": \"n\",\n \"component\": \"NumberFormat\",\n \"value\": 1299.99,\n \"numberStyle\": \"currency\",\n \"currency\": \"USD\"\n }\n]\n",
15597
+ "name": "currency"
15598
+ },
15599
+ {
15600
+ "description": "Fraction → percent (0.876 → 87.6%).",
15601
+ "a2ui": "[\n {\n \"id\": \"n\",\n \"component\": \"NumberFormat\",\n \"value\": 0.876,\n \"numberStyle\": \"percent\",\n \"maximumFractionDigits\": 1\n }\n]\n",
15602
+ "name": "percent"
15603
+ },
15604
+ {
15605
+ "description": "Compact-form (1.2M, 3.4K).",
15606
+ "a2ui": "[\n {\n \"id\": \"n\",\n \"component\": \"NumberFormat\",\n \"value\": 1234567,\n \"notation\": \"compact\"\n }\n]\n",
15607
+ "name": "compact"
15608
+ }
15609
+ ],
15610
+ "keywords": [
15611
+ "number-format",
15612
+ "format",
15613
+ "currency",
15614
+ "percent",
15615
+ "percentage",
15616
+ "compact",
15617
+ "number",
15618
+ "locale",
15619
+ "intl"
15620
+ ],
15621
+ "name": "UINumberFormat",
15622
+ "related": [
15623
+ "stat",
15624
+ "text",
15625
+ "badge",
15626
+ "input"
15627
+ ],
15628
+ "slots": {},
15629
+ "states": [
15630
+ {
15631
+ "description": "Default, displaying the formatted value.",
15632
+ "name": "idle"
15633
+ }
15634
+ ],
15635
+ "status": "stable",
15636
+ "synonyms": {
15637
+ "currency": [
15638
+ "number-format",
15639
+ "money",
15640
+ "price"
15641
+ ],
15642
+ "number": [
15643
+ "number-format",
15644
+ "format"
15645
+ ],
15646
+ "percent": [
15647
+ "number-format",
15648
+ "percentage"
15649
+ ]
15650
+ },
15651
+ "tag": "number-format-ui",
15652
+ "tokens": {},
15653
+ "traits": [],
15654
+ "version": 1
15655
+ }
15656
+ },
15657
+ "OnboardingChecklist": {
15658
+ "title": "OnboardingChecklist",
15659
+ "description": "Module-tier onboarding checklist — a progressive setup-step widget\n(\"Getting started\" card seen in Stripe / Linear / Vercel dashboards).\nComposes <progress-ui> (top fill bar), <list-ui> + <list-item-ui>\n(the step rows), <check-ui> (per-item completion checkbox), and\noptional <button-ui> (per-item action CTA).\n\nOwns the data model (items: array of {id, label, description, href,\ndone}), the persistence contract (storage-key writes a JSON blob to\nlocalStorage / sessionStorage), the auto-computed progress display,\nand the dismiss-on-complete behavior. Items are data, not slotted\nmarkup — host wiring uses stable per-item ids, not DOM positions.\n\nUse for the \"card of optional setup tasks\" case; use <step-progress-ui>\nfor horizontal multi-screen wizards where the user is locked into\nlinear progression.\n",
15660
+ "type": "object",
15661
+ "allOf": [
15662
+ {
15663
+ "$ref": "#/$defs/ComponentCommon"
15664
+ },
15665
+ {
15666
+ "$ref": "#/$defs/CatalogComponentCommon"
15667
+ }
15668
+ ],
15669
+ "properties": {
15670
+ "title": {
15671
+ "description": "Header label above the progress bar. Defaults to \"Get started\".",
15672
+ "type": "string",
15673
+ "default": "Get started"
15674
+ },
15675
+ "items": {
15676
+ "description": "Step list — each item is { id, label, description?, href?, done? }. Required, non-empty.",
15677
+ "$ref": "#/$defs/DynamicStringList"
15678
+ },
15679
+ "collapsed": {
15680
+ "description": "Initial / current collapsed state — hides the item list, keeps progress + header visible.",
15681
+ "$ref": "#/$defs/DynamicBoolean"
15682
+ },
15683
+ "collapsible": {
15684
+ "description": "Show a top-right collapse toggle.",
15685
+ "type": "boolean",
15686
+ "default": true
15687
+ },
15688
+ "component": {
15689
+ "const": "OnboardingChecklist"
15690
+ },
15691
+ "dismiss-on-complete": {
15191
15692
  "description": "Auto-hide the widget when all items are done.",
15192
15693
  "type": "boolean",
15193
15694
  "default": true
@@ -15938,14 +16439,28 @@
15938
16439
  "type": "number",
15939
16440
  "default": 1
15940
16441
  },
16442
+ "size": {
16443
+ "description": "Universal size — threads through to every nested `<button-ui size=…>`\nso pagination honors the substrate's 24/30/36 px size system\n(with [density] modifier). Default `md` matches `<button-ui>`'s\ndefault; pass `size=\"sm\"` for a denser numbered row.\n",
16444
+ "type": "string",
16445
+ "enum": [
16446
+ "sm",
16447
+ "md",
16448
+ "lg"
16449
+ ],
16450
+ "default": "md"
16451
+ },
15941
16452
  "total": {
15942
16453
  "description": "Total number of pages.",
15943
16454
  "type": "number",
15944
16455
  "default": 1
15945
16456
  },
15946
16457
  "variant": {
15947
- "description": "Visual variant",
16458
+ "description": "Visual variant — `default` (ghost buttons w/ hover bg) or `button` (1×1 bordered cells; active page filled).",
15948
16459
  "type": "string",
16460
+ "enum": [
16461
+ "default",
16462
+ "button"
16463
+ ],
15949
16464
  "default": "default"
15950
16465
  }
15951
16466
  },
@@ -15956,7 +16471,10 @@
15956
16471
  "x-adiaui": {
15957
16472
  "anti_patterns": [],
15958
16473
  "category": "navigation",
15959
- "composes": [],
16474
+ "composes": [
16475
+ "button-ui",
16476
+ "icon-ui"
16477
+ ],
15960
16478
  "events": {
15961
16479
  "page-change": {
15962
16480
  "description": "Fired when a page button is clicked. detail contains { page }.",
@@ -16141,6 +16659,156 @@
16141
16659
  "version": 1
16142
16660
  }
16143
16661
  },
16662
+ "PasswordStrength": {
16663
+ "title": "PasswordStrength",
16664
+ "description": "Visual strength indicator for password inputs — 4-segment bar (weak /\nfair / good / strong) computed from a heuristic combining length,\ncharacter-class diversity, and repeat-pattern penalty. Pairs with\n`<input-ui type=\"password\">` via JS:\n input.addEventListener('input', e => meter.value = e.target.value)\nRead-only display primitive — no form participation. Emits a\n`score-change` event when the bucket changes so consumers can gate\na submit button on `detail.satisfied` (score ≥ min-score).\n\n**Security note:** [value] is held as a JS property only, NOT\nreflected to a DOM attribute. The element stamps the bar + label\nfrom the property; the password never appears in the rendered HTML.\nDo not set the value via setAttribute (it will be no-op).\n",
16665
+ "type": "object",
16666
+ "allOf": [
16667
+ {
16668
+ "$ref": "#/$defs/ComponentCommon"
16669
+ },
16670
+ {
16671
+ "$ref": "#/$defs/CatalogComponentCommon"
16672
+ }
16673
+ ],
16674
+ "properties": {
16675
+ "component": {
16676
+ "const": "PasswordStrength"
16677
+ },
16678
+ "minScore": {
16679
+ "description": "Minimum acceptable score (0–3). The `score-change` event's\n`detail.satisfied` boolean reflects whether the current score\nmeets this threshold. Useful for gating a submit button.\n",
16680
+ "type": "number",
16681
+ "default": 2
16682
+ },
16683
+ "showLabel": {
16684
+ "description": "Display the textual score label (\"Weak\" / \"Fair\" / \"Good\" /\n\"Strong\") below the bar. Defaults to true.\n",
16685
+ "type": "boolean",
16686
+ "default": true
16687
+ },
16688
+ "value": {
16689
+ "description": "The password string to score. JS-property only — NOT reflected\nto a DOM attribute (so the password never leaks into rendered\nHTML). Wire to an input via `input.addEventListener('input', e =>\nmeter.value = e.target.value)`.\n",
16690
+ "$ref": "#/$defs/DynamicString"
16691
+ }
16692
+ },
16693
+ "required": [
16694
+ "component"
16695
+ ],
16696
+ "unevaluatedProperties": false,
16697
+ "x-adiaui": {
16698
+ "anti_patterns": [
16699
+ {
16700
+ "fix": "<password-strength-ui id=\"m\"></password-strength-ui>\n<script>document.getElementById('m').value = pwd;</script>\n",
16701
+ "why": "`value` is JS-property only; the attribute is ignored. The\npassword also shouldn't be authored into HTML at all (server\ntemplate / static page) — that defeats the purpose.\n",
16702
+ "wrong": "<password-strength-ui value=\"hunter2\"></password-strength-ui>\n"
16703
+ }
16704
+ ],
16705
+ "category": "display",
16706
+ "composes": [],
16707
+ "events": {
16708
+ "score-change": {
16709
+ "description": "Fired when the computed score crosses a bucket boundary (not on every keystroke). Detail carries the new score + label + satisfied flag.",
16710
+ "detail": {
16711
+ "label": "string",
16712
+ "satisfied": "boolean",
16713
+ "score": "number"
16714
+ }
16715
+ }
16716
+ },
16717
+ "examples": [
16718
+ {
16719
+ "description": "Standard pairing with input-ui[type=password] via input listener.",
16720
+ "a2ui": "[\n {\n \"id\": \"field\",\n \"component\": \"Field\",\n \"label\": \"Password\",\n \"children\": [\"pwd\", \"meter\"]\n },\n {\n \"id\": \"pwd\",\n \"component\": \"Input\",\n \"type\": \"password\",\n \"name\": \"password\"\n },\n {\n \"id\": \"meter\",\n \"component\": \"PasswordStrength\"\n }\n]\n",
16721
+ "name": "paired-with-input"
16722
+ }
16723
+ ],
16724
+ "keywords": [
16725
+ "password-strength",
16726
+ "strength-meter",
16727
+ "password",
16728
+ "strength",
16729
+ "meter",
16730
+ "security"
16731
+ ],
16732
+ "name": "UIPasswordStrength",
16733
+ "related": [
16734
+ "input",
16735
+ "field",
16736
+ "progress"
16737
+ ],
16738
+ "slots": {
16739
+ "default": {
16740
+ "description": "Optional area for requirements checklist content (e.g. <ul> of \"at least 8 characters\", \"mixed case\", etc.)."
16741
+ }
16742
+ },
16743
+ "states": [
16744
+ {
16745
+ "description": "Default — no value set, all segments grey.",
16746
+ "name": "idle"
16747
+ },
16748
+ {
16749
+ "description": "Value present; segments lit per score 0..3.",
16750
+ "attribute": "data-score",
16751
+ "name": "scored"
16752
+ }
16753
+ ],
16754
+ "status": "stable",
16755
+ "synonyms": {
16756
+ "password": [
16757
+ "password-strength",
16758
+ "strength-meter"
16759
+ ],
16760
+ "strength": [
16761
+ "password-strength",
16762
+ "meter"
16763
+ ]
16764
+ },
16765
+ "tag": "password-strength-ui",
16766
+ "tokens": {
16767
+ "--password-strength-color-fair": {
16768
+ "description": "Color for score=1 lit segments.",
16769
+ "default": "var(--a-warning-bg)"
16770
+ },
16771
+ "--password-strength-color-good": {
16772
+ "description": "Color for score=2 lit segments.",
16773
+ "default": "var(--a-info-bg)"
16774
+ },
16775
+ "--password-strength-color-strong": {
16776
+ "description": "Color for score=3 lit segments.",
16777
+ "default": "var(--a-success-bg)"
16778
+ },
16779
+ "--password-strength-color-weak": {
16780
+ "description": "Color for score=0 lit segments.",
16781
+ "default": "var(--a-danger-bg)"
16782
+ },
16783
+ "--password-strength-gap": {
16784
+ "description": "Gap between segments.",
16785
+ "default": "var(--a-space-1)"
16786
+ },
16787
+ "--password-strength-label-fg": {
16788
+ "description": "Label text color.",
16789
+ "default": "var(--a-fg-muted)"
16790
+ },
16791
+ "--password-strength-label-size": {
16792
+ "description": "Label font size.",
16793
+ "default": "var(--a-ui-sm)"
16794
+ },
16795
+ "--password-strength-radius": {
16796
+ "description": "Segment border radius.",
16797
+ "default": "var(--a-radius-full)"
16798
+ },
16799
+ "--password-strength-segment-bg": {
16800
+ "description": "Unlit segment background (track color).",
16801
+ "default": "var(--a-canvas-1-scrim)"
16802
+ },
16803
+ "--password-strength-segment-height": {
16804
+ "description": "Height of each bar segment.",
16805
+ "default": "4px"
16806
+ }
16807
+ },
16808
+ "traits": [],
16809
+ "version": 1
16810
+ }
16811
+ },
16144
16812
  "PaymentMethodForm": {
16145
16813
  "title": "PaymentMethodForm",
16146
16814
  "description": "Form-participating composite for capturing a payment method —\ncard number, expiry, CVC, name on card, billing address (optional),\nand country. The form chrome + structured validation + a single\nnormalized emit event; it does NOT integrate with Stripe Elements\nor a tokenization SDK directly (consumer responsibility).\n\nEach sub-field is a <field-ui> wrapper around an <input-ui> (or\n<select-ui> for country). Card number is Luhn-validated; expiry is\nparsed as MM/YY with month + year bounds; CVC is 3-4 digits.\nBrand detection (visa / mastercard / amex / discover) runs against\na small regex map and surfaces via the `change` event detail.\n\nForm value is a JSON-encoded payload of normalized field values\nserialized through ElementInternals under [name] (default\n\"paymentMethod\"). On submit, the host fires\n`submit-payment-method` with a flat detail\n`{ token, last4, brand, expMonth, expYear, name, country }`.\n`token` is a synthetic local-mode token (sha-like opaque string);\nconsumers integrating with a real processor handle tokenization\nin their own submit listener using `last4` / `brand` / etc.\n\nSpec: docs/specs/implementation-ready/SPEC-009-payment-method-form.md.\n",
@@ -17641,6 +18309,158 @@
17641
18309
  "version": 1
17642
18310
  }
17643
18311
  },
18312
+ "QRCode": {
18313
+ "title": "QRCode",
18314
+ "description": "Inline QR code generator — renders a scannable code as inline SVG.\nTwo modes:\n\n**A. Auto-encode (default).** Set `[value]` to a string (URL, plain\ntext, share link, 2FA secret). The component encodes the data with\nthe built-in zero-deps QR encoder (byte mode, ECC level configurable,\nversions 1–10 up to ~150 byte chars) and renders an SVG.\n\n**B. Bring-your-own matrix.** Set `[matrix]` to a JSON string of a\n2-D 0/1 array (`[[1,0,1,...],[...],...]`). The component renders the\nsupplied matrix directly without invoking its own encoder. Use this\nwhen you need versions 11–40, kanji/alphanumeric mode, or any\nencoder feature beyond the built-in. When both `[value]` and\n`[matrix]` are set, the matrix wins (BYO override).\n\nOutput is a single `<svg>` with `viewBox=\"0 0 N N\"`. Crisp-edges\nrendering preserves the scannable cell boundaries at any size.\nSizing is controlled by the `[size]` prop (host CSS-pixel dimension);\ninternal cell size is computed from `size / (matrix-size + 2 ·\nmargin)`. ARIA: `role=\"img\"` with `aria-label` (default \"QR code\"\nor the `[label]` prop).\n",
18315
+ "type": "object",
18316
+ "allOf": [
18317
+ {
18318
+ "$ref": "#/$defs/ComponentCommon"
18319
+ },
18320
+ {
18321
+ "$ref": "#/$defs/CatalogComponentCommon"
18322
+ }
18323
+ ],
18324
+ "properties": {
18325
+ "background": {
18326
+ "description": "Background (light-cell) color. **Empty defaults to `#ffffff` —\nhardcoded white** alongside the black foreground, for guaranteed\nscanability. Override only when paired with an explicit\n[color] (the contrast pair must scan).\n",
18327
+ "type": "string",
18328
+ "default": ""
18329
+ },
18330
+ "color": {
18331
+ "description": "Foreground (dark-cell) color. Any CSS color string (hex, rgb,\ntoken reference). **Empty defaults to `#000000` — hardcoded black\nfor guaranteed scanability** (theme-aware `currentColor` would\nproduce light-on-dark in dark mode, which most phone scanners\nrefuse to decode). Override for branded QRs only when you've\nverified the chosen color/background pair scans on the target\ndevices.\n",
18332
+ "type": "string",
18333
+ "default": ""
18334
+ },
18335
+ "component": {
18336
+ "const": "QRCode"
18337
+ },
18338
+ "errorCorrection": {
18339
+ "description": "Error-correction level (auto-encode mode only). `L` (7% recovery),\n`M` (15%, default), `Q` (25%), `H` (30%). Higher levels recover\nfrom more damage at the cost of QR-version size growth.\n",
18340
+ "type": "string",
18341
+ "enum": [
18342
+ "L",
18343
+ "M",
18344
+ "Q",
18345
+ "H"
18346
+ ],
18347
+ "default": "M"
18348
+ },
18349
+ "label": {
18350
+ "description": "`aria-label` for the SVG. Defaults to \"QR code\". Customize for\nbetter AT context (e.g. \"Share link QR code\", \"2FA setup QR\").\n",
18351
+ "type": "string",
18352
+ "default": "QR code"
18353
+ },
18354
+ "margin": {
18355
+ "description": "Quiet zone in cells around the QR pattern. QR spec requires a\nminimum 4-cell margin for reliable scanning; smaller values may\nnot scan on some devices. Default `4`.\n",
18356
+ "type": "number",
18357
+ "default": 4
18358
+ },
18359
+ "matrix": {
18360
+ "description": "BYO precomputed bit matrix as JSON — a 2-D array of 0/1\n(`[[1,0,...],[0,1,...],...]`). When set, the built-in encoder is\nbypassed and this matrix renders directly. Useful for QR variants\nthe built-in doesn't support (versions 11–40, alphanumeric mode,\nkanji, etc.) — bring your own encoder, pass the matrix here.\n",
18361
+ "type": "string",
18362
+ "default": ""
18363
+ },
18364
+ "size": {
18365
+ "description": "Host display size in CSS pixels (width and height; the SVG is\nalways square). Default 200. Internal cell size is computed from\nthis divided by `matrix-size + 2·margin`.\n",
18366
+ "type": "number",
18367
+ "default": 200
18368
+ },
18369
+ "value": {
18370
+ "description": "The string to encode (URL / text / share link / 2FA seed). When\n[matrix] is also set, the matrix wins. Empty value + empty matrix\nrenders nothing.\n",
18371
+ "type": "string",
18372
+ "default": ""
18373
+ }
18374
+ },
18375
+ "required": [
18376
+ "component"
18377
+ ],
18378
+ "unevaluatedProperties": false,
18379
+ "x-adiaui": {
18380
+ "anti_patterns": [
18381
+ {
18382
+ "fix": "Drop the ECC level (lower L gives more capacity for the same\nversion), OR shorten the URL (use a URL shortener), OR encode\nwith a BYO encoder library + pass the [matrix]:\n`<qr-code-ui matrix=\"[[1,0,1,...],...]\"></qr-code-ui>`\n",
18383
+ "why": "Built-in encoder covers versions 1–10. Data beyond v10 capacity\nthrows + renders empty + sets [data-error]. Console warns with\nthe byte length so consumers can diagnose.\n",
18384
+ "wrong": "<qr-code-ui value=\"https://very.long.url.that.exceeds.150.bytes.of.utf8.encoded.length...\"></qr-code-ui>\n"
18385
+ },
18386
+ {
18387
+ "fix": "<qr-code-ui value=\"...\" margin=\"4\"></qr-code-ui>\n",
18388
+ "why": "Zero margin breaks scanning. QR spec requires a 4-cell quiet\nzone for reliable detection.\n",
18389
+ "wrong": "<qr-code-ui value=\"...\" margin=\"0\"></qr-code-ui>\n"
18390
+ }
18391
+ ],
18392
+ "category": "display",
18393
+ "composes": [],
18394
+ "events": {},
18395
+ "examples": [
18396
+ {
18397
+ "description": "Plain URL encoding at default size + ECC-M.",
18398
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"QRCode\",\n \"value\": \"https://example.com\"\n }\n]\n",
18399
+ "name": "default"
18400
+ },
18401
+ {
18402
+ "description": "Custom colors matching brand chrome.",
18403
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"QRCode\",\n \"value\": \"https://adia.health/share/abc123\",\n \"size\": 280,\n \"color\": \"#1e293b\",\n \"background\": \"#ffffff\",\n \"errorCorrection\": \"Q\"\n }\n]\n",
18404
+ "name": "branded"
18405
+ },
18406
+ {
18407
+ "description": "BYO precomputed matrix from an external encoder.",
18408
+ "a2ui": "[\n {\n \"id\": \"q\",\n \"component\": \"QRCode\",\n \"matrix\": \"[[1,1,1,1,1,1,1,0,1,...]...]\",\n \"size\": 200,\n \"label\": \"Boarding pass QR\"\n }\n]\n",
18409
+ "name": "byo-matrix"
18410
+ }
18411
+ ],
18412
+ "keywords": [
18413
+ "qr-code",
18414
+ "qr",
18415
+ "barcode",
18416
+ "scan",
18417
+ "share",
18418
+ "2fa",
18419
+ "share-link"
18420
+ ],
18421
+ "name": "UIQRCode",
18422
+ "related": [
18423
+ "link",
18424
+ "share"
18425
+ ],
18426
+ "slots": {},
18427
+ "states": [
18428
+ {
18429
+ "description": "Default — QR rendered (or empty if no value/matrix).",
18430
+ "name": "idle"
18431
+ },
18432
+ {
18433
+ "description": "Auto-encode failed (data too long for v1–10 at requested ECC). Renders an empty placeholder; logs a console warning. Switch to a BYO matrix from an external encoder, or downgrade the ECC level.",
18434
+ "attribute": "data-error",
18435
+ "name": "error"
18436
+ }
18437
+ ],
18438
+ "status": "stable",
18439
+ "synonyms": {
18440
+ "qr": [
18441
+ "qr-code",
18442
+ "barcode"
18443
+ ],
18444
+ "scan": [
18445
+ "qr-code",
18446
+ "barcode"
18447
+ ]
18448
+ },
18449
+ "tag": "qr-code-ui",
18450
+ "tokens": {
18451
+ "--qr-code-bg": {
18452
+ "description": "Background (light) color when [background] is empty.",
18453
+ "default": "transparent"
18454
+ },
18455
+ "--qr-code-fg": {
18456
+ "description": "Foreground (dark) color when [color] is empty.",
18457
+ "default": "currentColor"
18458
+ }
18459
+ },
18460
+ "traits": [],
18461
+ "version": 1
18462
+ }
18463
+ },
17644
18464
  "Radio": {
17645
18465
  "title": "Radio",
17646
18466
  "description": "Radio button with pure CSS dot. Groups by name attribute (one selected value per group); form-associated and emits standard change events. Use for single-select option groups in forms; for richer styling or button-style options use <segment-ui> inside <segmented-ui> instead.",
@@ -18099,52 +18919,170 @@
18099
18919
  }
18100
18920
  },
18101
18921
  "required": [
18102
- "component",
18103
- "value"
18922
+ "component",
18923
+ "value"
18924
+ ],
18925
+ "unevaluatedProperties": false,
18926
+ "x-adiaui": {
18927
+ "anti_patterns": [],
18928
+ "category": "form",
18929
+ "composes": [],
18930
+ "events": {
18931
+ "[object Object]": {
18932
+ "description": "Fired on [object Object]."
18933
+ }
18934
+ },
18935
+ "examples": [],
18936
+ "keywords": [
18937
+ "rating",
18938
+ "stars",
18939
+ "review",
18940
+ "feedback",
18941
+ "score",
18942
+ "vote",
18943
+ "heart",
18944
+ "like"
18945
+ ],
18946
+ "name": "UIRating",
18947
+ "related": [
18948
+ "Field",
18949
+ "AgentFeedbackBar"
18950
+ ],
18951
+ "slots": {},
18952
+ "states": [
18953
+ {
18954
+ "description": "Default, ready for interaction.",
18955
+ "name": "idle"
18956
+ }
18957
+ ],
18958
+ "status": "stable",
18959
+ "synonyms": {
18960
+ "rating": [
18961
+ "rating",
18962
+ "star rating",
18963
+ "review score",
18964
+ "feedback rating"
18965
+ ]
18966
+ },
18967
+ "tag": "rating-ui",
18968
+ "tokens": {},
18969
+ "traits": [],
18970
+ "version": 1
18971
+ }
18972
+ },
18973
+ "RelativeTime": {
18974
+ "title": "RelativeTime",
18975
+ "description": "Display a timestamp as a human-readable relative time — \"3 hours ago\",\n\"in 2 days\", \"yesterday\". Wraps `Intl.RelativeTimeFormat` for i18n\n+ auto-updates on a configurable interval (default every 60 s) so\nrendered text stays current without re-mounting.\n\nSet `[datetime]` to an ISO 8601 timestamp; the element computes the\ndelta against `Date.now()` and renders the formatted string. Pair\nwith a `title` for full-precision-on-hover (the element sets one\nautomatically from a default locale-aware long format unless you\noverride).\n",
18976
+ "type": "object",
18977
+ "allOf": [
18978
+ {
18979
+ "$ref": "#/$defs/ComponentCommon"
18980
+ },
18981
+ {
18982
+ "$ref": "#/$defs/CatalogComponentCommon"
18983
+ }
18984
+ ],
18985
+ "properties": {
18986
+ "component": {
18987
+ "const": "RelativeTime"
18988
+ },
18989
+ "datetime": {
18990
+ "description": "ISO 8601 timestamp (e.g. `2026-05-25T09:30:00Z`) or any string\nparseable by `Date`. Required for output — empty value renders\nnothing.\n",
18991
+ "type": "string",
18992
+ "default": ""
18993
+ },
18994
+ "locale": {
18995
+ "description": "BCP-47 locale tag for the formatter. Empty defaults to the document\nlocale (`<html lang>`) then to the browser default.\n",
18996
+ "type": "string",
18997
+ "default": ""
18998
+ },
18999
+ "numeric": {
19000
+ "description": "`Intl.RelativeTimeFormat` `numeric` option. `auto` lets the\nformatter substitute \"yesterday\" / \"tomorrow\" for ±1 day deltas;\n`always` keeps the numeric form (\"1 day ago\"). Defaults to `auto`.\n",
19001
+ "type": "string",
19002
+ "enum": [
19003
+ "auto",
19004
+ "always"
19005
+ ],
19006
+ "default": "auto"
19007
+ },
19008
+ "timeStyle": {
19009
+ "description": "`Intl.RelativeTimeFormat` `style` option. `long` = \"3 hours ago\",\n`short` = \"3 hr. ago\", `narrow` = \"3h ago\". Defaults to `long`.\n",
19010
+ "type": "string",
19011
+ "enum": [
19012
+ "long",
19013
+ "short",
19014
+ "narrow"
19015
+ ],
19016
+ "default": "long"
19017
+ },
19018
+ "updateInterval": {
19019
+ "description": "Auto-refresh interval in seconds. The component restarts a\n`setInterval` tick that re-reads `Date.now()` and re-renders the\nrelative string. Set to `0` to disable auto-update (static\nrender). Default `60` (one minute) is the natural cadence for\n\"minutes ago\" granularity.\n",
19020
+ "type": "number",
19021
+ "default": 60
19022
+ }
19023
+ },
19024
+ "required": [
19025
+ "component"
18104
19026
  ],
18105
19027
  "unevaluatedProperties": false,
18106
19028
  "x-adiaui": {
18107
19029
  "anti_patterns": [],
18108
- "category": "form",
19030
+ "category": "display",
18109
19031
  "composes": [],
18110
- "events": {
18111
- "[object Object]": {
18112
- "description": "Fired on [object Object]."
19032
+ "events": {},
19033
+ "examples": [
19034
+ {
19035
+ "description": "A timestamp rendered as a long relative phrase, auto-updating every 60 s.",
19036
+ "a2ui": "[\n {\n \"id\": \"ts\",\n \"component\": \"RelativeTime\",\n \"datetime\": \"2026-05-25T09:00:00Z\"\n }\n]\n",
19037
+ "name": "default"
19038
+ },
19039
+ {
19040
+ "description": "Tight UI affordances — narrow form for chat bubble timestamps.",
19041
+ "a2ui": "[\n {\n \"id\": \"ts\",\n \"component\": \"RelativeTime\",\n \"datetime\": \"2026-05-25T11:30:00Z\",\n \"timeStyle\": \"narrow\"\n }\n]\n",
19042
+ "name": "short-narrow"
19043
+ },
19044
+ {
19045
+ "description": "A historical timestamp that doesn't need to tick (commit log row).",
19046
+ "a2ui": "[\n {\n \"id\": \"ts\",\n \"component\": \"RelativeTime\",\n \"datetime\": \"2025-11-01T00:00:00Z\",\n \"updateInterval\": 0\n }\n]\n",
19047
+ "name": "static-historical"
18113
19048
  }
18114
- },
18115
- "examples": [],
19049
+ ],
18116
19050
  "keywords": [
18117
- "rating",
18118
- "stars",
18119
- "review",
18120
- "feedback",
18121
- "score",
18122
- "vote",
18123
- "heart",
18124
- "like"
19051
+ "relative-time",
19052
+ "timeago",
19053
+ "time",
19054
+ "timestamp",
19055
+ "ago",
19056
+ "elapsed",
19057
+ "relative",
19058
+ "duration"
18125
19059
  ],
18126
- "name": "UIRating",
19060
+ "name": "UIRelativeTime",
18127
19061
  "related": [
18128
- "Field",
18129
- "AgentFeedbackBar"
19062
+ "text",
19063
+ "badge",
19064
+ "stat"
18130
19065
  ],
18131
19066
  "slots": {},
18132
19067
  "states": [
18133
19068
  {
18134
- "description": "Default, ready for interaction.",
19069
+ "description": "Default, displaying the formatted relative time.",
18135
19070
  "name": "idle"
18136
19071
  }
18137
19072
  ],
18138
19073
  "status": "stable",
18139
19074
  "synonyms": {
18140
- "rating": [
18141
- "rating",
18142
- "star rating",
18143
- "review score",
18144
- "feedback rating"
19075
+ "ago": [
19076
+ "relative-time",
19077
+ "timeago"
19078
+ ],
19079
+ "timestamp": [
19080
+ "relative-time",
19081
+ "time",
19082
+ "datetime"
18145
19083
  ]
18146
19084
  },
18147
- "tag": "rating-ui",
19085
+ "tag": "relative-time-ui",
18148
19086
  "tokens": {},
18149
19087
  "traits": [],
18150
19088
  "version": 1
@@ -19492,6 +20430,96 @@
19492
20430
  "version": 1
19493
20431
  }
19494
20432
  },
20433
+ "SkipNav": {
20434
+ "title": "SkipNav",
20435
+ "description": "Accessibility utility — visually-hidden link that becomes visible on\nkeyboard focus, letting keyboard users skip past repetitive navigation\nto the main content. WCAG 2.1 Success Criterion 2.4.1 \"Bypass Blocks\".\n\nPlace as the FIRST focusable element on the page (typically inside\n`<body>` before any nav / shell chrome). Target an `id` on your main\ncontent region (commonly `#main` / `#main-content`).\n",
20436
+ "type": "object",
20437
+ "allOf": [
20438
+ {
20439
+ "$ref": "#/$defs/ComponentCommon"
20440
+ },
20441
+ {
20442
+ "$ref": "#/$defs/CatalogComponentCommon"
20443
+ }
20444
+ ],
20445
+ "properties": {
20446
+ "component": {
20447
+ "const": "SkipNav"
20448
+ },
20449
+ "target": {
20450
+ "description": "CSS id (with leading `#`) of the main content region the link skips to.",
20451
+ "type": "string",
20452
+ "default": "#main"
20453
+ },
20454
+ "text": {
20455
+ "description": "Link label. Defaults to \"Skip to main content\"; localize per site.",
20456
+ "type": "string",
20457
+ "default": "Skip to main content"
20458
+ }
20459
+ },
20460
+ "required": [
20461
+ "component"
20462
+ ],
20463
+ "unevaluatedProperties": false,
20464
+ "x-adiaui": {
20465
+ "anti_patterns": [
20466
+ {
20467
+ "fix": "<body><skip-nav-ui></skip-nav-ui><header>…nav…</header><main id=\"main\" tabindex=\"-1\">…</main></body>",
20468
+ "why": "The skip link comes AFTER the nav — keyboard users have already tabbed through everything you wanted them to skip.",
20469
+ "wrong": "<header>…nav…</header><skip-nav-ui></skip-nav-ui><main id=\"main\">…</main>"
20470
+ }
20471
+ ],
20472
+ "category": "utility",
20473
+ "composes": [],
20474
+ "events": {},
20475
+ "examples": [
20476
+ {
20477
+ "description": "Standard skip-nav at the top of the page.",
20478
+ "a2ui": "[\n { \"id\": \"skip\", \"component\": \"SkipNav\", \"target\": \"#main\" }\n]\n",
20479
+ "name": "default"
20480
+ }
20481
+ ],
20482
+ "keywords": [
20483
+ "skip-nav",
20484
+ "skip-link",
20485
+ "bypass-blocks",
20486
+ "a11y",
20487
+ "accessibility",
20488
+ "keyboard-navigation"
20489
+ ],
20490
+ "name": "UISkipNav",
20491
+ "related": [
20492
+ "visually-hidden"
20493
+ ],
20494
+ "slots": {},
20495
+ "states": [
20496
+ {
20497
+ "description": "Default — link is visually hidden but focusable.",
20498
+ "name": "idle"
20499
+ },
20500
+ {
20501
+ "description": "Link is focused via keyboard and visible at the top of the viewport.",
20502
+ "attribute": ":focus-within",
20503
+ "name": "focused"
20504
+ }
20505
+ ],
20506
+ "status": "stable",
20507
+ "synonyms": {},
20508
+ "tag": "skip-nav-ui",
20509
+ "tokens": {
20510
+ "--skip-nav-bg": {
20511
+ "description": "Background of the visible (focused) skip link.",
20512
+ "default": "var(--a-accent-bg)"
20513
+ },
20514
+ "--skip-nav-fg": {
20515
+ "description": "Foreground of the visible (focused) skip link.",
20516
+ "default": "var(--a-accent-fg)"
20517
+ }
20518
+ },
20519
+ "traits": [],
20520
+ "version": 1
20521
+ }
20522
+ },
19495
20523
  "Slider": {
19496
20524
  "title": "Slider",
19497
20525
  "description": "Range slider with track, fill, and thumb. Supports label, suffix, and keyboard control. Form-associated.",
@@ -19518,6 +20546,11 @@
19518
20546
  "type": "boolean",
19519
20547
  "default": false
19520
20548
  },
20549
+ "dual": {
20550
+ "description": "Two-thumb range slider mode. When enabled, [lower-value] and\n[upper-value] are authoritative and [value] is ignored. The fill\nrenders between the two thumbs (not from left to thumb). Form-data\nunder [name] serializes as \"<lower>,<upper>\". Use for price filters,\ndate ranges, audio range gates, etc.",
20551
+ "type": "boolean",
20552
+ "default": false
20553
+ },
19521
20554
  "error": {
19522
20555
  "description": "Validation error",
19523
20556
  "type": "string",
@@ -19533,6 +20566,11 @@
19533
20566
  "type": "string",
19534
20567
  "default": ""
19535
20568
  },
20569
+ "lowerValue": {
20570
+ "description": "Lower thumb value (dual mode only; clamped to ≤ [upper-value]).",
20571
+ "type": "number",
20572
+ "default": 0
20573
+ },
19536
20574
  "max": {
19537
20575
  "description": "Maximum slider value",
19538
20576
  "type": "number",
@@ -19563,8 +20601,13 @@
19563
20601
  "type": "number",
19564
20602
  "default": 0
19565
20603
  },
20604
+ "upperValue": {
20605
+ "description": "Upper thumb value (dual mode only; clamped to ≥ [lower-value]).",
20606
+ "type": "number",
20607
+ "default": 100
20608
+ },
19566
20609
  "value": {
19567
- "description": "Current slider value",
20610
+ "description": "Current slider value (single-thumb mode; ignored when [dual] is set)",
19568
20611
  "type": "number",
19569
20612
  "default": 50
19570
20613
  }
@@ -21776,6 +22819,163 @@
21776
22819
  "version": 1
21777
22820
  }
21778
22821
  },
22822
+ "TableOfContents": {
22823
+ "title": "TableOfContents",
22824
+ "description": "Auto-generated in-page table of contents. Scans a target container\nfor headings (default `h2,h3`), ensures each has an `id` (slugifies\nthe text content if missing), and stamps a `<nav>` list of anchor\nlinks. An `IntersectionObserver` tracks the active heading and\napplies `[data-active]` to the matching link so consumers can style\nthe currently-visible section. Smooth-scroll on click is handled by\nthe global `scroll-behavior: smooth` set in resets.css.\n\nPair with a sticky container (`position: sticky; top: <offset>;`) in\nan aside / right rail for the classic docs-site outline pattern.\n",
22825
+ "type": "object",
22826
+ "allOf": [
22827
+ {
22828
+ "$ref": "#/$defs/ComponentCommon"
22829
+ },
22830
+ {
22831
+ "$ref": "#/$defs/CatalogComponentCommon"
22832
+ }
22833
+ ],
22834
+ "properties": {
22835
+ "component": {
22836
+ "const": "TableOfContents"
22837
+ },
22838
+ "headings": {
22839
+ "description": "CSS selector listing the heading tags to include (e.g. `h2,h3`).\nThe selector is matched against the target container's\ndescendants. Default `h2,h3` produces the common two-level\noutline.\n",
22840
+ "type": "string",
22841
+ "default": "h2,h3"
22842
+ },
22843
+ "label": {
22844
+ "description": "`aria-label` for the nav. Defaults to `Table of contents`.\n",
22845
+ "type": "string",
22846
+ "default": "Table of contents"
22847
+ },
22848
+ "offset": {
22849
+ "description": "Top offset in pixels for active-state detection. The\nIntersectionObserver's `rootMargin` is set to\n`-<offset>px 0px -50% 0px` so the active item becomes the\nheading nearest the top of the viewport BELOW any sticky header\nchrome. Tune to match the height of your sticky topbar (default\n`80` is a reasonable docs-shell value).\n",
22850
+ "type": "number",
22851
+ "default": 80
22852
+ },
22853
+ "target": {
22854
+ "description": "CSS selector pointing to the container to scan. Empty (default)\nscans the toc-ui's parent element. Set to `#article` /\n`[data-toc-target]` / `main` for a specific scope.\n",
22855
+ "type": "string",
22856
+ "default": ""
22857
+ }
22858
+ },
22859
+ "required": [
22860
+ "component"
22861
+ ],
22862
+ "unevaluatedProperties": false,
22863
+ "x-adiaui": {
22864
+ "anti_patterns": [
22865
+ {
22866
+ "fix": "<toc-ui target=\"#article\"></toc-ui>\n<article id=\"article\">\n <h2>...</h2><h3>...</h3>\n</article>\n",
22867
+ "why": "toc-ui's default scans its PARENT for headings. If toc-ui is a\nsibling of the content (not inside it), the scan finds the\nheadings inside the toc-ui's parent which usually means the\nheadings + the toc itself — works only by coincidence. Set\n[target] explicitly for clarity.\n",
22868
+ "wrong": "<toc-ui></toc-ui>\n<h2>...</h2><h3>...</h3>\n"
22869
+ }
22870
+ ],
22871
+ "category": "navigation",
22872
+ "composes": [],
22873
+ "events": {
22874
+ "section-change": {
22875
+ "description": "Fired when the active heading changes (the user scrolls into a new section). Detail carries the new active id.",
22876
+ "detail": {
22877
+ "activeId": "string"
22878
+ }
22879
+ }
22880
+ },
22881
+ "examples": [
22882
+ {
22883
+ "description": "TOC scanning the parent container.",
22884
+ "a2ui": "[\n {\n \"id\": \"page\",\n \"component\": \"Section\",\n \"children\": [\"toc\", \"h1\", \"h2-1\", \"p-1\", \"h2-2\", \"p-2\"]\n },\n {\"id\": \"toc\", \"component\": \"TableOfContents\"},\n {\"id\": \"h1\", \"component\": \"Text\", \"variant\": \"title\", \"textContent\": \"Article title\"},\n {\"id\": \"h2-1\", \"component\": \"Text\", \"variant\": \"heading\", \"textContent\": \"Introduction\"},\n {\"id\": \"p-1\", \"component\": \"Text\", \"textContent\": \"...\"},\n {\"id\": \"h2-2\", \"component\": \"Text\", \"variant\": \"heading\", \"textContent\": \"Conclusion\"},\n {\"id\": \"p-2\", \"component\": \"Text\", \"textContent\": \"...\"}\n]\n",
22885
+ "name": "default"
22886
+ },
22887
+ {
22888
+ "description": "TOC scanning a specific article container.",
22889
+ "a2ui": "[\n {\n \"id\": \"shell\",\n \"component\": \"Row\",\n \"children\": [\"toc\", \"article\"]\n },\n {\n \"id\": \"toc\",\n \"component\": \"TableOfContents\",\n \"target\": \"#main-article\",\n \"headings\": \"h2,h3,h4\"\n },\n {\n \"id\": \"article\",\n \"component\": \"Section\",\n \"attrs\": { \"id\": \"main-article\" },\n \"children\": []\n }\n]\n",
22890
+ "name": "targeted"
22891
+ }
22892
+ ],
22893
+ "keywords": [
22894
+ "toc",
22895
+ "table-of-contents",
22896
+ "outline",
22897
+ "sub-nav",
22898
+ "page-nav",
22899
+ "in-page-nav",
22900
+ "heading-nav"
22901
+ ],
22902
+ "name": "UITableOfContents",
22903
+ "related": [
22904
+ "aside",
22905
+ "nav",
22906
+ "link",
22907
+ "text"
22908
+ ],
22909
+ "slots": {
22910
+ "default": {
22911
+ "description": "Stamped automatically — a `<nav>` containing a flat `<ul>` of `<a href=\"#id\">` links. Override by authoring your own content; auto-stamp is skipped when a `<nav>` is already present."
22912
+ }
22913
+ },
22914
+ "states": [
22915
+ {
22916
+ "description": "Default — no active section yet.",
22917
+ "name": "idle"
22918
+ },
22919
+ {
22920
+ "description": "A section is in view; the matching `<a>` carries `[data-active]`.",
22921
+ "attribute": "data-active",
22922
+ "name": "active"
22923
+ }
22924
+ ],
22925
+ "status": "stable",
22926
+ "synonyms": {
22927
+ "outline": [
22928
+ "toc",
22929
+ "table-of-contents"
22930
+ ],
22931
+ "toc": [
22932
+ "table-of-contents",
22933
+ "outline"
22934
+ ]
22935
+ },
22936
+ "tag": "toc-ui",
22937
+ "tokens": {
22938
+ "--toc-fg": {
22939
+ "description": "Default link color.",
22940
+ "default": "var(--a-fg-muted)"
22941
+ },
22942
+ "--toc-fg-active": {
22943
+ "description": "Active-link color.",
22944
+ "default": "var(--a-fg)"
22945
+ },
22946
+ "--toc-fg-hover": {
22947
+ "description": "Hover color.",
22948
+ "default": "var(--a-fg)"
22949
+ },
22950
+ "--toc-gap": {
22951
+ "description": "Vertical gap between links.",
22952
+ "default": "var(--a-space-1)"
22953
+ },
22954
+ "--toc-indent": {
22955
+ "description": "Per-depth-level indent.",
22956
+ "default": "var(--a-space-3)"
22957
+ },
22958
+ "--toc-padding-block": {
22959
+ "description": "Per-link block padding (top/bottom).",
22960
+ "default": "var(--a-space-1)"
22961
+ },
22962
+ "--toc-padding-inline": {
22963
+ "description": "Per-link inline padding.",
22964
+ "default": "var(--a-space-2)"
22965
+ },
22966
+ "--toc-rule-active": {
22967
+ "description": "Active-item indicator rule color (left border).",
22968
+ "default": "var(--a-accent-bg)"
22969
+ },
22970
+ "--toc-size": {
22971
+ "description": "Link font-size.",
22972
+ "default": "var(--a-ui-sm)"
22973
+ }
22974
+ },
22975
+ "traits": [],
22976
+ "version": 1
22977
+ }
22978
+ },
21779
22979
  "TableToolbar": {
21780
22980
  "title": "TableToolbar",
21781
22981
  "description": "Header / companion bar for a sibling table-ui. Renders title + count badge, filter / sort / columns popovers, and a search input — all wired to the target table via an [for] id-ref. Modeled on chart-legend-ui's [for] binding pattern. Drop next to (or above) any table-ui to add the standard data-grid toolbar without re-implementing search, filter, sort, or column visibility. Filter rows auto-pick a primitive per column: ≤ 50 distinct values → multi- select (searchable when ≥ 12 options), id-like keys → free-text contains. The column descriptor's `filter` field overrides the auto-detect: `'select'` forces multi-select even on high-cardinality columns; `'text'` forces a contains input even on small enums.",
@@ -22199,6 +23399,16 @@
22199
23399
  "description": "Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after.",
22200
23400
  "$ref": "#/$defs/DynamicString"
22201
23401
  },
23402
+ "tone": {
23403
+ "description": "Fill style — orthogonal to [variant]. Three values:\n - `solid` (default for family variants) — saturated bg + on-strong\n (near-white) text. The chip IS the state.\n - `muted` — tinted bg with scheme-paired text. Matches <badge-ui>'s\n default look. Use on metadata chips in dense lists where the\n saturated default would compete for attention.\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.\nThe `default` variant (no family) stays quiet chrome regardless of\ntone unless `tone=\"solid\"` is set explicitly (high-contrast neutral\ninverse), or `tone=\"outline\"` (fg-muted text + subtle border).\n",
23404
+ "type": "string",
23405
+ "enum": [
23406
+ "solid",
23407
+ "muted",
23408
+ "outline"
23409
+ ],
23410
+ "default": "solid"
23411
+ },
22202
23412
  "variant": {
22203
23413
  "description": "Semantic variant — `default | info | success | warning | danger`.",
22204
23414
  "type": "string",
@@ -24960,6 +26170,75 @@
24960
26170
  "traits": [],
24961
26171
  "version": 1
24962
26172
  }
26173
+ },
26174
+ "VisuallyHidden": {
26175
+ "title": "VisuallyHidden",
26176
+ "description": "Accessibility utility — content visible to screen readers but hidden\nvisually (the canonical \"sr-only\" pattern). Use for icon-only buttons,\ncontextual labels on duplicate controls, status announcements via\nlive regions, and any text the AT needs but sighted users don't.\n\nDistinct from `[hidden]` / `display:none` (hidden from EVERYONE\nincluding AT) and from `aria-label` (which replaces visible text but\ndoesn't add invisible text). When you need both visible and invisible\ntext on the same element, `<visually-hidden-ui>` is the wrapper for\nthe invisible part.\n",
26177
+ "type": "object",
26178
+ "allOf": [
26179
+ {
26180
+ "$ref": "#/$defs/ComponentCommon"
26181
+ },
26182
+ {
26183
+ "$ref": "#/$defs/CatalogComponentCommon"
26184
+ }
26185
+ ],
26186
+ "properties": {
26187
+ "component": {
26188
+ "const": "VisuallyHidden"
26189
+ }
26190
+ },
26191
+ "required": [
26192
+ "component"
26193
+ ],
26194
+ "unevaluatedProperties": false,
26195
+ "x-adiaui": {
26196
+ "anti_patterns": [
26197
+ {
26198
+ "fix": "<button-ui icon=\"trash\"><visually-hidden-ui>Delete</visually-hidden-ui></button-ui> OR set aria-label=\"Delete\" — but visually-hidden-ui scales to longer context (\"Delete row 42 in the orders table\") without overloading the label attribute.",
26199
+ "why": "Icon-only buttons with no accessible name are unreadable for screen-reader users.",
26200
+ "wrong": "<button-ui icon=\"trash\"></button-ui>"
26201
+ }
26202
+ ],
26203
+ "category": "utility",
26204
+ "composes": [],
26205
+ "events": {},
26206
+ "examples": [
26207
+ {
26208
+ "description": "Sr-only label for an icon-only button.",
26209
+ "a2ui": "[\n { \"id\": \"btn\", \"component\": \"Button\", \"icon\": \"trash\", \"children\": [\"lbl\"] },\n { \"id\": \"lbl\", \"component\": \"VisuallyHidden\", \"textContent\": \"Delete row\" }\n]\n",
26210
+ "name": "icon-button-label"
26211
+ }
26212
+ ],
26213
+ "keywords": [
26214
+ "visually-hidden",
26215
+ "sr-only",
26216
+ "screen-reader",
26217
+ "a11y",
26218
+ "accessibility"
26219
+ ],
26220
+ "name": "UIVisuallyHidden",
26221
+ "related": [
26222
+ "text"
26223
+ ],
26224
+ "slots": {
26225
+ "default": {
26226
+ "description": "The text or content to hide visually while keeping accessible."
26227
+ }
26228
+ },
26229
+ "states": [
26230
+ {
26231
+ "description": "Default — content is visually hidden but in the accessibility tree.",
26232
+ "name": "idle"
26233
+ }
26234
+ ],
26235
+ "status": "stable",
26236
+ "synonyms": {},
26237
+ "tag": "visually-hidden-ui",
26238
+ "tokens": {},
26239
+ "traits": [],
26240
+ "version": 1
26241
+ }
24963
26242
  }
24964
26243
  },
24965
26244
  "functions": {