@hjmds/design-contracts 1.1.1 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/agreement.d.ts +183 -0
  2. package/dist/agreement.d.ts.map +1 -0
  3. package/dist/agreement.js +137 -0
  4. package/dist/agreement.js.map +1 -0
  5. package/dist/anchor.d.ts +62 -0
  6. package/dist/anchor.d.ts.map +1 -0
  7. package/dist/anchor.js +43 -0
  8. package/dist/anchor.js.map +1 -0
  9. package/dist/asset.d.ts +94 -0
  10. package/dist/asset.d.ts.map +1 -0
  11. package/dist/asset.js +60 -0
  12. package/dist/asset.js.map +1 -0
  13. package/dist/auth-screen.d.ts +119 -0
  14. package/dist/auth-screen.d.ts.map +1 -0
  15. package/dist/auth-screen.js +87 -0
  16. package/dist/auth-screen.js.map +1 -0
  17. package/dist/base-recipes.d.ts +19 -0
  18. package/dist/base-recipes.d.ts.map +1 -1
  19. package/dist/base-recipes.js +17 -0
  20. package/dist/base-recipes.js.map +1 -1
  21. package/dist/behaviors.d.ts +363 -3
  22. package/dist/behaviors.d.ts.map +1 -1
  23. package/dist/behaviors.js +37 -1
  24. package/dist/behaviors.js.map +1 -1
  25. package/dist/bottom-info.d.ts +58 -0
  26. package/dist/bottom-info.d.ts.map +1 -0
  27. package/dist/bottom-info.js +48 -0
  28. package/dist/bottom-info.js.map +1 -0
  29. package/dist/carousel.d.ts +3 -3
  30. package/dist/carousel.js +1 -1
  31. package/dist/carousel.js.map +1 -1
  32. package/dist/catalog.d.ts +1315 -245
  33. package/dist/catalog.d.ts.map +1 -1
  34. package/dist/catalog.js +67 -25
  35. package/dist/catalog.js.map +1 -1
  36. package/dist/collapsible.d.ts +56 -0
  37. package/dist/collapsible.d.ts.map +1 -0
  38. package/dist/collapsible.js +37 -0
  39. package/dist/collapsible.js.map +1 -0
  40. package/dist/component-definitions.d.ts +17 -0
  41. package/dist/component-definitions.d.ts.map +1 -1
  42. package/dist/component-definitions.js +17 -0
  43. package/dist/component-definitions.js.map +1 -1
  44. package/dist/component-recipes.d.ts +20 -3
  45. package/dist/component-recipes.d.ts.map +1 -1
  46. package/dist/component-recipes.js +24 -1
  47. package/dist/component-recipes.js.map +1 -1
  48. package/dist/context-menu.d.ts +53 -0
  49. package/dist/context-menu.d.ts.map +1 -0
  50. package/dist/context-menu.js +44 -0
  51. package/dist/context-menu.js.map +1 -0
  52. package/dist/counter-badge-recipe.d.ts +5 -0
  53. package/dist/counter-badge-recipe.d.ts.map +1 -1
  54. package/dist/counter-badge-recipe.js +5 -0
  55. package/dist/counter-badge-recipe.js.map +1 -1
  56. package/dist/dataviz.d.ts +76 -0
  57. package/dist/dataviz.d.ts.map +1 -0
  58. package/dist/dataviz.js +58 -0
  59. package/dist/dataviz.js.map +1 -0
  60. package/dist/date-range.d.ts +56 -0
  61. package/dist/date-range.d.ts.map +1 -0
  62. package/dist/date-range.js +79 -0
  63. package/dist/date-range.js.map +1 -0
  64. package/dist/design-system-provider.d.ts +24 -0
  65. package/dist/design-system-provider.d.ts.map +1 -1
  66. package/dist/design-system-provider.js +21 -0
  67. package/dist/design-system-provider.js.map +1 -1
  68. package/dist/floating-action-button.d.ts +1 -1
  69. package/dist/floating-action-button.d.ts.map +1 -1
  70. package/dist/floating-action-button.js +3 -1
  71. package/dist/floating-action-button.js.map +1 -1
  72. package/dist/formatters.d.ts +37 -0
  73. package/dist/formatters.d.ts.map +1 -0
  74. package/dist/formatters.js +69 -0
  75. package/dist/formatters.js.map +1 -0
  76. package/dist/heading.d.ts +82 -0
  77. package/dist/heading.d.ts.map +1 -0
  78. package/dist/heading.js +48 -0
  79. package/dist/heading.js.map +1 -0
  80. package/dist/index.d.ts +20 -0
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +20 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/menubar.d.ts +133 -0
  85. package/dist/menubar.d.ts.map +1 -0
  86. package/dist/menubar.js +80 -0
  87. package/dist/menubar.js.map +1 -0
  88. package/dist/native-platform.d.ts +88 -0
  89. package/dist/native-platform.d.ts.map +1 -0
  90. package/dist/native-platform.js +70 -0
  91. package/dist/native-platform.js.map +1 -0
  92. package/dist/popover.d.ts +19 -4
  93. package/dist/popover.d.ts.map +1 -1
  94. package/dist/popover.js +3 -0
  95. package/dist/popover.js.map +1 -1
  96. package/dist/progress-recipe.d.ts +14 -0
  97. package/dist/progress-recipe.d.ts.map +1 -1
  98. package/dist/progress-recipe.js +14 -1
  99. package/dist/progress-recipe.js.map +1 -1
  100. package/dist/provider-button.d.ts +140 -0
  101. package/dist/provider-button.d.ts.map +1 -0
  102. package/dist/provider-button.js +83 -0
  103. package/dist/provider-button.js.map +1 -0
  104. package/dist/recipes.d.ts +16 -1
  105. package/dist/recipes.d.ts.map +1 -1
  106. package/dist/recipes.js +15 -0
  107. package/dist/recipes.js.map +1 -1
  108. package/dist/sheet.d.ts +16 -0
  109. package/dist/sheet.d.ts.map +1 -1
  110. package/dist/sheet.js +33 -0
  111. package/dist/sheet.js.map +1 -1
  112. package/dist/sidebar.d.ts +168 -0
  113. package/dist/sidebar.d.ts.map +1 -0
  114. package/dist/sidebar.js +98 -0
  115. package/dist/sidebar.js.map +1 -0
  116. package/dist/skip-nav.d.ts +67 -0
  117. package/dist/skip-nav.d.ts.map +1 -0
  118. package/dist/skip-nav.js +47 -0
  119. package/dist/skip-nav.js.map +1 -0
  120. package/dist/tags-input.d.ts +157 -0
  121. package/dist/tags-input.d.ts.map +1 -0
  122. package/dist/tags-input.js +108 -0
  123. package/dist/tags-input.js.map +1 -0
  124. package/dist/text-formats.d.ts +85 -0
  125. package/dist/text-formats.d.ts.map +1 -0
  126. package/dist/text-formats.js +43 -0
  127. package/dist/text-formats.js.map +1 -0
  128. package/dist/toggle-group.d.ts +111 -0
  129. package/dist/toggle-group.d.ts.map +1 -0
  130. package/dist/toggle-group.js +78 -0
  131. package/dist/toggle-group.js.map +1 -0
  132. package/dist/top.d.ts +113 -0
  133. package/dist/top.d.ts.map +1 -0
  134. package/dist/top.js +72 -0
  135. package/dist/top.js.map +1 -0
  136. package/dist/version.d.ts +1 -1
  137. package/dist/version.js +1 -1
  138. package/dist/version.js.map +1 -1
  139. package/docs/agreement.md +33 -0
  140. package/docs/anchor.md +59 -59
  141. package/docs/ant-design-coverage.md +5 -3
  142. package/docs/asset.md +26 -0
  143. package/docs/auth-screen.md +65 -0
  144. package/docs/bottom-info.md +15 -0
  145. package/docs/breadcrumb.md +15 -15
  146. package/docs/button-label.md +20 -0
  147. package/docs/calendar.md +82 -154
  148. package/docs/carousel.md +27 -2
  149. package/docs/cascader.md +17 -0
  150. package/docs/chart.md +33 -0
  151. package/docs/clipboard.md +13 -0
  152. package/docs/collapsible.md +19 -0
  153. package/docs/command-palette.md +19 -0
  154. package/docs/confirm-popover.md +11 -1
  155. package/docs/context-menu.md +23 -0
  156. package/docs/data-table.md +22 -0
  157. package/docs/date-range.md +31 -0
  158. package/docs/density.md +52 -0
  159. package/docs/expansion-roadmap.md +16 -3
  160. package/docs/floating-action-button.md +35 -3
  161. package/docs/formatters.md +18 -0
  162. package/docs/generated/component-maturity.md +40 -23
  163. package/docs/generated/renderer-evidence.json +3029 -652
  164. package/docs/generated/renderer-evidence.md +55 -6
  165. package/docs/generated/showcase-manifest.json +1156 -81
  166. package/docs/heading.md +25 -0
  167. package/docs/identity.md +5 -0
  168. package/docs/layout.md +1 -1
  169. package/docs/library-gap-analysis.md +29 -9
  170. package/docs/list-row.md +14 -0
  171. package/docs/mentions.md +18 -0
  172. package/docs/menubar.md +22 -0
  173. package/docs/native-platform.md +36 -0
  174. package/docs/overlay-stack.md +24 -0
  175. package/docs/pagination.md +16 -8
  176. package/docs/popover.md +42 -13
  177. package/docs/product-audit-2026-09-15.md +88 -0
  178. package/docs/progress.md +16 -0
  179. package/docs/provider-button.md +33 -0
  180. package/docs/rating.md +19 -0
  181. package/docs/react-native-completion.md +347 -0
  182. package/docs/screen-chrome.md +52 -0
  183. package/docs/side-panel.md +23 -2
  184. package/docs/sidebar.md +30 -0
  185. package/docs/skip-nav.md +20 -0
  186. package/docs/splitter.md +22 -2
  187. package/docs/stable-promotion.md +51 -0
  188. package/docs/tags-input.md +25 -0
  189. package/docs/text-formats.md +15 -0
  190. package/docs/theming.md +84 -0
  191. package/docs/time-picker.md +22 -1
  192. package/docs/toast.md +18 -0
  193. package/docs/toggle-group.md +21 -0
  194. package/docs/top.md +32 -0
  195. package/docs/tour.md +23 -2
  196. package/docs/transfer-list.md +20 -0
  197. package/docs/tree-select.md +18 -0
  198. package/docs/tree.md +21 -0
  199. package/package.json +126 -6
