@adia-ai/a2ui-corpus 0.6.36 → 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",
@@ -7633,6 +7934,21 @@
7633
7934
  "type": "string",
7634
7935
  "default": "Select range"
7635
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
+ },
7636
7952
  "readonly": {
7637
7953
  "description": "Block edits; allow keyboard navigation for screen-reader inspection.",
7638
7954
  "type": "boolean",
@@ -8156,6 +8472,21 @@
8156
8472
  "type": "string",
8157
8473
  "default": "Select date and time"
8158
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
+ },
8159
8490
  "precision": {
8160
8491
  "description": "Time-pane precision. `minute` (default) emits `HH:mm`; `second` exposes the seconds segment and emits `HH:mm:ss`.",
8161
8492
  "type": "string",
@@ -15145,9 +15476,9 @@
15145
15476
  "version": 1
15146
15477
  }
15147
15478
  },
15148
- "OnboardingChecklist": {
15149
- "title": "OnboardingChecklist",
15150
- "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",
15151
15482
  "type": "object",
15152
15483
  "allOf": [
15153
15484
  {
@@ -15158,25 +15489,203 @@
15158
15489
  }
15159
15490
  ],
15160
15491
  "properties": {
15161
- "title": {
15162
- "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",
15163
15494
  "type": "string",
15164
- "default": "Get started"
15495
+ "enum": [
15496
+ "short",
15497
+ "long"
15498
+ ],
15499
+ "default": "short"
15165
15500
  },
15166
- "items": {
15167
- "description": "Step list — each item is { id, label, description?, href?, done? }. Required, non-empty.",
15168
- "$ref": "#/$defs/DynamicStringList"
15501
+ "component": {
15502
+ "const": "NumberFormat"
15169
15503
  },
15170
- "collapsed": {
15171
- "description": "Initial / current collapsed state hides the item list, keeps progress + header visible.",
15172
- "$ref": "#/$defs/DynamicBoolean"
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": ""
15173
15508
  },
15174
- "collapsible": {
15175
- "description": "Show a top-right collapse toggle.",
15176
- "type": "boolean",
15177
- "default": true
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": ""
15178
15513
  },
15179
- "component": {
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": {
15180
15689
  "const": "OnboardingChecklist"
15181
15690
  },
15182
15691
  "dismiss-on-complete": {
@@ -15930,14 +16439,28 @@
15930
16439
  "type": "number",
15931
16440
  "default": 1
15932
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
+ },
15933
16452
  "total": {
15934
16453
  "description": "Total number of pages.",
15935
16454
  "type": "number",
15936
16455
  "default": 1
15937
16456
  },
15938
16457
  "variant": {
15939
- "description": "Visual variant",
16458
+ "description": "Visual variant — `default` (ghost buttons w/ hover bg) or `button` (1×1 bordered cells; active page filled).",
15940
16459
  "type": "string",
16460
+ "enum": [
16461
+ "default",
16462
+ "button"
16463
+ ],
15941
16464
  "default": "default"
15942
16465
  }
15943
16466
  },
@@ -15948,7 +16471,10 @@
15948
16471
  "x-adiaui": {
15949
16472
  "anti_patterns": [],
15950
16473
  "category": "navigation",
15951
- "composes": [],
16474
+ "composes": [
16475
+ "button-ui",
16476
+ "icon-ui"
16477
+ ],
15952
16478
  "events": {
15953
16479
  "page-change": {
15954
16480
  "description": "Fired when a page button is clicked. detail contains { page }.",
@@ -16133,6 +16659,156 @@
16133
16659
  "version": 1
16134
16660
  }
16135
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
+ },
16136
16812
  "PaymentMethodForm": {
16137
16813
  "title": "PaymentMethodForm",
16138
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",
@@ -17633,6 +18309,158 @@
17633
18309
  "version": 1
17634
18310
  }
17635
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
+ },
17636
18464
  "Radio": {
17637
18465
  "title": "Radio",
17638
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.",
@@ -18087,56 +18915,174 @@
18087
18915
  "accent",
18088
18916
  "warning"
18089
18917
  ],
18090
- "default": ""
18918
+ "default": ""
18919
+ }
18920
+ },
18921
+ "required": [
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
18091
19022
  }
18092
19023
  },
18093
19024
  "required": [
18094
- "component",
18095
- "value"
19025
+ "component"
18096
19026
  ],
18097
19027
  "unevaluatedProperties": false,
