@boxcustodia/library 2.0.0-alpha.10 → 2.0.0-alpha.12

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 (352) hide show
  1. package/dist/index.cjs.js +70 -70
  2. package/dist/index.css +2 -0
  3. package/dist/index.d.ts +420 -272
  4. package/dist/index.es.js +34448 -27816
  5. package/dist/theme.css +1 -1
  6. package/package.json +11 -6
  7. package/src/__doc__/Changelog.mdx +6 -0
  8. package/src/__doc__/Components.mdx +73 -0
  9. package/src/__doc__/Examples.tsx +69 -0
  10. package/src/__doc__/Icons.mdx +41 -0
  11. package/src/__doc__/Intro.mdx +138 -0
  12. package/src/__doc__/MCP.mdx +71 -0
  13. package/src/__doc__/Migration.mdx +475 -0
  14. package/src/__doc__/Theme.mdx +132 -0
  15. package/src/__doc__/Types.mdx +252 -0
  16. package/src/components/alert/alert.stories.tsx +142 -0
  17. package/src/components/alert/alert.tsx +109 -0
  18. package/src/components/alert/index.ts +7 -0
  19. package/src/components/alert-dialog/alert-dialog.stories.tsx +173 -0
  20. package/src/components/alert-dialog/alert-dialog.test.tsx +49 -0
  21. package/src/components/alert-dialog/alert-dialog.tsx +265 -0
  22. package/src/components/alert-dialog/index.ts +1 -0
  23. package/src/components/auto-complete/auto-complete-primitives.tsx +155 -0
  24. package/src/components/auto-complete/auto-complete.stories.tsx +241 -0
  25. package/src/components/auto-complete/auto-complete.tsx +82 -0
  26. package/src/components/auto-complete/index.ts +2 -0
  27. package/src/components/avatar/avatar.stories.tsx +84 -0
  28. package/src/components/avatar/avatar.test.tsx +61 -0
  29. package/src/components/avatar/avatar.tsx +104 -0
  30. package/src/components/avatar/index.ts +1 -0
  31. package/src/components/background-image/background-image.stories.tsx +21 -0
  32. package/src/components/background-image/background-image.test.tsx +29 -0
  33. package/src/components/background-image/background-image.tsx +23 -0
  34. package/src/components/background-image/index.ts +1 -0
  35. package/src/components/button/button.stories.tsx +396 -0
  36. package/src/components/button/button.test.tsx +58 -0
  37. package/src/components/button/button.tsx +31 -0
  38. package/src/components/button/button.variants.ts +44 -0
  39. package/src/components/button/components/base-button.tsx +86 -0
  40. package/src/components/button/components/loader-overlay.tsx +21 -0
  41. package/src/components/button/components/loading-icon.tsx +47 -0
  42. package/src/components/button/index.ts +3 -0
  43. package/src/components/calendar/calendar.model.ts +86 -0
  44. package/src/components/calendar/calendar.stories.tsx +155 -0
  45. package/src/components/calendar/calendar.test.tsx +12 -0
  46. package/src/components/calendar/calendar.tsx +185 -0
  47. package/src/components/calendar/components/calendar-navigation.tsx +141 -0
  48. package/src/components/calendar/components/day.tsx +61 -0
  49. package/src/components/calendar/components/decade-view.tsx +45 -0
  50. package/src/components/calendar/components/index.ts +6 -0
  51. package/src/components/calendar/components/month-view.tsx +58 -0
  52. package/src/components/calendar/components/week-days.tsx +27 -0
  53. package/src/components/calendar/components/year-view.tsx +29 -0
  54. package/src/components/calendar/hooks/index.ts +4 -0
  55. package/src/components/calendar/hooks/use-calendar-navigation.ts +79 -0
  56. package/src/components/calendar/hooks/use-calendar.ts +90 -0
  57. package/src/components/calendar/hooks/use-multiple-calendar.ts +34 -0
  58. package/src/components/calendar/hooks/use-range-calendar.ts +91 -0
  59. package/src/components/calendar/hooks/use-single-calendar.ts +18 -0
  60. package/src/components/calendar/index.ts +1 -0
  61. package/src/components/calendar/utils/typeguards.ts +7 -0
  62. package/src/components/card/card.stories.tsx +116 -0
  63. package/src/components/card/card.tsx +74 -0
  64. package/src/components/card/index.ts +1 -0
  65. package/src/components/center/center.stories.tsx +81 -0
  66. package/src/components/center/center.tsx +24 -0
  67. package/src/components/center/index.ts +1 -0
  68. package/src/components/checkbox/checkbox.stories.tsx +307 -0
  69. package/src/components/checkbox/checkbox.tsx +273 -0
  70. package/src/components/checkbox/index.ts +1 -0
  71. package/src/components/checkbox-group/checkbox-group.stories.tsx +104 -0
  72. package/src/components/checkbox-group/checkbox-group.tsx +16 -0
  73. package/src/components/checkbox-group/index.ts +1 -0
  74. package/src/components/combobox/combobox.stories.tsx +339 -0
  75. package/src/components/combobox/combobox.tsx +892 -0
  76. package/src/components/combobox/index.ts +1 -0
  77. package/src/components/date-picker/date-input.stories.tsx +158 -0
  78. package/src/components/date-picker/date-input.tsx +163 -0
  79. package/src/components/date-picker/date-picker.model.ts +90 -0
  80. package/src/components/date-picker/date-picker.stories.tsx +200 -0
  81. package/src/components/date-picker/date-picker.test.tsx +23 -0
  82. package/src/components/date-picker/date-picker.tsx +298 -0
  83. package/src/components/date-picker/date-picker.utils.ts +260 -0
  84. package/src/components/date-picker/index.ts +3 -0
  85. package/src/components/date-picker/use-date-input-popover.ts +48 -0
  86. package/src/components/date-picker/use-date-input.ts +125 -0
  87. package/src/components/dialog/dialog.stories.tsx +171 -0
  88. package/src/components/dialog/dialog.test.tsx +68 -0
  89. package/src/components/dialog/dialog.tsx +277 -0
  90. package/src/components/dialog/index.ts +1 -0
  91. package/src/components/divider/divider.stories.tsx +70 -0
  92. package/src/components/divider/divider.test.tsx +22 -0
  93. package/src/components/divider/divider.tsx +23 -0
  94. package/src/components/divider/index.ts +1 -0
  95. package/src/components/dropzone/dropzone.stories.tsx +210 -0
  96. package/src/components/dropzone/dropzone.tsx +154 -0
  97. package/src/components/dropzone/file-types.ts +64 -0
  98. package/src/components/dropzone/index.ts +3 -0
  99. package/src/components/dropzone/upload-primitives.tsx +310 -0
  100. package/src/components/dropzone/use-dropzone.ts +122 -0
  101. package/src/components/empty-state/empty-state.stories.tsx +56 -0
  102. package/src/components/empty-state/empty-state.tsx +39 -0
  103. package/src/components/empty-state/index.ts +1 -0
  104. package/src/components/field/field.stories.tsx +223 -0
  105. package/src/components/field/field.tsx +229 -0
  106. package/src/components/field/index.ts +1 -0
  107. package/src/components/form/form.stories.tsx +594 -0
  108. package/src/components/form/form.tsx +30 -0
  109. package/src/components/form/index.ts +1 -0
  110. package/src/components/heading/heading.stories.tsx +74 -0
  111. package/src/components/heading/heading.tsx +28 -0
  112. package/src/components/heading/heading.variants.ts +27 -0
  113. package/src/components/heading/index.ts +1 -0
  114. package/src/components/index.ts +46 -0
  115. package/src/components/input/index.ts +1 -0
  116. package/src/components/input/input.stories.tsx +104 -0
  117. package/src/components/input/input.tsx +75 -0
  118. package/src/components/kbd/index.ts +1 -0
  119. package/src/components/kbd/kbd.stories.tsx +40 -0
  120. package/src/components/kbd/kbd.tsx +31 -0
  121. package/src/components/kbd/kbd.variants.ts +26 -0
  122. package/src/components/label/index.ts +1 -0
  123. package/src/components/label/label.stories.tsx +68 -0
  124. package/src/components/label/label.test.tsx +61 -0
  125. package/src/components/label/label.tsx +62 -0
  126. package/src/components/loader/index.ts +1 -0
  127. package/src/components/loader/loader.stories.tsx +60 -0
  128. package/src/components/loader/loader.test.tsx +26 -0
  129. package/src/components/loader/loader.tsx +60 -0
  130. package/src/components/menu/index.ts +2 -0
  131. package/src/components/menu/menu-primitives.tsx +248 -0
  132. package/src/components/menu/menu.stories.tsx +203 -0
  133. package/src/components/menu/menu.tsx +100 -0
  134. package/src/components/menu/util/render-menu-item.tsx +54 -0
  135. package/src/components/multi-select/hooks/use-multi-select.ts +66 -0
  136. package/src/components/multi-select/index.ts +1 -0
  137. package/src/components/multi-select/multi-select.stories.tsx +294 -0
  138. package/src/components/multi-select/multi-select.tsx +300 -0
  139. package/src/components/multi-select/multi-select.variants.ts +22 -0
  140. package/src/components/number-input/index.ts +1 -0
  141. package/src/components/number-input/number-input.stories.tsx +209 -0
  142. package/src/components/number-input/number-input.test.tsx +87 -0
  143. package/src/components/number-input/number-input.tsx +230 -0
  144. package/src/components/pagination/components/pagination-option.tsx +27 -0
  145. package/src/components/pagination/index.ts +1 -0
  146. package/src/components/pagination/pagination.stories.tsx +80 -0
  147. package/src/components/pagination/pagination.test.tsx +76 -0
  148. package/src/components/pagination/pagination.tsx +102 -0
  149. package/src/components/password/index.ts +1 -0
  150. package/src/components/password/password.stories.tsx +104 -0
  151. package/src/components/password/password.tsx +71 -0
  152. package/src/components/popover/index.ts +1 -0
  153. package/src/components/popover/popover.stories.tsx +213 -0
  154. package/src/components/popover/popover.tsx +203 -0
  155. package/src/components/progress/index.ts +1 -0
  156. package/src/components/progress/progress.stories.tsx +124 -0
  157. package/src/components/progress/progress.test.tsx +25 -0
  158. package/src/components/progress/progress.tsx +124 -0
  159. package/src/components/scroll-area/index.ts +1 -0
  160. package/src/components/scroll-area/scroll-area.stories.tsx +166 -0
  161. package/src/components/scroll-area/scroll-area.tsx +64 -0
  162. package/src/components/select/index.ts +1 -0
  163. package/src/components/select/select.stories.tsx +253 -0
  164. package/src/components/select/select.tsx +430 -0
  165. package/src/components/show/index.ts +1 -0
  166. package/src/components/show/show.stories.tsx +197 -0
  167. package/src/components/show/show.test.tsx +41 -0
  168. package/src/components/show/show.tsx +16 -0
  169. package/src/components/skeleton/index.ts +1 -0
  170. package/src/components/skeleton/skeleton.stories.tsx +36 -0
  171. package/src/components/skeleton/skeleton.test.tsx +14 -0
  172. package/src/components/skeleton/skeleton.tsx +15 -0
  173. package/src/components/stack/index.ts +1 -0
  174. package/src/components/stack/stack.stories.tsx +194 -0
  175. package/src/components/stack/stack.tsx +52 -0
  176. package/src/components/stepper/Stepper.tsx +190 -0
  177. package/src/components/stepper/context/stepper-context.tsx +11 -0
  178. package/src/components/stepper/index.ts +1 -0
  179. package/src/components/stepper/stepper.stories.tsx +130 -0
  180. package/src/components/stepper/stepper.test.tsx +91 -0
  181. package/src/components/switch/index.ts +1 -0
  182. package/src/components/switch/switch.stories.tsx +122 -0
  183. package/src/components/switch/switch.test.tsx +30 -0
  184. package/src/components/switch/switch.tsx +86 -0
  185. package/src/components/table/index.ts +3 -0
  186. package/src/components/table/table-primitives.tsx +122 -0
  187. package/src/components/table/table.model.ts +20 -0
  188. package/src/components/table/table.stories.tsx +169 -0
  189. package/src/components/table/table.test.tsx +91 -0
  190. package/src/components/table/table.tsx +109 -0
  191. package/src/components/table-pagination/index.ts +2 -0
  192. package/src/components/table-pagination/table-pagination.model.ts +2 -0
  193. package/src/components/table-pagination/table-pagination.stories.tsx +23 -0
  194. package/src/components/table-pagination/table-pagination.test.tsx +32 -0
  195. package/src/components/table-pagination/table-pagination.tsx +108 -0
  196. package/src/components/tabs/context/tabs-context.tsx +14 -0
  197. package/src/components/tabs/index.ts +1 -0
  198. package/src/components/tabs/tabs.stories.tsx +182 -0
  199. package/src/components/tabs/tabs.test.tsx +61 -0
  200. package/src/components/tabs/tabs.tsx +175 -0
  201. package/src/components/tag/index.ts +2 -0
  202. package/src/components/tag/tag.stories.tsx +170 -0
  203. package/src/components/tag/tag.test.tsx +18 -0
  204. package/src/components/tag/tag.tsx +99 -0
  205. package/src/components/tag/tag.variants.ts +31 -0
  206. package/src/components/textarea/index.ts +1 -0
  207. package/src/components/textarea/textarea.stories.tsx +73 -0
  208. package/src/components/textarea/textarea.tsx +105 -0
  209. package/src/components/timeline/index.ts +1 -0
  210. package/src/components/timeline/timeline-status.ts +5 -0
  211. package/src/components/timeline/timeline.stories.tsx +84 -0
  212. package/src/components/timeline/timeline.tsx +147 -0
  213. package/src/components/toast/index.ts +1 -0
  214. package/src/components/toast/toast.stories.tsx +392 -0
  215. package/src/components/toast/toast.test.tsx +50 -0
  216. package/src/components/toast/toast.tsx +411 -0
  217. package/src/components/tooltip/index.ts +1 -0
  218. package/src/components/tooltip/tooltip.stories.tsx +226 -0
  219. package/src/components/tooltip/tooltip.test.tsx +46 -0
  220. package/src/components/tooltip/tooltip.tsx +171 -0
  221. package/src/components/tree/hooks/use-controllable-tree-state.ts +80 -0
  222. package/src/components/tree/index.ts +2 -0
  223. package/src/components/tree/tree-primitives.tsx +126 -0
  224. package/src/components/tree/tree.stories.tsx +468 -0
  225. package/src/components/tree/tree.tsx +42 -0
  226. package/src/hooks/index.ts +26 -0
  227. package/src/hooks/useArray/__doc__/useArray.stories.tsx +100 -0
  228. package/src/hooks/useArray/__test__/useArray.test.tsx +88 -0
  229. package/src/hooks/useArray/index.ts +1 -0
  230. package/src/hooks/useArray/useArray.ts +76 -0
  231. package/src/hooks/useAsync/__doc__/useAsync.stories.tsx +149 -0
  232. package/src/hooks/useAsync/__test__/useAsync.test.tsx +68 -0
  233. package/src/hooks/useAsync/index.ts +1 -0
  234. package/src/hooks/useAsync/useAsync.ts +58 -0
  235. package/src/hooks/useClickOutside/__doc__/useClickOutside.stories.tsx +40 -0
  236. package/src/hooks/useClickOutside/__test__/useClickOutside.test.tsx +33 -0
  237. package/src/hooks/useClickOutside/index.ts +1 -0
  238. package/src/hooks/useClickOutside/useClickOutside.ts +26 -0
  239. package/src/hooks/useClipboard/__doc__/useClipboard.stories.tsx +45 -0
  240. package/src/hooks/useClipboard/__test__/useClipboard.test.tsx +19 -0
  241. package/src/hooks/useClipboard/index.ts +1 -0
  242. package/src/hooks/useClipboard/useClipboard.tsx +28 -0
  243. package/src/hooks/useDebounceCallback/__doc__/useDebouncedCallback.stories.tsx +84 -0
  244. package/src/hooks/useDebounceCallback/index.ts +1 -0
  245. package/src/hooks/useDebounceCallback/useDebouncedCallback.ts +23 -0
  246. package/src/hooks/useDebounceValue/__doc__/useDebouncedValue.stories.tsx +75 -0
  247. package/src/hooks/useDebounceValue/index.ts +1 -0
  248. package/src/hooks/useDebounceValue/useDebouncedValue.ts +17 -0
  249. package/src/hooks/useDisclosure/__doc__/useDisclosure.stories.tsx +39 -0
  250. package/src/hooks/useDisclosure/__test__/useDisclosure.test.ts +43 -0
  251. package/src/hooks/useDisclosure/index.ts +1 -0
  252. package/src/hooks/useDisclosure/useDisclosure.ts +37 -0
  253. package/src/hooks/useDocumentTitle/__doc__/useDocumentTitle.stories.tsx +26 -0
  254. package/src/hooks/useDocumentTitle/index.ts +1 -0
  255. package/src/hooks/useDocumentTitle/useDocumentTitle.tsx +11 -0
  256. package/src/hooks/useEventListener/__doc__/useEventListener.stories.tsx +28 -0
  257. package/src/hooks/useEventListener/__test__/useEventListener.test.tsx +26 -0
  258. package/src/hooks/useEventListener/index.ts +1 -0
  259. package/src/hooks/useEventListener/useEventListener.ts +25 -0
  260. package/src/hooks/useFocusTrap/__doc__/useFocusTrap.stories.tsx +37 -0
  261. package/src/hooks/useFocusTrap/index.ts +1 -0
  262. package/src/hooks/useFocusTrap/scopeTab.ts +38 -0
  263. package/src/hooks/useFocusTrap/tabbable.ts +70 -0
  264. package/src/hooks/useFocusTrap/useFocusTrap.ts +78 -0
  265. package/src/hooks/useHotkey/__docs__/useHotkey.stories.tsx +116 -0
  266. package/src/hooks/useHotkey/__test__/useHotkey.test.tsx +105 -0
  267. package/src/hooks/useHotkey/__utils__/create-hotkey-listener.ts +25 -0
  268. package/src/hooks/useHotkey/__utils__/index.ts +3 -0
  269. package/src/hooks/useHotkey/__utils__/is-input-field.ts +14 -0
  270. package/src/hooks/useHotkey/__utils__/match-key-modifiers.ts +25 -0
  271. package/src/hooks/useHotkey/index.ts +1 -0
  272. package/src/hooks/useHotkey/useHotkey.ts +34 -0
  273. package/src/hooks/useHover/__doc__/useHover.stories.tsx +41 -0
  274. package/src/hooks/useHover/__test__/useHover.test.tsx +45 -0
  275. package/src/hooks/useHover/index.ts +1 -0
  276. package/src/hooks/useHover/useHover.tsx +40 -0
  277. package/src/hooks/useIsVisible/__doc__/useIsVisible.stories.tsx +60 -0
  278. package/src/hooks/useIsVisible/index.ts +1 -0
  279. package/src/hooks/useIsVisible/useIsVisible.tsx +50 -0
  280. package/src/hooks/useLocalStorage/__doc__/useLocalStorage.stories.tsx +86 -0
  281. package/src/hooks/useLocalStorage/__test__/useLocalStorage.test.ts +85 -0
  282. package/src/hooks/useLocalStorage/index.ts +1 -0
  283. package/src/hooks/useLocalStorage/useLocalStorage.ts +57 -0
  284. package/src/hooks/useMediaQuery/__doc__/useMediaQuery.stories.tsx +39 -0
  285. package/src/hooks/useMediaQuery/index.ts +1 -0
  286. package/src/hooks/useMediaQuery/useMediaQuery.ts +22 -0
  287. package/src/hooks/useMemoizedFn/index.ts +1 -0
  288. package/src/hooks/useMemoizedFn/useMemoizedFn.ts +32 -0
  289. package/src/hooks/useMutation/__doc__/useMutation.stories.tsx +111 -0
  290. package/src/hooks/useMutation/__test__/useMutation.test.tsx +83 -0
  291. package/src/hooks/useMutation/index.ts +1 -0
  292. package/src/hooks/useMutation/useMutation.tsx +60 -0
  293. package/src/hooks/useObject/__doc__/useObject.stories.tsx +119 -0
  294. package/src/hooks/useObject/__test__/useObject.test.tsx +87 -0
  295. package/src/hooks/useObject/index.ts +1 -0
  296. package/src/hooks/useObject/useObject.tsx +48 -0
  297. package/src/hooks/usePagination/__doc__/usePagination.stories.tsx +72 -0
  298. package/src/hooks/usePagination/__test__/usePagination.test.tsx +98 -0
  299. package/src/hooks/usePagination/index.ts +2 -0
  300. package/src/hooks/usePagination/usePagination.tsx +74 -0
  301. package/src/hooks/usePortal/__doc__/usePortal.stories.tsx +19 -0
  302. package/src/hooks/usePortal/__test__/usePortal.test.tsx +20 -0
  303. package/src/hooks/usePortal/index.ts +1 -0
  304. package/src/hooks/usePortal/usePortal.ts +40 -0
  305. package/src/hooks/usePreventCloseWindow/__doc__/usePreventCloseWindow.stories.tsx +32 -0
  306. package/src/hooks/usePreventCloseWindow/index.ts +1 -0
  307. package/src/hooks/usePreventCloseWindow/usePreventCloseWindow.ts +33 -0
  308. package/src/hooks/useRangePagination/__test__/useRangePagination.test.tsx +63 -0
  309. package/src/hooks/useRangePagination/index.ts +2 -0
  310. package/src/hooks/useRangePagination/useRangePagination.tsx +72 -0
  311. package/src/hooks/useSelection/__doc__/useSelection.stories.tsx +140 -0
  312. package/src/hooks/useSelection/__test__/useSelection.test.tsx +57 -0
  313. package/src/hooks/useSelection/index.ts +1 -0
  314. package/src/hooks/useSelection/useSelection.ts +121 -0
  315. package/src/hooks/useStep/__doc__/useStep.stories.tsx +98 -0
  316. package/src/hooks/useStep/__test__/useStep.test.ts +51 -0
  317. package/src/hooks/useStep/index.ts +1 -0
  318. package/src/hooks/useStep/useStep.ts +57 -0
  319. package/src/hooks/useToggle/__doc__/useToggle.stories.tsx +25 -0
  320. package/src/hooks/useToggle/__test__/useToggle.test.tsx +43 -0
  321. package/src/hooks/useToggle/index.ts +1 -0
  322. package/src/hooks/useToggle/useToggle.ts +16 -0
  323. package/src/index.ts +6 -0
  324. package/src/lib/cn.ts +8 -0
  325. package/src/lib/index.ts +1 -0
  326. package/src/models/Generic.model.ts +67 -0
  327. package/src/models/index.ts +1 -0
  328. package/src/providers/index.ts +2 -0
  329. package/src/providers/library-provider.tsx +44 -0
  330. package/src/providers/theme/ThemeProvider.tsx +25 -0
  331. package/src/providers/theme/index.ts +3 -0
  332. package/src/providers/theme/types.ts +11 -0
  333. package/src/providers/theme/useThemeProps.ts +25 -0
  334. package/src/stores/theme.store.ts +31 -0
  335. package/src/styles/components.css +4 -0
  336. package/src/styles/index.css +2 -0
  337. package/src/styles/library.css +2 -0
  338. package/src/styles/theme.css +232 -0
  339. package/src/utils/dates/parseDateRange.utility.ts +39 -0
  340. package/src/utils/form.tsx +91 -0
  341. package/src/utils/functions/createSafeContext.ts +17 -0
  342. package/src/utils/functions/ensureReactElement.tsx +30 -0
  343. package/src/utils/functions/getFormData.ts +19 -0
  344. package/src/utils/functions/index.ts +4 -0
  345. package/src/utils/functions/mergeRefs.ts +18 -0
  346. package/src/utils/index.ts +3 -0
  347. package/src/utils/strings/extractInitials.utility.ts +10 -0
  348. package/src/utils/strings/index.ts +1 -0
  349. package/src/utils/tests/click.ts +3 -0
  350. package/src/utils/tests/index.ts +2 -0
  351. package/src/utils/tests/keyboard.ts +21 -0
  352. package/src/utils/tests/type.ts +6 -0
