@chromvoid/uikit 0.1.0

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 (246) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +96 -0
  3. package/dist/components/cv-accordion-item.d.ts +69 -0
  4. package/dist/components/cv-accordion-item.js +176 -0
  5. package/dist/components/cv-accordion.d.ts +79 -0
  6. package/dist/components/cv-accordion.js +310 -0
  7. package/dist/components/cv-alert-dialog.d.ts +86 -0
  8. package/dist/components/cv-alert-dialog.js +393 -0
  9. package/dist/components/cv-alert.d.ts +48 -0
  10. package/dist/components/cv-alert.js +156 -0
  11. package/dist/components/cv-badge.d.ts +56 -0
  12. package/dist/components/cv-badge.js +280 -0
  13. package/dist/components/cv-breadcrumb-item.d.ts +35 -0
  14. package/dist/components/cv-breadcrumb-item.js +64 -0
  15. package/dist/components/cv-breadcrumb.d.ts +39 -0
  16. package/dist/components/cv-breadcrumb.js +160 -0
  17. package/dist/components/cv-button.d.ts +83 -0
  18. package/dist/components/cv-button.js +541 -0
  19. package/dist/components/cv-callout.d.ts +32 -0
  20. package/dist/components/cv-callout.js +221 -0
  21. package/dist/components/cv-card.d.ts +48 -0
  22. package/dist/components/cv-card.js +269 -0
  23. package/dist/components/cv-carousel-slide.d.ts +25 -0
  24. package/dist/components/cv-carousel-slide.js +51 -0
  25. package/dist/components/cv-carousel.d.ts +96 -0
  26. package/dist/components/cv-carousel.js +457 -0
  27. package/dist/components/cv-checkbox.d.ts +84 -0
  28. package/dist/components/cv-checkbox.js +274 -0
  29. package/dist/components/cv-combobox-group.d.ts +15 -0
  30. package/dist/components/cv-combobox-group.js +34 -0
  31. package/dist/components/cv-combobox-option.d.ts +30 -0
  32. package/dist/components/cv-combobox-option.js +66 -0
  33. package/dist/components/cv-combobox.d.ts +135 -0
  34. package/dist/components/cv-combobox.js +834 -0
  35. package/dist/components/cv-command-item.d.ts +30 -0
  36. package/dist/components/cv-command-item.js +68 -0
  37. package/dist/components/cv-command-palette.d.ts +105 -0
  38. package/dist/components/cv-command-palette.js +578 -0
  39. package/dist/components/cv-context-menu.d.ts +98 -0
  40. package/dist/components/cv-context-menu.js +515 -0
  41. package/dist/components/cv-copy-button.d.ts +61 -0
  42. package/dist/components/cv-copy-button.js +318 -0
  43. package/dist/components/cv-date-picker.d.ts +161 -0
  44. package/dist/components/cv-date-picker.js +803 -0
  45. package/dist/components/cv-dialog.d.ts +89 -0
  46. package/dist/components/cv-dialog.js +459 -0
  47. package/dist/components/cv-disclosure.d.ts +57 -0
  48. package/dist/components/cv-disclosure.js +241 -0
  49. package/dist/components/cv-drawer.d.ts +102 -0
  50. package/dist/components/cv-drawer.js +595 -0
  51. package/dist/components/cv-feed-article.d.ts +26 -0
  52. package/dist/components/cv-feed-article.js +52 -0
  53. package/dist/components/cv-feed.d.ts +62 -0
  54. package/dist/components/cv-feed.js +310 -0
  55. package/dist/components/cv-grid-cell.d.ts +30 -0
  56. package/dist/components/cv-grid-cell.js +57 -0
  57. package/dist/components/cv-grid-column.d.ts +30 -0
  58. package/dist/components/cv-grid-column.js +43 -0
  59. package/dist/components/cv-grid-row.d.ts +30 -0
  60. package/dist/components/cv-grid-row.js +42 -0
  61. package/dist/components/cv-grid.d.ts +119 -0
  62. package/dist/components/cv-grid.js +567 -0
  63. package/dist/components/cv-icon.d.ts +57 -0
  64. package/dist/components/cv-icon.js +352 -0
  65. package/dist/components/cv-input.d.ts +127 -0
  66. package/dist/components/cv-input.js +482 -0
  67. package/dist/components/cv-landmark.d.ts +32 -0
  68. package/dist/components/cv-landmark.js +62 -0
  69. package/dist/components/cv-link.d.ts +22 -0
  70. package/dist/components/cv-link.js +99 -0
  71. package/dist/components/cv-listbox-group.d.ts +15 -0
  72. package/dist/components/cv-listbox-group.js +42 -0
  73. package/dist/components/cv-listbox.d.ts +81 -0
  74. package/dist/components/cv-listbox.js +388 -0
  75. package/dist/components/cv-menu-button.d.ts +118 -0
  76. package/dist/components/cv-menu-button.js +822 -0
  77. package/dist/components/cv-menu-group.d.ts +20 -0
  78. package/dist/components/cv-menu-group.js +48 -0
  79. package/dist/components/cv-menu-item.d.ts +52 -0
  80. package/dist/components/cv-menu-item.js +105 -0
  81. package/dist/components/cv-menu.d.ts +62 -0
  82. package/dist/components/cv-menu.js +414 -0
  83. package/dist/components/cv-meter.d.ts +66 -0
  84. package/dist/components/cv-meter.js +154 -0
  85. package/dist/components/cv-number.d.ts +139 -0
  86. package/dist/components/cv-number.js +553 -0
  87. package/dist/components/cv-option.d.ts +30 -0
  88. package/dist/components/cv-option.js +84 -0
  89. package/dist/components/cv-popover.d.ts +87 -0
  90. package/dist/components/cv-popover.js +373 -0
  91. package/dist/components/cv-progress-ring.d.ts +45 -0
  92. package/dist/components/cv-progress-ring.js +169 -0
  93. package/dist/components/cv-progress.d.ts +45 -0
  94. package/dist/components/cv-progress.js +148 -0
  95. package/dist/components/cv-radio-group.d.ts +79 -0
  96. package/dist/components/cv-radio-group.js +398 -0
  97. package/dist/components/cv-radio.d.ts +36 -0
  98. package/dist/components/cv-radio.js +123 -0
  99. package/dist/components/cv-select-group.d.ts +15 -0
  100. package/dist/components/cv-select-group.js +44 -0
  101. package/dist/components/cv-select-option.d.ts +30 -0
  102. package/dist/components/cv-select-option.js +66 -0
  103. package/dist/components/cv-select.d.ts +128 -0
  104. package/dist/components/cv-select.js +666 -0
  105. package/dist/components/cv-sidebar-item.d.ts +26 -0
  106. package/dist/components/cv-sidebar-item.js +142 -0
  107. package/dist/components/cv-sidebar.d.ts +171 -0
  108. package/dist/components/cv-sidebar.js +767 -0
  109. package/dist/components/cv-slider-multi-thumb.d.ts +73 -0
  110. package/dist/components/cv-slider-multi-thumb.js +374 -0
  111. package/dist/components/cv-slider.d.ts +84 -0
  112. package/dist/components/cv-slider.js +328 -0
  113. package/dist/components/cv-spinbutton.d.ts +121 -0
  114. package/dist/components/cv-spinbutton.js +486 -0
  115. package/dist/components/cv-spinner.d.ts +18 -0
  116. package/dist/components/cv-spinner.js +95 -0
  117. package/dist/components/cv-switch.d.ts +81 -0
  118. package/dist/components/cv-switch.js +285 -0
  119. package/dist/components/cv-tab-panel.d.ts +20 -0
  120. package/dist/components/cv-tab-panel.js +37 -0
  121. package/dist/components/cv-tab.d.ts +40 -0
  122. package/dist/components/cv-tab.js +132 -0
  123. package/dist/components/cv-table-cell.d.ts +31 -0
  124. package/dist/components/cv-table-cell.js +49 -0
  125. package/dist/components/cv-table-column.d.ts +37 -0
  126. package/dist/components/cv-table-column.js +63 -0
  127. package/dist/components/cv-table-row.d.ts +30 -0
  128. package/dist/components/cv-table-row.js +45 -0
  129. package/dist/components/cv-table.d.ts +147 -0
  130. package/dist/components/cv-table.js +607 -0
  131. package/dist/components/cv-tabs.d.ts +70 -0
  132. package/dist/components/cv-tabs.js +524 -0
  133. package/dist/components/cv-textarea.d.ts +108 -0
  134. package/dist/components/cv-textarea.js +328 -0
  135. package/dist/components/cv-toast-region.d.ts +39 -0
  136. package/dist/components/cv-toast-region.js +162 -0
  137. package/dist/components/cv-toast.d.ts +67 -0
  138. package/dist/components/cv-toast.js +315 -0
  139. package/dist/components/cv-toolbar-item.d.ts +25 -0
  140. package/dist/components/cv-toolbar-item.js +72 -0
  141. package/dist/components/cv-toolbar-separator.d.ts +25 -0
  142. package/dist/components/cv-toolbar-separator.js +45 -0
  143. package/dist/components/cv-toolbar.d.ts +63 -0
  144. package/dist/components/cv-toolbar.js +295 -0
  145. package/dist/components/cv-tooltip.d.ts +83 -0
  146. package/dist/components/cv-tooltip.js +455 -0
  147. package/dist/components/cv-treegrid-cell.d.ts +30 -0
  148. package/dist/components/cv-treegrid-cell.js +57 -0
  149. package/dist/components/cv-treegrid-column.d.ts +37 -0
  150. package/dist/components/cv-treegrid-column.js +53 -0
  151. package/dist/components/cv-treegrid-row.d.ts +55 -0
  152. package/dist/components/cv-treegrid-row.js +90 -0
  153. package/dist/components/cv-treegrid.d.ts +96 -0
  154. package/dist/components/cv-treegrid.js +632 -0
  155. package/dist/components/cv-treeitem.d.ts +58 -0
  156. package/dist/components/cv-treeitem.js +144 -0
  157. package/dist/components/cv-treeview.d.ts +70 -0
  158. package/dist/components/cv-treeview.js +396 -0
  159. package/dist/components/cv-window-splitter.d.ts +79 -0
  160. package/dist/components/cv-window-splitter.js +316 -0
  161. package/dist/components/index.d.ts +94 -0
  162. package/dist/components/index.js +79 -0
  163. package/dist/dialog/create-dialog-controller.d.ts +31 -0
  164. package/dist/dialog/create-dialog-controller.js +320 -0
  165. package/dist/dialog/index.d.ts +2 -0
  166. package/dist/dialog/index.js +1 -0
  167. package/dist/form-associated/FormAssociatedReatomElement.d.ts +25 -0
  168. package/dist/form-associated/FormAssociatedReatomElement.js +70 -0
  169. package/dist/form-associated/withFormAssociated.d.ts +5 -0
  170. package/dist/form-associated/withFormAssociated.js +1 -0
  171. package/dist/index.d.ts +10 -0
  172. package/dist/index.js +9 -0
  173. package/dist/reatom-lit/ReatomLitElement.d.ts +27 -0
  174. package/dist/reatom-lit/ReatomLitElement.js +118 -0
  175. package/dist/reatom-lit/html.d.ts +4 -0
  176. package/dist/reatom-lit/html.js +10 -0
  177. package/dist/reatom-lit/index.d.ts +4 -0
  178. package/dist/reatom-lit/index.js +4 -0
  179. package/dist/reatom-lit/watch.d.ts +15 -0
  180. package/dist/reatom-lit/watch.js +40 -0
  181. package/dist/reatom-lit/withReatomElement.d.ts +4 -0
  182. package/dist/reatom-lit/withReatomElement.js +57 -0
  183. package/dist/register.d.ts +1 -0
  184. package/dist/register.js +84 -0
  185. package/dist/styles/component-styles.d.ts +4 -0
  186. package/dist/styles/component-styles.js +78 -0
  187. package/dist/theme/cv-theme-provider.d.ts +32 -0
  188. package/dist/theme/cv-theme-provider.js +110 -0
  189. package/dist/theme/index.d.ts +4 -0
  190. package/dist/theme/index.js +2 -0
  191. package/dist/theme/theme-engine.d.ts +4 -0
  192. package/dist/theme/theme-engine.js +67 -0
  193. package/dist/theme/tokens.css +265 -0
  194. package/dist/theme/types.d.ts +7 -0
  195. package/dist/theme/types.js +1 -0
  196. package/dist/toast/create-toast-controller.d.ts +12 -0
  197. package/dist/toast/create-toast-controller.js +12 -0
  198. package/dist/toast/index.d.ts +2 -0
  199. package/dist/toast/index.js +1 -0
  200. package/package.json +146 -0
  201. package/specs/_template.md +110 -0
  202. package/specs/components/accordion.md +207 -0
  203. package/specs/components/alert.md +83 -0
  204. package/specs/components/badge.md +183 -0
  205. package/specs/components/breadcrumb.md +152 -0
  206. package/specs/components/button.md +227 -0
  207. package/specs/components/callout.md +153 -0
  208. package/specs/components/card.md +192 -0
  209. package/specs/components/carousel.md +232 -0
  210. package/specs/components/checkbox.md +141 -0
  211. package/specs/components/combobox.md +427 -0
  212. package/specs/components/context-menu.md +375 -0
  213. package/specs/components/copy-button.md +236 -0
  214. package/specs/components/date-picker.md +290 -0
  215. package/specs/components/dialog.md +184 -0
  216. package/specs/components/disclosure.md +151 -0
  217. package/specs/components/drawer.md +216 -0
  218. package/specs/components/feed.md +266 -0
  219. package/specs/components/grid.md +423 -0
  220. package/specs/components/input.md +237 -0
  221. package/specs/components/landmark.md +92 -0
  222. package/specs/components/link.md +117 -0
  223. package/specs/components/listbox.md +327 -0
  224. package/specs/components/menu.md +508 -0
  225. package/specs/components/meter.md +148 -0
  226. package/specs/components/number.md +268 -0
  227. package/specs/components/option.md +167 -0
  228. package/specs/components/popover.md +207 -0
  229. package/specs/components/progress-ring.md +134 -0
  230. package/specs/components/progress.md +110 -0
  231. package/specs/components/radio.md +208 -0
  232. package/specs/components/select.md +305 -0
  233. package/specs/components/sidebar.md +204 -0
  234. package/specs/components/spinbutton.md +157 -0
  235. package/specs/components/spinner.md +83 -0
  236. package/specs/components/switch.md +145 -0
  237. package/specs/components/table.md +372 -0
  238. package/specs/components/tabs.md +242 -0
  239. package/specs/components/textarea.md +166 -0
  240. package/specs/components/theme.md +364 -0
  241. package/specs/components/toast.md +198 -0
  242. package/specs/components/toolbar.md +258 -0
  243. package/specs/components/tooltip.md +152 -0
  244. package/specs/components/treegrid.md +363 -0
  245. package/specs/components/treeview.md +263 -0
  246. package/specs/components/window-splitter.md +225 -0
