@uni-design-system/uni-mcp 4.7.1 → 4.7.2

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.
@@ -7,16 +7,16 @@ import { z } from "zod";
7
7
  // src/data/uni-index.json
8
8
  var uni_index_default = {
9
9
  meta: {
10
- version: "8.3.0",
11
- builtAt: "2026-08-21T15:54:42.627Z",
10
+ version: "9.0.0",
11
+ builtAt: "2026-08-23T15:31:18.523Z",
12
12
  frameworks: [
13
13
  "angular"
14
14
  ],
15
15
  counts: {
16
16
  components: 79,
17
- tokens: 396,
17
+ tokens: 401,
18
18
  themes: 2,
19
- examples: 184
19
+ examples: 194
20
20
  }
21
21
  },
22
22
  components: [
@@ -27,7 +27,7 @@ var uni_index_default = {
27
27
  summary: "",
28
28
  description: "",
29
29
  category: "feedback",
30
- version: "8.3.0",
30
+ version: "9.0.0",
31
31
  bindings: {
32
32
  angular: {
33
33
  importPath: "@uni-design-system/uni-angular",
@@ -90,7 +90,7 @@ var uni_index_default = {
90
90
  relatedTokens: [
91
91
  "alert.behavior.topPosition",
92
92
  "alert.behavior.borderRadius",
93
- "alert.behavior.transitionSpeed",
93
+ "alert.behavior.motion",
94
94
  "alert.behavior.elevation"
95
95
  ]
96
96
  },
@@ -101,7 +101,7 @@ var uni_index_default = {
101
101
  summary: "Horizontal application bar: project leading controls (menu button, logo) with the `leading` attribute, actions with `trailing` (pushed to the far edge), and either pass `title` or project custom center content.",
102
102
  description: "Horizontal application bar: project leading controls (menu button, logo) with the `leading` attribute, actions with `trailing` (pushed to the far edge), and either pass `title` or project custom center content. Surface, divider, height, typography and spacing all resolve from `appBar` tokens. Place it inside your page's `<header>` landmark.",
103
103
  category: "components",
104
- version: "8.3.0",
104
+ version: "9.0.0",
105
105
  bindings: {
106
106
  angular: {
107
107
  importPath: "@uni-design-system/uni-angular",
@@ -158,7 +158,7 @@ var uni_index_default = {
158
158
  summary: "Identity avatar with a graceful fallback chain: image \u2192 initials from `name` \u2192 themed symbol.",
159
159
  description: "Identity avatar with a graceful fallback chain: image \u2192 initials from `name` \u2192 themed symbol. Coloring, radius, typeface and sizes all resolve from `avatar` theme tokens; `variant` picks the container palette.",
160
160
  category: "components",
161
- version: "8.3.0",
161
+ version: "9.0.0",
162
162
  bindings: {
163
163
  angular: {
164
164
  importPath: "@uni-design-system/uni-angular",
@@ -237,7 +237,7 @@ var uni_index_default = {
237
237
  summary: "Overlapping stack of avatars.",
238
238
  description: "Overlapping stack of avatars. `max` collapses the overflow into a themed \u201C+N\u201D chip (itself a `uni-avatar`). Overlap and separator ring resolve from `avatarGroup` theme tokens.",
239
239
  category: "components",
240
- version: "8.3.0",
240
+ version: "9.0.0",
241
241
  bindings: {
242
242
  angular: {
243
243
  importPath: "@uni-design-system/uni-angular",
@@ -270,7 +270,7 @@ var uni_index_default = {
270
270
  summary: "",
271
271
  description: "",
272
272
  category: "primitives",
273
- version: "8.3.0",
273
+ version: "9.0.0",
274
274
  bindings: {
275
275
  angular: {
276
276
  importPath: "@uni-design-system/uni-angular",
@@ -351,7 +351,7 @@ var uni_index_default = {
351
351
  summary: "",
352
352
  description: "",
353
353
  category: "feedback",
354
- version: "8.3.0",
354
+ version: "9.0.0",
355
355
  bindings: {
356
356
  angular: {
357
357
  importPath: "@uni-design-system/uni-angular",
@@ -432,7 +432,7 @@ var uni_index_default = {
432
432
  summary: "",
433
433
  description: "",
434
434
  category: "directives",
435
- version: "8.3.0",
435
+ version: "9.0.0",
436
436
  bindings: {
437
437
  angular: {
438
438
  importPath: "@uni-design-system/uni-angular",
@@ -454,20 +454,20 @@ var uni_index_default = {
454
454
  name: "Box",
455
455
  status: "stable",
456
456
  summary: 'The base layout primitive, applied as an attribute to any element so semantics stay yours: `<main box-layout [grow]="1" padding="md">`.',
457
- description: 'The base layout primitive, applied as an attribute to any element so semantics stay yours: `<main box-layout [grow]="1" padding="md">`. Exception: other components\' host elements (`<uni-card box-layout>` would put two components on one element) \u2014 wrap those in a `<div box-layout>`. Sizing convention (height/width/min/max/inset): a **number is px and needs a binding** \u2014 `[height]="420"`; a **plain attribute is a CSS length string** \u2014 `height="420px"`. Spacing/radius/color inputs take theme tokens.',
457
+ description: 'The base layout primitive, applied as an attribute to any element so semantics stay yours: `<main box-layout [grow]="1" padding="md">`. It is a directive, so it composes freely \u2014 with another layout attribute (`<div stack-layout uni-text="body-1-long">`) and with a component\'s own host element (`<uni-card box-layout padding="lg">`); Angular merges the host `class` bindings rather than letting one win. Sizing convention (height/width/min/max/inset): a **number is px and needs a binding** \u2014 `[height]="420"`; a **plain attribute is a CSS length string** \u2014 `height="420px"`. Spacing/radius/color inputs take theme tokens.',
458
458
  category: "layout",
459
- version: "8.3.0",
459
+ version: "9.0.0",
460
460
  bindings: {
461
461
  angular: {
462
462
  importPath: "@uni-design-system/uni-angular",
463
463
  selectorOrTag: "[uni-box-layout], [box-layout]",
464
464
  api: [
465
465
  {
466
- name: "color",
466
+ name: "containerColor",
467
467
  kind: "input",
468
468
  type: "ContainerColorToken",
469
469
  required: false,
470
- description: ""
470
+ description: "A container color *pair*: the named surface plus its paired on-color, so a box and its contents stay legible together. Named `containerColor`, not `color`, because it is not the CSS `color` property \u2014 `uni-text` owns that name, and it maps to it directly. The two directives share elements routinely (`<div row-layout uni-text>`), and one `color` binding would feed both: the box would paint the surface and the text would take the same token, rendering ink on identical ink."
471
471
  },
472
472
  {
473
473
  name: "backgroundColor",
@@ -638,6 +638,34 @@ var uni_index_default = {
638
638
  required: false,
639
639
  description: ""
640
640
  },
641
+ {
642
+ name: "flex",
643
+ kind: "input",
644
+ type: "number | string",
645
+ required: false,
646
+ description: 'The `flex` shorthand. `[flex]="1"` is `flex: 1` \u2014 grow, shrink and a zero basis \u2014 which `grow` alone cannot express, since it leaves `flex-basis: auto`. Wins over `grow` when both are set.'
647
+ },
648
+ {
649
+ name: "shrink",
650
+ kind: "input",
651
+ type: "number",
652
+ required: false,
653
+ description: ""
654
+ },
655
+ {
656
+ name: "basis",
657
+ kind: "input",
658
+ type: "number | string",
659
+ required: false,
660
+ description: ""
661
+ },
662
+ {
663
+ name: "marginInline",
664
+ kind: "input",
665
+ type: "'auto' | NullableSize",
666
+ required: false,
667
+ description: 'Inline-axis margin. `marginInline="auto"` centers a `maxWidth` container \u2014 the one thing flex centering cannot do without an extra wrapper. Only the inline axis is exposed: block margins collapse and fight `gap`, which is why the primitives carry no margin otherwise.'
668
+ },
641
669
  {
642
670
  name: "display",
643
671
  kind: "input",
@@ -801,11 +829,26 @@ var uni_index_default = {
801
829
  {
802
830
  title: "Primary",
803
831
  framework: "angular",
804
- code: "<!-- Storybook story: Primary -->\n<div box-layout ${argsToTemplate(props)}>\n<span uni-text>${ngContent}</span>\n</div>\n<!-- args:\n{\n color: 'secondary-container',\n borderRadius: 'md',\n padding: 'lg',\n ngContent: 'Box Content.',\n }\n-->"
832
+ code: "<!-- Storybook story: Primary -->\n<div box-layout ${argsToTemplate(props)}>\n<span uni-text>${ngContent}</span>\n</div>\n<!-- args:\n{\n containerColor: 'secondary-container',\n borderRadius: 'md',\n padding: 'lg',\n ngContent: 'Box Content.',\n }\n-->"
833
+ },
834
+ {
835
+ title: "Flex children",
836
+ framework: "angular",
837
+ code: "<!-- Storybook story: Flex children -->\n<div box-layout ${argsToTemplate(props)}>\n<span uni-text>${ngContent}</span>\n</div>"
838
+ },
839
+ {
840
+ title: "Centered page shell",
841
+ framework: "angular",
842
+ code: "<!-- Storybook story: Centered page shell -->\n<div box-layout ${argsToTemplate(props)}>\n<span uni-text>${ngContent}</span>\n</div>"
843
+ },
844
+ {
845
+ title: "Composition",
846
+ framework: "angular",
847
+ code: "<!-- Storybook story: Composition -->\n<div box-layout ${argsToTemplate(props)}>\n<span uni-text>${ngContent}</span>\n</div>"
805
848
  }
806
849
  ],
807
850
  guidelines: {
808
- whenToUse: "Box is the base Layout component. It is highly configurable.\nEach layout component extends the Box component while providing presets to support their application.",
851
+ whenToUse: "Box is the base layout primitive \u2014 an attribute directive you put on any element, so\nyour HTML semantics stay yours. It is highly configurable; every other layout\ndirective extends it and adds presets.\nBecause it is a directive rather than a component, it composes freely: with another\nlayout attribute, with `uni-text`, and with a component's own host element. Angular\nmerges the host `class` bindings, so each contributor's styles survive.\n```html\n```\nColors stay unambiguous across that composition. The box's surface is\n`containerColor` \u2014 a **pair**: the named surface plus its paired on-color \u2014 while\nplain `color` belongs to `uni-text` and maps to the CSS property. So an element\nwearing both can set each independently:\n```html\n```\nLayout attributes only apply when the directive is in your component's `imports`.\nAn unimported attribute compiles cleanly and silently does nothing \u2014 import\n`UNI_LAYOUT` to bring the whole family in at once.",
809
852
  dos: [],
810
853
  donts: [],
811
854
  accessibility: []
@@ -819,7 +862,7 @@ var uni_index_default = {
819
862
  summary: 'WAI-ARIA breadcrumb: a `nav` landmark wrapping an ordered list; the last item is the current page (`aria-current="page"`), separators are decorative.',
820
863
  description: 'WAI-ARIA breadcrumb: a `nav` landmark wrapping an ordered list; the last item is the current page (`aria-current="page"`), separators are decorative. Items with `href` render as real links; without one they render as link-styled buttons emitting `itemClicked` \u2014 wire that to your router.',
821
864
  category: "components",
822
- version: "8.3.0",
865
+ version: "9.0.0",
823
866
  bindings: {
824
867
  angular: {
825
868
  importPath: "@uni-design-system/uni-angular",
@@ -888,7 +931,7 @@ var uni_index_default = {
888
931
  summary: "",
889
932
  description: "",
890
933
  category: "primitives",
891
- version: "8.3.0",
934
+ version: "9.0.0",
892
935
  bindings: {
893
936
  angular: {
894
937
  importPath: "@uni-design-system/uni-angular",
@@ -1031,7 +1074,7 @@ var uni_index_default = {
1031
1074
  summary: "",
1032
1075
  description: "",
1033
1076
  category: "primitives",
1034
- version: "8.3.0",
1077
+ version: "9.0.0",
1035
1078
  bindings: {
1036
1079
  angular: {
1037
1080
  importPath: "@uni-design-system/uni-angular",
@@ -1063,7 +1106,7 @@ var uni_index_default = {
1063
1106
  summary: "Inline month calendar: single-date or start\u2013end range selection, day markers (availability dots), min/max fences and disabled dates.",
1064
1107
  description: "Inline month calendar: single-date or start\u2013end range selection, day markers (availability dots), min/max fences and disabled dates. One tab stop with a roving-tabindex `role=\"grid\"`; every day is a real button named with its full date. Values are plain ISO strings (`'YYYY-MM-DD'`), never `Date` objects, so bindings are timezone-free and serializable. Selection and today colours come from the theme's `primary` role pair; geometry and glyphs come from the `calendar` theme entry.",
1065
1108
  category: "forms",
1066
- version: "8.3.0",
1109
+ version: "9.0.0",
1067
1110
  bindings: {
1068
1111
  angular: {
1069
1112
  importPath: "@uni-design-system/uni-angular",
@@ -1289,7 +1332,7 @@ var uni_index_default = {
1289
1332
  summary: "Anchored coach-mark panel that dims the page and cuts a spotlight hole around its target.",
1290
1333
  description: 'Anchored coach-mark panel that dims the page and cuts a spotlight hole around its target. Both the scrim and the panel are `popover="manual"` elements shown in order, so they stack deterministically in the top layer above every app z-index, and every scrim piece is CSS-anchor-positioned to the target \u2014 the hole tracks scroll/resize/layout with zero listeners. The panel is a non-modal `role="dialog"` (deliberately no `aria-modal`): focus moves into it on open, Tab runs a "duet loop" over the panel\'s focusables plus the spotlit target while it stays interactive, and on close focus returns to the pre-open element \u2014 unless the user moved into the target, where it stays. Storage-free by rule: `key` and the `dismissed` output are the "don\'t show again" hooks; persistence is the app\'s business (e.g. cdk local-storage).',
1291
1334
  category: "components",
1292
- version: "8.3.0",
1335
+ version: "9.0.0",
1293
1336
  bindings: {
1294
1337
  angular: {
1295
1338
  importPath: "@uni-design-system/uni-angular",
@@ -1476,7 +1519,7 @@ var uni_index_default = {
1476
1519
  "callout.behavior.spotlightPadding",
1477
1520
  "callout.behavior.spotlightRadius",
1478
1521
  "callout.behavior.ringWidth",
1479
- "callout.behavior.transitionMs"
1522
+ "callout.behavior.motion"
1480
1523
  ]
1481
1524
  },
1482
1525
  {
@@ -1486,7 +1529,7 @@ var uni_index_default = {
1486
1529
  summary: "",
1487
1530
  description: "",
1488
1531
  category: "layout",
1489
- version: "8.3.0",
1532
+ version: "9.0.0",
1490
1533
  bindings: {
1491
1534
  angular: {
1492
1535
  importPath: "@uni-design-system/uni-angular",
@@ -1531,7 +1574,7 @@ var uni_index_default = {
1531
1574
  summary: "",
1532
1575
  description: "",
1533
1576
  category: "layout",
1534
- version: "8.3.0",
1577
+ version: "9.0.0",
1535
1578
  bindings: {
1536
1579
  angular: {
1537
1580
  importPath: "@uni-design-system/uni-angular",
@@ -1555,7 +1598,7 @@ var uni_index_default = {
1555
1598
  summary: "",
1556
1599
  description: "",
1557
1600
  category: "layout",
1558
- version: "8.3.0",
1601
+ version: "9.0.0",
1559
1602
  bindings: {
1560
1603
  angular: {
1561
1604
  importPath: "@uni-design-system/uni-angular",
@@ -1596,7 +1639,7 @@ var uni_index_default = {
1596
1639
  summary: "",
1597
1640
  description: "",
1598
1641
  category: "layout",
1599
- version: "8.3.0",
1642
+ version: "9.0.0",
1600
1643
  bindings: {
1601
1644
  angular: {
1602
1645
  importPath: "@uni-design-system/uni-angular",
@@ -1651,7 +1694,7 @@ var uni_index_default = {
1651
1694
  summary: "",
1652
1695
  description: "",
1653
1696
  category: "forms",
1654
- version: "8.3.0",
1697
+ version: "9.0.0",
1655
1698
  bindings: {
1656
1699
  angular: {
1657
1700
  importPath: "@uni-design-system/uni-angular",
@@ -1789,8 +1832,8 @@ var uni_index_default = {
1789
1832
  status: "stable",
1790
1833
  summary: "Form-bound, closed-set, single-select autocomplete: `FormValueControl<T | null>` over object `Options<T>`, type-to-filter, commit-on-select.",
1791
1834
  description: "Form-bound, closed-set, single-select autocomplete: `FormValueControl<T | null>` over object `Options<T>`, type-to-filter, commit-on-select. Typing produces a draft \u2014 a filter, never a value; the value changes only when an option commits, `clear()` runs, or the model is written from outside. Select semantics, not search: a real label, a chevron, no magnifier, nothing submits. For short lists with no need to type, prefer `uni-select` \u2014 the value contract is identical, so swapping is a template-only change.",
1792
- category: "layout",
1793
- version: "8.3.0",
1835
+ category: "forms",
1836
+ version: "9.0.0",
1794
1837
  bindings: {
1795
1838
  angular: {
1796
1839
  importPath: "@uni-design-system/uni-angular",
@@ -1990,6 +2033,11 @@ emptyText="No countries found"
1990
2033
  framework: "angular",
1991
2034
  code: '<!-- Storybook story: Async -->\n<uni-combobox\nlabel="Country"\nplaceholder="Type to search countries"\nemptyText="No countries found"\n[filterLocally]="false"\n[options]="options"\n(query)="onQuery($event)"\n/>\n<!-- args:\n{ required: true, invalid: true, touched: true }\n-->'
1992
2035
  },
2036
+ {
2037
+ title: "Create New Values",
2038
+ framework: "angular",
2039
+ code: '<!-- Storybook story: Create New Values -->\n<uni-combobox\nlabel="Country"\nplaceholder="Type to search countries"\nemptyText="No countries found"\n[filterLocally]="false"\n[options]="options"\n(query)="onQuery($event)"\n/>\n<!-- args:\n{ required: true, invalid: true, touched: true }\n-->'
2040
+ },
1993
2041
  {
1994
2042
  title: "Invalid",
1995
2043
  framework: "angular",
@@ -2016,12 +2064,13 @@ emptyText="No countries found"
2016
2064
  whenToUse: "The form-bound, **closed-set, single-select** autocomplete: object\n`Options<T>`, `FormValueControl<T | null>`, type-to-filter, commit-on-select.\nTyping produces a *draft* \u2014 a filter, never a value; the value changes only\nwhen an option commits, the field clears, or the model is written from\noutside. Select semantics, not search: a real label, a chevron, no magnifier,\nnothing submits.\nUnder ~10 options and no need to type \u2192 `uni-select`, the native, zero-JS,\nmobile-friendly answer. More options, or users know what they're looking for \u2192\n`uni-combobox`. The value contract is identical (`T | null`, `compareWith`),\nso swapping one for the other as a list grows is a template-only change \u2014 that\nis deliberate. For open sets, where typing *creates* values, use\n`uni-tag-input` (multi) or `uni-search-input` (queries); for closed multi\nsets, `uni-multi-select-dropdown`.",
2017
2065
  dos: [],
2018
2066
  donts: [
2019
- "Don't bolt \"create new\" onto it \u2014 that's an open set; use `uni-tag-input`'s",
2067
+ "Don't expect free text to commit implicitly \u2014 it never does. Offer creation",
2020
2068
  "Don't wire `(query)` \u2192 filter \u2192 `[options]` when the list is already in",
2021
2069
  "Don't use `Escape` to clear: it closes, then reverts. The \u2715 and an emptied"
2022
2070
  ],
2023
2071
  accessibility: [
2024
2072
  'The input is `role="combobox"` with `aria-expanded`, `aria-controls` and',
2073
+ "Home and End move the caret, never the list, per APG's editable-combobox",
2025
2074
  "`aria-selected` marks the **committed** option; the active one is carried by",
2026
2075
  "Disabled options are rendered, announced (`aria-disabled`), and skipped by",
2027
2076
  'Commits (*"Alabama selected."*), clears, refusals and debounced result',
@@ -2047,7 +2096,7 @@ emptyText="No countries found"
2047
2096
  summary: "",
2048
2097
  description: "",
2049
2098
  category: "feedback",
2050
- version: "8.3.0",
2099
+ version: "9.0.0",
2051
2100
  bindings: {
2052
2101
  angular: {
2053
2102
  importPath: "@uni-design-system/uni-angular",
@@ -2094,7 +2143,7 @@ emptyText="No countries found"
2094
2143
  summary: "",
2095
2144
  description: "",
2096
2145
  category: "forms",
2097
- version: "8.3.0",
2146
+ version: "9.0.0",
2098
2147
  bindings: {
2099
2148
  angular: {
2100
2149
  importPath: "@uni-design-system/uni-angular",
@@ -2177,7 +2226,7 @@ emptyText="No countries found"
2177
2226
  summary: "",
2178
2227
  description: "",
2179
2228
  category: "data",
2180
- version: "8.3.0",
2229
+ version: "9.0.0",
2181
2230
  bindings: {
2182
2231
  angular: {
2183
2232
  importPath: "@uni-design-system/uni-angular",
@@ -2278,7 +2327,7 @@ emptyText="No countries found"
2278
2327
  summary: "Date field with free-typed parsing and a popup calendar.",
2279
2328
  description: "Date field with free-typed parsing and a popup calendar. Type `aug 20`, `8/20/2026` or `2026-08-20`, or pick from the grid \u2014 the form gets the same canonical `'YYYY-MM-DD'` string either way. Parsing is `Intl`-driven (locale digit order and month names, never hardcoded); unreadable text stays in the field, flagged, with a `rejected` event. The popup is a native popover hosting the same `uni-calendar` an app could render inline.",
2280
2329
  category: "forms",
2281
- version: "8.3.0",
2330
+ version: "9.0.0",
2282
2331
  bindings: {
2283
2332
  angular: {
2284
2333
  importPath: "@uni-design-system/uni-angular",
@@ -2486,7 +2535,7 @@ emptyText="No countries found"
2486
2535
  summary: "One field for a date and a time: a thin composer seating a uni-date-input and a uni-time-input in one input-box chrome under one label, yielding one combined `'YYYY-MM-DDTHH:mm'` value.",
2487
2536
  description: "One field for a date and a time: a thin composer seating a uni-date-input and a uni-time-input in one input-box chrome under one label, yielding one combined `'YYYY-MM-DDTHH:mm'` value. The value emits only when both parts are set \u2014 a time without a day is not an answer \u2014 and clearing the date clears it. With `slotsFor`, the time part stays disabled until a day is chosen and offers exactly that day's slots: the scheduling flow in one attribute. Two honest tab stops (it is two questions); apps needing a different arrangement compose the primitives directly.",
2488
2537
  category: "forms",
2489
- version: "8.3.0",
2538
+ version: "9.0.0",
2490
2539
  bindings: {
2491
2540
  angular: {
2492
2541
  importPath: "@uni-design-system/uni-angular",
@@ -2656,7 +2705,7 @@ emptyText="No countries found"
2656
2705
  summary: "Text input that emits `change` only after the user pauses typing.",
2657
2706
  description: "Text input that emits `change` only after the user pauses typing. Wears the shared input chrome (themed color, border, typeface, focus ring) via `uni-input-box`; project adornments with the `pre-input` / `post-input` slots, matching `uni-input`'s convention. The ARIA passthrough inputs let a wrapping composite (e.g. SearchInput's combobox) annotate the real input element.",
2658
2707
  category: "forms",
2659
- version: "8.3.0",
2708
+ version: "9.0.0",
2660
2709
  bindings: {
2661
2710
  angular: {
2662
2711
  importPath: "@uni-design-system/uni-angular",
@@ -2707,6 +2756,28 @@ emptyText="No countries found"
2707
2756
  default: "false",
2708
2757
  description: ""
2709
2758
  },
2759
+ {
2760
+ name: "type",
2761
+ kind: "input",
2762
+ type: "UniInputType",
2763
+ required: false,
2764
+ default: "'text'",
2765
+ description: "Native input type; text-like only, matching `uni-input`."
2766
+ },
2767
+ {
2768
+ name: "autocomplete",
2769
+ kind: "input",
2770
+ type: "string",
2771
+ required: false,
2772
+ description: ""
2773
+ },
2774
+ {
2775
+ name: "inputMode",
2776
+ kind: "input",
2777
+ type: "UniInputMode",
2778
+ required: false,
2779
+ description: ""
2780
+ },
2710
2781
  {
2711
2782
  name: "role",
2712
2783
  kind: "input",
@@ -2737,11 +2808,11 @@ emptyText="No countries found"
2737
2808
  description: ""
2738
2809
  },
2739
2810
  {
2740
- name: "change",
2811
+ name: "valueChange",
2741
2812
  kind: "output",
2742
2813
  type: "string",
2743
2814
  required: false,
2744
- description: ""
2815
+ description: "The debounced value, emitted once the user pauses typing."
2745
2816
  }
2746
2817
  ]
2747
2818
  }
@@ -2751,7 +2822,7 @@ emptyText="No countries found"
2751
2822
  title: "Primary",
2752
2823
  framework: "angular",
2753
2824
  code: `<!-- Storybook story: Primary -->
2754
- <uni-debounce-input \${argsToTemplate(props)} (change)="lastEmitted = $event" #debounce />
2825
+ <uni-debounce-input \${argsToTemplate(props)} (valueChange)="lastEmitted = $event" #debounce />
2755
2826
  <div box-layout paddingTop="md">
2756
2827
  <div>Live value: {{ debounce.value() }}</div>
2757
2828
  <div>Debounced value: {{ lastEmitted }}</div>
@@ -2765,7 +2836,7 @@ emptyText="No countries found"
2765
2836
  }
2766
2837
  ],
2767
2838
  guidelines: {
2768
- whenToUse: "A themed text input that emits its `change` output only after the user pauses typing\n(400&nbsp;ms by default) and only when the value actually changed \u2014 a signal-based\ndebounce with no rxjs involved. The live value is exposed as the `value` signal, and\n`clear()` empties the field immediately (cancelling any pending emit).\nIt wears the shared input chrome (color, border, typeface, focus ring) via the input\nbox, and offers `pre-input` / `post-input` attribute slots for adornments plus ARIA\npassthrough inputs (`role`, `ariaExpanded`, `ariaControls`, `ariaActivedescendant`)\nso composite widgets can annotate the real input element.\nUsed by the [Search Input](?path=/docs/components-forms-search-input--search-input), which\nprojects its magnifier and clear button through the slots and drives the combobox\nARIA through the passthroughs.",
2839
+ whenToUse: "A themed text input that emits its `valueChange` output only after the user pauses typing\n(400&nbsp;ms by default) and only when the value actually changed \u2014 a signal-based\ndebounce with no rxjs involved. The live value is exposed as the `value` signal, and\n`clear()` empties the field immediately (cancelling any pending emit).\nIt wears the shared input chrome (color, border, typeface, focus ring) via the input\nbox, and offers `pre-input` / `post-input` attribute slots for adornments plus ARIA\npassthrough inputs (`role`, `ariaExpanded`, `ariaControls`, `ariaActivedescendant`)\nso composite widgets can annotate the real input element.\nUsed by the [Search Input](?path=/docs/components-forms-search-input--search-input), which\nprojects its magnifier and clear button through the slots and drives the combobox\nARIA through the passthroughs.",
2769
2840
  dos: [],
2770
2841
  donts: [],
2771
2842
  accessibility: [
@@ -2782,7 +2853,7 @@ emptyText="No countries found"
2782
2853
  summary: "",
2783
2854
  description: "",
2784
2855
  category: "feedback",
2785
- version: "8.3.0",
2856
+ version: "9.0.0",
2786
2857
  bindings: {
2787
2858
  angular: {
2788
2859
  importPath: "@uni-design-system/uni-angular",
@@ -2860,7 +2931,7 @@ emptyText="No countries found"
2860
2931
  summary: "",
2861
2932
  description: "",
2862
2933
  category: "feedback",
2863
- version: "8.3.0",
2934
+ version: "9.0.0",
2864
2935
  bindings: {
2865
2936
  angular: {
2866
2937
  importPath: "@uni-design-system/uni-angular",
@@ -2948,7 +3019,7 @@ emptyText="No countries found"
2948
3019
  summary: "",
2949
3020
  description: "",
2950
3021
  category: "feedback",
2951
- version: "8.3.0",
3022
+ version: "9.0.0",
2952
3023
  bindings: {
2953
3024
  angular: {
2954
3025
  importPath: "@uni-design-system/uni-angular",
@@ -2972,7 +3043,7 @@ emptyText="No countries found"
2972
3043
  summary: "",
2973
3044
  description: "",
2974
3045
  category: "layout",
2975
- version: "8.3.0",
3046
+ version: "9.0.0",
2976
3047
  bindings: {
2977
3048
  angular: {
2978
3049
  importPath: "@uni-design-system/uni-angular",
@@ -3028,18 +3099,18 @@ emptyText="No countries found"
3028
3099
  summary: "",
3029
3100
  description: "",
3030
3101
  category: "directives",
3031
- version: "8.3.0",
3102
+ version: "9.0.0",
3032
3103
  bindings: {
3033
3104
  angular: {
3034
3105
  importPath: "@uni-design-system/uni-angular",
3035
3106
  selectorOrTag: "[uni-drag-n-drop], [dragAndDrop]",
3036
3107
  api: [
3037
3108
  {
3038
- name: "onFileDropped",
3109
+ name: "fileDropped",
3039
3110
  kind: "output",
3040
3111
  type: "FileList",
3041
3112
  required: false,
3042
- description: ""
3113
+ description: "The dropped files."
3043
3114
  }
3044
3115
  ]
3045
3116
  }
@@ -3060,7 +3131,7 @@ emptyText="No countries found"
3060
3131
  summary: "Navigation drawer with two modes sharing one content slot: - `side` \u2014 an in-flow `<aside>` that pushes content (dashboard sidenav); opening/closing animates its width, and the divider border primitive separates it from the page.",
3061
3132
  description: "Navigation drawer with two modes sharing one content slot: - `side` \u2014 an in-flow `<aside>` that pushes content (dashboard sidenav); opening/closing animates its width, and the divider border primitive separates it from the page. - `over` \u2014 a native `<dialog>` in the top layer: focus trap, Escape and scrim backdrop come from the platform (same machinery as `uni-dialog`), sliding in from its edge. Surface, width, divider, elevation, padding and backdrop all resolve from `drawer` theme tokens.",
3062
3133
  category: "components",
3063
- version: "8.3.0",
3134
+ version: "9.0.0",
3064
3135
  bindings: {
3065
3136
  angular: {
3066
3137
  importPath: "@uni-design-system/uni-angular",
@@ -3139,7 +3210,7 @@ emptyText="No countries found"
3139
3210
  summary: "",
3140
3211
  description: "",
3141
3212
  category: "components",
3142
- version: "8.3.0",
3213
+ version: "9.0.0",
3143
3214
  bindings: {
3144
3215
  angular: {
3145
3216
  importPath: "@uni-design-system/uni-angular",
@@ -3212,11 +3283,11 @@ emptyText="No countries found"
3212
3283
  description: ""
3213
3284
  },
3214
3285
  {
3215
- name: "color",
3286
+ name: "containerColor",
3216
3287
  kind: "input",
3217
3288
  type: "ContainerColorToken | undefined",
3218
3289
  required: false,
3219
- description: ""
3290
+ description: "A container color pair; `color` belongs to `uni-text` across the library."
3220
3291
  },
3221
3292
  {
3222
3293
  name: "dropdownShowing",
@@ -3246,7 +3317,8 @@ emptyText="No countries found"
3246
3317
  "dropdown.behavior.border",
3247
3318
  "dropdown.behavior.borderRadius",
3248
3319
  "dropdown.behavior.color",
3249
- "dropdown.behavior.shadow"
3320
+ "dropdown.behavior.shadow",
3321
+ "dropdown.behavior.motion"
3250
3322
  ]
3251
3323
  },
3252
3324
  {
@@ -3256,7 +3328,7 @@ emptyText="No countries found"
3256
3328
  summary: "",
3257
3329
  description: "",
3258
3330
  category: "layout",
3259
- version: "8.3.0",
3331
+ version: "9.0.0",
3260
3332
  bindings: {
3261
3333
  angular: {
3262
3334
  importPath: "@uni-design-system/uni-angular",
@@ -3334,7 +3406,7 @@ emptyText="No countries found"
3334
3406
  ]
3335
3407
  },
3336
3408
  relatedTokens: [
3337
- "expand.behavior.transitionSpeed"
3409
+ "expand.behavior.motion"
3338
3410
  ]
3339
3411
  },
3340
3412
  {
@@ -3344,7 +3416,7 @@ emptyText="No countries found"
3344
3416
  summary: "",
3345
3417
  description: "",
3346
3418
  category: "layout",
3347
- version: "8.3.0",
3419
+ version: "9.0.0",
3348
3420
  bindings: {
3349
3421
  angular: {
3350
3422
  importPath: "@uni-design-system/uni-angular",
@@ -3414,8 +3486,8 @@ emptyText="No countries found"
3414
3486
  status: "stable",
3415
3487
  summary: "Trigger for a {@link UniExpandComponent} region.",
3416
3488
  description: "Trigger for a {@link UniExpandComponent} region. Two shapes, chosen by whether `label` is set: - **Icon only** (default) \u2014 the bare chevron, sized for a Card Header. - **Labelled** \u2014 chevron plus a label and optional muted sublabel, as a single full-width button. Most real disclosures need a name for the section, and building that row by hand is the thing this saves; it also makes the label the button's accessible name rather than adjacent text.",
3417
- category: "forms",
3418
- version: "8.3.0",
3489
+ category: "layout",
3490
+ version: "9.0.0",
3419
3491
  bindings: {
3420
3492
  angular: {
3421
3493
  importPath: "@uni-design-system/uni-angular",
@@ -3500,7 +3572,7 @@ emptyText="No countries found"
3500
3572
  summary: "",
3501
3573
  description: "",
3502
3574
  category: "forms",
3503
- version: "8.3.0",
3575
+ version: "9.0.0",
3504
3576
  bindings: {
3505
3577
  angular: {
3506
3578
  importPath: "@uni-design-system/uni-angular",
@@ -3658,7 +3730,7 @@ emptyText="No countries found"
3658
3730
  summary: "",
3659
3731
  description: "",
3660
3732
  category: "layout",
3661
- version: "8.3.0",
3733
+ version: "9.0.0",
3662
3734
  bindings: {
3663
3735
  angular: {
3664
3736
  importPath: "@uni-design-system/uni-angular",
@@ -3716,19 +3788,19 @@ emptyText="No countries found"
3716
3788
  framework: "angular",
3717
3789
  code: `<!-- Storybook story: Simple Grid -->
3718
3790
  <div grid-layout \${argsToTemplate(props)}>
3719
- <div box-layout gridArea="nav" color="quaternary" padding="md" borderRadius="sm">
3791
+ <div box-layout gridArea="nav" containerColor="quaternary" padding="md" borderRadius="sm">
3720
3792
  <span uni-text>nav</span>
3721
3793
  </div>
3722
- <div box-layout gridArea="a1" color="primary" padding="md" borderRadius="sm">
3794
+ <div box-layout gridArea="a1" containerColor="primary" padding="md" borderRadius="sm">
3723
3795
  <span uni-text>a1</span>
3724
3796
  </div>
3725
- <div box-layout gridArea="a2" color="secondary" padding="md" borderRadius="sm">
3797
+ <div box-layout gridArea="a2" containerColor="secondary" padding="md" borderRadius="sm">
3726
3798
  <span uni-text>a2</span>
3727
3799
  </div>
3728
- <div box-layout gridArea="b1" color="tertiary" padding="md" borderRadius="sm">
3800
+ <div box-layout gridArea="b1" containerColor="tertiary" padding="md" borderRadius="sm">
3729
3801
  <span uni-text>b1</span>
3730
3802
  </div>
3731
- <div box-layout gridArea="b2" color="warn" padding="md" borderRadius="sm">
3803
+ <div box-layout gridArea="b2" containerColor="warn" padding="md" borderRadius="sm">
3732
3804
  <span uni-text>b2</span>
3733
3805
  </div>
3734
3806
  </div>
@@ -3755,7 +3827,7 @@ emptyText="No countries found"
3755
3827
  summary: "",
3756
3828
  description: "",
3757
3829
  category: "layout",
3758
- version: "8.3.0",
3830
+ version: "9.0.0",
3759
3831
  bindings: {
3760
3832
  angular: {
3761
3833
  importPath: "@uni-design-system/uni-angular",
@@ -3787,7 +3859,7 @@ emptyText="No countries found"
3787
3859
  summary: "",
3788
3860
  description: "",
3789
3861
  category: "primitives",
3790
- version: "8.3.0",
3862
+ version: "9.0.0",
3791
3863
  bindings: {
3792
3864
  angular: {
3793
3865
  importPath: "@uni-design-system/uni-angular",
@@ -3847,7 +3919,7 @@ emptyText="No countries found"
3847
3919
  summary: "",
3848
3920
  description: "",
3849
3921
  category: "primitives",
3850
- version: "8.3.0",
3922
+ version: "9.0.0",
3851
3923
  bindings: {
3852
3924
  angular: {
3853
3925
  importPath: "@uni-design-system/uni-angular",
@@ -3950,7 +4022,7 @@ emptyText="No countries found"
3950
4022
  summary: "",
3951
4023
  description: "",
3952
4024
  category: "forms",
3953
- version: "8.3.0",
4025
+ version: "9.0.0",
3954
4026
  bindings: {
3955
4027
  angular: {
3956
4028
  importPath: "@uni-design-system/uni-angular",
@@ -4025,6 +4097,129 @@ emptyText="No countries found"
4025
4097
  required: false,
4026
4098
  default: "''",
4027
4099
  description: ""
4100
+ },
4101
+ {
4102
+ name: "type",
4103
+ kind: "input",
4104
+ type: "UniInputType",
4105
+ required: false,
4106
+ default: "'text'",
4107
+ description: "Native input type. Text-like types only \u2014 `date`/`time` have dedicated components, and non-text types break the input chrome and the string value."
4108
+ },
4109
+ {
4110
+ name: "readonly",
4111
+ kind: "input",
4112
+ type: "boolean",
4113
+ required: false,
4114
+ default: "false",
4115
+ description: ""
4116
+ },
4117
+ {
4118
+ name: "name",
4119
+ kind: "input",
4120
+ type: "string",
4121
+ required: false,
4122
+ default: "''",
4123
+ description: ""
4124
+ },
4125
+ {
4126
+ name: "min",
4127
+ kind: "input",
4128
+ type: "number | undefined",
4129
+ required: false,
4130
+ default: "undefined",
4131
+ description: ""
4132
+ },
4133
+ {
4134
+ name: "max",
4135
+ kind: "input",
4136
+ type: "number | undefined",
4137
+ required: false,
4138
+ default: "undefined",
4139
+ description: ""
4140
+ },
4141
+ {
4142
+ name: "minLength",
4143
+ kind: "input",
4144
+ type: "number | undefined",
4145
+ required: false,
4146
+ default: "undefined",
4147
+ description: ""
4148
+ },
4149
+ {
4150
+ name: "maxLength",
4151
+ kind: "input",
4152
+ type: "number | undefined",
4153
+ required: false,
4154
+ default: "undefined",
4155
+ description: ""
4156
+ },
4157
+ {
4158
+ name: "pattern",
4159
+ kind: "input",
4160
+ type: "readonly RegExp[]",
4161
+ required: false,
4162
+ default: "[]",
4163
+ description: "Patterns the value must match \u2014 all of them, per Signal Forms. The native `pattern` attribute can only express one, so it is reflected only when there is exactly one; Signal Forms validates the rest either way."
4164
+ },
4165
+ {
4166
+ name: "step",
4167
+ kind: "input",
4168
+ type: "number | string",
4169
+ required: false,
4170
+ description: "Granularity for `type=\"number\"`, e.g. `0.01` or `'any'`."
4171
+ },
4172
+ {
4173
+ name: "autocomplete",
4174
+ kind: "input",
4175
+ type: "string",
4176
+ required: false,
4177
+ description: "Autofill hint, e.g. `email`, `current-password`, `off`."
4178
+ },
4179
+ {
4180
+ name: "inputMode",
4181
+ kind: "input",
4182
+ type: "UniInputMode",
4183
+ required: false,
4184
+ description: "On-screen keyboard hint; defaults to whatever `type` implies."
4185
+ },
4186
+ {
4187
+ name: "list",
4188
+ kind: "input",
4189
+ type: "string",
4190
+ required: false,
4191
+ description: "Id of a `<datalist>` supplying suggestions."
4192
+ },
4193
+ {
4194
+ name: "spellcheck",
4195
+ kind: "input",
4196
+ type: "boolean",
4197
+ required: false,
4198
+ description: ""
4199
+ },
4200
+ {
4201
+ name: "width",
4202
+ kind: "input",
4203
+ type: "string | number | undefined",
4204
+ required: false,
4205
+ default: "undefined",
4206
+ description: ""
4207
+ },
4208
+ {
4209
+ name: "fullWidth",
4210
+ kind: "input",
4211
+ type: "boolean",
4212
+ required: false,
4213
+ default: "false",
4214
+ description: ""
4215
+ },
4216
+ {
4217
+ name: "grow",
4218
+ kind: "input",
4219
+ type: "number | undefined",
4220
+ required: false,
4221
+ default: "undefined",
4222
+ description: ""
4028
4223
  }
4029
4224
  ]
4030
4225
  }
@@ -4059,6 +4254,16 @@ emptyText="No countries found"
4059
4254
  title: "Long Label",
4060
4255
  framework: "angular",
4061
4256
  code: "<!-- Storybook story: Long Label -->\n<uni-input ${argsToTemplate(props)}>\n</uni-input>\n<!-- args:\n{\n label: 'A Very Long Label That Demonstrates How The Component Handles Extended Text',\n placeholder: 'Enter some text',\n value: '',\n disabled: false,\n touched: false,\n invalid: false,\n dirty: false,\n }\n-->"
4257
+ },
4258
+ {
4259
+ title: "Types",
4260
+ framework: "angular",
4261
+ code: "<!-- Storybook story: Types -->\n<uni-input ${argsToTemplate(props)}>\n</uni-input>"
4262
+ },
4263
+ {
4264
+ title: "With datalist",
4265
+ framework: "angular",
4266
+ code: "<!-- Storybook story: With datalist -->\n<uni-input ${argsToTemplate(props)}>\n</uni-input>"
4062
4267
  }
4063
4268
  ],
4064
4269
  guidelines: {
@@ -4095,7 +4300,7 @@ emptyText="No countries found"
4095
4300
  summary: "",
4096
4301
  description: "",
4097
4302
  category: "forms",
4098
- version: "8.3.0",
4303
+ version: "9.0.0",
4099
4304
  bindings: {
4100
4305
  angular: {
4101
4306
  importPath: "@uni-design-system/uni-angular",
@@ -4132,6 +4337,30 @@ emptyText="No countries found"
4132
4337
  required: false,
4133
4338
  default: "undefined",
4134
4339
  description: "Override the themed field height, e.g. `'auto'` for multi-line fields."
4340
+ },
4341
+ {
4342
+ name: "width",
4343
+ kind: "input",
4344
+ type: "string | number | undefined",
4345
+ required: false,
4346
+ default: "undefined",
4347
+ description: ""
4348
+ },
4349
+ {
4350
+ name: "fullWidth",
4351
+ kind: "input",
4352
+ type: "boolean",
4353
+ required: false,
4354
+ default: "false",
4355
+ description: ""
4356
+ },
4357
+ {
4358
+ name: "grow",
4359
+ kind: "input",
4360
+ type: "number | undefined",
4361
+ required: false,
4362
+ default: "undefined",
4363
+ description: ""
4135
4364
  }
4136
4365
  ]
4137
4366
  }
@@ -4168,7 +4397,7 @@ emptyText="No countries found"
4168
4397
  summary: "",
4169
4398
  description: "",
4170
4399
  category: "components",
4171
- version: "8.3.0",
4400
+ version: "9.0.0",
4172
4401
  bindings: {
4173
4402
  angular: {
4174
4403
  importPath: "@uni-design-system/uni-angular",
@@ -4238,7 +4467,7 @@ emptyText="No countries found"
4238
4467
  summary: "",
4239
4468
  description: "",
4240
4469
  category: "layout",
4241
- version: "8.3.0",
4470
+ version: "9.0.0",
4242
4471
  bindings: {
4243
4472
  angular: {
4244
4473
  importPath: "@uni-design-system/uni-angular",
@@ -4281,7 +4510,7 @@ emptyText="No countries found"
4281
4510
  title: "Primary",
4282
4511
  framework: "angular",
4283
4512
  code: `<!-- Storybook story: Primary -->
4284
- <div box-layout color="primary" padding="sm">
4513
+ <div box-layout containerColor="primary" padding="sm">
4285
4514
  <uni-menu \${argsToTemplate(props)}>
4286
4515
  <button text-button variant="ghost" symbolRight="arrow_drop_down">Menu</button>
4287
4516
  </uni-menu>
@@ -4300,7 +4529,7 @@ emptyText="No countries found"
4300
4529
  title: "Tones",
4301
4530
  framework: "angular",
4302
4531
  code: `<!-- Storybook story: Tones -->
4303
- <div box-layout color="primary" padding="sm">
4532
+ <div box-layout containerColor="primary" padding="sm">
4304
4533
  <uni-menu \${argsToTemplate(props)}>
4305
4534
  <button text-button variant="ghost" symbolRight="arrow_drop_down">Menu</button>
4306
4535
  </uni-menu>
@@ -4342,7 +4571,7 @@ emptyText="No countries found"
4342
4571
  summary: "",
4343
4572
  description: "",
4344
4573
  category: "layout",
4345
- version: "8.3.0",
4574
+ version: "9.0.0",
4346
4575
  bindings: {
4347
4576
  angular: {
4348
4577
  importPath: "@uni-design-system/uni-angular",
@@ -4424,7 +4653,7 @@ emptyText="No countries found"
4424
4653
  summary: "",
4425
4654
  description: "",
4426
4655
  category: "forms",
4427
- version: "8.3.0",
4656
+ version: "9.0.0",
4428
4657
  bindings: {
4429
4658
  angular: {
4430
4659
  importPath: "@uni-design-system/uni-angular",
@@ -4488,6 +4717,11 @@ emptyText="No countries found"
4488
4717
  framework: "angular",
4489
4718
  code: "<!-- Storybook story: Single Selection -->\n<uni-multi-select ${argsToTemplate(props)}>\n</uni-multi-select>\n<!-- args:\n{\n options: [\n { value: 'red', label: 'Red' },\n { value: 'green', label: 'Green' },\n { value: 'blue', label: 'Blue' },\n ],\n selections: ['red'],\n }\n-->"
4490
4719
  },
4720
+ {
4721
+ title: "Disabled Options",
4722
+ framework: "angular",
4723
+ code: "<!-- Storybook story: Disabled Options -->\n<uni-multi-select ${argsToTemplate(props)}>\n</uni-multi-select>\n<!-- args:\n{\n options: [\n { value: 'email', label: 'Email' },\n { value: 'sms', label: 'SMS \u2014 verify a phone number first', disabled: true },\n { value: 'push', label: 'Push' },\n { value: 'fax', label: 'Fax \u2014 retired', disabled: true },\n ],\n selections: ['email'],\n }\n-->"
4724
+ },
4491
4725
  {
4492
4726
  title: "Many Options",
4493
4727
  framework: "angular",
@@ -4500,7 +4734,8 @@ emptyText="No countries found"
4500
4734
  donts: [],
4501
4735
  accessibility: [
4502
4736
  "Options are real checkboxes in a labelled group \u2014 Space toggles, Tab moves between them.",
4503
- "Selection state is announced per option."
4737
+ "Selection state is announced per option.",
4738
+ "Disabled options stay rendered and announced, not hidden \u2014 removing them would"
4504
4739
  ]
4505
4740
  },
4506
4741
  relatedTokens: []
@@ -4512,7 +4747,7 @@ emptyText="No countries found"
4512
4747
  summary: "",
4513
4748
  description: "",
4514
4749
  category: "forms",
4515
- version: "8.3.0",
4750
+ version: "9.0.0",
4516
4751
  bindings: {
4517
4752
  angular: {
4518
4753
  importPath: "@uni-design-system/uni-angular",
@@ -4627,6 +4862,11 @@ emptyText="No countries found"
4627
4862
  framework: "angular",
4628
4863
  code: "<!-- Storybook story: Many Options -->\n<uni-multi-select-dropdown ${argsToTemplate(props)}>\n</uni-multi-select-dropdown>\n<!-- args:\n{\n options: [\n { value: 'option1', label: 'First Option' },\n { value: 'option2', label: 'Second Option' },\n { value: 'option3', label: 'Third Option' },\n { value: 'option4', label: 'Fourth Option' },\n { value: 'option5', label: 'Fifth Option' },\n { value: 'option6', label: 'Sixth Option' },\n { value: 'option7', label: 'Seventh Option' },\n { value: 'option8', label: 'Eighth Option' },\n ],\n value: ['option2', 'option4', 'option6'],\n }\n-->"
4629
4864
  },
4865
+ {
4866
+ title: "Disabled Options",
4867
+ framework: "angular",
4868
+ code: "<!-- Storybook story: Disabled Options -->\n<uni-multi-select-dropdown ${argsToTemplate(props)}>\n</uni-multi-select-dropdown>\n<!-- args:\n{\n options: [\n { value: 'email', label: 'Email' },\n { value: 'sms', label: 'SMS \u2014 verify a phone number first', disabled: true },\n { value: 'push', label: 'Push' },\n { value: 'fax', label: 'Fax \u2014 retired', disabled: true },\n ],\n value: ['email'],\n }\n-->"
4869
+ },
4630
4870
  {
4631
4871
  title: "Disabled",
4632
4872
  framework: "angular",
@@ -4650,7 +4890,8 @@ emptyText="No countries found"
4650
4890
  accessibility: [
4651
4891
  'The trigger is a disclosure (`aria-haspopup="dialog"`, `aria-expanded`); the popover contains native focusables Tab reaches normally.',
4652
4892
  "The search input is labelled; options are real checkboxes announced with their state.",
4653
- "Escape closes the popover and returns focus to the trigger."
4893
+ "Escape closes the popover and returns focus to the trigger.",
4894
+ "Disabled options stay rendered and announced; arrows step over them and"
4654
4895
  ]
4655
4896
  },
4656
4897
  relatedTokens: []
@@ -4662,7 +4903,7 @@ emptyText="No countries found"
4662
4903
  summary: "",
4663
4904
  description: "",
4664
4905
  category: "feedback",
4665
- version: "8.3.0",
4906
+ version: "9.0.0",
4666
4907
  bindings: {
4667
4908
  angular: {
4668
4909
  importPath: "@uni-design-system/uni-angular",
@@ -4906,7 +5147,7 @@ emptyText="No countries found"
4906
5147
  summary: "",
4907
5148
  description: "",
4908
5149
  category: "feedback",
4909
- version: "8.3.0",
5150
+ version: "9.0.0",
4910
5151
  bindings: {
4911
5152
  angular: {
4912
5153
  importPath: "@uni-design-system/uni-angular",
@@ -4930,7 +5171,7 @@ emptyText="No countries found"
4930
5171
  summary: "",
4931
5172
  description: "",
4932
5173
  category: "data",
4933
- version: "8.3.0",
5174
+ version: "9.0.0",
4934
5175
  bindings: {
4935
5176
  angular: {
4936
5177
  importPath: "@uni-design-system/uni-angular",
@@ -5015,7 +5256,7 @@ emptyText="No countries found"
5015
5256
  summary: "Anchored, top-layer panel on the native `popover` element \u2014 the browser owns positioning (CSS anchor positioning), stacking, and, in rich mode, light dismissal.",
5016
5257
  description: 'Anchored, top-layer panel on the native `popover` element \u2014 the browser owns positioning (CSS anchor positioning), stacking, and, in rich mode, light dismissal. Two modes share one implementation: - `rich` (default): a click-toggled disclosure. The projected `[trigger]` carries `aria-expanded`/`aria-controls`; with no trigger content the app drives `open` and no element claims controller ARIA. Focus stays on the trigger (APG disclosure) unless the panel marks an `[autofocus]` field, and returns to the trigger on close. - `tooltip`: hover/focus-triggered, `role="tooltip"` + `aria-describedby`, WCAG 1.4.13 dismissable/hoverable/persistent. Content must not contain focusable elements. Anchoring and control are separate: `anchor` re-anchors the panel to any element (or id) while the trigger keeps the disclosure semantics.',
5017
5258
  category: "layout",
5018
- version: "8.3.0",
5259
+ version: "9.0.0",
5019
5260
  bindings: {
5020
5261
  angular: {
5021
5262
  importPath: "@uni-design-system/uni-angular",
@@ -5180,7 +5421,8 @@ emptyText="No countries found"
5180
5421
  "popover.behavior.headerTypeface",
5181
5422
  "popover.behavior.tooltipPadding",
5182
5423
  "popover.behavior.tooltipOpenDelay",
5183
- "popover.behavior.tooltipCloseDelay"
5424
+ "popover.behavior.tooltipCloseDelay",
5425
+ "popover.behavior.motion"
5184
5426
  ]
5185
5427
  },
5186
5428
  {
@@ -5190,7 +5432,7 @@ emptyText="No countries found"
5190
5432
  summary: "",
5191
5433
  description: "",
5192
5434
  category: "feedback",
5193
- version: "8.3.0",
5435
+ version: "9.0.0",
5194
5436
  bindings: {
5195
5437
  angular: {
5196
5438
  importPath: "@uni-design-system/uni-angular",
@@ -5254,7 +5496,7 @@ emptyText="No countries found"
5254
5496
  summary: "",
5255
5497
  description: "",
5256
5498
  category: "feedback",
5257
- version: "8.3.0",
5499
+ version: "9.0.0",
5258
5500
  bindings: {
5259
5501
  angular: {
5260
5502
  importPath: "@uni-design-system/uni-angular",
@@ -5310,7 +5552,7 @@ emptyText="No countries found"
5310
5552
  summary: "",
5311
5553
  description: "",
5312
5554
  category: "forms",
5313
- version: "8.3.0",
5555
+ version: "9.0.0",
5314
5556
  bindings: {
5315
5557
  angular: {
5316
5558
  importPath: "@uni-design-system/uni-angular",
@@ -5452,7 +5694,7 @@ emptyText="No countries found"
5452
5694
  "radio.behavior.size",
5453
5695
  "radio.behavior.ringColor",
5454
5696
  "radio.behavior.fillColor",
5455
- "radio.behavior.transitionSpeed"
5697
+ "radio.behavior.motion"
5456
5698
  ]
5457
5699
  },
5458
5700
  {
@@ -5462,7 +5704,7 @@ emptyText="No countries found"
5462
5704
  summary: "",
5463
5705
  description: "",
5464
5706
  category: "directives",
5465
- version: "8.3.0",
5707
+ version: "9.0.0",
5466
5708
  bindings: {
5467
5709
  angular: {
5468
5710
  importPath: "@uni-design-system/uni-angular",
@@ -5486,7 +5728,7 @@ emptyText="No countries found"
5486
5728
  summary: "",
5487
5729
  description: "",
5488
5730
  category: "layout",
5489
- version: "8.3.0",
5731
+ version: "9.0.0",
5490
5732
  bindings: {
5491
5733
  angular: {
5492
5734
  importPath: "@uni-design-system/uni-angular",
@@ -5541,18 +5783,18 @@ emptyText="No countries found"
5541
5783
  summary: "Native scroll area with theme-driven scrollbar styling.",
5542
5784
  description: "Native scroll area with theme-driven scrollbar styling. Scrollbars are styled entirely through Emotion-generated CSS: `::-webkit-scrollbar` rules cover Chromium/Safari, with a `scrollbar-width`/`scrollbar-color` fallback for Firefox.",
5543
5785
  category: "layout",
5544
- version: "8.3.0",
5786
+ version: "9.0.0",
5545
5787
  bindings: {
5546
5788
  angular: {
5547
5789
  importPath: "@uni-design-system/uni-angular",
5548
5790
  selectorOrTag: "[uni-scroll-area], [scroll-area]",
5549
5791
  api: [
5550
5792
  {
5551
- name: "color",
5793
+ name: "containerColor",
5552
5794
  kind: "input",
5553
5795
  type: "ContainerColorToken",
5554
5796
  required: false,
5555
- description: ""
5797
+ description: "A container color *pair*: the named surface plus its paired on-color. Named `containerColor`, not `color`, for the same reason as the layout primitives: this is an attribute directive-style selector that shares elements with `uni-text`, which owns `color` and maps it to the CSS property. One `color` binding feeding both would render ink on ink."
5556
5798
  },
5557
5799
  {
5558
5800
  name: "borderRadius",
@@ -5670,7 +5912,7 @@ emptyText="No countries found"
5670
5912
  {
5671
5913
  title: "Primary",
5672
5914
  framework: "angular",
5673
- code: '<!-- Storybook story: Primary -->\n<div scroll-area ${argsToTemplate(props)} #scrollArea>\n <button size="sm" text-button variant="ghost" symbolLeft="arrow_downward" (click)="scrollArea.scrollToBottom()">Scroll to bottom</button>\n ${ngContent}\n <button size="sm" text-button variant="ghost" symbolLeft="arrow_upward" (click)="scrollArea.scrollToTop()">Back to top</button>\n</div>\n<!-- args:\n{\n border: \'quaternary\',\n color: \'tertiary-surface\',\n height: 200,\n ngContent: `\n <span uni-text="headline-medium">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</span>\n <span uni-text="body-1-long">\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quis facere debitis ullam, quae quidem, impedit\n culpa nam\n repellat in voluptatibus esse ab harum, hic? Aliquam nesciunt voluptates repellendus assumenda labore.\n </p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro quos voluptate doloribus. Optio unde\n inventore, tempore\n nemo repellat expedita! Quod, accusamus nobis iure. Aliquam quibusdam, nemo explicabo ipsum provident\n asperiores.</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat, qui, rem! Debitis cum maiores iste,\n possimus!\n Obcaecati accusamus eaque expedita quo soluta quis, repudiandae similique, veritatis repellendus facere\n suscipit!\n Et!</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum doloremque repellat praesentium quae et\n consectetur\n iure quos porro, provident voluptates reprehenderit a. Accusamus ut, quaerat asperiores blanditiis\n voluptate, sint\n facilis.</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus beatae inventore nobis esse\n temporibus\n exercitationem\n eos illo minima non magnam, provident sit doloribus maiores odio in animi quidem unde. Perferendis.</p>\n\n </span>\n\n\n `,\n }\n-->'
5915
+ code: '<!-- Storybook story: Primary -->\n<div scroll-area ${argsToTemplate(props)} #scrollArea>\n <button size="sm" text-button variant="ghost" symbolLeft="arrow_downward" (click)="scrollArea.scrollToBottom()">Scroll to bottom</button>\n ${ngContent}\n <button size="sm" text-button variant="ghost" symbolLeft="arrow_upward" (click)="scrollArea.scrollToTop()">Back to top</button>\n</div>\n<!-- args:\n{\n border: \'quaternary\',\n containerColor: \'tertiary-surface\',\n height: 200,\n ngContent: `\n <span uni-text="headline-medium">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</span>\n <span uni-text="body-1-long">\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quis facere debitis ullam, quae quidem, impedit\n culpa nam\n repellat in voluptatibus esse ab harum, hic? Aliquam nesciunt voluptates repellendus assumenda labore.\n </p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro quos voluptate doloribus. Optio unde\n inventore, tempore\n nemo repellat expedita! Quod, accusamus nobis iure. Aliquam quibusdam, nemo explicabo ipsum provident\n asperiores.</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat, qui, rem! Debitis cum maiores iste,\n possimus!\n Obcaecati accusamus eaque expedita quo soluta quis, repudiandae similique, veritatis repellendus facere\n suscipit!\n Et!</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum doloremque repellat praesentium quae et\n consectetur\n iure quos porro, provident voluptates reprehenderit a. Accusamus ut, quaerat asperiores blanditiis\n voluptate, sint\n facilis.</p>\n <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus beatae inventore nobis esse\n temporibus\n exercitationem\n eos illo minima non magnam, provident sit doloribus maiores odio in animi quidem unde. Perferendis.</p>\n\n </span>\n\n\n `,\n }\n-->'
5674
5916
  }
5675
5917
  ],
5676
5918
  guidelines: {
@@ -5688,7 +5930,7 @@ emptyText="No countries found"
5688
5930
  summary: "Generic search field: shared input chrome with a leading magnifier, a clear button while there's a query, Enter to submit, and optional type-ahead \u2014 pass `suggestions` (refresh them from `change`) and the field becomes an ARIA combobox with a keyboard-navigable listbox.",
5689
5931
  description: "Generic search field: shared input chrome with a leading magnifier, a clear button while there's a query, Enter to submit, and optional type-ahead \u2014 pass `suggestions` (refresh them from `change`) and the field becomes an ARIA combobox with a keyboard-navigable listbox. Escape closes the list first, then clears the query.",
5690
5932
  category: "forms",
5691
- version: "8.3.0",
5933
+ version: "9.0.0",
5692
5934
  bindings: {
5693
5935
  angular: {
5694
5936
  importPath: "@uni-design-system/uni-angular",
@@ -5733,18 +5975,18 @@ emptyText="No countries found"
5733
5975
  description: "Type-ahead entries. Keep them fresh from `change` emissions; the list shows while the field has focus and entries exist."
5734
5976
  },
5735
5977
  {
5736
- name: "change",
5978
+ name: "searchChange",
5737
5979
  kind: "output",
5738
5980
  type: "string",
5739
5981
  required: false,
5740
- description: ""
5982
+ description: "The debounced query, emitted as the user types."
5741
5983
  },
5742
5984
  {
5743
- name: "search",
5985
+ name: "searchSubmit",
5744
5986
  kind: "output",
5745
5987
  type: "string",
5746
5988
  required: false,
5747
- description: ""
5989
+ description: "A committed search: Enter, or a suggestion chosen from the list."
5748
5990
  },
5749
5991
  {
5750
5992
  name: "suggestionSelected",
@@ -5766,8 +6008,8 @@ emptyText="No countries found"
5766
6008
  label="Search the docs"
5767
6009
  [debounceTime]="200"
5768
6010
  [suggestions]="suggestions"
5769
- (change)="filter($event)"
5770
- (search)="log($event)"
6011
+ (searchChange)="filter($event)"
6012
+ (searchSubmit)="log($event)"
5771
6013
  ></uni-search-input>
5772
6014
  </div>
5773
6015
  <!-- args:
@@ -5777,11 +6019,11 @@ emptyText="No countries found"
5777
6019
  {
5778
6020
  title: "Type-ahead",
5779
6021
  framework: "angular",
5780
- code: '<!-- Storybook story: Type-ahead -->\n<div box-layout maxWidth="420px">\n<uni-search-input\n label="Search the docs"\n [debounceTime]="200"\n [suggestions]="suggestions"\n (change)="filter($event)"\n (search)="log($event)"\n></uni-search-input>\n</div>'
6022
+ code: '<!-- Storybook story: Type-ahead -->\n<div box-layout maxWidth="420px">\n<uni-search-input\n label="Search the docs"\n [debounceTime]="200"\n [suggestions]="suggestions"\n (searchChange)="filter($event)"\n (searchSubmit)="log($event)"\n></uni-search-input>\n</div>'
5781
6023
  }
5782
6024
  ],
5783
6025
  guidelines: {
5784
- whenToUse: "Generic search field wearing the shared input chrome: a decorative leading magnifier,\na clear button while there's a query, and Enter to submit (`search`). `change` emits\ndebounced as the user types \u2014 use it to refresh results or the `suggestions` input.\nWith `suggestions`, the field becomes an ARIA combobox: entries render in a listbox\nunder the field, ArrowUp/Down move the highlight, Enter selects (emitting both\n`suggestionSelected` and `search`), and Escape closes the list first, then clears the\nquery. The suggestion list's surface, elevation and radius resolve from the theme's\n`searchInput` options, alongside the search/clear symbols.",
6026
+ whenToUse: "Generic search field wearing the shared input chrome: a decorative leading magnifier,\na clear button while there's a query, and Enter to submit (`searchSubmit`). `searchChange` emits\ndebounced as the user types \u2014 use it to refresh results or the `suggestions` input.\nWith `suggestions`, the field becomes an ARIA combobox: entries render in a listbox\nunder the field, ArrowUp/Down move the highlight, Enter selects (emitting both\n`suggestionSelected` and `searchSubmit`), and Escape closes the list first, then clears the\nquery. The suggestion list's surface, elevation and radius resolve from the theme's\n`searchInput` options, alongside the search/clear symbols.",
5785
6027
  dos: [],
5786
6028
  donts: [],
5787
6029
  accessibility: [
@@ -5799,7 +6041,7 @@ emptyText="No countries found"
5799
6041
  summary: "",
5800
6042
  description: "",
5801
6043
  category: "forms",
5802
- version: "8.3.0",
6044
+ version: "9.0.0",
5803
6045
  bindings: {
5804
6046
  angular: {
5805
6047
  importPath: "@uni-design-system/uni-angular",
@@ -5875,6 +6117,30 @@ emptyText="No countries found"
5875
6117
  required: false,
5876
6118
  description: ""
5877
6119
  },
6120
+ {
6121
+ name: "width",
6122
+ kind: "input",
6123
+ type: "string | number | undefined",
6124
+ required: false,
6125
+ default: "undefined",
6126
+ description: ""
6127
+ },
6128
+ {
6129
+ name: "fullWidth",
6130
+ kind: "input",
6131
+ type: "boolean",
6132
+ required: false,
6133
+ default: "false",
6134
+ description: ""
6135
+ },
6136
+ {
6137
+ name: "grow",
6138
+ kind: "input",
6139
+ type: "number | undefined",
6140
+ required: false,
6141
+ default: "undefined",
6142
+ description: ""
6143
+ },
5878
6144
  {
5879
6145
  name: "ariaLabel",
5880
6146
  kind: "input",
@@ -5901,6 +6167,11 @@ emptyText="No countries found"
5901
6167
  framework: "angular",
5902
6168
  code: "<!-- Storybook story: Disabled -->\n<uni-select ${argsToTemplate(props)}>\n</uni-select>\n<!-- args:\n{\n placeholder: 'Cannot select...',\n options: [\n { value: 'option1', label: 'Option 1' },\n { value: 'option2', label: 'Option 2' },\n { value: 'option3', label: 'Option 3' },\n ],\n value: 'option2',\n disabled: true,\n touched: false,\n invalid: false,\n dirty: false,\n }\n-->"
5903
6169
  },
6170
+ {
6171
+ title: "Disabled Options",
6172
+ framework: "angular",
6173
+ code: "<!-- Storybook story: Disabled Options -->\n<uni-select ${argsToTemplate(props)}>\n</uni-select>\n<!-- args:\n{\n placeholder: 'Select a plan...',\n options: [\n { value: 'free', label: 'Free' },\n { value: 'pro', label: 'Pro' },\n { value: 'team', label: 'Team \u2014 requires an organization', disabled: true },\n { value: 'enterprise', label: 'Enterprise \u2014 contact sales', disabled: true },\n ],\n value: null,\n disabled: false,\n touched: false,\n invalid: false,\n dirty: false,\n }\n-->"
6174
+ },
5904
6175
  {
5905
6176
  title: "Invalid",
5906
6177
  framework: "angular",
@@ -5923,7 +6194,8 @@ emptyText="No countries found"
5923
6194
  donts: [],
5924
6195
  accessibility: [
5925
6196
  "Native `<select>`: platform keyboard interaction and mobile pickers for free.",
5926
- "`label` becomes the accessible name; `aria-invalid` reflects the touched error state."
6197
+ "`label` becomes the accessible name; `aria-invalid` reflects the touched error state.",
6198
+ "Disabled options are rendered and announced, not hidden \u2014 removing them would"
5927
6199
  ]
5928
6200
  },
5929
6201
  relatedTokens: []
@@ -5933,9 +6205,9 @@ emptyText="No countries found"
5933
6205
  name: "Skeleton",
5934
6206
  status: "stable",
5935
6207
  summary: "Loading placeholder painted with surface tokens.",
5936
- description: "Loading placeholder painted with surface tokens. `text` renders one or more lines (the last line shortened, as real text would be), `rect` and `circle` render fixed shapes. The shimmer only animates when the user allows motion; it degrades to static blocks under `prefers-reduced-motion`.",
6208
+ description: "Loading placeholder painted with surface tokens. `text` renders one or more lines (the last line shortened, as real text would be), `rect` and `circle` render fixed shapes. The shimmer only animates when the user allows motion; it degrades to static blocks under `prefers-reduced-motion`. Color and radius are theme options with per-instance overrides, because one app routinely needs several: skeletons on a card and on the page background want different tints, and a pill placeholder wants a different corner than the text bars beside it.",
5937
6209
  category: "components",
5938
- version: "8.3.0",
6210
+ version: "9.0.0",
5939
6211
  bindings: {
5940
6212
  angular: {
5941
6213
  importPath: "@uni-design-system/uni-angular",
@@ -5972,6 +6244,38 @@ emptyText="No countries found"
5972
6244
  required: false,
5973
6245
  default: "1",
5974
6246
  description: "Number of text lines (text shape only)."
6247
+ },
6248
+ {
6249
+ name: "color",
6250
+ kind: "input",
6251
+ type: "ColorKey | undefined",
6252
+ required: false,
6253
+ default: "undefined",
6254
+ description: "Base color token; overrides the theme option for this skeleton."
6255
+ },
6256
+ {
6257
+ name: "highlightColor",
6258
+ kind: "input",
6259
+ type: "ColorKey | undefined",
6260
+ required: false,
6261
+ default: "undefined",
6262
+ description: "Shimmer highlight token; overrides the theme option for this skeleton."
6263
+ },
6264
+ {
6265
+ name: "borderRadius",
6266
+ kind: "input",
6267
+ type: "Radius | undefined",
6268
+ required: false,
6269
+ default: "undefined",
6270
+ description: "Radius token; overrides the theme option. Circles are always round."
6271
+ },
6272
+ {
6273
+ name: "label",
6274
+ kind: "input",
6275
+ type: "string | undefined",
6276
+ required: false,
6277
+ default: "undefined",
6278
+ description: "Announces the skeleton to assistive tech as a polite status. Leave unset when a container already carries `aria-busy` \u2014 the skeleton then stays `aria-hidden`, as a decorative placeholder should."
5975
6279
  }
5976
6280
  ]
5977
6281
  }
@@ -5981,37 +6285,42 @@ emptyText="No countries found"
5981
6285
  title: "Text Lines",
5982
6286
  framework: "angular",
5983
6287
  code: `<!-- Storybook story: Text Lines -->
5984
- <div box-layout maxWidth="360px">
6288
+ <div box-layout maxWidth="360px" gap="md">
5985
6289
  <uni-card>
5986
- <div row-layout gap="sm" alignItems="center" padding="md">
5987
- <uni-skeleton shape="circle" [height]="40" />
5988
- <div box-layout [grow]="1">
5989
- <uni-skeleton [lines]="2" />
6290
+ <div box-layout padding="md" gap="sm">
6291
+ <div row-layout gap="sm" alignItems="center">
6292
+ <uni-skeleton shape="rect" borderRadius="max" [width]="56" [height]="20" />
6293
+ <uni-skeleton shape="rect" [width]="120" [height]="12" />
5990
6294
  </div>
5991
- </div>
5992
- <div box-layout paddingHorizontal="md" paddingBottom="md">
5993
- <uni-skeleton shape="rect" [height]="120" />
6295
+ <uni-skeleton [lines]="2" />
5994
6296
  </div>
5995
6297
  </uni-card>
6298
+ <uni-skeleton color="surface" highlightColor="surface-variant" [lines]="2" />
5996
6299
  </div>
5997
6300
  <!-- args:
5998
6301
  { shape: 'text', lines: 3 }
5999
6302
  -->`
6000
6303
  },
6304
+ {
6305
+ title: "Per Instance Tokens",
6306
+ framework: "angular",
6307
+ code: '<!-- Storybook story: Per Instance Tokens -->\n<div box-layout maxWidth="360px" gap="md">\n<uni-card>\n <div box-layout padding="md" gap="sm">\n <div row-layout gap="sm" alignItems="center">\n <uni-skeleton shape="rect" borderRadius="max" [width]="56" [height]="20" />\n <uni-skeleton shape="rect" [width]="120" [height]="12" />\n </div>\n <uni-skeleton [lines]="2" />\n </div>\n</uni-card>\n<uni-skeleton color="surface" highlightColor="surface-variant" [lines]="2" />\n</div>'
6308
+ },
6001
6309
  {
6002
6310
  title: "Card Placeholder",
6003
6311
  framework: "angular",
6004
- code: '<!-- Storybook story: Card Placeholder -->\n<div box-layout maxWidth="360px">\n<uni-card>\n <div row-layout gap="sm" alignItems="center" padding="md">\n <uni-skeleton shape="circle" [height]="40" />\n <div box-layout [grow]="1">\n <uni-skeleton [lines]="2" />\n </div>\n </div>\n <div box-layout paddingHorizontal="md" paddingBottom="md">\n <uni-skeleton shape="rect" [height]="120" />\n </div>\n</uni-card>\n</div>'
6312
+ code: '<!-- Storybook story: Card Placeholder -->\n<div box-layout maxWidth="360px" gap="md">\n<uni-card>\n <div box-layout padding="md" gap="sm">\n <div row-layout gap="sm" alignItems="center">\n <uni-skeleton shape="rect" borderRadius="max" [width]="56" [height]="20" />\n <uni-skeleton shape="rect" [width]="120" [height]="12" />\n </div>\n <uni-skeleton [lines]="2" />\n </div>\n</uni-card>\n<uni-skeleton color="surface" highlightColor="surface-variant" [lines]="2" />\n</div>'
6005
6313
  }
6006
6314
  ],
6007
6315
  guidelines: {
6008
- whenToUse: "Loading placeholder that sketches the shape of incoming content: `text` renders one or\nmore lines (ending on a short line, as real copy would), `rect` stands in for media and\ncharts, `circle` for avatars. Skeletons paint with the theme's surface tokens so they\nsit naturally on any brand in both modes, and the shimmer sweep only animates for users\nwho allow motion \u2014 under `prefers-reduced-motion` it degrades to calm static blocks.\nSkeletons are `aria-hidden`; announce loading on the container (e.g. `aria-busy`)\nwhere your app knows what is actually loading.",
6316
+ whenToUse: "Loading placeholder that sketches the shape of incoming content: `text` renders one or\nmore lines (ending on a short line, as real copy would), `rect` stands in for media and\ncharts, `circle` for avatars. Skeletons paint with the theme's surface tokens so they\nsit naturally on any brand in both modes, and the shimmer sweep only animates for users\nwho allow motion \u2014 under `prefers-reduced-motion` it degrades to calm static blocks.\nSkeletons are `aria-hidden` by default; announce loading on the container (e.g. `aria-busy`)\nwhere your app knows what is actually loading, or give a standalone skeleton a `label`.",
6009
6317
  dos: [],
6010
6318
  donts: [
6011
- "Announce individual skeletons to assistive tech \u2014 they are decorative placeholders"
6319
+ "Announce every skeleton in a group \u2014 label the container, or one skeleton, not twelve"
6012
6320
  ],
6013
6321
  accessibility: [
6014
- "Skeletons are `aria-hidden` \u2014 announce loading on the container (e.g. `aria-busy`) where your app knows what is loading.",
6322
+ "Skeletons are `aria-hidden` unless given a `label` \u2014 announce loading on the container (e.g. `aria-busy`) where your app knows what is loading.",
6323
+ 'A `label` puts `role="status"` on the host with visually hidden text, so a standalone skeleton announces politely on mount.',
6015
6324
  "The shimmer respects `prefers-reduced-motion`, degrading to static blocks."
6016
6325
  ]
6017
6326
  },
@@ -6021,6 +6330,8 @@ emptyText="No countries found"
6021
6330
  "skeleton.behavior.borderRadius",
6022
6331
  "skeleton.behavior.animation",
6023
6332
  "skeleton.behavior.duration",
6333
+ "skeleton.behavior.direction",
6334
+ "skeleton.behavior.highlightWidth",
6024
6335
  "skeleton.behavior.gap"
6025
6336
  ]
6026
6337
  },
@@ -6031,7 +6342,7 @@ emptyText="No countries found"
6031
6342
  summary: 'Range slider on a native `<input type="range">` \u2014 keyboard interaction and the ARIA slider contract come from the platform.',
6032
6343
  description: 'Range slider on a native `<input type="range">` \u2014 keyboard interaction and the ARIA slider contract come from the platform. Fill, track, thumb and radii resolve from `slider` theme tokens; the fill percentage rides a CSS custom property so dragging never regenerates styles.',
6033
6344
  category: "forms",
6034
- version: "8.3.0",
6345
+ version: "9.0.0",
6035
6346
  bindings: {
6036
6347
  angular: {
6037
6348
  importPath: "@uni-design-system/uni-angular",
@@ -6168,7 +6479,7 @@ emptyText="No countries found"
6168
6479
  summary: "",
6169
6480
  description: "",
6170
6481
  category: "feedback",
6171
- version: "8.3.0",
6482
+ version: "9.0.0",
6172
6483
  bindings: {
6173
6484
  angular: {
6174
6485
  importPath: "@uni-design-system/uni-angular",
@@ -6245,11 +6556,15 @@ emptyText="No countries found"
6245
6556
  whenToUse: "The Snackbar component is used to give feedback to users after an action has taken place.\nIt appears near the bottom center of the screen temporarily and floats above the UI to not affect the application's layout.\nA side action can be defined (e.g. undoing a process or navigating to the details of a newly created record).",
6246
6557
  dos: [],
6247
6558
  donts: [],
6248
- accessibility: []
6559
+ accessibility: [
6560
+ '`role="status"` announces the message politely, without moving focus away',
6561
+ "The bar renders in the browser's top layer, so it cannot be covered by a",
6562
+ 'It is a `popover="manual"`, not a modal: the rest of the page stays'
6563
+ ]
6249
6564
  },
6250
6565
  relatedTokens: [
6251
6566
  "snackbar.behavior.bottomPosition",
6252
- "snackbar.behavior.transitionDelay",
6567
+ "snackbar.behavior.motion",
6253
6568
  "snackbar.behavior.autoCloseDelay"
6254
6569
  ]
6255
6570
  },
@@ -6260,7 +6575,7 @@ emptyText="No countries found"
6260
6575
  summary: "",
6261
6576
  description: "",
6262
6577
  category: "data",
6263
- version: "8.3.0",
6578
+ version: "9.0.0",
6264
6579
  bindings: {
6265
6580
  angular: {
6266
6581
  importPath: "@uni-design-system/uni-angular",
@@ -6319,7 +6634,7 @@ emptyText="No countries found"
6319
6634
  summary: "",
6320
6635
  description: "",
6321
6636
  category: "layout",
6322
- version: "8.3.0",
6637
+ version: "9.0.0",
6323
6638
  bindings: {
6324
6639
  angular: {
6325
6640
  importPath: "@uni-design-system/uni-angular",
@@ -6374,7 +6689,7 @@ emptyText="No countries found"
6374
6689
  summary: 'KPI stat tile: muted label, large value (numbers auto-compact: 48234 \u2192 "48.2K"), an optional delta whose ink is decided by *direction \xD7 whether up is good* (never direction alone \u2014 churn going down is good news), and an optional decorative sparkline.',
6375
6690
  description: 'KPI stat tile: muted label, large value (numbers auto-compact: 48234 \u2192 "48.2K"), an optional delta whose ink is decided by *direction \xD7 whether up is good* (never direction alone \u2014 churn going down is good news), and an optional decorative sparkline. Frame, typography and inks are all `stat` theme tokens.',
6376
6691
  category: "components",
6377
- version: "8.3.0",
6692
+ version: "9.0.0",
6378
6693
  bindings: {
6379
6694
  angular: {
6380
6695
  importPath: "@uni-design-system/uni-angular",
@@ -6476,7 +6791,7 @@ emptyText="No countries found"
6476
6791
  summary: "",
6477
6792
  description: "",
6478
6793
  category: "primitives",
6479
- version: "8.3.0",
6794
+ version: "9.0.0",
6480
6795
  bindings: {
6481
6796
  angular: {
6482
6797
  importPath: "@uni-design-system/uni-angular",
@@ -6549,7 +6864,7 @@ emptyText="No countries found"
6549
6864
  summary: "One tab inside `uni-tabs`: a label for the tablist plus projected panel content.",
6550
6865
  description: "One tab inside `uni-tabs`: a label for the tablist plus projected panel content. Content is captured in a template and only instantiated while the tab is selected, so inactive panels cost nothing.",
6551
6866
  category: "components",
6552
- version: "8.3.0",
6867
+ version: "9.0.0",
6553
6868
  bindings: {
6554
6869
  angular: {
6555
6870
  importPath: "@uni-design-system/uni-angular",
@@ -6589,7 +6904,7 @@ emptyText="No countries found"
6589
6904
  summary: "WAI-ARIA tabs: roving tabindex, automatic activation (arrow keys move focus and select), Home/End, disabled tabs skipped.",
6590
6905
  description: "WAI-ARIA tabs: roving tabindex, automatic activation (arrow keys move focus and select), Home/End, disabled tabs skipped. Only the selected panel is instantiated. All styling resolves from `tabs` theme option tokens.",
6591
6906
  category: "components",
6592
- version: "8.3.0",
6907
+ version: "9.0.0",
6593
6908
  bindings: {
6594
6909
  angular: {
6595
6910
  importPath: "@uni-design-system/uni-angular",
@@ -6653,7 +6968,7 @@ emptyText="No countries found"
6653
6968
  summary: "Compact chip for categories, states, filters and tokens.",
6654
6969
  description: "Compact chip for categories, states, filters and tokens. Two orthogonal style axes: `variant` picks the colour role and `tone` picks the archetype (soft / solid / outline). Both live in the theme's `tag` entry, so a theme restyles every chip in the app without touching markup. Structurally a chip is **body + trailing action as siblings**, never nested buttons: an interactive chip whose body is a `<button>` cannot contain the remove `<button>` (invalid HTML, and the inner control becomes unreachable for keyboard users). Both stay independently operable.",
6655
6970
  category: "data",
6656
- version: "8.3.0",
6971
+ version: "9.0.0",
6657
6972
  bindings: {
6658
6973
  angular: {
6659
6974
  importPath: "@uni-design-system/uni-angular",
@@ -7015,7 +7330,7 @@ emptyText="No countries found"
7015
7330
  summary: "",
7016
7331
  description: "",
7017
7332
  category: "forms",
7018
- version: "8.3.0",
7333
+ version: "9.0.0",
7019
7334
  bindings: {
7020
7335
  angular: {
7021
7336
  importPath: "@uni-design-system/uni-angular",
@@ -7330,9 +7645,9 @@ placeholder="Name or address\u2026"
7330
7645
  name: "Text",
7331
7646
  status: "stable",
7332
7647
  summary: "The typography primitive, applied as an attribute to any element so semantics stay yours.",
7333
- description: 'The typography primitive, applied as an attribute to any element so semantics stay yours. The attribute value is the typeface: `<h1 uni-text="display-small">`, `<span uni-text="caption">`, dynamic via `[uni-text]="role()"`. With no value, the typeface is inferred from the host element (h1 \u2192 headline-large, p \u2192 body-1-long, \u2026), falling back to `title-small`; the `typeface` input remains as an explicit override.',
7648
+ description: 'The typography primitive, applied as an attribute to any element so semantics stay yours. The attribute value is the typeface: `<h1 uni-text="display-small">`, `<span uni-text="caption">`, dynamic via `[uni-text]="role()"`. With no value, the typeface is inferred from the host element (h1 \u2192 headline-large, p \u2192 body-1-long, \u2026), falling back to `title-small`; the `typeface` input remains as an explicit override. It is a directive, so it stacks with anything else on the element \u2014 a layout attribute (`<div stack-layout uni-text="title-small">`) or a component\'s own host \u2014 rather than colliding with it.',
7334
7649
  category: "primitives",
7335
- version: "8.3.0",
7650
+ version: "9.0.0",
7336
7651
  bindings: {
7337
7652
  angular: {
7338
7653
  importPath: "@uni-design-system/uni-angular",
@@ -7359,7 +7674,7 @@ placeholder="Name or address\u2026"
7359
7674
  kind: "input",
7360
7675
  type: "ColorKey",
7361
7676
  required: false,
7362
- description: ""
7677
+ description: "The ink, mapping straight to the CSS `color` property."
7363
7678
  },
7364
7679
  {
7365
7680
  name: "display",
@@ -7413,7 +7728,7 @@ placeholder="Name or address\u2026"
7413
7728
  }
7414
7729
  ],
7415
7730
  guidelines: {
7416
- whenToUse: 'The typography primitive, applied as an **attribute on any element** so your HTML\nsemantics stay intact. The attribute value is the typeface \u2014\n`<h1 uni-text="display-small">` \u2014 and `[uni-text]="role()"` binds it dynamically.\nWith no value, the typeface is inferred from the host element (`h1` \u2192\n`headline-large`, `p` \u2192 `body-1-long`, `small` \u2192 `caption`, `blockquote` \u2192 `quote`,\nfalling back to `title-small`), so plain semantic markup is correctly set with zero\nconfiguration. `color` takes any theme color token; `align`, `nowrap`, `maxWidth`,\nand `ellipsis` handle common text layout.',
7731
+ whenToUse: 'The typography primitive, applied as an **attribute on any element** so your HTML\nsemantics stay intact. The attribute value is the typeface \u2014\n`<h1 uni-text="display-small">` \u2014 and `[uni-text]="role()"` binds it dynamically.\nWith no value, the typeface is inferred from the host element (`h1` \u2192\n`headline-large`, `p` \u2192 `body-1-long`, `small` \u2192 `caption`, `blockquote` \u2192 `quote`,\nfalling back to `title-small`), so plain semantic markup is correctly set with zero\nconfiguration. `color` takes any theme color token; `align`, `nowrap`, `maxWidth`,\nand `ellipsis` handle common text layout.\nIt is a directive, so it stacks with anything else on the element \u2014 a layout\nattribute or a component\'s own host \u2014 rather than colliding with it:\n```html\n```\nText owns `color`, because it maps straight to the CSS property. The layout\ndirectives name their container pair `containerColor`, so the two never compete\nfor one binding \u2014 set both on the same element and each reaches its own\ndirective:\n```html\n Heading\n```\n`containerColor` sets a background **and** its paired on-color, so both\ndirectives write `color` to the element. An explicit `uni-text` `color` always\nwins that \u2014 it is emitted at higher specificity rather than left to stylesheet\norder. Set no `color` and the container\'s on-color shows through, which is the\npoint of a pair.',
7417
7732
  dos: [
7418
7733
  "Reach for semantic elements first and let the element-aware defaults set the type"
7419
7734
  ],
@@ -7433,8 +7748,8 @@ placeholder="Name or address\u2026"
7433
7748
  status: "stable",
7434
7749
  summary: "",
7435
7750
  description: "",
7436
- category: "primitives",
7437
- version: "8.3.0",
7751
+ category: "forms",
7752
+ version: "9.0.0",
7438
7753
  bindings: {
7439
7754
  angular: {
7440
7755
  importPath: "@uni-design-system/uni-angular",
@@ -7516,7 +7831,77 @@ placeholder="Name or address\u2026"
7516
7831
  type: "number | undefined",
7517
7832
  required: false,
7518
7833
  default: "undefined",
7519
- description: "Visible text rows. Defaults to the theme's `textarea` options."
7834
+ description: "Visible text rows. Defaults to the theme's `textarea` options."
7835
+ },
7836
+ {
7837
+ name: "readonly",
7838
+ kind: "input",
7839
+ type: "boolean",
7840
+ required: false,
7841
+ default: "false",
7842
+ description: ""
7843
+ },
7844
+ {
7845
+ name: "name",
7846
+ kind: "input",
7847
+ type: "string",
7848
+ required: false,
7849
+ default: "''",
7850
+ description: ""
7851
+ },
7852
+ {
7853
+ name: "minLength",
7854
+ kind: "input",
7855
+ type: "number | undefined",
7856
+ required: false,
7857
+ default: "undefined",
7858
+ description: ""
7859
+ },
7860
+ {
7861
+ name: "maxLength",
7862
+ kind: "input",
7863
+ type: "number | undefined",
7864
+ required: false,
7865
+ default: "undefined",
7866
+ description: ""
7867
+ },
7868
+ {
7869
+ name: "autocomplete",
7870
+ kind: "input",
7871
+ type: "string",
7872
+ required: false,
7873
+ description: ""
7874
+ },
7875
+ {
7876
+ name: "spellcheck",
7877
+ kind: "input",
7878
+ type: "boolean",
7879
+ required: false,
7880
+ description: ""
7881
+ },
7882
+ {
7883
+ name: "width",
7884
+ kind: "input",
7885
+ type: "string | number | undefined",
7886
+ required: false,
7887
+ default: "undefined",
7888
+ description: ""
7889
+ },
7890
+ {
7891
+ name: "fullWidth",
7892
+ kind: "input",
7893
+ type: "boolean",
7894
+ required: false,
7895
+ default: "false",
7896
+ description: ""
7897
+ },
7898
+ {
7899
+ name: "grow",
7900
+ kind: "input",
7901
+ type: "number | undefined",
7902
+ required: false,
7903
+ default: "undefined",
7904
+ description: ""
7520
7905
  }
7521
7906
  ]
7522
7907
  }
@@ -7564,7 +7949,7 @@ placeholder="Name or address\u2026"
7564
7949
  summary: "",
7565
7950
  description: "",
7566
7951
  category: "primitives",
7567
- version: "8.3.0",
7952
+ version: "9.0.0",
7568
7953
  bindings: {
7569
7954
  angular: {
7570
7955
  importPath: "@uni-design-system/uni-angular",
@@ -7594,7 +7979,7 @@ placeholder="Name or address\u2026"
7594
7979
  summary: "Drop-in switcher for the themes registered via `UNI_THEMES`: a select over `ThemeService.themeOptions` that applies the choice through `selectTheme` (so it persists across reloads like any other theme selection).",
7595
7980
  description: "Drop-in switcher for the themes registered via `UNI_THEMES`: a select over `ThemeService.themeOptions` that applies the choice through `selectTheme` (so it persists across reloads like any other theme selection).",
7596
7981
  category: "components",
7597
- version: "8.3.0",
7982
+ version: "9.0.0",
7598
7983
  bindings: {
7599
7984
  angular: {
7600
7985
  importPath: "@uni-design-system/uni-angular",
@@ -7652,7 +8037,7 @@ placeholder="Name or address\u2026"
7652
8037
  summary: "Time field: a combobox over time options \u2014 the same listbox contract as uni-search-input and uni-tag-input.",
7653
8038
  description: "Time field: a combobox over time options \u2014 the same listbox contract as uni-search-input and uni-tag-input. Type `3p`, `930` or `15:00`, or pick `3:00 PM` from the list; the form always gets 24-hour `'HH:mm'` (`hour12` affects display only). The list is assistive, not exhaustive: any parseable time commits, unless `slots` pins the choices (a slot picker) \u2014 then a typed time must match one. Unreadable or unavailable text stays in the field, flagged, with a `rejected` event.",
7654
8039
  category: "forms",
7655
- version: "8.3.0",
8040
+ version: "9.0.0",
7656
8041
  bindings: {
7657
8042
  angular: {
7658
8043
  importPath: "@uni-design-system/uni-angular",
@@ -7844,7 +8229,7 @@ placeholder="Name or address\u2026"
7844
8229
  summary: "",
7845
8230
  description: "",
7846
8231
  category: "forms",
7847
- version: "8.3.0",
8232
+ version: "9.0.0",
7848
8233
  bindings: {
7849
8234
  angular: {
7850
8235
  importPath: "@uni-design-system/uni-angular",
@@ -7974,7 +8359,7 @@ placeholder="Name or address\u2026"
7974
8359
  summary: "",
7975
8360
  description: "",
7976
8361
  category: "feedback",
7977
- version: "8.3.0",
8362
+ version: "9.0.0",
7978
8363
  bindings: {
7979
8364
  angular: {
7980
8365
  importPath: "@uni-design-system/uni-angular",
@@ -8010,14 +8395,6 @@ placeholder="Name or address\u2026"
8010
8395
  required: false,
8011
8396
  default: "false",
8012
8397
  description: ""
8013
- },
8014
- {
8015
- name: "appendToBody",
8016
- kind: "input",
8017
- type: "boolean",
8018
- required: false,
8019
- default: "false",
8020
- description: "@deprecated The tooltip renders in the native top layer; ignored."
8021
8398
  }
8022
8399
  ]
8023
8400
  }
@@ -8053,7 +8430,7 @@ placeholder="Name or address\u2026"
8053
8430
  summary: 'A thin sequencer over one `uni-callout`: steps spotlight their targets, a footer walks Next/Back with dots-or-fraction progress, and `advanceOn` gates a step behind an interaction with its target (auto-advancing for clicks, unlocking Next otherwise \u2014 announced through one `role="status"` region).',
8054
8431
  description: 'A thin sequencer over one `uni-callout`: steps spotlight their targets, a footer walks Next/Back with dots-or-fraction progress, and `advanceOn` gates a step behind an interaction with its target (auto-advancing for clicks, unlocking Next otherwise \u2014 announced through one `role="status"` region). Escape or the close button skips the tour and reports the step. `active` is a two-way model, so a tour is deep-linkable and inspectable; steps whose declared target cannot be resolved are skipped (with a dev warning) in the direction of travel rather than erroring.',
8055
8432
  category: "components",
8056
- version: "8.3.0",
8433
+ version: "9.0.0",
8057
8434
  bindings: {
8058
8435
  angular: {
8059
8436
  importPath: "@uni-design-system/uni-angular",
@@ -8164,7 +8541,7 @@ placeholder="Name or address\u2026"
8164
8541
  summary: "",
8165
8542
  description: "",
8166
8543
  category: "layout",
8167
- version: "8.3.0",
8544
+ version: "9.0.0",
8168
8545
  bindings: {
8169
8546
  angular: {
8170
8547
  importPath: "@uni-design-system/uni-angular",
@@ -9196,6 +9573,17 @@ placeholder="Name or address\u2026"
9196
9573
  DarkTheme: "64px"
9197
9574
  }
9198
9575
  },
9576
+ {
9577
+ id: "spacing.xxl",
9578
+ value: "128px",
9579
+ type: "spacing",
9580
+ kind: "style",
9581
+ target: "emotion-css",
9582
+ themeValues: {
9583
+ LightTheme: "128px",
9584
+ DarkTheme: "128px"
9585
+ }
9586
+ },
9199
9587
  {
9200
9588
  id: "border.primary",
9201
9589
  value: "1px solid #6A6F8F",
@@ -9683,15 +10071,15 @@ placeholder="Name or address\u2026"
9683
10071
  }
9684
10072
  },
9685
10073
  {
9686
- id: "alert.behavior.transitionSpeed",
9687
- value: 0.35,
9688
- type: "number",
10074
+ id: "alert.behavior.motion",
10075
+ value: "notification",
10076
+ type: "string",
9689
10077
  kind: "behavioral",
9690
10078
  target: "component-prop",
9691
10079
  appliesTo: "alert",
9692
10080
  themeValues: {
9693
- LightTheme: 0.35,
9694
- DarkTheme: 0.35
10081
+ LightTheme: "notification",
10082
+ DarkTheme: "notification"
9695
10083
  }
9696
10084
  },
9697
10085
  {
@@ -10151,15 +10539,15 @@ placeholder="Name or address\u2026"
10151
10539
  }
10152
10540
  },
10153
10541
  {
10154
- id: "radio.behavior.transitionSpeed",
10155
- value: 0.3,
10156
- type: "number",
10542
+ id: "radio.behavior.motion",
10543
+ value: "control",
10544
+ type: "string",
10157
10545
  kind: "behavioral",
10158
10546
  target: "component-prop",
10159
10547
  appliesTo: "radio",
10160
10548
  themeValues: {
10161
- LightTheme: 0.3,
10162
- DarkTheme: 0.3
10549
+ LightTheme: "control",
10550
+ DarkTheme: "control"
10163
10551
  }
10164
10552
  },
10165
10553
  {
@@ -10474,6 +10862,18 @@ placeholder="Name or address\u2026"
10474
10862
  DarkTheme: "menu"
10475
10863
  }
10476
10864
  },
10865
+ {
10866
+ id: "dropdown.behavior.motion",
10867
+ value: "popup",
10868
+ type: "string",
10869
+ kind: "behavioral",
10870
+ target: "component-prop",
10871
+ appliesTo: "dropdown",
10872
+ themeValues: {
10873
+ LightTheme: "popup",
10874
+ DarkTheme: "popup"
10875
+ }
10876
+ },
10477
10877
  {
10478
10878
  id: "menu.behavior.minWidth",
10479
10879
  value: 184,
@@ -10619,15 +11019,15 @@ placeholder="Name or address\u2026"
10619
11019
  }
10620
11020
  },
10621
11021
  {
10622
- id: "menuItem.behavior.transitionSpeed",
10623
- value: 0.35,
10624
- type: "number",
11022
+ id: "menuItem.behavior.motion",
11023
+ value: "control",
11024
+ type: "string",
10625
11025
  kind: "behavioral",
10626
11026
  target: "component-prop",
10627
11027
  appliesTo: "menuItem",
10628
11028
  themeValues: {
10629
- LightTheme: 0.35,
10630
- DarkTheme: 0.35
11029
+ LightTheme: "control",
11030
+ DarkTheme: "control"
10631
11031
  }
10632
11032
  },
10633
11033
  {
@@ -10799,15 +11199,27 @@ placeholder="Name or address\u2026"
10799
11199
  }
10800
11200
  },
10801
11201
  {
10802
- id: "expand.behavior.transitionSpeed",
10803
- value: 0.35,
10804
- type: "number",
11202
+ id: "popover.behavior.motion",
11203
+ value: "panel",
11204
+ type: "string",
11205
+ kind: "behavioral",
11206
+ target: "component-prop",
11207
+ appliesTo: "popover",
11208
+ themeValues: {
11209
+ LightTheme: "panel",
11210
+ DarkTheme: "panel"
11211
+ }
11212
+ },
11213
+ {
11214
+ id: "expand.behavior.motion",
11215
+ value: "reveal",
11216
+ type: "string",
10805
11217
  kind: "behavioral",
10806
11218
  target: "component-prop",
10807
11219
  appliesTo: "expand",
10808
11220
  themeValues: {
10809
- LightTheme: 0.35,
10810
- DarkTheme: 0.35
11221
+ LightTheme: "reveal",
11222
+ DarkTheme: "reveal"
10811
11223
  }
10812
11224
  },
10813
11225
  {
@@ -12442,6 +12854,30 @@ placeholder="Name or address\u2026"
12442
12854
  DarkTheme: 1.4
12443
12855
  }
12444
12856
  },
12857
+ {
12858
+ id: "skeleton.behavior.direction",
12859
+ value: "ltr",
12860
+ type: "string",
12861
+ kind: "behavioral",
12862
+ target: "component-prop",
12863
+ appliesTo: "skeleton",
12864
+ themeValues: {
12865
+ LightTheme: "ltr",
12866
+ DarkTheme: "ltr"
12867
+ }
12868
+ },
12869
+ {
12870
+ id: "skeleton.behavior.highlightWidth",
12871
+ value: 40,
12872
+ type: "number",
12873
+ kind: "behavioral",
12874
+ target: "component-prop",
12875
+ appliesTo: "skeleton",
12876
+ themeValues: {
12877
+ LightTheme: 40,
12878
+ DarkTheme: 40
12879
+ }
12880
+ },
12445
12881
  {
12446
12882
  id: "skeleton.behavior.gap",
12447
12883
  value: "sm",
@@ -12467,15 +12903,15 @@ placeholder="Name or address\u2026"
12467
12903
  }
12468
12904
  },
12469
12905
  {
12470
- id: "snackbar.behavior.transitionDelay",
12471
- value: "0.35s",
12906
+ id: "snackbar.behavior.motion",
12907
+ value: "notification",
12472
12908
  type: "string",
12473
12909
  kind: "behavioral",
12474
12910
  target: "component-prop",
12475
12911
  appliesTo: "snackbar",
12476
12912
  themeValues: {
12477
- LightTheme: "0.35s",
12478
- DarkTheme: "0.35s"
12913
+ LightTheme: "notification",
12914
+ DarkTheme: "notification"
12479
12915
  }
12480
12916
  },
12481
12917
  {
@@ -12791,15 +13227,15 @@ placeholder="Name or address\u2026"
12791
13227
  }
12792
13228
  },
12793
13229
  {
12794
- id: "callout.behavior.transitionMs",
12795
- value: 250,
12796
- type: "number",
13230
+ id: "callout.behavior.motion",
13231
+ value: "panel",
13232
+ type: "string",
12797
13233
  kind: "behavioral",
12798
13234
  target: "component-prop",
12799
13235
  appliesTo: "callout",
12800
13236
  themeValues: {
12801
- LightTheme: 250,
12802
- DarkTheme: 250
13237
+ LightTheme: "panel",
13238
+ DarkTheme: "panel"
12803
13239
  }
12804
13240
  },
12805
13241
  {
@@ -12923,6 +13359,7 @@ placeholder="Name or address\u2026"
12923
13359
  "spacing.md": "16px",
12924
13360
  "spacing.lg": "32px",
12925
13361
  "spacing.xl": "64px",
13362
+ "spacing.xxl": "128px",
12926
13363
  "border.primary": "1px solid #6A6F8F",
12927
13364
  "border.secondary": "1px solid #8C685D",
12928
13365
  "border.tertiary": "1px solid #597B66",
@@ -12970,7 +13407,7 @@ placeholder="Name or address\u2026"
12970
13407
  alert: {
12971
13408
  topPosition: 40,
12972
13409
  borderRadius: "sm",
12973
- transitionSpeed: 0.35,
13410
+ motion: "notification",
12974
13411
  elevation: "md"
12975
13412
  },
12976
13413
  breadcrumb: {
@@ -13025,7 +13462,7 @@ placeholder="Name or address\u2026"
13025
13462
  size: 20,
13026
13463
  ringColor: "outline",
13027
13464
  fillColor: "surface",
13028
- transitionSpeed: 0.3
13465
+ motion: "control"
13029
13466
  },
13030
13467
  dialog: {
13031
13468
  borderRadius: "lg",
@@ -13059,7 +13496,8 @@ placeholder="Name or address\u2026"
13059
13496
  border: "none",
13060
13497
  borderRadius: "xxs",
13061
13498
  color: "primary-surface",
13062
- shadow: "menu"
13499
+ shadow: "menu",
13500
+ motion: "popup"
13063
13501
  },
13064
13502
  menu: {
13065
13503
  minWidth: 184,
@@ -13076,7 +13514,7 @@ placeholder="Name or address\u2026"
13076
13514
  typeface: "label",
13077
13515
  hoverColor: "primary-container",
13078
13516
  activeSymbol: "check",
13079
- transitionSpeed: 0.35
13517
+ motion: "control"
13080
13518
  },
13081
13519
  popover: {
13082
13520
  color: "primary-surface",
@@ -13092,10 +13530,11 @@ placeholder="Name or address\u2026"
13092
13530
  headerTypeface: "title-small",
13093
13531
  tooltipPadding: "4px 8px",
13094
13532
  tooltipOpenDelay: 500,
13095
- tooltipCloseDelay: 150
13533
+ tooltipCloseDelay: 150,
13534
+ motion: "panel"
13096
13535
  },
13097
13536
  expand: {
13098
- transitionSpeed: 0.35
13537
+ motion: "reveal"
13099
13538
  },
13100
13539
  footer: {
13101
13540
  height: 52,
@@ -13278,11 +13717,13 @@ placeholder="Name or address\u2026"
13278
13717
  borderRadius: "xs",
13279
13718
  animation: "shimmer",
13280
13719
  duration: 1.4,
13720
+ direction: "ltr",
13721
+ highlightWidth: 40,
13281
13722
  gap: "sm"
13282
13723
  },
13283
13724
  snackbar: {
13284
13725
  bottomPosition: 40,
13285
- transitionDelay: "0.35s",
13726
+ motion: "notification",
13286
13727
  autoCloseDelay: 35e3
13287
13728
  },
13288
13729
  symbol: {
@@ -13317,7 +13758,7 @@ placeholder="Name or address\u2026"
13317
13758
  spotlightPadding: 6,
13318
13759
  spotlightRadius: "xs",
13319
13760
  ringWidth: 2,
13320
- transitionMs: 250
13761
+ motion: "panel"
13321
13762
  },
13322
13763
  tour: {
13323
13764
  progressStyle: "dots",
@@ -13421,6 +13862,7 @@ placeholder="Name or address\u2026"
13421
13862
  "spacing.md": "16px",
13422
13863
  "spacing.lg": "32px",
13423
13864
  "spacing.xl": "64px",
13865
+ "spacing.xxl": "128px",
13424
13866
  "border.primary": "1px solid #AFB5D8",
13425
13867
  "border.secondary": "1px solid #D5ADA1",
13426
13868
  "border.tertiary": "1px solid #9EC2AB",
@@ -13468,7 +13910,7 @@ placeholder="Name or address\u2026"
13468
13910
  alert: {
13469
13911
  topPosition: 40,
13470
13912
  borderRadius: "sm",
13471
- transitionSpeed: 0.35,
13913
+ motion: "notification",
13472
13914
  elevation: "md"
13473
13915
  },
13474
13916
  breadcrumb: {
@@ -13523,7 +13965,7 @@ placeholder="Name or address\u2026"
13523
13965
  size: 20,
13524
13966
  ringColor: "outline",
13525
13967
  fillColor: "surface",
13526
- transitionSpeed: 0.3
13968
+ motion: "control"
13527
13969
  },
13528
13970
  dialog: {
13529
13971
  borderRadius: "lg",
@@ -13557,7 +13999,8 @@ placeholder="Name or address\u2026"
13557
13999
  border: "none",
13558
14000
  borderRadius: "xxs",
13559
14001
  color: "primary-surface",
13560
- shadow: "menu"
14002
+ shadow: "menu",
14003
+ motion: "popup"
13561
14004
  },
13562
14005
  menu: {
13563
14006
  minWidth: 184,
@@ -13574,7 +14017,7 @@ placeholder="Name or address\u2026"
13574
14017
  typeface: "label",
13575
14018
  hoverColor: "primary-container",
13576
14019
  activeSymbol: "check",
13577
- transitionSpeed: 0.35
14020
+ motion: "control"
13578
14021
  },
13579
14022
  popover: {
13580
14023
  color: "primary-surface",
@@ -13590,10 +14033,11 @@ placeholder="Name or address\u2026"
13590
14033
  headerTypeface: "title-small",
13591
14034
  tooltipPadding: "4px 8px",
13592
14035
  tooltipOpenDelay: 500,
13593
- tooltipCloseDelay: 150
14036
+ tooltipCloseDelay: 150,
14037
+ motion: "panel"
13594
14038
  },
13595
14039
  expand: {
13596
- transitionSpeed: 0.35
14040
+ motion: "reveal"
13597
14041
  },
13598
14042
  footer: {
13599
14043
  height: 52,
@@ -13776,11 +14220,13 @@ placeholder="Name or address\u2026"
13776
14220
  borderRadius: "xs",
13777
14221
  animation: "shimmer",
13778
14222
  duration: 1.4,
14223
+ direction: "ltr",
14224
+ highlightWidth: 40,
13779
14225
  gap: "sm"
13780
14226
  },
13781
14227
  snackbar: {
13782
14228
  bottomPosition: 40,
13783
- transitionDelay: "0.35s",
14229
+ motion: "notification",
13784
14230
  autoCloseDelay: 35e3
13785
14231
  },
13786
14232
  symbol: {
@@ -13815,7 +14261,7 @@ placeholder="Name or address\u2026"
13815
14261
  spotlightPadding: 6,
13816
14262
  spotlightRadius: "xs",
13817
14263
  ringWidth: 2,
13818
- transitionMs: 250
14264
+ motion: "panel"
13819
14265
  },
13820
14266
  tour: {
13821
14267
  progressStyle: "dots",
@@ -13829,6 +14275,128 @@ placeholder="Name or address\u2026"
13829
14275
  {
13830
14276
  package: "@uni-design-system/uni-angular",
13831
14277
  releases: [
14278
+ {
14279
+ version: "9.0.0",
14280
+ entries: [
14281
+ {
14282
+ bump: "major",
14283
+ title: "Box learns `flex` / `shrink` / `basis` and `marginInline`.",
14284
+ body: '**`flex`.** `grow` emits `flex-grow` alone, which leaves `flex-basis: auto` \u2014 so\nit cannot express `flex: 1`, and any layout wanting siblings to share space\nevenly regardless of content width had to stay in CSS. `[flex]="1"` now emits\nthe shorthand; `shrink` and `basis` cover the rest. `grow` is unchanged, so no\nexisting layout moves.\n\nThese three go through a new `ThemeService.styleIfSet()`, which treats only\n`undefined` as unset \u2014 the shared `style()` helper drops falsy values, which\nwould have silently swallowed `[shrink]="0"`, the single most useful value.\n\n**`marginInline`.** `margin: 0 auto` on a max-width container had no Box\nequivalent, so page shells kept an inline style for it. `marginInline="auto"`\ncenters such a container, and a spacing token works too.\n\n```html\n<main box-layout maxWidth="1200px" marginInline="auto" padding="lg">\u2026</main>\n```\n\nOnly the inline axis is exposed. Block margins collapse and fight `gap`, which\nis why the primitives carry no margin otherwise \u2014 inline margins do neither, so\nthis is a deliberate line rather than a crack in the token-only surface.',
14285
+ commit: "c0c6056"
14286
+ },
14287
+ {
14288
+ bump: "major",
14289
+ title: "Every deprecated API is removed. The library now carries no `@deprecated`",
14290
+ body: "symbols at all.\n\n**Per-component duration options \u2192 the `motion` scale.** Six components carried\ntheir own duration knob that predated the motion scale and _won over_ it:\n`expand.transitionSpeed`, `callout.transitionMs`, `radio.transitionSpeed`,\n`menuItem.transitionSpeed`, `alert.transitionSpeed` and\n`snackbar.transitionDelay`. All are gone, along with the precedence branch each\none required \u2014 timing now comes from the token, full stop.\n\nRetime the token instead; one edit covers every component pointing at it. To\nretime a single component, define a token of your own and point that\ncomponent's `motion` option at it:\n\n```ts\ncreateTheme({\n \u2026,\n motion: { productive: { duration: 110, easing: 'ease' } },\n components: { menuItem: { options: { motion: 'productive' } } },\n});\n```\n\nA `duration: 0` token is how a theme opts out of motion \u2014 that is what\n`transitionSpeed: 0` used to mean. Both showcase themes are migrated this way\n(Carbon to a 110ms `productive` token, Wellsourced to an `instant` one).\n\n**Options that never did anything.** `card.transitionSpeed` and\n`inputBox.transitionSpeed` were read by nothing and never had been. Delete them\nfrom your theme; nothing replaces them.\n\n**Renames and obsolete APIs**\n- `inputBox.typeFace` \u2192 `typeface` (the casing every other component uses).\n- `uni-tooltip`'s `appendToBody` input \u2014 inert since the tooltip moved to the\n native top layer, which escapes any overflow context by itself.\n- Box's `elevation` input \u2192 `shadow`, in both the Angular and React packages.\n It was a second name for the same thing.\n- The Angular `icons` re-export \u2192 import `BaseIcons` from\n `@uni-design-system/uni-core`. The default set ships with every theme.\n\n**The HSL color legacy is gone from uni-core.** `uniColor`, `randomRangeValue`,\n`CategorySaturation` and `CategoryLightness` are removed, superseded by the\ndeterministic OKLCH engine (`generateThemes` / `generatePalette`) \u2014 same input,\nsame theme, WCAG-checked. `RoleHues` and the `UniColor` type go with them: they\nwere reachable only through `uniColor`, and `RoleHues` had gone stale enough to\nhold saturation values in a table of hues.\n\n**Deferred output renames.** Three outputs were held back because renaming is\nbreaking; this is that release. Each also drops an eslint escape it needed for\nshadowing a native event name or using an `on` prefix.\n\n| Component | Before | After |\n| -------------------- | ----------------- | ---------------- |\n| `uni-debounce-input` | `(change)` | `(valueChange)` |\n| `uni-search-input` | `(change)` | `(searchChange)` |\n| `uni-search-input` | `(search)` | `(searchSubmit)` |\n| `dragAndDrop` | `(onFileDropped)` | `(fileDropped)` |\n\n**`uni-dropdown`'s `color` input \u2192 `containerColor`,** completing the rule the\nlayout directives set: every container-pair input in the library is now\n`containerColor`, and plain `color` always means the CSS property.\n\n**`ThemeService.getSpacing('none')` now returns `0`, not the string `'none'`.**\n`'none'` is not a valid length, so it was silently dropped wherever it landed \u2014\n`uni-menu` carried a comment working around exactly that, which is now deleted.",
14291
+ commit: "8250162"
14292
+ },
14293
+ {
14294
+ bump: "major",
14295
+ title: "`uni-input` gets a `type`, and the input chrome stops needing a wrapper div.",
14296
+ body: "**Types.** `uni-input` was text-only with no `type` at all, so every email, URL,\nnumber and phone field had to fall back to `uni-input-box` plus a hand-written\nnative `<input>`, and `type=\"password\"` could not go through it. It now takes\nthe text-like types: `text` (default), `email`, `password`, `search`, `tel`,\n`url`, `number`.\n\nNon-text types (`checkbox`, `radio`, `file`, `range`, `color`) stay out \u2014 they\nbreak both the input chrome and the `FormValueControl<string>` value contract \u2014\nas do `date` / `time` / `datetime-local`, which have dedicated components.\n\n**Native passthroughs.** `autocomplete`, `inputMode`, `list` (a `<datalist>` id),\n`step` and `spellcheck` are plain passthroughs; an unset one emits no attribute.\n`readonly`, `name`, `min`, `max`, `minLength`, `maxLength` and `pattern` are\nSignal Forms' own optional control inputs, so the `[field]` directive syncs them\nfrom your validators exactly as it already syncs `required` \u2014 and they are\nreflected onto the native element so the browser contributes too. Signal Forms\ntreats multiple `pattern`s as all-must-match, which the native attribute cannot\nexpress, so it is reflected only when there is exactly one.\n\n`uni-textarea` gains `readonly`, `name`, `minLength`, `maxLength`, `autocomplete`\nand `spellcheck`; `uni-debounce-input` gains `type`, `autocomplete` and\n`inputMode`.\n\n**Sizing.** `uni-input-box`'s host is `display: contents`, so a width or layout\nattribute set on the element itself was silently dropped and every call site\nneeded a wrapper `<div>`. It now takes `width`, `fullWidth` and `grow` (joining\n`minWidth`), which reach the real box inside; `uni-input`, `uni-textarea` and\n`uni-select` forward all four. The `display: contents` behavior is now documented\ntoo \u2014 it stays surprising even once sizing works.\n\nBoth `uni-input` and `uni-debounce-input` now accept the adornment slots as\neither element or attribute selectors (`<span pre-input>` as well as\n`<pre-input>`), which had drifted apart between them.",
14297
+ commit: "c0c6056"
14298
+ },
14299
+ {
14300
+ bump: "major",
14301
+ title: "The layout primitives and `uni-text` are now **directives**, so they compose.",
14302
+ body: 'They were components with attribute-only selectors, which meant any two of them\non one element threw NG0300 ("multiple components match"). `<div row-layout\nso it reached production as a silent style mismatch. `<uni-card box-layout>`\nwas blocked for the same reason, and `box.component.ts` documented the\nwrap-it-in-a-div workaround as permanent.\n\nAll eight are pure host-styling wrappers (an `<ng-content>`-only template plus a\n`[class]` host binding), so as directives they render identically and now stack\nfreely \u2014 with each other, with `uni-text`, and with a component\'s own host\nelement. Angular reconciles the host `class` bindings additively, so each\ncontributor\'s styles survive rather than one silently winning; there is a spec\npinning that.\n\n```html\n<div row-layout uni-text="title-small" padding="md">Heading</div>\n<uni-card box-layout padding="lg">\u2026</uni-card>\n```\n\n**BREAKING: class renames.** `UniBoxComponent` \u2192 `UniBoxDirective`, and likewise\nfor Row, Stack, Center, Wrap, Grid, GridArea and Text. No compatibility aliases:\na major is where the break belongs, and an alias shipped on day one of a major\ntends to survive to the next one. Rename the symbols in your `imports: []`.\n\n**BREAKING: the layout directives\' `color` is now `containerColor`.**\n\nComposing the two directives exposed a name collision. `color` was an input on\nboth \u2014 a _container pair_ on the layout primitives, the CSS `color` property on\n`uni-text` \u2014 so on a shared element one binding fed both: the box painted the\nsurface, the text took the same token, and the text rendered as ink on identical\nink. A deprecated alias would have kept that path alive, so there isn\'t one.\n\n`color` belongs to `uni-text`, which maps it straight to the CSS property. The\ncontainer pair is an invented concept and now says so:\n\n```html\n<!-- before -->\n<div box-layout color="surface">\n <!-- after -->\n <div box-layout containerColor="surface"></div>\n</div>\n```\n\nThis applies to all seven layout directives (Box and its subclasses) and to\n`uni-scroll-area`, which is attribute-selected too and carried the identical\nhazard. `backgroundColor`, which sets only the background and no paired\non-color, is unchanged, as is `color` on `uni-icon` / `uni-skeleton` /\n`uni-badge` \u2014 there it already means a foreground color, the same sense as\n`uni-text`\'s.\n\nCodemod: rename `color` \u2192 `containerColor` on any element carrying a `*-layout`\nor `scroll-area` attribute; leave `color` alone everywhere else.\n\nThe rename fixed the input collision; a second one sat underneath it in CSS.\n`containerColor` emits a background **and** its paired on-color, so both\ndirectives write `color` to the element \u2014 at equal specificity, which left the\ncascade to Emotion\'s insertion order (text won on `row-layout`, lost on\n`scroll-area`). An explicit `uni-text` `color` is now emitted at doubled\nspecificity, so it deterministically wins; with no explicit color, the\ncontainer\'s on-color still shows through as intended.\n\n`uni-dropdown` still names its container pair `color`. It is an element selector\n(`<uni-dropdown>`), so the collision needs someone to put `uni-text` on a\ncomponent host \u2014 possible, but not the natural path the layout attributes are.\n\n**New: `UNI_LAYOUT` and `UNI_FORMS`.** These are attribute selectors, so an\nelement carrying one whose directive was never imported compiles cleanly and\nsilently does nothing. Spreading a family is the cheapest guard:\n\n```ts\nimports: [...UNI_LAYOUT];\n```',
14303
+ commit: "c0c6056"
14304
+ },
14305
+ {
14306
+ bump: "major",
14307
+ title: "The spacing scale is open, and `createTheme` finally accepts one.",
14308
+ body: 'The scale was a closed seven-name union on a doubling curve (2/4/8/16/32/64px).\nReal layouts are rarely built exclusively on one \u2014 the gaps between 8 and 16,\nand 16 and 32, are where a lot of real spacing lives \u2014 and there was no way to\nadd a step, because **`ThemeConfig` had no `spacing` field at all**:\n`createTheme` hardcoded the base scale. The Wellsourced showcase theme had to\nbolt its scale on after the fact with a post-hoc spread.\n\nThree changes, which only work together:\n- `NullableSize` gains a `(string & {})` arm, so any name the theme defines is a\n valid `padding` / `gap` / `marginInline` value while the seven named steps keep\n their autocomplete. `Size` itself stays closed \u2014 it also types _component_\n sizes, where an arbitrary name has nothing to resolve against.\n- `Spacing` is spelled out as named-optional-keys plus an index signature\n (mirroring `Typography`), rather than a `Partial<Record<\u2026>>` that would\n collapse to a plain string record and lose the named steps.\n- `createTheme({ spacing })` merges over the base scale.\n\n```ts\ncreateTheme({ id, name, colors, spacing: { tight: \'6px\', snug: \'10px\' } });\n```\n\n```html\n<div stack-layout padding="tight" gap="snug">\u2026</div>\n```\n\nBecause the scale is open, a mistyped token can no longer be a compile error. It\nis dropped \u2014 an `undefined` CSS value simply does not render \u2014 and\n`ThemeService` now warns once per unknown token in development, naming the\ntokens the active theme does define. Scaffolded `uni-theme.ts` files carry a\n`spacing` block so the static theme file stays the editable source of truth.\n\n**Behavior change:** `xxl` was in the `Size` union but defined by no base theme,\nso `padding="xxl"` type-checked and rendered nothing. It is now `128px`,\ncompleting the doubling \u2014 any element relying on the silent drop will start\nshowing spacing.',
14309
+ commit: "c0c6056"
14310
+ }
14311
+ ],
14312
+ dependencyBumps: [
14313
+ "@uni-design-system/uni-core@9.0.0"
14314
+ ]
14315
+ },
14316
+ {
14317
+ version: "8.4.0",
14318
+ entries: [
14319
+ {
14320
+ bump: "minor",
14321
+ title: "`uni-callout` and `uni-expand` now read their timing from the theme's `motion`",
14322
+ body: "scale, so every animated surface in the library is retimed from one place.\nThey were the last two carrying their own motion options \u2014 in different units,\nunder different names (`transitionMs` in milliseconds, `transitionSpeed` in\nseconds).\n\nA third token joins `popup` and `panel`:\n\n| Token | Default | Used by |\n| -------- | ----------------- | --------------------- |\n| `reveal` | 350ms ease-in-out | expand, expand-toggle |\n\n`reveal` is a _base_ speed, not a final duration: `uni-expand` still scales it\nby content height (\u221A-of-height, clamped) so short regions stay snappy and tall\nones aren't rushed, and its easing now drives the reveal curve, which was\nhardcoded. `uni-expand-toggle` resolves the token the same way, so the chevron\nand the region cannot drift apart. `uni-callout` maps onto `panel`, whose\n250ms matches what it already used.\n\n**Not breaking.** `transitionMs` and `transitionSpeed` are deprecated but\nstill honoured, and deliberately outrank `motion` \u2014 a theme that set either\nkeeps precisely its current timing rather than being retimed underneath it.\nThey are removed next major. Per-instance inputs, like `uni-expand`'s\n`transitionSpeed`, still outrank everything.\n\nNothing moves differently by default: callout renders 0.25s ease and expand\n0.35s ease-in-out exactly as before, verified against the rendered styles.",
14323
+ commit: "1aca747"
14324
+ },
14325
+ {
14326
+ bump: "minor",
14327
+ title: "New `createAnnouncer()` in the CDK's a11y helpers: the polite live region a",
14328
+ body: 'form control uses for its running commentary \u2014 commits, clears, refused\nentries, result counts \u2014 changes a sighted user sees but that are otherwise\nsilent to a screen reader.\n\n`uni-combobox`, `uni-tag-input`, `uni-time-input`, `uni-date-input`,\n`uni-calendar` and `uni-tour` now share it instead of carrying byte-identical\ncopies. The helper holds no DOM and no styling: the `role="status"` element\nstays in each component\'s own template, where its placement and\nvisually-hidden class already belong.\n\nThis fixes a real bug in `uni-tour`, which had a plain signal rather than a\ncopy of the shared idiom. Assistive tech reads a live region when its content\n_changes_, so writing the identical string is a no-op \u2014 its "Next available"\ngate message was announced on the first step that used it and silently dropped\non every later one. `createAnnouncer` breaks the equality with a trailing\nspace, inaudible to a screen reader, alternating between the two forms so\nnothing accumulates.\n\nConsuming the helper directly:\n\n```ts\nprotected readonly announcer = createAnnouncer();\n// this.announcer.announce(\'Alabama selected.\');\n```\n\n```html\n<span role="status" aria-live="polite" [class]="srOnly"> {{ announcer.message() }} </span>\n```\n\nThe region must already be in the DOM when the component renders \u2014 one added\nat the moment it gains text is not reliably announced.',
14329
+ commit: "e459f91"
14330
+ },
14331
+ {
14332
+ bump: "minor",
14333
+ title: "Home and End now move the caret in the combobox-style controls \u2014",
14334
+ body: "`uni-combobox`, `uni-search-input`, `uni-tag-input` \u2014 instead of jumping to\nthe ends of the suggestion list. APG reserves those keys for text editing in\nan editable combobox, and a field that claims them makes its own text\nun-navigable exactly when you are most likely to be editing it: with the list\nopen. `uni-time-input` already behaved this way.\n\nNothing is lost. ArrowUp on a closed list already opens it on the last option,\nArrowDown on the first, and navigation wraps at both ends, so every position\nHome/End reached is still one keystroke away.\n\n`uni-multi-select-dropdown` keeps them: its roving focus rides the option\ncheckboxes rather than a text field, so there is no caret with a better claim.\n\n`ListboxNavigation` carries the switch as `homeEndNavigates`, defaulting to\nfalse \u2014 off is the right default for a control built around a text input,\nwhich is every consumer but one. If you build on the CDK helper directly and\nwant the old behavior, pass `homeEndNavigates: true`.\n\nThis also fixes a sharper bug in `uni-search-input` and `uni-tag-input`, where\nHome/End reached the navigation helper unconditionally: pressing either not\nonly moved the active option but _opened a closed suggestion list_.",
14335
+ commit: "6e2cfb1"
14336
+ },
14337
+ {
14338
+ bump: "minor",
14339
+ title: "The four listbox popups \u2014 `uni-search-input`, `uni-tag-input`,",
14340
+ body: "`uni-time-input` and `uni-combobox` \u2014 now render in the browser's top layer,\nanchored to their field, instead of as absolutely-positioned children of it.\nPut any of them inside a card, a table cell, a scroll area or a dialog and the\nsuggestion list is no longer clipped by that ancestor's `overflow`. The browser\ntracks the field natively, so the list follows on scroll and resize with no\nlisteners, and flips above the field near the bottom of the viewport.\n\nThey also open the way `uni-dropdown` does now \u2014 the same 100 ms scale-and-fade\n\u2014 so every popup panel in the library animates alike instead of the listboxes\nalone snapping into place. The origin is measured from where the popup actually\nopened, so one that flips above its field near the bottom of the viewport still\ngrows out of the edge it is attached to. Under `prefers-reduced-motion` there is\nno transition at all.\n\nNothing changes in the components' APIs or in how they dismiss. The popups use\n`popover=\"manual\"`, not `auto`: these controls already own dismissal through\nfocusout, Escape and commit, and `auto`'s light-dismiss fires on pointerdown\noutside the popup \u2014 which includes their own input, so it would close the list\non every click into the field.\n\nPositioning is gated on CSS anchor positioning support, checked together with\nthe top layer rather than separately. Browsers that have `popover` but not\nanchors \u2014 Safari 17 through 25 \u2014 keep the previous in-flow popup, which still\nclips inside `overflow: hidden` ancestors but stays on its field; promoting it\nthere would strand the list a viewport height down the page, since a top-layer\nelement has no positioned ancestor to resolve against.\n\nShared plumbing lives in `components/forms/listbox-popup.ts` alongside\n`listboxPopupStyles()`, which grew an optional `anchor` and now emits the\nin-flow rules as the base with the anchored ones in an `@supports` block.",
14341
+ commit: "dd33baa"
14342
+ },
14343
+ {
14344
+ bump: "minor",
14345
+ title: "`Option.disabled` now works in the three remaining `Options<T>` consumers, not",
14346
+ body: "just `uni-combobox`: `uni-select`, `uni-multi-select-dropdown` and\n`uni-multi-select`. Marking an individual choice `disabled` shows it without\noffering it \u2014 the plan that needs an upgrade, the channel that needs a verified\nphone number \u2014 instead of dropping it from the array and leaving the list\nlying about what exists.\n\n`uni-select` passes it to the native `<option>`, so the platform handles\nskipping, greying and announcement. The two multi-selects disable the option's\ncheckbox and refuse the toggle even when called directly. In\n`uni-multi-select-dropdown` the arrow keys step over disabled rows and Home/End\nland on the nearest enabled option \u2014 `ListboxNavigation` already knew how, it\njust was not being told which rows were disabled \u2014 so focus never parks on a\ncheckbox that cannot take it.\n\n`selectAll()` on both multi-selects now selects only enabled options. A\ndisabled option is not committable, so nothing may commit one on the user's\nbehalf; `deselectAll()` still clears everything. If you relied on `selectAll()`\nreturning every value including disabled ones, note that only options you have\nexplicitly marked `disabled` are affected. Whole-field `disabled` is unchanged\nand still disables the entire control.",
14347
+ commit: "2910c67"
14348
+ },
14349
+ {
14350
+ bump: "minor",
14351
+ title: "`uni-alert`, `uni-snackbar`, `uni-radio` and `uni-menu-item` now read their",
14352
+ body: "timing from the theme's `motion` scale, which completes the migration: every\nanimated component in the library is retimed from one place.\n\nTwo tokens join `popup`, `panel` and `reveal`:\n\n| Token | Default | Used by |\n| -------------- | ----------------- | ---------------- |\n| `notification` | 350ms ease-in-out | alert, snackbar |\n| `control` | 300ms ease | radio, menu-item |\n\n**One thing moves differently:** `menu-item`'s hover transition goes from\n0.35s to 0.3s, joining `radio` on the shared `control` token. The two were\nnever deliberately different \u2014 `radio`'s own option documented its 0.3 as\n\"matching menuItem\", which was not true \u2014 so this corrects drift rather than\nchanging a decision. A theme that wants the old timing can set the deprecated\n`transitionSpeed`, or retime `control`. Everything else is byte-identical,\nverified against the rendered styles.\n\n**Deprecated, still honoured, removed next major:**\n`alert.transitionSpeed`, `snackbar.transitionDelay`, `radio.transitionSpeed`\nand `menuItem.transitionSpeed` all still work and still outrank `motion`, so a\ntheme that set them keeps its exact timing. `menu-item`'s escape hatch is\nintact too: with neither the option nor a token set it still renders no\ntransition at all, and a token with `duration: 0` is the way to ask for\ninstant now.\n\n`card.transitionSpeed` and `input-box.transitionSpeed` are also deprecated,\nfor a different reason: **neither was ever read by its component.** Setting\nthem has never had any effect. They are removed next major and nothing needs\nto replace them.\n\n`uni-skeleton` is deliberately left out. Its shimmer is a loop rather than a\ntransition, and folding a repeating animation into a scale built around\nentering and leaving would make the scale mean two different things.",
14353
+ commit: "6f76c1d"
14354
+ },
14355
+ {
14356
+ bump: "minor",
14357
+ title: '`uni-skeleton` picks up the knobs an app theme could not reach. `color`, `highlightColor` and `borderRadius` are now inputs that take a token name and fall back to the theme option, because one screen routinely needs several of each \u2014 text bars and a pill chip do not share a corner (`borderRadius="max"`), and a skeleton on a card wants a different tint than one on the page background.',
14358
+ body: "The shimmer is now a band swept with `transform` rather than an animated `background-position`: it composites instead of repainting every frame, and its geometry is themeable via two new options, `direction` (`'ltr' | 'rtl'`, default `'ltr'` \u2014 the sweep previously ran right-to-left) and `highlightWidth` (band width as a percentage of the block, default `40`). Both ends of the band are the base color, so it dissolves into the block with no alpha and no fringing.\n\nA new `label` input announces a standalone skeleton: set it and the host becomes `role=\"status\"` with visually hidden text instead of `aria-hidden=\"true\"`. Unlabelled skeletons stay `aria-hidden`, so container-level `aria-busy` patterns are unchanged.",
14359
+ commit: "228c17f"
14360
+ },
14361
+ {
14362
+ bump: "minor",
14363
+ title: "`uni-snackbar` now renders in the browser's top layer, so it can no longer be",
14364
+ body: 'covered by a high `z-index` or clipped by an `overflow: hidden` or transformed\nancestor. It was the last overlay in the library still competing on stacking\norder: a `<dialog>` opened with `.show()`, which is the _non-modal_ form and\nnever enters the top layer, left it relying on `zIndex: Z_INDEX.dialog`. That\nheld only because apps mount the bar near the root \u2014 anywhere else, a\nconfirmation of what just happened could be silently buried.\n\nThe bar is now a `popover="manual"`. Manual rather than auto because a\nsnackbar must not light-dismiss: a click anywhere else on the page would tear\nit away from someone still reading it. It is not `showModal()` either \u2014 that\nwould make the rest of the page inert to announce a transient message.\n\n`role="status"`, the auto-close timer, its pause-on-hover and pause-on-focus\nbehaviour, the entry and exit animations, and the `[(show)]` / `open()` /\n`close()` API are all unchanged.\n\nThe element behind the component changed from `<dialog>` to `<div>`: the bar\nis never modal, and `<dialog>`\'s `open` attribute would have been a second,\ncompeting notion of "shown" alongside the popover\'s own state. Styles that\nreach inside the component to target `uni-snackbar dialog` need updating \u2014\n`uni-snackbar [role="status"]` is the stable selector.',
14365
+ commit: "eb795a3"
14366
+ },
14367
+ {
14368
+ bump: "minor",
14369
+ title: "Overlay timing is now a theme token. `UniTheme` gains a `motion` scale",
14370
+ body: "alongside `radii`, `shadows` and the rest, and the overlays point at it by\nname instead of carrying their own hardcoded durations.\n\nUntil now a theme could slow a skeleton shimmer but not a dropdown: `expand`,\n`skeleton` and `callout` each exposed their own motion option while\n`uni-dropdown` hardcoded 100ms and the combobox-style listbox popups copied\nthat constant. Retiming the library meant editing components.\n\nTwo tokens ship, because two things genuinely move differently \u2014 a small panel\nattached to a control snaps, a larger free-floating surface settles:\n\n| Token | Default | Used by |\n| ------- | ------------------ | --------------------------------------------------------------------------- |\n| `popup` | 100ms linear, \xD70.8 | dropdown, menu, multi-select, combobox, search-input, tag-input, time-input |\n| `panel` | 250ms ease | popover |\n\nA token carries `duration` (ms), `easing`, and an optional `scale` for panels\nthat grow into place \u2014 one token rather than separate duration and easing\nscales, because they are one design decision: slowing a panel without\nsoftening its curve reads as sluggish rather than calm.\n\n```ts\ncreateTheme({\n id: 'Calm',\n name: 'Calm',\n colors,\n motion: { popup: { duration: 240, easing: 'ease-out', scale: 0.95 } },\n});\n```\n\nTokens you don't restate keep their base values, and a component can still\npoint at a token of its own through its `motion` option.\n\nNothing moves differently by default \u2014 every current duration, easing and\nscale is preserved exactly, verified against the rendered styles. Themes that\npredate the scale keep working: `createTheme` fills it in, the validator does\nnot require it, and a theme registered as JSON without it resolves to the base\ntiming rather than failing. `motionSafe` remains the floor, so a theme decides\nhow overlays move for people who want movement, never whether they move at\nall.\n\n`callout`'s existing `transitionMs` option and the `expand`/`skeleton`\ndurations are untouched for now; folding them into this scale is a follow-up.",
14371
+ commit: "3b51ace"
14372
+ },
14373
+ {
14374
+ bump: "patch",
14375
+ title: "`uni-dropdown` now uses the CDK's overlay helpers instead of its own copies of",
14376
+ body: "them. It predates `cdk/overlay`, so it had been carrying a duplicate\nplacement-to-`transform-origin` map, a duplicate focus-restore rule, a\nduplicate discrete-transition block, and hand-written anchor and toggle-state\ncode. `TRANSFORM_ORIGINS` had no consumers at all as a result \u2014 the shared\nconstant existed while the one component that needed it used its own copy.\n\nNo behaviour change: the dropdown's 100 ms linear scale-and-fade, its measured\ntransform origin, its focus restore and its ARIA wiring are all identical,\nverified against the rendered styles. Every export in `cdk/overlay` now has a\nconsumer, and the component is 35 lines shorter.\n\n`discreteOverlayTransition()` takes an optional fourth argument, a\n`transition-timing-function`. Omitted, nothing is emitted and the CSS initial\nvalue stands, so existing callers are untouched.\n\nOne real inconsistency fixed along the way: the listbox popups\n(`uni-combobox`, `uni-search-input`, `uni-tag-input`, `uni-time-input`) were\nintroduced to match `uni-dropdown`'s animation but ran on the default `ease`,\nwhile the dropdown uses `linear` \u2014 so a combobox and a multi-select dropdown\nin the same form opened at visibly different rates. They now share the\ndropdown's easing exactly.",
14377
+ commit: "676ec55"
14378
+ }
14379
+ ],
14380
+ dependencyBumps: []
14381
+ },
14382
+ {
14383
+ version: "8.3.1",
14384
+ entries: [
14385
+ {
14386
+ bump: "patch",
14387
+ title: '`uni-combobox` docs: "Allowing new values" \u2014 free text never commits implicitly (closed-set contract: typing filters, a non-matching draft reverts with `(rejected)`). The supported create-new pattern is now documented with a working story: drive `[options]` from the debounced `(query)` with `[filterLocally]="false"` and, when nothing matches exactly, append a sentinel option \u2014 `{ label: `Create "${text}"`, value: \u2026 }`. As a real option it commits through every normal path (arrow + Enter, click, Enter when the filter narrows to it alone); resolve it in `(selected)` by minting the entity and writing the model. Blur intentionally never commits the sentinel \u2014 creation takes an explicit Enter or click. Lighter alternative: listen to `(rejected: { query })` and offer creation outside the control. If most values are user-created, use `uni-tag-input` (open set) instead.',
14388
+ body: "",
14389
+ commit: "66f4051"
14390
+ },
14391
+ {
14392
+ bump: "patch",
14393
+ title: "`uni-dropdown` (and everything riding it \u2014 the date picker popup, menus, multi-select): the open/close scale animation now originates from the corner actually touching the trigger. The origin was mapped statically from the _requested_ placement, but `position-try-fallbacks` lets the browser flip the panel at viewport edges \u2014 so a `bottom-end` date picker repositioned above its field still animated from the top-right corner. The panel is now measured on each toggle (open and close-start) and the transform origin follows the rendered position, via the new cdk helper `transformOriginFor(panelRect, triggerRect)`.",
14394
+ body: "",
14395
+ commit: "dc7aef9"
14396
+ }
14397
+ ],
14398
+ dependencyBumps: []
14399
+ },
13832
14400
  {
13833
14401
  version: "8.3.0",
13834
14402
  entries: [
@@ -14327,6 +14895,59 @@ placeholder="Name or address\u2026"
14327
14895
  {
14328
14896
  package: "@uni-design-system/uni-core",
14329
14897
  releases: [
14898
+ {
14899
+ version: "9.0.0",
14900
+ entries: [
14901
+ {
14902
+ bump: "major",
14903
+ title: "Every deprecated API is removed. The library now carries no `@deprecated`",
14904
+ body: "symbols at all.\n\n**Per-component duration options \u2192 the `motion` scale.** Six components carried\ntheir own duration knob that predated the motion scale and _won over_ it:\n`expand.transitionSpeed`, `callout.transitionMs`, `radio.transitionSpeed`,\n`menuItem.transitionSpeed`, `alert.transitionSpeed` and\n`snackbar.transitionDelay`. All are gone, along with the precedence branch each\none required \u2014 timing now comes from the token, full stop.\n\nRetime the token instead; one edit covers every component pointing at it. To\nretime a single component, define a token of your own and point that\ncomponent's `motion` option at it:\n\n```ts\ncreateTheme({\n \u2026,\n motion: { productive: { duration: 110, easing: 'ease' } },\n components: { menuItem: { options: { motion: 'productive' } } },\n});\n```\n\nA `duration: 0` token is how a theme opts out of motion \u2014 that is what\n`transitionSpeed: 0` used to mean. Both showcase themes are migrated this way\n(Carbon to a 110ms `productive` token, Wellsourced to an `instant` one).\n\n**Options that never did anything.** `card.transitionSpeed` and\n`inputBox.transitionSpeed` were read by nothing and never had been. Delete them\nfrom your theme; nothing replaces them.\n\n**Renames and obsolete APIs**\n- `inputBox.typeFace` \u2192 `typeface` (the casing every other component uses).\n- `uni-tooltip`'s `appendToBody` input \u2014 inert since the tooltip moved to the\n native top layer, which escapes any overflow context by itself.\n- Box's `elevation` input \u2192 `shadow`, in both the Angular and React packages.\n It was a second name for the same thing.\n- The Angular `icons` re-export \u2192 import `BaseIcons` from\n `@uni-design-system/uni-core`. The default set ships with every theme.\n\n**The HSL color legacy is gone from uni-core.** `uniColor`, `randomRangeValue`,\n`CategorySaturation` and `CategoryLightness` are removed, superseded by the\ndeterministic OKLCH engine (`generateThemes` / `generatePalette`) \u2014 same input,\nsame theme, WCAG-checked. `RoleHues` and the `UniColor` type go with them: they\nwere reachable only through `uniColor`, and `RoleHues` had gone stale enough to\nhold saturation values in a table of hues.\n\n**Deferred output renames.** Three outputs were held back because renaming is\nbreaking; this is that release. Each also drops an eslint escape it needed for\nshadowing a native event name or using an `on` prefix.\n\n| Component | Before | After |\n| -------------------- | ----------------- | ---------------- |\n| `uni-debounce-input` | `(change)` | `(valueChange)` |\n| `uni-search-input` | `(change)` | `(searchChange)` |\n| `uni-search-input` | `(search)` | `(searchSubmit)` |\n| `dragAndDrop` | `(onFileDropped)` | `(fileDropped)` |\n\n**`uni-dropdown`'s `color` input \u2192 `containerColor`,** completing the rule the\nlayout directives set: every container-pair input in the library is now\n`containerColor`, and plain `color` always means the CSS property.\n\n**`ThemeService.getSpacing('none')` now returns `0`, not the string `'none'`.**\n`'none'` is not a valid length, so it was silently dropped wherever it landed \u2014\n`uni-menu` carried a comment working around exactly that, which is now deleted.",
14905
+ commit: "8250162"
14906
+ },
14907
+ {
14908
+ bump: "major",
14909
+ title: "The spacing scale is open, and `createTheme` finally accepts one.",
14910
+ body: 'The scale was a closed seven-name union on a doubling curve (2/4/8/16/32/64px).\nReal layouts are rarely built exclusively on one \u2014 the gaps between 8 and 16,\nand 16 and 32, are where a lot of real spacing lives \u2014 and there was no way to\nadd a step, because **`ThemeConfig` had no `spacing` field at all**:\n`createTheme` hardcoded the base scale. The Wellsourced showcase theme had to\nbolt its scale on after the fact with a post-hoc spread.\n\nThree changes, which only work together:\n- `NullableSize` gains a `(string & {})` arm, so any name the theme defines is a\n valid `padding` / `gap` / `marginInline` value while the seven named steps keep\n their autocomplete. `Size` itself stays closed \u2014 it also types _component_\n sizes, where an arbitrary name has nothing to resolve against.\n- `Spacing` is spelled out as named-optional-keys plus an index signature\n (mirroring `Typography`), rather than a `Partial<Record<\u2026>>` that would\n collapse to a plain string record and lose the named steps.\n- `createTheme({ spacing })` merges over the base scale.\n\n```ts\ncreateTheme({ id, name, colors, spacing: { tight: \'6px\', snug: \'10px\' } });\n```\n\n```html\n<div stack-layout padding="tight" gap="snug">\u2026</div>\n```\n\nBecause the scale is open, a mistyped token can no longer be a compile error. It\nis dropped \u2014 an `undefined` CSS value simply does not render \u2014 and\n`ThemeService` now warns once per unknown token in development, naming the\ntokens the active theme does define. Scaffolded `uni-theme.ts` files carry a\n`spacing` block so the static theme file stays the editable source of truth.\n\n**Behavior change:** `xxl` was in the `Size` union but defined by no base theme,\nso `padding="xxl"` type-checked and rendered nothing. It is now `128px`,\ncompleting the doubling \u2014 any element relying on the silent drop will start\nshowing spacing.',
14911
+ commit: "c0c6056"
14912
+ }
14913
+ ],
14914
+ dependencyBumps: []
14915
+ },
14916
+ {
14917
+ version: "8.4.0",
14918
+ entries: [
14919
+ {
14920
+ bump: "minor",
14921
+ title: "`uni-callout` and `uni-expand` now read their timing from the theme's `motion`",
14922
+ body: "scale, so every animated surface in the library is retimed from one place.\nThey were the last two carrying their own motion options \u2014 in different units,\nunder different names (`transitionMs` in milliseconds, `transitionSpeed` in\nseconds).\n\nA third token joins `popup` and `panel`:\n\n| Token | Default | Used by |\n| -------- | ----------------- | --------------------- |\n| `reveal` | 350ms ease-in-out | expand, expand-toggle |\n\n`reveal` is a _base_ speed, not a final duration: `uni-expand` still scales it\nby content height (\u221A-of-height, clamped) so short regions stay snappy and tall\nones aren't rushed, and its easing now drives the reveal curve, which was\nhardcoded. `uni-expand-toggle` resolves the token the same way, so the chevron\nand the region cannot drift apart. `uni-callout` maps onto `panel`, whose\n250ms matches what it already used.\n\n**Not breaking.** `transitionMs` and `transitionSpeed` are deprecated but\nstill honoured, and deliberately outrank `motion` \u2014 a theme that set either\nkeeps precisely its current timing rather than being retimed underneath it.\nThey are removed next major. Per-instance inputs, like `uni-expand`'s\n`transitionSpeed`, still outrank everything.\n\nNothing moves differently by default: callout renders 0.25s ease and expand\n0.35s ease-in-out exactly as before, verified against the rendered styles.",
14923
+ commit: "1aca747"
14924
+ },
14925
+ {
14926
+ bump: "minor",
14927
+ title: "`uni-alert`, `uni-snackbar`, `uni-radio` and `uni-menu-item` now read their",
14928
+ body: "timing from the theme's `motion` scale, which completes the migration: every\nanimated component in the library is retimed from one place.\n\nTwo tokens join `popup`, `panel` and `reveal`:\n\n| Token | Default | Used by |\n| -------------- | ----------------- | ---------------- |\n| `notification` | 350ms ease-in-out | alert, snackbar |\n| `control` | 300ms ease | radio, menu-item |\n\n**One thing moves differently:** `menu-item`'s hover transition goes from\n0.35s to 0.3s, joining `radio` on the shared `control` token. The two were\nnever deliberately different \u2014 `radio`'s own option documented its 0.3 as\n\"matching menuItem\", which was not true \u2014 so this corrects drift rather than\nchanging a decision. A theme that wants the old timing can set the deprecated\n`transitionSpeed`, or retime `control`. Everything else is byte-identical,\nverified against the rendered styles.\n\n**Deprecated, still honoured, removed next major:**\n`alert.transitionSpeed`, `snackbar.transitionDelay`, `radio.transitionSpeed`\nand `menuItem.transitionSpeed` all still work and still outrank `motion`, so a\ntheme that set them keeps its exact timing. `menu-item`'s escape hatch is\nintact too: with neither the option nor a token set it still renders no\ntransition at all, and a token with `duration: 0` is the way to ask for\ninstant now.\n\n`card.transitionSpeed` and `input-box.transitionSpeed` are also deprecated,\nfor a different reason: **neither was ever read by its component.** Setting\nthem has never had any effect. They are removed next major and nothing needs\nto replace them.\n\n`uni-skeleton` is deliberately left out. Its shimmer is a loop rather than a\ntransition, and folding a repeating animation into a scale built around\nentering and leaving would make the scale mean two different things.",
14929
+ commit: "6f76c1d"
14930
+ },
14931
+ {
14932
+ bump: "minor",
14933
+ title: '`uni-skeleton` picks up the knobs an app theme could not reach. `color`, `highlightColor` and `borderRadius` are now inputs that take a token name and fall back to the theme option, because one screen routinely needs several of each \u2014 text bars and a pill chip do not share a corner (`borderRadius="max"`), and a skeleton on a card wants a different tint than one on the page background.',
14934
+ body: "The shimmer is now a band swept with `transform` rather than an animated `background-position`: it composites instead of repainting every frame, and its geometry is themeable via two new options, `direction` (`'ltr' | 'rtl'`, default `'ltr'` \u2014 the sweep previously ran right-to-left) and `highlightWidth` (band width as a percentage of the block, default `40`). Both ends of the band are the base color, so it dissolves into the block with no alpha and no fringing.\n\nA new `label` input announces a standalone skeleton: set it and the host becomes `role=\"status\"` with visually hidden text instead of `aria-hidden=\"true\"`. Unlabelled skeletons stay `aria-hidden`, so container-level `aria-busy` patterns are unchanged.",
14935
+ commit: "228c17f"
14936
+ },
14937
+ {
14938
+ bump: "minor",
14939
+ title: "Overlay timing is now a theme token. `UniTheme` gains a `motion` scale",
14940
+ body: "alongside `radii`, `shadows` and the rest, and the overlays point at it by\nname instead of carrying their own hardcoded durations.\n\nUntil now a theme could slow a skeleton shimmer but not a dropdown: `expand`,\n`skeleton` and `callout` each exposed their own motion option while\n`uni-dropdown` hardcoded 100ms and the combobox-style listbox popups copied\nthat constant. Retiming the library meant editing components.\n\nTwo tokens ship, because two things genuinely move differently \u2014 a small panel\nattached to a control snaps, a larger free-floating surface settles:\n\n| Token | Default | Used by |\n| ------- | ------------------ | --------------------------------------------------------------------------- |\n| `popup` | 100ms linear, \xD70.8 | dropdown, menu, multi-select, combobox, search-input, tag-input, time-input |\n| `panel` | 250ms ease | popover |\n\nA token carries `duration` (ms), `easing`, and an optional `scale` for panels\nthat grow into place \u2014 one token rather than separate duration and easing\nscales, because they are one design decision: slowing a panel without\nsoftening its curve reads as sluggish rather than calm.\n\n```ts\ncreateTheme({\n id: 'Calm',\n name: 'Calm',\n colors,\n motion: { popup: { duration: 240, easing: 'ease-out', scale: 0.95 } },\n});\n```\n\nTokens you don't restate keep their base values, and a component can still\npoint at a token of its own through its `motion` option.\n\nNothing moves differently by default \u2014 every current duration, easing and\nscale is preserved exactly, verified against the rendered styles. Themes that\npredate the scale keep working: `createTheme` fills it in, the validator does\nnot require it, and a theme registered as JSON without it resolves to the base\ntiming rather than failing. `motionSafe` remains the floor, so a theme decides\nhow overlays move for people who want movement, never whether they move at\nall.\n\n`callout`'s existing `transitionMs` option and the `expand`/`skeleton`\ndurations are untouched for now; folding them into this scale is a follow-up.",
14941
+ commit: "3b51ace"
14942
+ }
14943
+ ],
14944
+ dependencyBumps: []
14945
+ },
14946
+ {
14947
+ version: "8.3.1",
14948
+ entries: [],
14949
+ dependencyBumps: []
14950
+ },
14330
14951
  {
14331
14952
  version: "8.3.0",
14332
14953
  entries: [
@@ -14721,6 +15342,35 @@ placeholder="Name or address\u2026"
14721
15342
  {
14722
15343
  package: "@uni-design-system/uni-react",
14723
15344
  releases: [
15345
+ {
15346
+ version: "9.0.0",
15347
+ entries: [
15348
+ {
15349
+ bump: "major",
15350
+ title: "Every deprecated API is removed. The library now carries no `@deprecated`",
15351
+ body: "symbols at all.\n\n**Per-component duration options \u2192 the `motion` scale.** Six components carried\ntheir own duration knob that predated the motion scale and _won over_ it:\n`expand.transitionSpeed`, `callout.transitionMs`, `radio.transitionSpeed`,\n`menuItem.transitionSpeed`, `alert.transitionSpeed` and\n`snackbar.transitionDelay`. All are gone, along with the precedence branch each\none required \u2014 timing now comes from the token, full stop.\n\nRetime the token instead; one edit covers every component pointing at it. To\nretime a single component, define a token of your own and point that\ncomponent's `motion` option at it:\n\n```ts\ncreateTheme({\n \u2026,\n motion: { productive: { duration: 110, easing: 'ease' } },\n components: { menuItem: { options: { motion: 'productive' } } },\n});\n```\n\nA `duration: 0` token is how a theme opts out of motion \u2014 that is what\n`transitionSpeed: 0` used to mean. Both showcase themes are migrated this way\n(Carbon to a 110ms `productive` token, Wellsourced to an `instant` one).\n\n**Options that never did anything.** `card.transitionSpeed` and\n`inputBox.transitionSpeed` were read by nothing and never had been. Delete them\nfrom your theme; nothing replaces them.\n\n**Renames and obsolete APIs**\n- `inputBox.typeFace` \u2192 `typeface` (the casing every other component uses).\n- `uni-tooltip`'s `appendToBody` input \u2014 inert since the tooltip moved to the\n native top layer, which escapes any overflow context by itself.\n- Box's `elevation` input \u2192 `shadow`, in both the Angular and React packages.\n It was a second name for the same thing.\n- The Angular `icons` re-export \u2192 import `BaseIcons` from\n `@uni-design-system/uni-core`. The default set ships with every theme.\n\n**The HSL color legacy is gone from uni-core.** `uniColor`, `randomRangeValue`,\n`CategorySaturation` and `CategoryLightness` are removed, superseded by the\ndeterministic OKLCH engine (`generateThemes` / `generatePalette`) \u2014 same input,\nsame theme, WCAG-checked. `RoleHues` and the `UniColor` type go with them: they\nwere reachable only through `uniColor`, and `RoleHues` had gone stale enough to\nhold saturation values in a table of hues.\n\n**Deferred output renames.** Three outputs were held back because renaming is\nbreaking; this is that release. Each also drops an eslint escape it needed for\nshadowing a native event name or using an `on` prefix.\n\n| Component | Before | After |\n| -------------------- | ----------------- | ---------------- |\n| `uni-debounce-input` | `(change)` | `(valueChange)` |\n| `uni-search-input` | `(change)` | `(searchChange)` |\n| `uni-search-input` | `(search)` | `(searchSubmit)` |\n| `dragAndDrop` | `(onFileDropped)` | `(fileDropped)` |\n\n**`uni-dropdown`'s `color` input \u2192 `containerColor`,** completing the rule the\nlayout directives set: every container-pair input in the library is now\n`containerColor`, and plain `color` always means the CSS property.\n\n**`ThemeService.getSpacing('none')` now returns `0`, not the string `'none'`.**\n`'none'` is not a valid length, so it was silently dropped wherever it landed \u2014\n`uni-menu` carried a comment working around exactly that, which is now deleted.",
15352
+ commit: "8250162"
15353
+ }
15354
+ ],
15355
+ dependencyBumps: []
15356
+ },
15357
+ {
15358
+ version: "8.4.0",
15359
+ entries: [
15360
+ {
15361
+ bump: "minor",
15362
+ title: 'React layout primitives, at parity with Angular: `Box`, `Stack`, `Row`, `Center`, `Wrap`, `Grid` and `GridArea`. Angular applies layout as an attribute so the element\'s semantics stay the author\'s (`<main box-layout>`); React\'s equivalent is the polymorphic `as` prop \u2014 `<Box as="main" padding="md">` \u2014 with refs and DOM props forwarded to whatever element it renders.',
15363
+ body: 'Props, defaults and resolution order are ported one-for-one from `UniBoxComponent`, so the same tokens produce the same CSS in both frameworks: token-driven color pairs, padding, radius, border, shadow, gap and z-index; a number is px and a string is a CSS length for every sizing prop; `dashBorder` draws the SVG dashed outline; `ignoreDir` (default on) still flips flex direction under `dir="rtl"`. `Stack` keeps its `minHeight: fit-content` guard and `Row` its `minWidth: fit-content` \u2014 set `minHeight={0}` / `minWidth={0}` to shrink inside a constrained flex parent.\n\nSupporting this: `createThemeStyles`/`useThemeStyles` \u2014 the React port of the Angular `ThemeService` token \u2192 CSS resolvers, method-for-method \u2014 and `@emotion/css` (new peer dependency, matching the Angular package) so pseudo-selectors like `:dir(rtl)` resolve in a real class rather than an inline style. A Box that paints a container color now also provides that token to its descendants, so `Text` inside it picks up the matching on-color.',
15364
+ commit: "82d1341"
15365
+ }
15366
+ ],
15367
+ dependencyBumps: []
15368
+ },
15369
+ {
15370
+ version: "8.3.1",
15371
+ entries: [],
15372
+ dependencyBumps: []
15373
+ },
14724
15374
  {
14725
15375
  version: "8.3.0",
14726
15376
  entries: [],
@@ -14903,6 +15553,18 @@ placeholder="Name or address\u2026"
14903
15553
  {
14904
15554
  package: "@uni-design-system/uni-mcp",
14905
15555
  releases: [
15556
+ {
15557
+ version: "4.7.2",
15558
+ entries: [
15559
+ {
15560
+ bump: "patch",
15561
+ title: "Fix three miscategorized components in the index.",
15562
+ body: 'Categories come from an ordered list of substring regexes, so a name that merely\ncontains an earlier row\'s keyword lands in the wrong bucket \u2014 and a\nmiscategorized component is invisible to `list-components --category`, which is\nhow agents and humans find things.\n- `textarea` \u2192 **forms** (was `primitives`: `/text/` matches inside "textarea"\n and wins before the forms row is tried)\n- `combobox` \u2192 **forms** (was `layout`: `/box/` matches inside "combobox")\n- `expand-toggle` \u2192 **layout** (was `forms`: `/toggle/` beat `/expand/`)\n\nKnown ids now go through an explicit override map consulted before the keyword\npass, so a fix is a one-line entry rather than a regex that has to be reasoned\nabout globally.\n\nAlso: MDX pages are matched to their source by basename, stripping only\n`.component.ts`. With the layout primitives and `uni-text` becoming directives,\n`.directive.ts` is stripped too, so their docs keep attaching by name instead of\nfalling through to the same-directory fallback.',
15563
+ commit: "c0c6056"
15564
+ }
15565
+ ],
15566
+ dependencyBumps: []
15567
+ },
14906
15568
  {
14907
15569
  version: "4.7.1",
14908
15570
  entries: [
@@ -15339,6 +16001,32 @@ var EXPAND_MIN_DURATION = 0.15;
15339
16001
  var EXPAND_MAX_DURATION = 0.6;
15340
16002
  var MIN_SCALE = EXPAND_MIN_DURATION / EXPAND_DEFAULT_SPEED;
15341
16003
  var MAX_SCALE = EXPAND_MAX_DURATION / EXPAND_DEFAULT_SPEED;
16004
+ var clamp$2 = (value, min, max) => Math.min(max, Math.max(min, value));
16005
+ var toHex2 = (value) => clamp$2(Math.round(value), 0, 255).toString(16).padStart(2, "0");
16006
+ var rgbToHex = ({ red, green, blue }) => `#${toHex2(red)}${toHex2(green)}${toHex2(blue)}`.toUpperCase();
16007
+ var hexToRgb = (hex) => {
16008
+ let h = hex.replace("#", "").trim();
16009
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
16010
+ const int = parseInt(h, 16);
16011
+ return {
16012
+ red: int >> 16 & 255,
16013
+ green: int >> 8 & 255,
16014
+ blue: int & 255
16015
+ };
16016
+ };
16017
+ var relativeLuminance = ({ red, green, blue }) => {
16018
+ const channel = (value) => {
16019
+ const v = value / 255;
16020
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
16021
+ };
16022
+ return 0.2126 * channel(red) + 0.7152 * channel(green) + 0.0722 * channel(blue);
16023
+ };
16024
+ var contrastRatio = (a, b) => {
16025
+ const la = relativeLuminance(typeof a === "string" ? hexToRgb(a) : a);
16026
+ const lb = relativeLuminance(typeof b === "string" ? hexToRgb(b) : b);
16027
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
16028
+ return (hi + 0.05) / (lo + 0.05);
16029
+ };
15342
16030
  var cycle = (angle) => {
15343
16031
  if (angle > 360) return angle - 360;
15344
16032
  if (angle < 0) return angle + 360;
@@ -15390,32 +16078,6 @@ var schemeHues = (hue, scheme) => {
15390
16078
  }
15391
16079
  }
15392
16080
  };
15393
- var clamp$2 = (value, min, max) => Math.min(max, Math.max(min, value));
15394
- var toHex2 = (value) => clamp$2(Math.round(value), 0, 255).toString(16).padStart(2, "0");
15395
- var rgbToHex = ({ red, green, blue }) => `#${toHex2(red)}${toHex2(green)}${toHex2(blue)}`.toUpperCase();
15396
- var hexToRgb = (hex) => {
15397
- let h = hex.replace("#", "").trim();
15398
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
15399
- const int = parseInt(h, 16);
15400
- return {
15401
- red: int >> 16 & 255,
15402
- green: int >> 8 & 255,
15403
- blue: int & 255
15404
- };
15405
- };
15406
- var relativeLuminance = ({ red, green, blue }) => {
15407
- const channel = (value) => {
15408
- const v = value / 255;
15409
- return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
15410
- };
15411
- return 0.2126 * channel(red) + 0.7152 * channel(green) + 0.0722 * channel(blue);
15412
- };
15413
- var contrastRatio = (a, b) => {
15414
- const la = relativeLuminance(typeof a === "string" ? hexToRgb(a) : a);
15415
- const lb = relativeLuminance(typeof b === "string" ? hexToRgb(b) : b);
15416
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
15417
- return (hi + 0.05) / (lo + 0.05);
15418
- };
15419
16081
  var clamp$1 = (value, min, max) => Math.min(max, Math.max(min, value));
15420
16082
  var srgbToLinear = (channel) => channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
15421
16083
  var linearToSrgb = (channel) => channel <= 31308e-7 ? 12.92 * channel : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;
@@ -16088,13 +16750,37 @@ var BaseSpacing = {
16088
16750
  sm: "8px",
16089
16751
  md: "16px",
16090
16752
  lg: "32px",
16091
- xl: "64px"
16753
+ xl: "64px",
16754
+ xxl: "128px"
16092
16755
  };
16093
16756
  var BaseThicknesses = {
16094
16757
  thin: 1,
16095
16758
  standard: 2,
16096
16759
  thick: 4
16097
16760
  };
16761
+ var BaseMotion = {
16762
+ popup: {
16763
+ duration: 100,
16764
+ easing: "linear",
16765
+ scale: 0.8
16766
+ },
16767
+ panel: {
16768
+ duration: 250,
16769
+ easing: "ease"
16770
+ },
16771
+ reveal: {
16772
+ duration: 350,
16773
+ easing: "ease-in-out"
16774
+ },
16775
+ notification: {
16776
+ duration: 350,
16777
+ easing: "ease-in-out"
16778
+ },
16779
+ control: {
16780
+ duration: 300,
16781
+ easing: "ease"
16782
+ }
16783
+ };
16098
16784
  var BaseRadii = {
16099
16785
  none: "none",
16100
16786
  xxs: "4px",
@@ -16132,7 +16818,7 @@ var buildComponents = (c) => ({
16132
16818
  alert: { options: {
16133
16819
  topPosition: 40,
16134
16820
  borderRadius: "sm",
16135
- transitionSpeed: 0.35,
16821
+ motion: "notification",
16136
16822
  elevation: "md"
16137
16823
  } },
16138
16824
  breadcrumb: { options: {
@@ -16238,7 +16924,7 @@ var buildComponents = (c) => ({
16238
16924
  size: 20,
16239
16925
  ringColor: "outline",
16240
16926
  fillColor: "surface",
16241
- transitionSpeed: 0.3
16927
+ motion: "control"
16242
16928
  } },
16243
16929
  dialog: { options: {
16244
16930
  borderRadius: "lg",
@@ -16275,7 +16961,8 @@ var buildComponents = (c) => ({
16275
16961
  border: "none",
16276
16962
  borderRadius: "xxs",
16277
16963
  color: "primary-surface",
16278
- shadow: "menu"
16964
+ shadow: "menu",
16965
+ motion: "popup"
16279
16966
  } },
16280
16967
  menu: { options: {
16281
16968
  minWidth: 184,
@@ -16298,7 +16985,7 @@ var buildComponents = (c) => ({
16298
16985
  textColor: void 0,
16299
16986
  hoverColor: "primary-container",
16300
16987
  activeSymbol: "check",
16301
- transitionSpeed: 0.35
16988
+ motion: "control"
16302
16989
  },
16303
16990
  variants: { warn: {
16304
16991
  color: c.warn,
@@ -16322,9 +17009,10 @@ var buildComponents = (c) => ({
16322
17009
  headerTypeface: "title-small",
16323
17010
  tooltipPadding: "4px 8px",
16324
17011
  tooltipOpenDelay: 500,
16325
- tooltipCloseDelay: 150
17012
+ tooltipCloseDelay: 150,
17013
+ motion: "panel"
16326
17014
  } },
16327
- expand: { options: { transitionSpeed: 0.35 } },
17015
+ expand: { options: { motion: "reveal" } },
16328
17016
  footer: { options: {
16329
17017
  height: 52,
16330
17018
  color: "primary",
@@ -16785,11 +17473,13 @@ var buildComponents = (c) => ({
16785
17473
  borderRadius: "xs",
16786
17474
  animation: "shimmer",
16787
17475
  duration: 1.4,
17476
+ direction: "ltr",
17477
+ highlightWidth: 40,
16788
17478
  gap: "sm"
16789
17479
  } },
16790
17480
  snackbar: { options: {
16791
17481
  bottomPosition: 40,
16792
- transitionDelay: "0.35s",
17482
+ motion: "notification",
16793
17483
  autoCloseDelay: 35e3
16794
17484
  } },
16795
17485
  symbol: { options: {
@@ -16825,7 +17515,7 @@ var buildComponents = (c) => ({
16825
17515
  spotlightPadding: 6,
16826
17516
  spotlightRadius: "xs",
16827
17517
  ringWidth: 2,
16828
- transitionMs: 250
17518
+ motion: "panel"
16829
17519
  } },
16830
17520
  tour: { options: {
16831
17521
  progressStyle: "dots",
@@ -16839,7 +17529,7 @@ var deepMerge = (base, override) => {
16839
17529
  for (const [key, value] of Object.entries(override)) out[key] = isRecord$1(value) && isRecord$1(out[key]) ? deepMerge(out[key], value) : value;
16840
17530
  return out;
16841
17531
  };
16842
- var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows = BaseShadows, typography, borders, thicknesses, components }) => ({
17532
+ var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows = BaseShadows, motion, typography, borders, thicknesses, spacing, components }) => ({
16843
17533
  id,
16844
17534
  name,
16845
17535
  colors,
@@ -16847,7 +17537,14 @@ var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows =
16847
17537
  borders: deepMerge(buildBorders(colors), borders),
16848
17538
  radii,
16849
17539
  shadows,
16850
- spacing: BaseSpacing,
17540
+ spacing: {
17541
+ ...BaseSpacing,
17542
+ ...spacing
17543
+ },
17544
+ motion: {
17545
+ ...BaseMotion,
17546
+ ...motion
17547
+ },
16851
17548
  thicknesses: {
16852
17549
  ...BaseThicknesses,
16853
17550
  ...thicknesses
@@ -17026,6 +17723,7 @@ var themeExport = (exportName, displayName, colorsConst, shadowsConst, radii) =>
17026
17723
  ` shadows: ${shadowsConst},`,
17027
17724
  " icons,",
17028
17725
  ...radii ? [" radii,"] : [],
17726
+ " spacing,",
17029
17727
  "});"
17030
17728
  ].join("\n");
17031
17729
  var emitThemeFile = (input) => {
@@ -17072,6 +17770,7 @@ var emitThemeFile = (input) => {
17072
17770
  " type ComponentThemes,",
17073
17771
  " type Icons,",
17074
17772
  " type Shadows,",
17773
+ " type Spacing,",
17075
17774
  " type UniTheme,",
17076
17775
  "} from '@uni-design-system/uni-core';",
17077
17776
  "",
@@ -17114,6 +17813,15 @@ ${recordLiteral(shadows, " ")}
17114
17813
  " */",
17115
17814
  "const icons: Icons = {};",
17116
17815
  "",
17816
+ "/**",
17817
+ " * Spacing steps, merged over the base scale",
17818
+ " * (none: 0, xxs: 2px, xs: 4px, sm: 8px, md: 16px, lg: 32px, xl: 64px, xxl: 128px).",
17819
+ " * Restate a named step to retune the rhythm, and add your own names for the",
17820
+ " * gaps your design actually uses \u2014 every extra key is then a valid `padding`,",
17821
+ " * `gap` or `marginInline` value: `<div stack-layout gap='tight'>`.",
17822
+ " */",
17823
+ "const spacing: Spacing = {};",
17824
+ "",
17117
17825
  ...radii ? [
17118
17826
  `/** Shape language: '${input.shape}'. */`,
17119
17827
  `const radii = {
@@ -18176,4 +18884,4 @@ export {
18176
18884
  buildStoredTheme,
18177
18885
  createUniServer
18178
18886
  };
18179
- //# sourceMappingURL=chunk-YLYBDQAV.js.map
18887
+ //# sourceMappingURL=chunk-HXXP4PTK.js.map