@@ -0,0 +1,104 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { useState } from "react";
3
+ import { Checkbox } from "../checkbox";
4
+ import { CheckboxGroup } from "./checkbox-group";
5
+
6
+ /**
7
+ * CheckboxGroup manages a set of `Checkbox` components as a single value
8
+ * (`string[]`). Each child `Checkbox` must receive a `value` prop to be
9
+ * tracked by the group.
10
+ *
11
+ * Use `defaultValue` for uncontrolled mode or `value` + `onValueChange` for
12
+ * controlled mode. Pass `allValues` to enable the parent checkbox pattern:
13
+ * a `Checkbox` with `parent` will automatically toggle between checked,
14
+ * unchecked, and indeterminate based on how many items are selected — no manual
15
+ * state needed.
16
+ */
17
+ const meta: Meta<typeof CheckboxGroup> = {
18
+ title: "Components/CheckboxGroup",
19
+ component: CheckboxGroup,
20
+ };
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof CheckboxGroup>;
24
+
25
+ const NOTIFICATIONS = [
26
+ { label: "Comments on my posts", value: "comments" },
27
+ { label: "Mentions", value: "mentions" },
28
+ { label: "Direct messages", value: "messages" },
29
+ { label: "System updates", value: "system" },
30
+ ];
31
+
32
+ export const Default: Story = {
33
+ render: () => (
34
+ <CheckboxGroup defaultValue={["comments"]}>
35
+ {NOTIFICATIONS.map(({ label, value }) => (
36
+ <Checkbox.Item key={value} value={value} label={label} />
37
+ ))}
38
+ </CheckboxGroup>
39
+ ),
40
+ };
41
+
42
+ /**
43
+ * `value` + `onValueChange` for controlled mode. `onValueChange` receives the
44
+ * updated array of selected values.
45
+ */
46
+ export const Controlled: Story = {
47
+ render: () => {
48
+ const [value, setValue] = useState<string[]>(["comments", "mentions"]);
49
+
50
+ return (
51
+ <div className="space-y-4">
52
+ <CheckboxGroup value={value} onValueChange={setValue}>
53
+ {NOTIFICATIONS.map(({ label, value: v }) => (
54
+ <Checkbox.Item key={v} value={v} label={label} />
55
+ ))}
56
+ </CheckboxGroup>
57
+ <p className="text-sm text-muted-foreground">
58
+ Active: {value.length > 0 ? value.join(", ") : "none"}
59
+ </p>
60
+ </div>
61
+ );
62
+ },
63
+ };
64
+
65
+ /**
66
+ * `allValues` enables the parent checkbox pattern. The `Checkbox` with `parent`
67
+ * computes its state automatically: checked when all items are selected,
68
+ * unchecked when none, indeterminate on partial selection — no manual state
69
+ * needed.
70
+ */
71
+ export const WithParent: Story = {
72
+ render: () => {
73
+ const allValues = NOTIFICATIONS.map((n) => n.value);
74
+ const [value, setValue] = useState<string[]>(["comments"]);
75
+
76
+ return (
77
+ <CheckboxGroup
78
+ value={value}
79
+ onValueChange={setValue}
80
+ allValues={allValues}
81
+ >
82
+ <div className="flex items-center gap-2">
83
+ <Checkbox parent />
84
+ <span className="text-sm select-none">Enable all notifications</span>
85
+ </div>
86
+ <div className="ml-6 flex flex-col gap-3 border-l-2 pl-4">
87
+ {NOTIFICATIONS.map(({ label, value: v }) => (
88
+ <Checkbox.Item key={v} value={v} label={label} />
89
+ ))}
90
+ </div>
91
+ </CheckboxGroup>
92
+ );
93
+ },
94
+ };
95
+
96
+ export const Disabled: Story = {
97
+ render: () => (
98
+ <CheckboxGroup defaultValue={["comments"]} disabled>
99
+ {NOTIFICATIONS.map(({ label, value }) => (
100
+ <Checkbox.Item key={value} value={value} label={label} />
101
+ ))}
102
+ </CheckboxGroup>
103
+ ),
104
+ };
@@ -0,0 +1,16 @@
1
+ import { CheckboxGroup as CheckboxGroupPrimitive } from "@base-ui/react/checkbox-group";
2
+ import type * as React from "react";
3
+ import { cn } from "../../lib";
4
+
5
+ export function CheckboxGroup({
6
+ className,
7
+ ...props
8
+ }: CheckboxGroupPrimitive.Props): React.ReactElement {
9
+ return (
10
+ <CheckboxGroupPrimitive
11
+ className={cn("flex flex-col items-start gap-3", className)}
12
+ data-slot="checkbox-group"
13
+ {...props}
14
+ />
15
+ );
16
+ }
@@ -0,0 +1 @@
1
+ export * from "./checkbox-group";
@@ -0,0 +1,339 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { useState } from "react";
3
+ import { Button } from "../button";
4
+ import { Field } from "../field";
5
+ import { Form } from "../form";
6
+ import {
7
+ Combobox,
8
+ ComboboxChip,
9
+ ComboboxChips,
10
+ ComboboxChipsInput,
11
+ ComboboxEmpty,
12
+ ComboboxInput,
13
+ ComboboxItem,
14
+ ComboboxList,
15
+ ComboboxPopup,
16
+ ComboboxRoot,
17
+ ComboboxValue,
18
+ } from "./combobox";
19
+
20
+ interface Item {
21
+ label: string;
22
+ value: string;
23
+ }
24
+
25
+ const items: Item[] = [
26
+ { label: "Apple", value: "apple" },
27
+ { label: "Banana", value: "banana" },
28
+ { label: "Orange", value: "orange" },
29
+ { label: "Grape", value: "grape" },
30
+ { label: "Strawberry", value: "strawberry" },
31
+ { label: "Mango", value: "mango" },
32
+ { label: "Pineapple", value: "pineapple" },
33
+ { label: "Kiwi", value: "kiwi" },
34
+ { label: "Peach", value: "peach" },
35
+ { label: "Pear", value: "pear" },
36
+ ];
37
+
38
+ /**
39
+ * Composite combobox supporting single and multiple selection, built on Base UI.
40
+ *
41
+ * Renders a text input as the trigger. `multiple` mode renders a chip input that
42
+ * fits as many chips as the container allows — extras show as "+N más". Items shaped
43
+ * as `{ label, value }` or plain strings/numbers need no extra props; provide
44
+ * `getLabel` / `getValue` for other shapes.
45
+ *
46
+ * `showClear` (default `true`) shows a clear button when a value is selected —
47
+ * in single mode the chevron switches to X; in multiple mode only X appears.
48
+ *
49
+ * `renderItem` customizes the content inside each dropdown item — the checkmark
50
+ * indicator is always rendered by the item wrapper.
51
+ *
52
+ * Exposes `onChange` instead of Base UI's `onValueChange`. For controlled usage,
53
+ * pass `value` + `onChange` together. Use `ComboboxRoot` + primitives for full
54
+ * structural control beyond what escape-hatch props (`inputProps`, `popupProps`,
55
+ * etc.) offer.
56
+ *
57
+ * Reference: [Combobox – Base UI](https://base-ui.com/react/components/combobox)
58
+ */
59
+ const meta: Meta<typeof Combobox> = {
60
+ title: "Components/Combobox",
61
+ component: Combobox,
62
+ parameters: { layout: "centered" },
63
+ decorators: [
64
+ (Story) => (
65
+ <div className="w-84">
66
+ <Story />
67
+ </div>
68
+ ),
69
+ ],
70
+ argTypes: {
71
+ onChange: { control: false },
72
+ onOpenChange: { control: false },
73
+ onInputValueChange: { control: false },
74
+ onItemHighlighted: { control: false },
75
+ getLabel: { control: false },
76
+ getValue: { control: false },
77
+ renderItem: { control: false },
78
+ inputProps: { control: false },
79
+ chipsProps: { control: false },
80
+ chipsInputProps: { control: false },
81
+ popupProps: { control: false },
82
+ itemProps: { control: false },
83
+ listProps: { control: false },
84
+ },
85
+ };
86
+
87
+ export default meta;
88
+ type Story = StoryObj<typeof Combobox>;
89
+
90
+ // ─── Composite stories ────────────────────────────────────────────────────────
91
+
92
+ export const Default: Story = {
93
+ render: () => <Combobox<Item> items={items} placeholder="Select a fruit…" />,
94
+ };
95
+
96
+ /**
97
+ * Fully controlled: selection state lives outside the component.
98
+ * Omitting `onChange` while providing `value` locks the selection.
99
+ */
100
+ export const Controlled: Story = {
101
+ render: () => {
102
+ const [value, setValue] = useState<Item | null>(null);
103
+ return (
104
+ <div className="flex flex-col gap-4">
105
+ <Combobox<Item>
106
+ items={items}
107
+ placeholder="Select a fruit…"
108
+ value={value}
109
+ onChange={setValue}
110
+ />
111
+ <p className="text-sm text-muted-foreground">
112
+ Selected: {value ? value.label : "none"}
113
+ </p>
114
+ </div>
115
+ );
116
+ },
117
+ };
118
+
119
+ export const Multiple: Story = {
120
+ render: () => (
121
+ <Combobox<Item> items={items} multiple placeholder="Select fruits…" />
122
+ ),
123
+ };
124
+
125
+ interface TechItem {
126
+ label: string;
127
+ value: string;
128
+ emoji: string;
129
+ description: string;
130
+ }
131
+
132
+ const TECH_ITEMS: TechItem[] = [
133
+ {
134
+ label: "TypeScript",
135
+ value: "typescript",
136
+ emoji: "🔷",
137
+ description: "Typed JavaScript superset",
138
+ },
139
+ {
140
+ label: "Python",
141
+ value: "python",
142
+ emoji: "🐍",
143
+ description: "General-purpose scripting",
144
+ },
145
+ {
146
+ label: "Rust",
147
+ value: "rust",
148
+ emoji: "⚙",
149
+ description: "Memory-safe systems language",
150
+ },
151
+ {
152
+ label: "Go",
153
+ value: "go",
154
+ emoji: "🔵",
155
+ description: "Concurrent, cloud-native",
156
+ },
157
+ {
158
+ label: "Swift",
159
+ value: "swift",
160
+ emoji: "🧡",
161
+ description: "Apple platforms",
162
+ },
163
+ {
164
+ label: "Kotlin",
165
+ value: "kotlin",
166
+ emoji: "🟣",
167
+ description: "JVM + Android",
168
+ },
169
+ ];
170
+
171
+ /**
172
+ * `renderItem` controls the content **inside** each `ComboboxItem` — the
173
+ * checkmark indicator is always rendered by the item wrapper. Use it to show
174
+ * rich content: icons, subtitles, badges, or avatars alongside the label.
175
+ */
176
+ export const WithRenderItem: Story = {
177
+ render: () => (
178
+ <Combobox<TechItem>
179
+ items={TECH_ITEMS}
180
+ placeholder="Select a language…"
181
+ renderItem={(item) => (
182
+ <span className="flex items-center gap-2.5 py-0.5">
183
+ <span className="text-base leading-none">{item.emoji}</span>
184
+ <span className="flex flex-col gap-0.5">
185
+ <span className="text-sm font-medium leading-none">
186
+ {item.label}
187
+ </span>
188
+ <span className="text-xs leading-none text-muted-foreground">
189
+ {item.description}
190
+ </span>
191
+ </span>
192
+ </span>
193
+ )}
194
+ />
195
+ ),
196
+ };
197
+
198
+ /**
199
+ * Plain strings require no extra props — `getLabel` and `getValue` default to
200
+ * `String(item)` when items are primitives.
201
+ */
202
+ export const StringItems: Story = {
203
+ render: () => (
204
+ <Combobox
205
+ items={["Apple", "Banana", "Orange", "Grape", "Strawberry"]}
206
+ placeholder="Select a fruit…"
207
+ />
208
+ ),
209
+ };
210
+
211
+ export const LibraryForm: Story = {
212
+ name: "Form",
213
+ render: () => {
214
+ return (
215
+ <Form className="space-y-1" onSubmit={console.log}>
216
+ <Field name="fruit" label="Fruits">
217
+ <Combobox items={items} required />
218
+ </Field>
219
+ <Button type="submit">Submit</Button>
220
+ </Form>
221
+ );
222
+ },
223
+ };
224
+
225
+ // ─── Primitive stories ────────────────────────────────────────────────────────
226
+
227
+ /**
228
+ * Fully controlled single selection using primitives. Use this pattern when
229
+ * composite escape-hatch props (`inputProps`, `popupProps`, etc.) are not
230
+ * enough — for example to insert custom elements between parts, swap the input
231
+ * for a select-style trigger (`ComboboxSelectTrigger`), or add a search input
232
+ * inside the popup (`ComboboxSearchInput`).
233
+ *
234
+ * `ComboboxRoot` requires `items` so Base UI can manage the hidden form input
235
+ * and built-in filtering. `itemToStringLabel` / `itemToStringValue` are
236
+ * inferred automatically for `{ label, value }` shapes.
237
+ *
238
+ * ```tsx
239
+ * <ComboboxRoot items={items} value={value} onChange={setValue}>
240
+ * <ComboboxInput placeholder="…" />
241
+ * <ComboboxPopup>
242
+ * <ComboboxEmpty>No items found.</ComboboxEmpty>
243
+ * <ComboboxList>
244
+ * {(item) => (
245
+ * <ComboboxItem key={item.value} value={item}>
246
+ * {item.label}
247
+ * </ComboboxItem>
248
+ * )}
249
+ * </ComboboxList>
250
+ * </ComboboxPopup>
251
+ * </ComboboxRoot>
252
+ * ```
253
+ */
254
+ export const PrimitiveControlled: Story = {
255
+ render: () => {
256
+ const [value, setValue] = useState<Item | null>(null);
257
+ return (
258
+ <div className="flex flex-col gap-4">
259
+ <ComboboxRoot items={items} value={value} onChange={setValue}>
260
+ <ComboboxInput
261
+ aria-label="Select a fruit"
262
+ placeholder="Select a fruit…"
263
+ />
264
+ <ComboboxPopup>
265
+ <ComboboxEmpty>No items found.</ComboboxEmpty>
266
+ <ComboboxList>
267
+ {(item: Item) => (
268
+ <ComboboxItem key={item.value} value={item}>
269
+ {item.label}
270
+ </ComboboxItem>
271
+ )}
272
+ </ComboboxList>
273
+ </ComboboxPopup>
274
+ </ComboboxRoot>
275
+ <p className="text-sm text-muted-foreground">
276
+ Selected: {value ? value.label : "none"}
277
+ </p>
278
+ </div>
279
+ );
280
+ },
281
+ };
282
+
283
+ /**
284
+ * Multiple selection using primitives. `ComboboxChipsInput` must be placed
285
+ * inside the `ComboboxValue` render function so it always sits after the last chip.
286
+ *
287
+ * ```tsx
288
+ * <ComboboxRoot items={items} multiple>
289
+ * <ComboboxChips>
290
+ * <ComboboxValue>
291
+ * {(value: Item[]) => (
292
+ * <>
293
+ * {value.map((item) => (
294
+ * <ComboboxChip key={item.value} aria-label={item.label}>
295
+ * {item.label}
296
+ * </ComboboxChip>
297
+ * ))}
298
+ * <ComboboxChipsInput placeholder={value.length === 0 ? "Select..." : undefined} />
299
+ * </>
300
+ * )}
301
+ * </ComboboxValue>
302
+ * </ComboboxChips>
303
+ * <ComboboxPopup>...</ComboboxPopup>
304
+ * </ComboboxRoot>
305
+ * ```
306
+ */
307
+ export const PrimitiveMultiple: Story = {
308
+ render: () => (
309
+ <ComboboxRoot items={items} multiple loopFocus>
310
+ <ComboboxChips>
311
+ <ComboboxValue>
312
+ {(value: Item[]) => (
313
+ <>
314
+ {value.map((item) => (
315
+ <ComboboxChip aria-label={item.label} key={item.value}>
316
+ {item.label}
317
+ </ComboboxChip>
318
+ ))}
319
+ <ComboboxChipsInput
320
+ aria-label="Select a fruit"
321
+ placeholder={value.length > 0 ? undefined : "Select a fruit…"}
322
+ />
323
+ </>
324
+ )}
325
+ </ComboboxValue>
326
+ </ComboboxChips>
327
+ <ComboboxPopup>
328
+ <ComboboxEmpty>No items found.</ComboboxEmpty>
329
+ <ComboboxList>
330
+ {(item: Item) => (
331
+ <ComboboxItem key={item.value} value={item}>
332
+ {item.label}
333
+ </ComboboxItem>
334
+ )}
335
+ </ComboboxList>
336
+ </ComboboxPopup>
337
+ </ComboboxRoot>
338
+ ),
339
+ };