@@ -0,0 +1,232 @@
1
+ # cv-carousel
2
+
3
+ Slideshow component that cycles through a set of slides with navigation controls, indicators, and optional autoplay.
4
+
5
+ **Headless:** [`createCarousel`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/carousel.md)
6
+
7
+ ## Anatomy
8
+
9
+ ```
10
+ <cv-carousel> (host)
11
+ └── <section part="base" role="region" aria-roledescription="carousel">
12
+ ├── <div part="controls">
13
+ │ ├── <button part="control prev" aria-label="Previous slide">
14
+ │ ├── <button part="control next" aria-label="Next slide">
15
+ │ └── <button part="control play-pause" aria-label="Stop/Start slide rotation">
16
+ ├── <div part="slides" role="group">
17
+ │ └── <slot> ← cv-carousel-slide elements
18
+ └── <div part="indicators">
19
+ └── <button part="indicator"> ← one per slide
20
+ ```
21
+
22
+ ## Attributes
23
+
24
+ | Attribute | Type | Default | Description |
25
+ | ------------------- | ------- | ------- | ------------------------------------------------------------------- |
26
+ | `value` | String | `""` | Identifier of the active slide (matches `cv-carousel-slide[value]`) |
27
+ | `active-index` | Number | `0` | Zero-based index of the active slide |
28
+ | `autoplay` | Boolean | `false` | Enables automatic slide rotation |
29
+ | `autoplay-interval` | Number | `5000` | Autoplay interval in milliseconds |
30
+ | `visible-slides` | Number | `1` | Number of slides visible at once |
31
+ | `paused` | Boolean | `false` | Whether autoplay is paused |
32
+ | `aria-label` | String | `""` | Accessible name for the carousel region |
33
+ | `aria-labelledby` | String | `""` | ID of the element that labels the carousel |
34
+
35
+ `value` and `active-index` are synchronized: setting one updates the other. When both are set, `value` takes precedence.
36
+
37
+ ## Slots
38
+
39
+ | Slot | Description |
40
+ | ----------- | ---------------------------- |
41
+ | `(default)` | `cv-carousel-slide` elements |
42
+
43
+ ## CSS Parts
44
+
45
+ | Part | Element | Description |
46
+ | ------------ | ----------- | ---------------------------------------------------------------------------- |
47
+ | `base` | `<section>` | Root wrapper with `role="region"` and `aria-roledescription="carousel"` |
48
+ | `controls` | `<div>` | Container for navigation and play/pause buttons |
49
+ | `slides` | `<div>` | Slide container with `role="group"` |
50
+ | `indicators` | `<div>` | Container for indicator buttons |
51
+ | `control` | `<button>` | Shared part on all control buttons (prev, next, play-pause) |
52
+ | `prev` | `<button>` | Previous slide button (also has `control` part) |
53
+ | `next` | `<button>` | Next slide button (also has `control` part) |
54
+ | `play-pause` | `<button>` | Play/pause toggle button (also has `control` part) |
55
+ | `indicator` | `<button>` | Individual indicator button; `[data-active="true"]` when its slide is active |
56
+
57
+ ## CSS Custom Properties
58
+
59
+ | Property | Default | Description |
60
+ | -------------------------------- | -------------------------- | --------------------------------------------------------------- |
61
+ | `--cv-carousel-gap` | `var(--cv-space-2, 8px)` | Gap between base layout sections (controls, slides, indicators) |
62
+ | `--cv-carousel-control-size` | `32px` | Min block/inline size of control and indicator buttons |
63
+ | `--cv-carousel-control-radius` | `var(--cv-radius-sm, 6px)` | Border radius of control and indicator buttons |
64
+ | `--cv-carousel-slide-min-height` | `120px` | Minimum block size of each slide |
65
+
66
+ ## Visual States
67
+
68
+ | Host selector | Description |
69
+ | ----------------------- | ---------------------------------------------------------- |
70
+ | `:host([autoplay])` | Autoplay is enabled |
71
+ | `:host([paused])` | Autoplay is paused (user-initiated or focus/hover-induced) |
72
+ | `:host([active-index])` | Reflects the current active slide index |
73
+
74
+ ## Events
75
+
76
+ | Event | Detail | Description |
77
+ | ----------- | --------------------------------------------------------------------- | -------------------------------------------------------- |
78
+ | `cv-input` | `{activeIndex: number, activeValue: string \| null, paused: boolean}` | Fires on any state change (active index or paused state) |
79
+ | `cv-change` | `{activeIndex: number, activeValue: string \| null, paused: boolean}` | Fires when the active slide index changes |
80
+
81
+ Both events bubble and are composed. `cv-input` fires on every state change (index or pause). `cv-change` fires only when the active index changes.
82
+
83
+ ## Reactive State Mapping
84
+
85
+ `cv-carousel` is a visual adapter over headless `createCarousel`.
86
+
87
+ | UIKit Property | Direction | Headless Binding |
88
+ | ------------------- | -------------- | ----------------------------------------------------------------- |
89
+ | `active-index` | attr -> action | `actions.moveTo(value)` |
90
+ | `value` | attr -> action | resolved to index via slide records, then `actions.moveTo(index)` |
91
+ | `paused` | attr -> action | `actions.pause()` / `actions.play()` |
92
+ | `autoplay` | attr -> option | passed as `autoplay` in `createCarousel(options)` |
93
+ | `autoplay-interval` | attr -> option | passed as `autoplayIntervalMs` in `createCarousel(options)` |
94
+ | `visible-slides` | attr -> option | passed as `visibleSlides` in `createCarousel(options)` |
95
+ | `aria-label` | attr -> option | passed as `ariaLabel` in `createCarousel(options)` |
96
+ | `aria-labelledby` | attr -> option | passed as `ariaLabelledBy` in `createCarousel(options)` |
97
+
98
+ | Headless State | Direction | DOM Reflection |
99
+ | ----------------------------- | --------------- | ---------------------------------------------------- |
100
+ | `state.activeSlideIndex()` | state -> attr | `[active-index]` host attribute |
101
+ | `state.isPaused()` | state -> attr | `[paused]` host attribute |
102
+ | `state.slideCount()` | state -> render | determines number of indicator buttons |
103
+ | `state.visibleSlideIndices()` | state -> render | determines `aria-hidden` and `data-active` on slides |
104
+
105
+ **Contract spreading:**
106
+
107
+ - `contracts.getRootProps()` is spread onto `[part="base"]` (`role`, `aria-roledescription`, `aria-label`, `aria-labelledby`, `aria-live`, focus/pointer handlers).
108
+ - `contracts.getSlideGroupProps()` is spread onto `[part="slides"]` (`role`, `aria-label`).
109
+ - `contracts.getSlideProps(index)` is spread onto each `cv-carousel-slide` element (`role`, `aria-roledescription`, `aria-label`, `aria-hidden`, `data-active`).
110
+ - `contracts.getPrevButtonProps()` is spread onto `[part="prev"]` (`aria-controls`, `aria-label`, `onClick`).
111
+ - `contracts.getNextButtonProps()` is spread onto `[part="next"]` (`aria-controls`, `aria-label`, `onClick`).
112
+ - `contracts.getPlayPauseButtonProps()` is spread onto `[part="play-pause"]` (`aria-controls`, `aria-label`, `onClick`). Returns `aria-label` only, no `aria-pressed` per W3C APG guidance.
113
+ - `contracts.getIndicatorProps(index)` is spread onto each `[part="indicator"]` (`aria-controls`, `aria-label`, `aria-current`, `data-active`, `onClick`).
114
+
115
+ **UIKit does NOT own:**
116
+
117
+ - Navigation logic (wrapping, clamping) -- headless `moveNext`/`movePrev`/`moveTo`.
118
+ - Autoplay timer lifecycle -- headless manages start/stop/resume.
119
+ - `aria-live` toggling -- headless sets `off` during autoplay, `polite` on manual navigation.
120
+ - Pause-on-focus / pause-on-hover -- headless focus/pointer handlers.
121
+
122
+ ## Keyboard Interaction
123
+
124
+ Keyboard events are delegated to `actions.handleKeyDown()`. The UIKit layer only prevents default on carousel-relevant keys.
125
+
126
+ | Key | Action |
127
+ | ------------ | ---------------------- |
128
+ | `ArrowRight` | Move to next slide |
129
+ | `ArrowLeft` | Move to previous slide |
130
+ | `Home` | Move to first slide |
131
+ | `End` | Move to last slide |
132
+
133
+ ## Swipe Gesture
134
+
135
+ The UIKit adapter provides basic horizontal swipe detection on the `[part="slides"]` area:
136
+
137
+ - A horizontal swipe right-to-left triggers `actions.moveNext()`.
138
+ - A horizontal swipe left-to-right triggers `actions.movePrev()`.
139
+ - Swipe detection uses `pointerdown` / `pointermove` / `pointerup` with a minimum distance threshold.
140
+ - Vertical scrolling is not intercepted; the gesture must be predominantly horizontal to trigger navigation.
141
+
142
+ This is a UIKit-only concern; the headless model does not handle touch/swipe.
143
+
144
+ ## Imperative API
145
+
146
+ | Method | Description |
147
+ | --------- | ------------------------- |
148
+ | `next()` | Advance to the next slide |
149
+ | `prev()` | Go to the previous slide |
150
+ | `play()` | Resume autoplay |
151
+ | `pause()` | Pause autoplay |
152
+
153
+ ## Usage
154
+
155
+ ```html
156
+ <!-- Basic carousel -->
157
+ <cv-carousel aria-label="Product gallery">
158
+ <cv-carousel-slide value="slide-1">Slide 1 content</cv-carousel-slide>
159
+ <cv-carousel-slide value="slide-2">Slide 2 content</cv-carousel-slide>
160
+ <cv-carousel-slide value="slide-3">Slide 3 content</cv-carousel-slide>
161
+ </cv-carousel>
162
+
163
+ <!-- Autoplay carousel -->
164
+ <cv-carousel aria-label="News feed" autoplay autoplay-interval="3000">
165
+ <cv-carousel-slide value="news-1">Breaking news</cv-carousel-slide>
166
+ <cv-carousel-slide value="news-2">Sports update</cv-carousel-slide>
167
+ </cv-carousel>
168
+
169
+ <!-- Multiple visible slides -->
170
+ <cv-carousel aria-label="Team members" visible-slides="3">
171
+ <cv-carousel-slide value="member-1">Alice</cv-carousel-slide>
172
+ <cv-carousel-slide value="member-2">Bob</cv-carousel-slide>
173
+ <cv-carousel-slide value="member-3">Charlie</cv-carousel-slide>
174
+ <cv-carousel-slide value="member-4">Diana</cv-carousel-slide>
175
+ </cv-carousel>
176
+
177
+ <!-- Controlled by value -->
178
+ <cv-carousel aria-label="Steps" value="step-2">
179
+ <cv-carousel-slide value="step-1">Step 1</cv-carousel-slide>
180
+ <cv-carousel-slide value="step-2">Step 2</cv-carousel-slide>
181
+ <cv-carousel-slide value="step-3">Step 3</cv-carousel-slide>
182
+ </cv-carousel>
183
+ ```
184
+
185
+ ## Child Elements
186
+
187
+ ### cv-carousel-slide
188
+
189
+ Individual slide within a carousel. The parent `cv-carousel` manages all ARIA attributes on this element via headless contracts.
190
+
191
+ #### Anatomy
192
+
193
+ ```
194
+ <cv-carousel-slide> (host)
195
+ └── <div part="base">
196
+ └── <slot>
197
+ ```
198
+
199
+ #### Attributes
200
+
201
+ | Attribute | Type | Default | Description |
202
+ | --------- | ------- | ------- | --------------------------------------------------------------------------- |
203
+ | `value` | String | `""` | Unique identifier for this slide. Auto-generated as `slide-{n}` if omitted. |
204
+ | `label` | String | `""` | Accessible label for the slide. Falls back to `textContent` if omitted. |
205
+ | `active` | Boolean | `false` | Whether this slide is currently active. Managed by parent. |
206
+
207
+ #### Slots
208
+
209
+ | Slot | Description |
210
+ | ----------- | ------------- |
211
+ | `(default)` | Slide content |
212
+
213
+ #### CSS Parts
214
+
215
+ | Part | Element | Description |
216
+ | ------ | ------- | ---------------------------------- |
217
+ | `base` | `<div>` | Root wrapper for the slide content |
218
+
219
+ #### CSS Custom Properties
220
+
221
+ | Property | Default | Description |
222
+ | -------------------------------- | --------------------------- | ------------------------------- |
223
+ | `--cv-carousel-slide-min-height` | `120px` | Minimum block size of the slide |
224
+ | `--cv-carousel-slide-padding` | `var(--cv-space-4, 16px)` | Padding inside the slide |
225
+ | `--cv-carousel-slide-radius` | `var(--cv-radius-md, 10px)` | Border radius of the slide |
226
+
227
+ #### Visual States
228
+
229
+ | Host selector | Description |
230
+ | ----------------- | ----------------------------------------------------------- |
231
+ | `:host([active])` | Slide is currently active; border uses `--cv-color-primary` |
232
+ | `:host([hidden])` | Slide is not visible; `display: none` |
@@ -0,0 +1,141 @@
1
+ # cv-checkbox
2
+
3
+ Two-state or three-state (indeterminate) toggle control with a visual indicator.
4
+
5
+ **Headless:** [`createCheckbox`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/checkbox.md)
6
+
7
+ ## Cross-Spec Consistency
8
+
9
+ This document is the UIKit surface contract for Checkbox.
10
+
11
+ - The canonical state model, invariants, and user-driven transitions are defined by the headless spec.
12
+ - Any intentional divergence between UIKit and headless MUST be explicitly documented in both specs to prevent drift.
13
+
14
+ ## Anatomy
15
+
16
+ ```
17
+ <cv-checkbox> (host)
18
+ └── <div part="base" role="checkbox">
19
+ ├── <span part="indicator">
20
+ │ └── <span part="checkmark">
21
+ └── <slot> ← label
22
+ ```
23
+
24
+ ## Attributes
25
+
26
+ | Attribute | Type | Default | Description |
27
+ | --------------- | ------- | ------- | -------------------------------------------------------------- |
28
+ | `checked` | Boolean | `false` | Checked state |
29
+ | `indeterminate` | Boolean | `false` | Indeterminate state (takes precedence over `checked` visually) |
30
+ | `disabled` | Boolean | `false` | Prevents interaction |
31
+ | `read-only` | Boolean | `false` | Visible but not toggleable |
32
+
33
+ ## Slots
34
+
35
+ | Slot | Description |
36
+ | ----------- | ------------------------------------------- |
37
+ | `(default)` | Label text or content next to the indicator |
38
+
39
+ ## CSS Parts
40
+
41
+ | Part | Element | Description |
42
+ | ----------- | -------- | ------------------------------------------------------------------------------- |
43
+ | `base` | `<div>` | Root interactive element with `role="checkbox"` |
44
+ | `indicator` | `<span>` | Box that contains the checkmark |
45
+ | `checkmark` | `<span>` | Visual mark inside the indicator (square when checked, line when indeterminate) |
46
+
47
+ ## CSS Custom Properties
48
+
49
+ No component-specific custom properties. Styling uses design tokens:
50
+
51
+ - `--cv-space-2` — gap between indicator and label
52
+ - `--cv-radius-sm` — indicator border radius
53
+ - `--cv-color-border` — indicator border color
54
+ - `--cv-color-surface` — indicator background
55
+ - `--cv-color-primary` — checked/indeterminate accent color
56
+ - `--cv-color-text` — label text color
57
+ - `--cv-duration-fast` — transition duration
58
+ - `--cv-easing-standard` — transition easing
59
+
60
+ ## Visual States
61
+
62
+ | Host selector | Description |
63
+ | ------------------------ | --------------------------------------------------------------- |
64
+ | `:host([checked])` | Primary-tinted indicator border and background, solid checkmark |
65
+ | `:host([indeterminate])` | Horizontal line checkmark (2px height, full width) |
66
+ | `:host([disabled])` | Reduced opacity (`0.55`), `cursor: not-allowed` |
67
+
68
+ ## ARIA
69
+
70
+ - When `checked=true` and `indeterminate=false`, `aria-checked="true"`.
71
+ - When `checked=false` and `indeterminate=true`, `aria-checked="mixed"`.
72
+ - When `checked=false` and `indeterminate=false`, `aria-checked="false"`.
73
+
74
+ ## State Invariants and Transitions
75
+
76
+ - Canonical conceptual states are exactly: `unchecked`, `checked`, `indeterminate`.
77
+ - If represented as booleans, `indeterminate=true` implies `checked=false`.
78
+ - User toggle transition: `indeterminate` -> `checked`.
79
+ - Disabled or read-only checkboxes do not respond to toggle actions.
80
+
81
+ ## Events
82
+
83
+ | Event | Detail | Description |
84
+ | ----------- | -------------------------------------------------------------- | ------------------------ |
85
+ | `cv-input` | `{ checked: boolean, indeterminate: boolean, value?: string }` | Fires on toggle |
86
+ | `cv-change` | `{ checked: boolean, indeterminate: boolean, value?: string }` | Fires when state commits |
87
+
88
+ ## Usage
89
+
90
+ ```html
91
+ <cv-checkbox>Accept terms</cv-checkbox>
92
+
93
+ <cv-checkbox checked>Remember me</cv-checkbox>
94
+
95
+ <cv-checkbox indeterminate>Select all (partial)</cv-checkbox>
96
+
97
+ <cv-checkbox disabled>Unavailable option</cv-checkbox>
98
+ ```
99
+
100
+ ## Migration Notes (Non-normative)
101
+
102
+ This section documents known terminology/payload changes and the breaking-change communication policy.
103
+
104
+ ### Terminology change: `mixed` -> `indeterminate`
105
+
106
+ - `indeterminate` is the canonical third-state term.
107
+ - `mixed` remains an ARIA token only (used exclusively in `aria-checked="mixed"`).
108
+
109
+ ### Payload change: legacy detail -> current detail
110
+
111
+ - Old (legacy docs): `{ value: boolean | "mixed", checked: boolean, mixed: boolean }`.
112
+ - New (current contract): `{ checked: boolean, indeterminate: boolean, value?: string }`.
113
+
114
+ Mappings:
115
+
116
+ - `value === "mixed"` or `mixed === true` -> `indeterminate=true` and `checked=false`.
117
+ - Prefer reading `indeterminate` and `checked` instead of interpreting `value`.
118
+
119
+ ### Breaking-change communication policy
120
+
121
+ This change is breaking for consumers that relied on legacy terminology (`mixed`) or the legacy event detail shape.
122
+
123
+ When this contract changes in a breaking way, this section MUST explicitly document:
124
+
125
+ - terminology changes (old term -> new term)
126
+ - payload shape changes (old shape -> new shape)
127
+ - a short statement that the change is breaking and requires consumer migration
128
+
129
+ ### Parity matrix (Headless vs UIKit)
130
+
131
+ This matrix is intentionally short and exists to prevent drift between `headless-ui/specs/components/checkbox.md` and `uikit/specs/components/checkbox.md`.
132
+
133
+ | Surface | Headless | UIKit |
134
+ | ---------------------------- | ------------------------------------------ | ---------------------------------------- |
135
+ | Canonical third-state term | `indeterminate` | `indeterminate` attribute + event detail |
136
+ | ARIA token for third state | `aria-checked="mixed"` only | `aria-checked="mixed"` only |
137
+ | State representation | `checked:boolean`, `indeterminate:boolean` | `checked`/`indeterminate` attributes |
138
+ | User toggle transition | `indeterminate` -> `checked` | `indeterminate` -> `checked` |
139
+ | Disabled/read-only semantics | cannot toggle | cannot toggle |
140
+ | Payload on user interaction | N/A (actions/state API) | `{ checked, indeterminate, value? }` |
141
+ | Form primitives | specified (see headless spec) | not specified on `cv-checkbox` surface |