@@ -1 +1 @@
1
- {"version":3,"file":"carousel.js","sourceRoot":"","sources":["../src/carousel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport type { SemanticIconName } from \"./icon.js\";\nimport { focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, motionPreset, opacity, spacing } from \"./foundations.js\";\nimport { assertFiniteNumber } from \"./number-field.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * Ant Design Carousel's infinite loop and default autoplay are intentionally\n * not reproduced — both remove the one thing this contract treats as\n * non-negotiable: a reliable answer to \"where am I, and where does it end\".\n * See docs/carousel.md for the accessibility rationale on every point below.\n */\nexport type CarouselSlideDescriptor<Id extends string = string> = Readonly<{\n id: Id;\n /** Accessible name for the slide, e.g. \"8/19 두산 vs LG\". The slide's visual content is product-owned. */\n label: string;\n}>;\n\nexport type CarouselAutoplayConfig = Readonly<{\n /** Minimum time a slide stays current before an automatic advance. */\n intervalMs: number;\n}>;\n\n/**\n * Renderer-facing prop shape only — mirrors SelectSelection's controlled/\n * uncontrolled duality, but the resolver below always takes a concrete,\n * already-resolved `currentKey` (see CarouselDescriptor) so validation and\n * position math never have to branch on which mode the product chose.\n */\nexport type ControlledCarouselSelection<Id extends string = string> = Readonly<{\n currentKey: Id;\n defaultCurrentKey?: never;\n onCurrentKeyChange(key: Id): void;\n}>;\n\nexport type UncontrolledCarouselSelection<Id extends string = string> = Readonly<{\n currentKey?: never;\n defaultCurrentKey?: Id;\n onCurrentKeyChange?: (key: Id) => void;\n}>;\n\nexport type CarouselSelection<Id extends string = string> =\n | ControlledCarouselSelection<Id>\n | UncontrolledCarouselSelection<Id>;\n\nexport type CarouselDescriptor<Id extends string = string> = Readonly<{\n slides: readonly CarouselSlideDescriptor<Id>[];\n currentKey: Id;\n /** Absent by default. Autoplay is opt-in — see docs/carousel.md. */\n autoplay?: CarouselAutoplayConfig;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Carousel ${field} must not be empty`);\n }\n}\n\nexport function validateCarouselSlide<Id extends string>(\n slide: CarouselSlideDescriptor<Id>,\n): void {\n assertNonEmpty(slide.id, \"slide id\");\n if (slide.id !== slide.id.trim()) {\n throw new TypeError(\"Carousel slide id must not start or end with whitespace\");\n }\n assertNonEmpty(slide.label, \"slide label\");\n}\n\nexport function validateCarouselAutoplayConfig(\n autoplay: CarouselAutoplayConfig,\n): void {\n assertFiniteNumber(autoplay.intervalMs, \"autoplay.intervalMs\");\n if (autoplay.intervalMs <= 0) {\n throw new RangeError(\"Carousel autoplay.intervalMs must be greater than zero\");\n }\n}\n\nexport function validateCarouselDescriptor<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n): void {\n if (descriptor.slides.length === 0) {\n throw new RangeError(\"Carousel must contain at least one slide\");\n }\n const ids = new Set<Id>();\n for (const slide of descriptor.slides) {\n validateCarouselSlide(slide);\n if (ids.has(slide.id)) {\n throw new TypeError(`Duplicate Carousel slide id: ${slide.id}`);\n }\n ids.add(slide.id);\n }\n if (!ids.has(descriptor.currentKey)) {\n throw new RangeError(\n `Carousel currentKey does not match any slide id: ${String(descriptor.currentKey)}`,\n );\n }\n if (descriptor.autoplay) {\n validateCarouselAutoplayConfig(descriptor.autoplay);\n }\n}\n\nexport type CarouselAccessibleNameInfo = Readonly<{\n position: number;\n total: number;\n label: string;\n}>;\n\n/**\n * Same reason Steps and Timeline do not assemble their own accessible name:\n * counter-word grammar and phrase order are product-owned copy decisions.\n */\nexport type ComposeCarouselAccessibleName = (\n info: CarouselAccessibleNameInfo,\n) => string;\n\nexport type ResolvedCarouselSlideDescriptor<Id extends string = string> =\n CarouselSlideDescriptor<Id> &\n Readonly<{\n /** 1-indexed so position and label both preserve reading order for renderers. */\n position: number;\n total: number;\n current: boolean;\n /**\n * True for every slide but the current one. A renderer must exclude an\n * inert slide's interactive content from both focus and the\n * accessibility tree — a hidden slide whose link can still receive\n * focus is worse than one that is simply unreachable until the user\n * advances to it (see docs/carousel.md).\n */\n inert: boolean;\n accessibleName: string;\n }>;\n\nexport type ResolveCarouselOptions = Readonly<{\n composeAccessibleName: ComposeCarouselAccessibleName;\n}>;\n\n/**\n * Attaches order, current/inert, and the composed accessible name used by\n * both the slide group and its indicator dot — one composer, reused for\n * every render target, the same way Steps reuses a single composer.\n */\nexport function resolveCarouselDescriptor<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n options: ResolveCarouselOptions,\n): readonly ResolvedCarouselSlideDescriptor<Id>[] {\n validateCarouselDescriptor(descriptor);\n if (typeof options.composeAccessibleName !== \"function\") {\n throw new TypeError(\"Carousel composeAccessibleName must be a function\");\n }\n\n const total = descriptor.slides.length;\n return descriptor.slides.map((slide, index) => {\n const position = index + 1;\n const current = slide.id === descriptor.currentKey;\n const accessibleName = options.composeAccessibleName({\n position,\n total,\n label: slide.label,\n });\n if (typeof accessibleName !== \"string\" || accessibleName.trim().length === 0) {\n throw new TypeError(\n \"Carousel composeAccessibleName must return a non-empty string\",\n );\n }\n return { ...slide, position, total, current, inert: !current, accessibleName };\n });\n}\n\nexport type CarouselNavigationIntent = \"next\" | \"previous\" | \"first\" | \"last\";\n\n/**\n * Clamps at the first/last slide instead of wrapping — infinite loop is out\n * of scope (see docs/carousel.md), so there is no modulo here at all, unlike\n * getCollectionNavigationTarget's `loop` parameter elsewhere in this package.\n */\nexport function getCarouselNavigationTarget<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n intent: CarouselNavigationIntent,\n): Id {\n validateCarouselDescriptor(descriptor);\n const { slides, currentKey } = descriptor;\n if (intent === \"first\") return slides[0]!.id;\n if (intent === \"last\") return slides.at(-1)!.id;\n const currentIndex = slides.findIndex((slide) => slide.id === currentKey);\n const delta = intent === \"next\" ? 1 : -1;\n const clampedIndex = Math.min(\n Math.max(currentIndex + delta, 0),\n slides.length - 1,\n );\n return slides[clampedIndex]!.id;\n}\n\nexport type CarouselAutoplayInputs = Readonly<{\n /** True whenever a platform reduce-motion preference is active. */\n reducedMotion: boolean;\n /** Renderer-combined pointer hover, focus-within, and drag signal. */\n paused: boolean;\n}>;\n\n/**\n * Autoplay is never active without an explicit config, under reduce motion,\n * or while the user is hovering, focusing, or dragging the carousel — the\n * three guards the brief requires are one function so a renderer cannot wire\n * an autoplay timer that forgets one of them.\n */\nexport function isCarouselAutoplayActive(\n autoplay: CarouselAutoplayConfig | undefined,\n inputs: CarouselAutoplayInputs,\n): boolean {\n if (!autoplay) return false;\n validateCarouselAutoplayConfig(autoplay);\n return !inputs.reducedMotion && !inputs.paused;\n}\n\nexport const carouselBehaviorDefaults = {\n autoplay: false,\n} as const satisfies Readonly<{ autoplay: boolean }>;\n\nexport const carouselBehavior = {\n controlled: [\"currentKey\", \"defaultCurrentKey\", \"onCurrentKeyChange\"],\n inputs: [\"autoplay\", \"reducedMotion\", \"dragged\"],\n defaults: carouselBehaviorDefaults,\n stateAxes: {\n interaction: [\"idle\", \"dragged\"],\n value: [\"selected\"],\n },\n web: {\n roles: [\"region\", \"group\"],\n keyboard: [\"Tab\", \"Enter\", \"Space\", \"ArrowLeft\", \"ArrowRight\"],\n focus: \"roving\",\n },\n native: {\n roles: [\"adjustable\"],\n states: [\"selected\"],\n actions: [\"increment\", \"decrement\"],\n },\n scenarios: [\n \"current-position-is-announced-with-a-readable-name-not-dots-alone\",\n \"inactive-slide-content-is-excluded-from-focus-and-the-accessibility-tree\",\n \"previous-next-and-dot-controls-stay-in-tab-order-regardless-of-current-slide\",\n \"arrow-keys-move-one-slide-on-web-swipe-moves-one-slide-on-native\",\n \"boundary-slides-clamp-instead-of-wrapping-because-loop-is-out-of-scope\",\n \"autoplay-is-opt-in-and-off-by-default\",\n \"autoplay-never-runs-when-reduced-motion-is-active\",\n \"autoplay-pauses-on-hover-focus-or-drag-and-does-not-announce-automatic-transitions\",\n ],\n} as const satisfies BehaviorContract;\n\nexport type CarouselSize = \"medium\";\n\nexport const carouselRecipe = {\n slots: [\n \"root\",\n \"track\",\n \"slide\",\n \"dots\",\n \"dot\",\n \"previousControl\",\n \"nextControl\",\n ] as const,\n defaults: { size: \"medium\" },\n sizes: {\n medium: {\n gap: spacing.sm,\n controlHitTarget: control.minTouchTarget,\n controlIcon: \"sm\",\n },\n },\n dot: {\n diameter: 8,\n hitTarget: control.minTouchTarget,\n color: {\n inactive: semanticColors.border.strong,\n current: semanticColors.content.brand,\n },\n },\n /** Previous/next chrome is composed from IconButton (ghost tone) rather than owning new button visuals. */\n control: {\n icons: {\n previous: \"chevronStart\",\n next: \"chevronEnd\",\n } as const satisfies Readonly<{ previous: SemanticIconName; next: SemanticIconName }>,\n },\n states: {\n focus: focusIndicatorContract,\n draggedOpacity: opacity.dragged,\n },\n /**\n * Manual slide-to-slide movement crossfades rather than snapping under\n * Reduce Motion, reusing the existing \"context\" preset instead of a new\n * token — autoplay itself simply does not run at all (isCarouselAutoplayActive).\n */\n transition: motionPreset.context,\n} as const satisfies {\n slots: readonly string[];\n defaults: { size: CarouselSize };\n sizes: Record<\n CarouselSize,\n { gap: number; controlHitTarget: number; controlIcon: string }\n >;\n dot: {\n diameter: number;\n hitTarget: number;\n color: Record<\"inactive\" | \"current\", ColorReference>;\n };\n control: {\n icons: Readonly<{ previous: SemanticIconName; next: SemanticIconName }>;\n };\n states: {\n focus: typeof focusIndicatorContract;\n draggedOpacity: number;\n };\n transition: typeof motionPreset.context;\n};\n"]}
1
+ {"version":3,"file":"carousel.js","sourceRoot":"","sources":["../src/carousel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport type { SemanticIconName } from \"./icon.js\";\nimport { focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, motionPreset, opacity, spacing } from \"./foundations.js\";\nimport { assertFiniteNumber } from \"./number-field.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * Ant Design Carousel's default infinite loop is intentionally not reproduced;\n * autoplay remains opt-in in both libraries — automatic movement can obscure what this contract treats as\n * non-negotiable: a reliable answer to \"where am I, and where does it end\".\n * See docs/carousel.md for the accessibility rationale on every point below.\n */\nexport type CarouselSlideDescriptor<Id extends string = string> = Readonly<{\n id: Id;\n /** Accessible name for the slide, e.g. \"8/19 두산 vs LG\". The slide's visual content is product-owned. */\n label: string;\n}>;\n\nexport type CarouselAutoplayConfig = Readonly<{\n /** Minimum time a slide stays current before an automatic advance. */\n intervalMs: number;\n}>;\n\n/**\n * Renderer-facing prop shape only — mirrors SelectSelection's controlled/\n * uncontrolled duality, but the resolver below always takes a concrete,\n * already-resolved `currentKey` (see CarouselDescriptor) so validation and\n * position math never have to branch on which mode the product chose.\n */\nexport type ControlledCarouselSelection<Id extends string = string> = Readonly<{\n currentKey: Id;\n defaultCurrentKey?: never;\n onCurrentKeyChange(key: Id): void;\n}>;\n\nexport type UncontrolledCarouselSelection<Id extends string = string> = Readonly<{\n currentKey?: never;\n defaultCurrentKey?: Id;\n onCurrentKeyChange?: (key: Id) => void;\n}>;\n\nexport type CarouselSelection<Id extends string = string> =\n | ControlledCarouselSelection<Id>\n | UncontrolledCarouselSelection<Id>;\n\nexport type CarouselDescriptor<Id extends string = string> = Readonly<{\n slides: readonly CarouselSlideDescriptor<Id>[];\n currentKey: Id;\n /** Absent by default. Autoplay is opt-in — see docs/carousel.md. */\n autoplay?: CarouselAutoplayConfig;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Carousel ${field} must not be empty`);\n }\n}\n\nexport function validateCarouselSlide<Id extends string>(\n slide: CarouselSlideDescriptor<Id>,\n): void {\n assertNonEmpty(slide.id, \"slide id\");\n if (slide.id !== slide.id.trim()) {\n throw new TypeError(\"Carousel slide id must not start or end with whitespace\");\n }\n assertNonEmpty(slide.label, \"slide label\");\n}\n\nexport function validateCarouselAutoplayConfig(\n autoplay: CarouselAutoplayConfig,\n): void {\n assertFiniteNumber(autoplay.intervalMs, \"autoplay.intervalMs\");\n if (autoplay.intervalMs <= 0) {\n throw new RangeError(\"Carousel autoplay.intervalMs must be greater than zero\");\n }\n}\n\nexport function validateCarouselDescriptor<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n): void {\n if (descriptor.slides.length === 0) {\n throw new RangeError(\"Carousel must contain at least one slide\");\n }\n const ids = new Set<Id>();\n for (const slide of descriptor.slides) {\n validateCarouselSlide(slide);\n if (ids.has(slide.id)) {\n throw new TypeError(`Duplicate Carousel slide id: ${slide.id}`);\n }\n ids.add(slide.id);\n }\n if (!ids.has(descriptor.currentKey)) {\n throw new RangeError(\n `Carousel currentKey does not match any slide id: ${String(descriptor.currentKey)}`,\n );\n }\n if (descriptor.autoplay) {\n validateCarouselAutoplayConfig(descriptor.autoplay);\n }\n}\n\nexport type CarouselAccessibleNameInfo = Readonly<{\n position: number;\n total: number;\n label: string;\n}>;\n\n/**\n * Same reason Steps and Timeline do not assemble their own accessible name:\n * counter-word grammar and phrase order are product-owned copy decisions.\n */\nexport type ComposeCarouselAccessibleName = (\n info: CarouselAccessibleNameInfo,\n) => string;\n\nexport type ResolvedCarouselSlideDescriptor<Id extends string = string> =\n CarouselSlideDescriptor<Id> &\n Readonly<{\n /** 1-indexed so position and label both preserve reading order for renderers. */\n position: number;\n total: number;\n current: boolean;\n /**\n * True for every slide but the current one. A renderer must exclude an\n * inert slide's interactive content from both focus and the\n * accessibility tree — a hidden slide whose link can still receive\n * focus is worse than one that is simply unreachable until the user\n * advances to it (see docs/carousel.md).\n */\n inert: boolean;\n accessibleName: string;\n }>;\n\nexport type ResolveCarouselOptions = Readonly<{\n composeAccessibleName: ComposeCarouselAccessibleName;\n}>;\n\n/**\n * Attaches order, current/inert, and the composed accessible name used by\n * both the slide group and its indicator dot — one composer, reused for\n * every render target, the same way Steps reuses a single composer.\n */\nexport function resolveCarouselDescriptor<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n options: ResolveCarouselOptions,\n): readonly ResolvedCarouselSlideDescriptor<Id>[] {\n validateCarouselDescriptor(descriptor);\n if (typeof options.composeAccessibleName !== \"function\") {\n throw new TypeError(\"Carousel composeAccessibleName must be a function\");\n }\n\n const total = descriptor.slides.length;\n return descriptor.slides.map((slide, index) => {\n const position = index + 1;\n const current = slide.id === descriptor.currentKey;\n const accessibleName = options.composeAccessibleName({\n position,\n total,\n label: slide.label,\n });\n if (typeof accessibleName !== \"string\" || accessibleName.trim().length === 0) {\n throw new TypeError(\n \"Carousel composeAccessibleName must return a non-empty string\",\n );\n }\n return { ...slide, position, total, current, inert: !current, accessibleName };\n });\n}\n\nexport type CarouselNavigationIntent = \"next\" | \"previous\" | \"first\" | \"last\";\n\n/**\n * Clamps at the first/last slide instead of wrapping — infinite loop is out\n * of scope (see docs/carousel.md), so there is no modulo here at all, unlike\n * getCollectionNavigationTarget's `loop` parameter elsewhere in this package.\n */\nexport function getCarouselNavigationTarget<Id extends string>(\n descriptor: CarouselDescriptor<Id>,\n intent: CarouselNavigationIntent,\n): Id {\n validateCarouselDescriptor(descriptor);\n const { slides, currentKey } = descriptor;\n if (intent === \"first\") return slides[0]!.id;\n if (intent === \"last\") return slides.at(-1)!.id;\n const currentIndex = slides.findIndex((slide) => slide.id === currentKey);\n const delta = intent === \"next\" ? 1 : -1;\n const clampedIndex = Math.min(\n Math.max(currentIndex + delta, 0),\n slides.length - 1,\n );\n return slides[clampedIndex]!.id;\n}\n\nexport type CarouselAutoplayInputs = Readonly<{\n /** True whenever a platform reduce-motion preference is active. */\n reducedMotion: boolean;\n /** Renderer-combined pointer hover, focus-within, and drag signal. */\n paused: boolean;\n}>;\n\n/**\n * Autoplay is never active without an explicit config, under reduce motion,\n * or while the user is hovering, focusing, or dragging the carousel — the\n * three guards the brief requires are one function so a renderer cannot wire\n * an autoplay timer that forgets one of them.\n */\nexport function isCarouselAutoplayActive(\n autoplay: CarouselAutoplayConfig | undefined,\n inputs: CarouselAutoplayInputs,\n): boolean {\n if (!autoplay) return false;\n validateCarouselAutoplayConfig(autoplay);\n return !inputs.reducedMotion && !inputs.paused;\n}\n\nexport const carouselBehaviorDefaults = {\n autoplay: false,\n} as const satisfies Readonly<{ autoplay: boolean }>;\n\nexport const carouselBehavior = {\n controlled: [\"currentKey\", \"defaultCurrentKey\", \"onCurrentKeyChange\"],\n inputs: [\"autoplay\", \"reducedMotion\", \"dragged\"],\n defaults: carouselBehaviorDefaults,\n stateAxes: {\n interaction: [\"idle\", \"dragged\"],\n value: [\"selected\"],\n },\n web: {\n roles: [\"region\", \"group\"],\n keyboard: [\"Tab\", \"Enter\", \"Space\", \"ArrowLeft\", \"ArrowRight\"],\n focus: \"native\",\n },\n native: {\n roles: [\"adjustable\"],\n states: [\"selected\"],\n actions: [\"increment\", \"decrement\"],\n },\n scenarios: [\n \"current-position-is-announced-with-a-readable-name-not-dots-alone\",\n \"inactive-slide-content-is-excluded-from-focus-and-the-accessibility-tree\",\n \"previous-next-and-dot-controls-stay-in-tab-order-regardless-of-current-slide\",\n \"arrow-keys-move-one-slide-on-web-swipe-moves-one-slide-on-native\",\n \"boundary-slides-clamp-instead-of-wrapping-because-loop-is-out-of-scope\",\n \"autoplay-is-opt-in-and-off-by-default\",\n \"autoplay-never-runs-when-reduced-motion-is-active\",\n \"autoplay-pauses-on-hover-focus-or-drag-and-does-not-announce-automatic-transitions\",\n ],\n} as const satisfies BehaviorContract;\n\nexport type CarouselSize = \"medium\";\n\nexport const carouselRecipe = {\n slots: [\n \"root\",\n \"track\",\n \"slide\",\n \"dots\",\n \"dot\",\n \"previousControl\",\n \"nextControl\",\n ] as const,\n defaults: { size: \"medium\" },\n sizes: {\n medium: {\n gap: spacing.sm,\n controlHitTarget: control.minTouchTarget,\n controlIcon: \"sm\",\n },\n },\n dot: {\n diameter: 8,\n hitTarget: control.minTouchTarget,\n color: {\n inactive: semanticColors.border.strong,\n current: semanticColors.content.brand,\n },\n },\n /** Previous/next chrome is composed from IconButton (ghost tone) rather than owning new button visuals. */\n control: {\n icons: {\n previous: \"chevronStart\",\n next: \"chevronEnd\",\n } as const satisfies Readonly<{ previous: SemanticIconName; next: SemanticIconName }>,\n },\n states: {\n focus: focusIndicatorContract,\n draggedOpacity: opacity.dragged,\n },\n /**\n * Manual slide-to-slide movement crossfades rather than snapping under\n * Reduce Motion, reusing the existing \"context\" preset instead of a new\n * token — autoplay itself simply does not run at all (isCarouselAutoplayActive).\n */\n transition: motionPreset.context,\n} as const satisfies {\n slots: readonly string[];\n defaults: { size: CarouselSize };\n sizes: Record<\n CarouselSize,\n { gap: number; controlHitTarget: number; controlIcon: string }\n >;\n dot: {\n diameter: number;\n hitTarget: number;\n color: Record<\"inactive\" | \"current\", ColorReference>;\n };\n control: {\n icons: Readonly<{ previous: SemanticIconName; next: SemanticIconName }>;\n };\n states: {\n focus: typeof focusIndicatorContract;\n draggedOpacity: number;\n };\n transition: typeof motionPreset.context;\n};\n"]}