18098
19028
  "x-adiaui": {
18099
19029
  "anti_patterns": [],
18100
- "category": "form",
19030
+ "category": "display",
18101
19031
  "composes": [],
18102
- "events": {
18103
- "[object Object]": {
18104
- "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"
18105
19048
  }
18106
- },
18107
- "examples": [],
19049
+ ],
18108
19050
  "keywords": [
18109
- "rating",
18110
- "stars",
18111
- "review",
18112
- "feedback",
18113
- "score",
18114
- "vote",
18115
- "heart",
18116
- "like"
19051
+ "relative-time",
19052
+ "timeago",
19053
+ "time",
19054
+ "timestamp",
19055
+ "ago",
19056
+ "elapsed",
19057
+ "relative",
19058
+ "duration"
18117
19059
  ],
18118
- "name": "UIRating",
19060
+ "name": "UIRelativeTime",
18119
19061
  "related": [
18120
- "Field",
18121
- "AgentFeedbackBar"
19062
+ "text",
19063
+ "badge",
19064
+ "stat"
18122
19065
  ],
18123
19066
  "slots": {},
18124
19067
  "states": [
18125
19068
  {
18126
- "description": "Default, ready for interaction.",
19069
+ "description": "Default, displaying the formatted relative time.",
18127
19070
  "name": "idle"
18128
19071
  }
18129
19072
  ],
18130
19073
  "status": "stable",
18131
19074
  "synonyms": {
18132
- "rating": [
18133
- "rating",
18134
- "star rating",
18135
- "review score",
18136
- "feedback rating"
19075
+ "ago": [
19076
+ "relative-time",
19077
+ "timeago"
19078
+ ],
19079
+ "timestamp": [
19080
+ "relative-time",
19081
+ "time",
19082
+ "datetime"
18137
19083
  ]
18138
19084
  },
18139
- "tag": "rating-ui",
19085
+ "tag": "relative-time-ui",
18140
19086
  "tokens": {},
18141
19087
  "traits": [],
18142
19088
  "version": 1
@@ -19484,6 +20430,96 @@
19484
20430
  "version": 1
19485
20431
  }
19486
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
+ },
19487
20523
  "Slider": {
19488
20524
  "title": "Slider",
19489
20525
  "description": "Range slider with track, fill, and thumb. Supports label, suffix, and keyboard control. Form-associated.",
@@ -19510,6 +20546,11 @@
19510
20546
  "type": "boolean",
19511
20547
  "default": false
19512
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
+ },
19513
20554
  "error": {
19514
20555
  "description": "Validation error",
19515
20556
  "type": "string",
@@ -19525,6 +20566,11 @@
19525
20566
  "type": "string",
19526
20567
  "default": ""
19527
20568
  },
20569
+ "lowerValue": {
20570
+ "description": "Lower thumb value (dual mode only; clamped to ≤ [upper-value]).",
20571
+ "type": "number",
20572
+ "default": 0
20573
+ },
19528
20574
  "max": {
19529
20575
  "description": "Maximum slider value",
19530
20576
  "type": "number",
@@ -19555,8 +20601,13 @@
19555
20601
  "type": "number",
19556
20602
  "default": 0
19557
20603
  },
20604
+ "upperValue": {
20605
+ "description": "Upper thumb value (dual mode only; clamped to ≥ [lower-value]).",
20606
+ "type": "number",
20607
+ "default": 100
20608
+ },
19558
20609
  "value": {
19559
- "description": "Current slider value",
20610
+ "description": "Current slider value (single-thumb mode; ignored when [dual] is set)",
19560
20611
  "type": "number",
19561
20612
  "default": 50
19562
20613
  }
@@ -21768,6 +22819,163 @@
21768
22819
  "version": 1
21769
22820
  }
21770
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
+ },
21771
22979
  "TableToolbar": {
21772
22980
  "title": "TableToolbar",
21773
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.",
@@ -22192,11 +23400,12 @@
22192
23400
  "$ref": "#/$defs/DynamicString"
22193
23401
  },
22194
23402
  "tone": {
22195
- "description": "Fill style — orthogonal to [variant]. Default (`solid`) for family\nvariants is a saturated bg with on-strong (near-white) text the\nchip IS the state. Opt-out via `tone=\"muted\"` for a tinted bg with\nscheme-paired text (matches <badge-ui>'s default look) when the\nchip is metadata in a dense list rather than a status stamp. The\n`default` variant stays quiet chrome regardless of tone unless\n`tone=\"solid\"` is set explicitly (high-contrast neutral inverse).\n",
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",
22196
23404
  "type": "string",
22197
23405
  "enum": [
22198
23406
  "solid",
22199
- "muted"
23407
+ "muted",
23408
+ "outline"
22200
23409
  ],
22201
23410
  "default": "solid"
22202
23411
  },
@@ -24961,6 +26170,75 @@
24961
26170
  "traits": [],
24962
26171
  "version": 1
24963
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
+ }
24964
26242
  }
24965
26243
  },
24966
26244
  "functions": {