@boxcustodia/library 2.0.0-alpha.11 → 2.0.0-alpha.13

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 +38 -38
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +28 -29
  4. package/dist/index.es.js +6804 -6792
  5. package/package.json +4 -3
  6. package/src/__doc__/Changelog.mdx +6 -0
  7. package/src/__doc__/Components.mdx +73 -0
  8. package/src/__doc__/Examples.tsx +69 -0
  9. package/src/__doc__/Icons.mdx +41 -0
  10. package/src/__doc__/Intro.mdx +138 -0
  11. package/src/__doc__/MCP.mdx +71 -0
  12. package/src/__doc__/Migration.mdx +451 -0
  13. package/src/__doc__/Theme.mdx +132 -0
  14. package/src/__doc__/Types.mdx +252 -0
  15. package/src/components/alert/alert.stories.tsx +142 -0
  16. package/src/components/alert/alert.tsx +109 -0
  17. package/src/components/alert/index.ts +7 -0
  18. package/src/components/alert-dialog/alert-dialog.stories.tsx +173 -0
  19. package/src/components/alert-dialog/alert-dialog.test.tsx +49 -0
  20. package/src/components/alert-dialog/alert-dialog.tsx +265 -0
  21. package/src/components/alert-dialog/index.ts +1 -0
  22. package/src/components/auto-complete/auto-complete-primitives.tsx +155 -0
  23. package/src/components/auto-complete/auto-complete.stories.tsx +241 -0
  24. package/src/components/auto-complete/auto-complete.tsx +82 -0
  25. package/src/components/auto-complete/index.ts +2 -0
  26. package/src/components/avatar/avatar.stories.tsx +84 -0
  27. package/src/components/avatar/avatar.test.tsx +61 -0
  28. package/src/components/avatar/avatar.tsx +104 -0
  29. package/src/components/avatar/index.ts +1 -0
  30. package/src/components/background-image/background-image.stories.tsx +21 -0
  31. package/src/components/background-image/background-image.test.tsx +29 -0
  32. package/src/components/background-image/background-image.tsx +23 -0
  33. package/src/components/background-image/index.ts +1 -0
  34. package/src/components/button/button.stories.tsx +396 -0
  35. package/src/components/button/button.test.tsx +58 -0
  36. package/src/components/button/button.tsx +31 -0
  37. package/src/components/button/button.variants.ts +44 -0
  38. package/src/components/button/components/base-button.tsx +86 -0
  39. package/src/components/button/components/loader-overlay.tsx +21 -0
  40. package/src/components/button/components/loading-icon.tsx +47 -0
  41. package/src/components/button/index.ts +3 -0
  42. package/src/components/calendar/calendar.model.ts +86 -0
  43. package/src/components/calendar/calendar.stories.tsx +155 -0
  44. package/src/components/calendar/calendar.test.tsx +12 -0
  45. package/src/components/calendar/calendar.tsx +185 -0
  46. package/src/components/calendar/components/calendar-navigation.tsx +141 -0
  47. package/src/components/calendar/components/day.tsx +61 -0
  48. package/src/components/calendar/components/decade-view.tsx +45 -0
  49. package/src/components/calendar/components/index.ts +6 -0
  50. package/src/components/calendar/components/month-view.tsx +58 -0
  51. package/src/components/calendar/components/week-days.tsx +27 -0
  52. package/src/components/calendar/components/year-view.tsx +29 -0
  53. package/src/components/calendar/hooks/index.ts +4 -0
  54. package/src/components/calendar/hooks/use-calendar-navigation.ts +79 -0
  55. package/src/components/calendar/hooks/use-calendar.ts +90 -0
  56. package/src/components/calendar/hooks/use-multiple-calendar.ts +34 -0
  57. package/src/components/calendar/hooks/use-range-calendar.ts +91 -0
  58. package/src/components/calendar/hooks/use-single-calendar.ts +18 -0
  59. package/src/components/calendar/index.ts +1 -0
  60. package/src/components/calendar/utils/typeguards.ts +7 -0
  61. package/src/components/card/card.stories.tsx +116 -0
  62. package/src/components/card/card.tsx +74 -0
  63. package/src/components/card/index.ts +1 -0
  64. package/src/components/center/center.stories.tsx +81 -0
  65. package/src/components/center/center.tsx +24 -0
  66. package/src/components/center/index.ts +1 -0
  67. package/src/components/checkbox/checkbox.stories.tsx +307 -0
  68. package/src/components/checkbox/checkbox.tsx +273 -0
  69. package/src/components/checkbox/index.ts +1 -0
  70. package/src/components/checkbox-group/checkbox-group.stories.tsx +104 -0
  71. package/src/components/checkbox-group/checkbox-group.tsx +16 -0
  72. package/src/components/checkbox-group/index.ts +1 -0
  73. package/src/components/combobox/combobox.stories.tsx +339 -0
  74. package/src/components/combobox/combobox.tsx +898 -0
  75. package/src/components/combobox/index.ts +1 -0
  76. package/src/components/date-picker/date-input.stories.tsx +158 -0
  77. package/src/components/date-picker/date-input.tsx +163 -0
  78. package/src/components/date-picker/date-picker.model.ts +90 -0
  79. package/src/components/date-picker/date-picker.stories.tsx +200 -0
  80. package/src/components/date-picker/date-picker.test.tsx +23 -0
  81. package/src/components/date-picker/date-picker.tsx +298 -0
  82. package/src/components/date-picker/date-picker.utils.ts +260 -0
  83. package/src/components/date-picker/index.ts +3 -0
  84. package/src/components/date-picker/use-date-input-popover.ts +48 -0
  85. package/src/components/date-picker/use-date-input.ts +125 -0
  86. package/src/components/dialog/dialog.stories.tsx +171 -0
  87. package/src/components/dialog/dialog.test.tsx +68 -0
  88. package/src/components/dialog/dialog.tsx +277 -0
  89. package/src/components/dialog/index.ts +1 -0
  90. package/src/components/divider/divider.stories.tsx +139 -0
  91. package/src/components/divider/divider.test.tsx +22 -0
  92. package/src/components/divider/divider.tsx +23 -0
  93. package/src/components/divider/index.ts +1 -0
  94. package/src/components/dropzone/dropzone.stories.tsx +210 -0
  95. package/src/components/dropzone/dropzone.tsx +154 -0
  96. package/src/components/dropzone/file-types.ts +64 -0
  97. package/src/components/dropzone/index.ts +3 -0
  98. package/src/components/dropzone/upload-primitives.tsx +310 -0
  99. package/src/components/dropzone/use-dropzone.ts +122 -0
  100. package/src/components/empty-state/empty-state.stories.tsx +56 -0
  101. package/src/components/empty-state/empty-state.tsx +39 -0
  102. package/src/components/empty-state/index.ts +1 -0
  103. package/src/components/field/field.stories.tsx +223 -0
  104. package/src/components/field/field.tsx +229 -0
  105. package/src/components/field/index.ts +1 -0
  106. package/src/components/form/form.stories.tsx +594 -0
  107. package/src/components/form/form.tsx +30 -0
  108. package/src/components/form/index.ts +1 -0
  109. package/src/components/heading/heading.stories.tsx +74 -0
  110. package/src/components/heading/heading.tsx +28 -0
  111. package/src/components/heading/heading.variants.ts +27 -0
  112. package/src/components/heading/index.ts +1 -0
  113. package/src/components/index.ts +46 -0
  114. package/src/components/input/index.ts +1 -0
  115. package/src/components/input/input.stories.tsx +104 -0
  116. package/src/components/input/input.tsx +75 -0
  117. package/src/components/kbd/index.ts +1 -0
  118. package/src/components/kbd/kbd.stories.tsx +40 -0
  119. package/src/components/kbd/kbd.tsx +31 -0
  120. package/src/components/kbd/kbd.variants.ts +26 -0
  121. package/src/components/label/index.ts +1 -0
  122. package/src/components/label/label.stories.tsx +68 -0
  123. package/src/components/label/label.test.tsx +61 -0
  124. package/src/components/label/label.tsx +62 -0
  125. package/src/components/loader/index.ts +1 -0
  126. package/src/components/loader/loader.stories.tsx +60 -0
  127. package/src/components/loader/loader.test.tsx +26 -0
  128. package/src/components/loader/loader.tsx +60 -0
  129. package/src/components/menu/index.ts +2 -0
  130. package/src/components/menu/menu-primitives.tsx +248 -0
  131. package/src/components/menu/menu.stories.tsx +203 -0
  132. package/src/components/menu/menu.tsx +100 -0
  133. package/src/components/menu/util/render-menu-item.tsx +54 -0
  134. package/src/components/multi-select/hooks/use-multi-select.ts +66 -0
  135. package/src/components/multi-select/index.ts +1 -0
  136. package/src/components/multi-select/multi-select.stories.tsx +294 -0
  137. package/src/components/multi-select/multi-select.tsx +300 -0
  138. package/src/components/multi-select/multi-select.variants.ts +22 -0
  139. package/src/components/number-input/index.ts +1 -0
  140. package/src/components/number-input/number-input.stories.tsx +209 -0
  141. package/src/components/number-input/number-input.test.tsx +87 -0
  142. package/src/components/number-input/number-input.tsx +232 -0
  143. package/src/components/pagination/components/pagination-option.tsx +27 -0
  144. package/src/components/pagination/index.ts +1 -0
  145. package/src/components/pagination/pagination.stories.tsx +80 -0
  146. package/src/components/pagination/pagination.test.tsx +76 -0
  147. package/src/components/pagination/pagination.tsx +102 -0
  148. package/src/components/password/index.ts +1 -0
  149. package/src/components/password/password.stories.tsx +104 -0
  150. package/src/components/password/password.tsx +75 -0
  151. package/src/components/popover/index.ts +1 -0
  152. package/src/components/popover/popover.stories.tsx +213 -0
  153. package/src/components/popover/popover.tsx +203 -0
  154. package/src/components/progress/index.ts +1 -0
  155. package/src/components/progress/progress.stories.tsx +124 -0
  156. package/src/components/progress/progress.test.tsx +25 -0
  157. package/src/components/progress/progress.tsx +124 -0
  158. package/src/components/scroll-area/index.ts +1 -0
  159. package/src/components/scroll-area/scroll-area.stories.tsx +166 -0
  160. package/src/components/scroll-area/scroll-area.tsx +64 -0
  161. package/src/components/select/index.ts +1 -0
  162. package/src/components/select/select.stories.tsx +253 -0
  163. package/src/components/select/select.tsx +430 -0
  164. package/src/components/show/index.ts +1 -0
  165. package/src/components/show/show.stories.tsx +197 -0
  166. package/src/components/show/show.test.tsx +41 -0
  167. package/src/components/show/show.tsx +16 -0
  168. package/src/components/skeleton/index.ts +1 -0
  169. package/src/components/skeleton/skeleton.stories.tsx +36 -0
  170. package/src/components/skeleton/skeleton.test.tsx +14 -0
  171. package/src/components/skeleton/skeleton.tsx +15 -0
  172. package/src/components/stack/index.ts +1 -0
  173. package/src/components/stack/stack.stories.tsx +194 -0
  174. package/src/components/stack/stack.tsx +52 -0
  175. package/src/components/stepper/Stepper.tsx +190 -0
  176. package/src/components/stepper/context/stepper-context.tsx +11 -0
  177. package/src/components/stepper/index.ts +1 -0
  178. package/src/components/stepper/stepper.stories.tsx +130 -0
  179. package/src/components/stepper/stepper.test.tsx +91 -0
  180. package/src/components/switch/index.ts +1 -0
  181. package/src/components/switch/switch.stories.tsx +122 -0
  182. package/src/components/switch/switch.test.tsx +30 -0
  183. package/src/components/switch/switch.tsx +86 -0
  184. package/src/components/table/index.ts +3 -0
  185. package/src/components/table/table-primitives.tsx +122 -0
  186. package/src/components/table/table.model.ts +20 -0
  187. package/src/components/table/table.stories.tsx +169 -0
  188. package/src/components/table/table.test.tsx +91 -0
  189. package/src/components/table/table.tsx +109 -0
  190. package/src/components/table-pagination/index.ts +2 -0
  191. package/src/components/table-pagination/table-pagination.model.ts +2 -0
  192. package/src/components/table-pagination/table-pagination.stories.tsx +23 -0
  193. package/src/components/table-pagination/table-pagination.test.tsx +32 -0
  194. package/src/components/table-pagination/table-pagination.tsx +108 -0
  195. package/src/components/tabs/context/tabs-context.tsx +14 -0
  196. package/src/components/tabs/index.ts +1 -0
  197. package/src/components/tabs/tabs.stories.tsx +182 -0
  198. package/src/components/tabs/tabs.test.tsx +61 -0
  199. package/src/components/tabs/tabs.tsx +175 -0
  200. package/src/components/tag/index.ts +2 -0
  201. package/src/components/tag/tag.stories.tsx +170 -0
  202. package/src/components/tag/tag.test.tsx +18 -0
  203. package/src/components/tag/tag.tsx +99 -0
  204. package/src/components/tag/tag.variants.ts +31 -0
  205. package/src/components/textarea/index.ts +1 -0
  206. package/src/components/textarea/textarea.stories.tsx +73 -0
  207. package/src/components/textarea/textarea.tsx +105 -0
  208. package/src/components/timeline/index.ts +1 -0
  209. package/src/components/timeline/timeline-status.ts +5 -0
  210. package/src/components/timeline/timeline.stories.tsx +84 -0
  211. package/src/components/timeline/timeline.tsx +147 -0
  212. package/src/components/toast/index.ts +1 -0
  213. package/src/components/toast/toast.stories.tsx +392 -0
  214. package/src/components/toast/toast.test.tsx +50 -0
  215. package/src/components/toast/toast.tsx +411 -0
  216. package/src/components/tooltip/index.ts +1 -0
  217. package/src/components/tooltip/tooltip.stories.tsx +226 -0
  218. package/src/components/tooltip/tooltip.test.tsx +46 -0
  219. package/src/components/tooltip/tooltip.tsx +171 -0
  220. package/src/components/tree/hooks/use-controllable-tree-state.ts +80 -0
  221. package/src/components/tree/index.ts +2 -0
  222. package/src/components/tree/tree-primitives.tsx +126 -0
  223. package/src/components/tree/tree.stories.tsx +468 -0
  224. package/src/components/tree/tree.tsx +42 -0
  225. package/src/hooks/index.ts +26 -0
  226. package/src/hooks/useArray/__doc__/useArray.stories.tsx +100 -0
  227. package/src/hooks/useArray/__test__/useArray.test.tsx +88 -0
  228. package/src/hooks/useArray/index.ts +1 -0
  229. package/src/hooks/useArray/useArray.ts +76 -0
  230. package/src/hooks/useAsync/__doc__/useAsync.stories.tsx +149 -0
  231. package/src/hooks/useAsync/__test__/useAsync.test.tsx +68 -0
  232. package/src/hooks/useAsync/index.ts +1 -0
  233. package/src/hooks/useAsync/useAsync.ts +58 -0
  234. package/src/hooks/useClickOutside/__doc__/useClickOutside.stories.tsx +40 -0
  235. package/src/hooks/useClickOutside/__test__/useClickOutside.test.tsx +33 -0
  236. package/src/hooks/useClickOutside/index.ts +1 -0
  237. package/src/hooks/useClickOutside/useClickOutside.ts +26 -0
  238. package/src/hooks/useClipboard/__doc__/useClipboard.stories.tsx +45 -0
  239. package/src/hooks/useClipboard/__test__/useClipboard.test.tsx +19 -0
  240. package/src/hooks/useClipboard/index.ts +1 -0
  241. package/src/hooks/useClipboard/useClipboard.tsx +28 -0
  242. package/src/hooks/useDebounceCallback/__doc__/useDebouncedCallback.stories.tsx +84 -0
  243. package/src/hooks/useDebounceCallback/index.ts +1 -0
  244. package/src/hooks/useDebounceCallback/useDebouncedCallback.ts +23 -0
  245. package/src/hooks/useDebounceValue/__doc__/useDebouncedValue.stories.tsx +75 -0
  246. package/src/hooks/useDebounceValue/index.ts +1 -0
  247. package/src/hooks/useDebounceValue/useDebouncedValue.ts +17 -0
  248. package/src/hooks/useDisclosure/__doc__/useDisclosure.stories.tsx +39 -0
  249. package/src/hooks/useDisclosure/__test__/useDisclosure.test.ts +43 -0
  250. package/src/hooks/useDisclosure/index.ts +1 -0
  251. package/src/hooks/useDisclosure/useDisclosure.ts +37 -0
  252. package/src/hooks/useDocumentTitle/__doc__/useDocumentTitle.stories.tsx +26 -0
  253. package/src/hooks/useDocumentTitle/index.ts +1 -0
  254. package/src/hooks/useDocumentTitle/useDocumentTitle.tsx +11 -0
  255. package/src/hooks/useEventListener/__doc__/useEventListener.stories.tsx +28 -0
  256. package/src/hooks/useEventListener/__test__/useEventListener.test.tsx +26 -0
  257. package/src/hooks/useEventListener/index.ts +1 -0
  258. package/src/hooks/useEventListener/useEventListener.ts +25 -0
  259. package/src/hooks/useFocusTrap/__doc__/useFocusTrap.stories.tsx +37 -0
  260. package/src/hooks/useFocusTrap/index.ts +1 -0
  261. package/src/hooks/useFocusTrap/scopeTab.ts +38 -0
  262. package/src/hooks/useFocusTrap/tabbable.ts +70 -0
  263. package/src/hooks/useFocusTrap/useFocusTrap.ts +78 -0
  264. package/src/hooks/useHotkey/__docs__/useHotkey.stories.tsx +116 -0
  265. package/src/hooks/useHotkey/__test__/useHotkey.test.tsx +105 -0
  266. package/src/hooks/useHotkey/__utils__/create-hotkey-listener.ts +25 -0
  267. package/src/hooks/useHotkey/__utils__/index.ts +3 -0
  268. package/src/hooks/useHotkey/__utils__/is-input-field.ts +14 -0
  269. package/src/hooks/useHotkey/__utils__/match-key-modifiers.ts +25 -0
  270. package/src/hooks/useHotkey/index.ts +1 -0
  271. package/src/hooks/useHotkey/useHotkey.ts +34 -0
  272. package/src/hooks/useHover/__doc__/useHover.stories.tsx +41 -0
  273. package/src/hooks/useHover/__test__/useHover.test.tsx +45 -0
  274. package/src/hooks/useHover/index.ts +1 -0
  275. package/src/hooks/useHover/useHover.tsx +40 -0
  276. package/src/hooks/useIsVisible/__doc__/useIsVisible.stories.tsx +60 -0
  277. package/src/hooks/useIsVisible/index.ts +1 -0
  278. package/src/hooks/useIsVisible/useIsVisible.tsx +50 -0
  279. package/src/hooks/useLocalStorage/__doc__/useLocalStorage.stories.tsx +86 -0
  280. package/src/hooks/useLocalStorage/__test__/useLocalStorage.test.ts +85 -0
  281. package/src/hooks/useLocalStorage/index.ts +1 -0
  282. package/src/hooks/useLocalStorage/useLocalStorage.ts +57 -0
  283. package/src/hooks/useMediaQuery/__doc__/useMediaQuery.stories.tsx +39 -0
  284. package/src/hooks/useMediaQuery/index.ts +1 -0
  285. package/src/hooks/useMediaQuery/useMediaQuery.ts +22 -0
  286. package/src/hooks/useMemoizedFn/index.ts +1 -0
  287. package/src/hooks/useMemoizedFn/useMemoizedFn.ts +32 -0
  288. package/src/hooks/useMutation/__doc__/useMutation.stories.tsx +111 -0
  289. package/src/hooks/useMutation/__test__/useMutation.test.tsx +83 -0
  290. package/src/hooks/useMutation/index.ts +1 -0
  291. package/src/hooks/useMutation/useMutation.tsx +60 -0
  292. package/src/hooks/useObject/__doc__/useObject.stories.tsx +119 -0
  293. package/src/hooks/useObject/__test__/useObject.test.tsx +87 -0
  294. package/src/hooks/useObject/index.ts +1 -0
  295. package/src/hooks/useObject/useObject.tsx +48 -0
  296. package/src/hooks/usePagination/__doc__/usePagination.stories.tsx +72 -0
  297. package/src/hooks/usePagination/__test__/usePagination.test.tsx +98 -0
  298. package/src/hooks/usePagination/index.ts +2 -0
  299. package/src/hooks/usePagination/usePagination.tsx +74 -0
  300. package/src/hooks/usePortal/__doc__/usePortal.stories.tsx +19 -0
  301. package/src/hooks/usePortal/__test__/usePortal.test.tsx +20 -0
  302. package/src/hooks/usePortal/index.ts +1 -0
  303. package/src/hooks/usePortal/usePortal.ts +40 -0
  304. package/src/hooks/usePreventCloseWindow/__doc__/usePreventCloseWindow.stories.tsx +32 -0
  305. package/src/hooks/usePreventCloseWindow/index.ts +1 -0
  306. package/src/hooks/usePreventCloseWindow/usePreventCloseWindow.ts +33 -0
  307. package/src/hooks/useRangePagination/__test__/useRangePagination.test.tsx +63 -0
  308. package/src/hooks/useRangePagination/index.ts +2 -0
  309. package/src/hooks/useRangePagination/useRangePagination.tsx +72 -0
  310. package/src/hooks/useSelection/__doc__/useSelection.stories.tsx +140 -0
  311. package/src/hooks/useSelection/__test__/useSelection.test.tsx +57 -0
  312. package/src/hooks/useSelection/index.ts +1 -0
  313. package/src/hooks/useSelection/useSelection.ts +121 -0
  314. package/src/hooks/useStep/__doc__/useStep.stories.tsx +98 -0
  315. package/src/hooks/useStep/__test__/useStep.test.ts +51 -0
  316. package/src/hooks/useStep/index.ts +1 -0
  317. package/src/hooks/useStep/useStep.ts +57 -0
  318. package/src/hooks/useToggle/__doc__/useToggle.stories.tsx +25 -0
  319. package/src/hooks/useToggle/__test__/useToggle.test.tsx +43 -0
  320. package/src/hooks/useToggle/index.ts +1 -0
  321. package/src/hooks/useToggle/useToggle.ts +16 -0
  322. package/src/index.ts +6 -0
  323. package/src/lib/cn.ts +8 -0
  324. package/src/lib/index.ts +1 -0
  325. package/src/models/Generic.model.ts +67 -0
  326. package/src/models/index.ts +1 -0
  327. package/src/providers/index.ts +2 -0
  328. package/src/providers/library-provider.tsx +44 -0
  329. package/src/providers/theme/ThemeProvider.tsx +25 -0
  330. package/src/providers/theme/index.ts +3 -0
  331. package/src/providers/theme/types.ts +11 -0
  332. package/src/providers/theme/useThemeProps.ts +25 -0
  333. package/src/stores/theme.store.ts +31 -0
  334. package/src/styles/components.css +4 -0
  335. package/src/styles/index.css +2 -0
  336. package/src/styles/library.css +2 -0
  337. package/src/styles/theme.css +232 -0
  338. package/src/utils/dates/parseDateRange.utility.ts +39 -0
  339. package/src/utils/form.tsx +91 -0
  340. package/src/utils/functions/createSafeContext.ts +17 -0
  341. package/src/utils/functions/ensureReactElement.tsx +30 -0
  342. package/src/utils/functions/getFormData.ts +19 -0
  343. package/src/utils/functions/index.ts +4 -0
  344. package/src/utils/functions/mergeRefs.ts +18 -0
  345. package/src/utils/index.ts +3 -0
  346. package/src/utils/strings/extractInitials.utility.ts +10 -0
  347. package/src/utils/strings/index.ts +1 -0
  348. package/src/utils/tests/click.ts +3 -0
  349. package/src/utils/tests/index.ts +2 -0
  350. package/src/utils/tests/keyboard.ts +21 -0
  351. package/src/utils/tests/type.ts +6 -0
  352. package/dist/components.css +0 -2
@@ -0,0 +1,60 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import { LoaderCircle, type LucideProps } from "lucide-react";
3
+ import { cn } from "../../lib";
4
+
5
+ const loaderVariants = cva("animate-spin", {
6
+ variants: {
7
+ variant: {
8
+ primary: "text-primary",
9
+ secondary: "text-secondary",
10
+ ghost: "text-muted-foreground",
11
+ error: "text-error",
12
+ success: "text-success",
13
+ warning: "text-warning",
14
+ info: "text-info",
15
+ },
16
+ size: {
17
+ xs: "size-3",
18
+ sm: "size-4",
19
+ default: "size-7",
20
+ lg: "size-10",
21
+ xl: "size-14",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "primary",
26
+ size: "default",
27
+ },
28
+ });
29
+
30
+ type LoaderVariants = VariantProps<typeof loaderVariants>;
31
+
32
+ type Props = LucideProps &
33
+ LoaderVariants & {
34
+ center?: boolean;
35
+ containerClassName?: string;
36
+ };
37
+
38
+ export const Loader = ({
39
+ center,
40
+ containerClassName,
41
+ variant,
42
+ size,
43
+ ...props
44
+ }: Props) => {
45
+ return (
46
+ <div
47
+ className={cn(
48
+ containerClassName,
49
+ center && "fixed inset-0 grid place-items-center",
50
+ )}
51
+ data-slot="loader"
52
+ >
53
+ <LoaderCircle
54
+ data-slot="loader-icon"
55
+ {...props}
56
+ className={cn(loaderVariants({ variant, size }), props.className)}
57
+ />
58
+ </div>
59
+ );
60
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./menu";
2
+ export * from "./menu-primitives";
@@ -0,0 +1,248 @@
1
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
2
+ import { Check, ChevronRight, Circle } from "lucide-react";
3
+ import * as React from "react";
4
+ import { useHotkey } from "../../hooks";
5
+ import { HotkeyOptions, Keys } from "../../hooks/useHotkey/useHotkey";
6
+ import { cn } from "../../lib";
7
+
8
+ const MenuRoot = (
9
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.Root>,
10
+ ) => {
11
+ return <DropdownMenuPrimitive.Root data-slot="menu" {...props} />;
12
+ };
13
+
14
+ const MenuTrigger = (
15
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>,
16
+ ) => {
17
+ return <DropdownMenuPrimitive.Trigger data-slot="menu-trigger" {...props} />;
18
+ };
19
+
20
+ const MenuGroup = (
21
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.Group>,
22
+ ) => {
23
+ return <DropdownMenuPrimitive.Group data-slot="menu-group" {...props} />;
24
+ };
25
+
26
+ const MenuPortal = (
27
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>,
28
+ ) => {
29
+ return <DropdownMenuPrimitive.Portal data-slot="menu-portal" {...props} />;
30
+ };
31
+
32
+ const MenuSub = (
33
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>,
34
+ ) => {
35
+ return <DropdownMenuPrimitive.Sub data-slot="menu-sub" {...props} />;
36
+ };
37
+
38
+ const MenuRadioGroup = (
39
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,
40
+ ) => {
41
+ return (
42
+ <DropdownMenuPrimitive.RadioGroup data-slot="menu-radio-group" {...props} />
43
+ );
44
+ };
45
+
46
+ type MenuSubTriggerProps = React.ComponentProps<
47
+ typeof DropdownMenuPrimitive.SubTrigger
48
+ > & {
49
+ inset?: boolean;
50
+ };
51
+
52
+ const MenuSubTrigger = ({
53
+ className,
54
+ inset,
55
+ children,
56
+ ...props
57
+ }: MenuSubTriggerProps) => (
58
+ <DropdownMenuPrimitive.SubTrigger
59
+ data-slot="menu-sub-trigger"
60
+ className={cn(
61
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state='open']:bg-accent",
62
+ inset && "pl-8",
63
+ className,
64
+ )}
65
+ {...props}
66
+ >
67
+ {children}
68
+ <ChevronRight className="ml-auto h-4 w-4" />
69
+ </DropdownMenuPrimitive.SubTrigger>
70
+ );
71
+
72
+ type MenuSubContentProps = React.ComponentProps<
73
+ typeof DropdownMenuPrimitive.SubContent
74
+ >;
75
+
76
+ const MenuSubContent = ({ className, ...props }: MenuSubContentProps) => (
77
+ <DropdownMenuPrimitive.SubContent
78
+ data-slot="menu-sub-content"
79
+ className={cn(
80
+ "z-float min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state='open']:animate-in data-[state='closed']:animate-out data-[state='closed']:fade-out-0 data-[state='open']:fade-in-0 data-[state='closed']:zoom-out-95 data-[state='open']:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
81
+ className,
82
+ )}
83
+ {...props}
84
+ />
85
+ );
86
+
87
+ type MenuContentProps = React.ComponentProps<
88
+ typeof DropdownMenuPrimitive.Content
89
+ >;
90
+
91
+ const MenuContent = ({
92
+ className,
93
+ sideOffset = 4,
94
+ ...props
95
+ }: MenuContentProps) => (
96
+ <DropdownMenuPrimitive.Portal data-slot="menu-portal">
97
+ <DropdownMenuPrimitive.Content
98
+ data-slot="menu-content"
99
+ sideOffset={sideOffset}
100
+ className={cn(
101
+ "z-float min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state='open']:animate-in data-[state='closed']:animate-out data-[state='closed']:fade-out-0 data-[state='open']:fade-in-0 data-[state='closed']:zoom-out-95 data-[state='open']:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
102
+ className,
103
+ )}
104
+ {...props}
105
+ />
106
+ </DropdownMenuPrimitive.Portal>
107
+ );
108
+
109
+ type MenuItemProps = React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
110
+ inset?: boolean;
111
+ };
112
+
113
+ const MenuItem = ({ className, inset, ...props }: MenuItemProps) => (
114
+ <DropdownMenuPrimitive.Item
115
+ data-slot="menu-item"
116
+ className={cn(
117
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
118
+ inset && "pl-8",
119
+ className,
120
+ )}
121
+ {...props}
122
+ />
123
+ );
124
+
125
+ type MenuCheckboxItemProps = React.ComponentProps<
126
+ typeof DropdownMenuPrimitive.CheckboxItem
127
+ >;
128
+
129
+ const MenuCheckboxItem = ({
130
+ className,
131
+ children,
132
+ checked,
133
+ ...props
134
+ }: MenuCheckboxItemProps) => (
135
+ <DropdownMenuPrimitive.CheckboxItem
136
+ data-slot="menu-checkbox-item"
137
+ className={cn(
138
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
139
+ className,
140
+ )}
141
+ checked={checked}
142
+ {...props}
143
+ >
144
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
145
+ <DropdownMenuPrimitive.ItemIndicator>
146
+ <Check className="h-4 w-4" />
147
+ </DropdownMenuPrimitive.ItemIndicator>
148
+ </span>
149
+ {children}
150
+ </DropdownMenuPrimitive.CheckboxItem>
151
+ );
152
+
153
+ type MenuRadioItemProps = React.ComponentProps<
154
+ typeof DropdownMenuPrimitive.RadioItem
155
+ >;
156
+
157
+ const MenuRadioItem = ({
158
+ className,
159
+ children,
160
+ ...props
161
+ }: MenuRadioItemProps) => (
162
+ <DropdownMenuPrimitive.RadioItem
163
+ data-slot="menu-radio-item"
164
+ className={cn(
165
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
166
+ className,
167
+ )}
168
+ {...props}
169
+ >
170
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
171
+ <DropdownMenuPrimitive.ItemIndicator>
172
+ <Circle className="h-2 w-2 fill-current" />
173
+ </DropdownMenuPrimitive.ItemIndicator>
174
+ </span>
175
+ {children}
176
+ </DropdownMenuPrimitive.RadioItem>
177
+ );
178
+
179
+ type MenuLabelProps = React.ComponentProps<
180
+ typeof DropdownMenuPrimitive.Label
181
+ > & {
182
+ inset?: boolean;
183
+ };
184
+
185
+ const MenuLabel = ({ className, inset, ...props }: MenuLabelProps) => (
186
+ <DropdownMenuPrimitive.Label
187
+ data-slot="menu-label"
188
+ className={cn(
189
+ "px-2 py-1.5 text-sm font-semibold",
190
+ inset && "pl-8",
191
+ className,
192
+ )}
193
+ {...props}
194
+ />
195
+ );
196
+
197
+ type MenuSeparatorProps = React.ComponentProps<
198
+ typeof DropdownMenuPrimitive.Separator
199
+ >;
200
+
201
+ const MenuSeparator = ({ className, ...props }: MenuSeparatorProps) => (
202
+ <DropdownMenuPrimitive.Separator
203
+ data-slot="menu-separator"
204
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
205
+ {...props}
206
+ />
207
+ );
208
+
209
+ type MenuShortcutProps = React.ComponentPropsWithoutRef<"span"> & {
210
+ keys: Keys;
211
+ handler: (event: KeyboardEvent) => any;
212
+ options?: HotkeyOptions;
213
+ };
214
+
215
+ const MenuShortcut = ({
216
+ className,
217
+ keys,
218
+ handler,
219
+ options = {},
220
+ ...props
221
+ }: MenuShortcutProps) => {
222
+ useHotkey(keys, handler, options);
223
+ return (
224
+ <span
225
+ data-slot="menu-shortcut"
226
+ className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
227
+ {...props}
228
+ />
229
+ );
230
+ };
231
+
232
+ export {
233
+ MenuCheckboxItem,
234
+ MenuContent,
235
+ MenuGroup,
236
+ MenuItem,
237
+ MenuLabel,
238
+ MenuPortal,
239
+ MenuRadioGroup,
240
+ MenuRadioItem,
241
+ MenuRoot,
242
+ MenuSeparator,
243
+ MenuShortcut,
244
+ MenuSub,
245
+ MenuSubContent,
246
+ MenuSubTrigger,
247
+ MenuTrigger,
248
+ };
@@ -0,0 +1,203 @@
1
+ import {
2
+ Button,
3
+ Menu,
4
+ MenuContent,
5
+ MenuGroup,
6
+ MenuItem,
7
+ MenuLabel,
8
+ MenuPortal,
9
+ MenuRoot,
10
+ MenuSeparator,
11
+ MenuShortcut,
12
+ MenuSub,
13
+ MenuSubContent,
14
+ MenuSubTrigger,
15
+ MenuTrigger,
16
+ } from "../../components";
17
+ import { createToastManager, ToastProvider } from "../toast";
18
+
19
+ const toastManager = createToastManager();
20
+
21
+ import type { Meta, StoryObj } from "@storybook/react-vite";
22
+ import {
23
+ Archive,
24
+ Bell,
25
+ Calendar,
26
+ CheckCircle,
27
+ Clipboard,
28
+ LogOut,
29
+ PlusCircle,
30
+ Settings,
31
+ Tag,
32
+ Trash2,
33
+ } from "lucide-react";
34
+ import { useMemo, useState } from "react";
35
+ import { MenuItemType } from ".";
36
+
37
+ const meta: Meta<typeof Menu> = {
38
+ title: "Data display/Menu",
39
+ component: Menu,
40
+ };
41
+
42
+ export default meta;
43
+ type Story = StoryObj<typeof Menu>;
44
+
45
+ /**
46
+ * ```tsx
47
+ * type ItemType = "item" | "checkbox" | "radio" | "label" | "separator" | "submenu"
48
+ * ```
49
+ */
50
+ export const Generic: Story = {
51
+ decorators: [
52
+ (Story) => (
53
+ <ToastProvider toastManager={toastManager}>
54
+ <Story />
55
+ </ToastProvider>
56
+ ),
57
+ ],
58
+ render: (args) => {
59
+ const [autosave, setAutosave] = useState<boolean>(true);
60
+
61
+ const items: MenuItemType[] = useMemo(
62
+ () => [
63
+ { type: "item", label: "File" },
64
+ {
65
+ type: "item",
66
+ label: "New File",
67
+ shortcut: "Ctrl+O",
68
+ onShortcut: () =>
69
+ toastManager.add({
70
+ variant: "success",
71
+ description: "New file created successfully",
72
+ }),
73
+ },
74
+ { type: "item", label: "Open File..." },
75
+ { type: "separator" },
76
+ {
77
+ type: "checkbox",
78
+ label: "Autosave",
79
+ checked: autosave,
80
+ onCheckedChange: setAutosave,
81
+ },
82
+ { type: "separator" },
83
+ {
84
+ type: "submenu",
85
+ label: "Export",
86
+ items: [
87
+ { type: "item", label: "PDF" },
88
+ { type: "item", label: "Word Document" },
89
+ ],
90
+ },
91
+ ],
92
+ [autosave],
93
+ );
94
+
95
+ return (
96
+ <Menu {...args} trigger={<Button>Open Menu</Button>} items={items} />
97
+ );
98
+ },
99
+ };
100
+
101
+ /**
102
+ * Se exportan los primitivos para poder construir cualquier tipo de Menu
103
+ */
104
+ export const Primitive: Story = {
105
+ decorators: [
106
+ (Story) => (
107
+ <ToastProvider toastManager={toastManager}>
108
+ <Story />
109
+ </ToastProvider>
110
+ ),
111
+ ],
112
+ render: () => (
113
+ <MenuRoot>
114
+ <MenuTrigger asChild>
115
+ <Button variant="outline">Menu</Button>
116
+ </MenuTrigger>
117
+ <MenuContent className="w-56">
118
+ <MenuLabel>Task Manager</MenuLabel>
119
+ <MenuSeparator />
120
+ <MenuGroup>
121
+ <MenuItem>
122
+ <Clipboard className="mr-2 h-4 w-4" />
123
+ <span>All Tasks</span>
124
+ </MenuItem>
125
+ <MenuItem>
126
+ <CheckCircle className="mr-2 h-4 w-4" />
127
+ <span>Completed</span>
128
+ </MenuItem>
129
+ <MenuItem>
130
+ <Calendar className="mr-2 h-4 w-4" />
131
+ <span>Upcoming</span>
132
+ </MenuItem>
133
+ </MenuGroup>
134
+ <MenuSeparator />
135
+ <MenuGroup>
136
+ <MenuSub>
137
+ <MenuSubTrigger>
138
+ <Tag className="mr-2 h-4 w-4" />
139
+ <span>Categories</span>
140
+ </MenuSubTrigger>
141
+ <MenuPortal>
142
+ <MenuSubContent>
143
+ <MenuItem>
144
+ <Tag className="mr-2 h-4 w-4" />
145
+ <span>Work</span>
146
+ </MenuItem>
147
+ <MenuItem>
148
+ <Tag className="mr-2 h-4 w-4" />
149
+ <span>Personal</span>
150
+ </MenuItem>
151
+ <MenuItem>
152
+ <Tag className="mr-2 h-4 w-4" />
153
+ <span>Shopping</span>
154
+ </MenuItem>
155
+ <MenuItem>
156
+ <PlusCircle className="mr-2 h-4 w-4" />
157
+ <span>Create category</span>
158
+ </MenuItem>
159
+ </MenuSubContent>
160
+ </MenuPortal>
161
+ </MenuSub>
162
+ <MenuItem>
163
+ <PlusCircle className="mr-2 h-4 w-4" />
164
+ <span>Add Task</span>
165
+ <MenuShortcut
166
+ keys="ctrl+b"
167
+ handler={() =>
168
+ toastManager.add({
169
+ variant: "success",
170
+ description: "Creando tarea...",
171
+ })
172
+ }
173
+ >
174
+ Ctrl+B
175
+ </MenuShortcut>
176
+ </MenuItem>
177
+ </MenuGroup>
178
+ <MenuSeparator />
179
+ <MenuItem>
180
+ <Bell className="mr-2 h-4 w-4" />
181
+ <span>Notifications</span>
182
+ </MenuItem>
183
+ <MenuItem>
184
+ <Settings className="mr-2 h-4 w-4" />
185
+ <span>Settings</span>
186
+ </MenuItem>
187
+ <MenuItem>
188
+ <Trash2 className="mr-2 h-4 w-4" />
189
+ <span>Trash</span>
190
+ </MenuItem>
191
+ <MenuItem disabled>
192
+ <Archive className="mr-2 h-4 w-4" />
193
+ <span>Archived</span>
194
+ </MenuItem>
195
+ <MenuSeparator />
196
+ <MenuItem>
197
+ <LogOut className="mr-2 h-4 w-4" />
198
+ <span>Log out</span>
199
+ </MenuItem>
200
+ </MenuContent>
201
+ </MenuRoot>
202
+ ),
203
+ };
@@ -0,0 +1,100 @@
1
+ import React, { ComponentPropsWithoutRef, ElementType, ReactNode } from "react";
2
+ import {
3
+ MenuCheckboxItem,
4
+ MenuContent,
5
+ MenuItem,
6
+ MenuLabel,
7
+ MenuRadioItem,
8
+ MenuRoot,
9
+ MenuSeparator,
10
+ MenuShortcut,
11
+ MenuSubTrigger,
12
+ MenuTrigger,
13
+ } from "./menu-primitives";
14
+ import { renderMenuItem } from "./util/render-menu-item";
15
+
16
+ type MenuShortcutProps = ComponentPropsWithoutRef<typeof MenuShortcut>;
17
+
18
+ type Shortcut = Partial<{
19
+ shortcut: MenuShortcutProps["keys"];
20
+ onShortcut: MenuShortcutProps["handler"];
21
+ shortcutOptions: MenuShortcutProps["options"];
22
+ }>;
23
+
24
+ type MenuItemBase<T extends ElementType> = ComponentPropsWithoutRef<T> & {
25
+ label?: ReactNode;
26
+ type: string;
27
+ } & Shortcut;
28
+
29
+ type MenuItemItem = MenuItemBase<typeof MenuItem> & {
30
+ type: "item";
31
+ };
32
+ type MenuItemCheckbox = MenuItemBase<typeof MenuCheckboxItem> & {
33
+ type: "checkbox";
34
+ };
35
+
36
+ type MenuItemRadio = MenuItemBase<typeof MenuRadioItem> & {
37
+ type: "radio";
38
+ };
39
+ type MenuItemLabel = MenuItemBase<typeof MenuLabel> & {
40
+ type: "label";
41
+ };
42
+
43
+ type MenuItemSeparator = MenuItemBase<typeof MenuSeparator> & {
44
+ type: "separator";
45
+ };
46
+
47
+ type MenuItemSubmenu = MenuItemBase<typeof MenuSubTrigger> & {
48
+ type: "submenu";
49
+ items: MenuItemType[];
50
+ };
51
+
52
+ export type MenuItemType =
53
+ | MenuItemItem
54
+ | MenuItemCheckbox
55
+ | MenuItemRadio
56
+ | MenuItemLabel
57
+ | MenuItemSeparator
58
+ | MenuItemSubmenu;
59
+
60
+ export interface GenericMenuProps {
61
+ trigger: React.ReactNode;
62
+ items: MenuItemType[];
63
+ side?: "top" | "right" | "bottom" | "left";
64
+ offset?: ComponentPropsWithoutRef<typeof MenuContent>["sideOffset"];
65
+ contentProps?: ComponentPropsWithoutRef<typeof MenuContent>;
66
+ }
67
+
68
+ export const Menu = ({
69
+ trigger,
70
+ items,
71
+ contentProps,
72
+ side = "bottom",
73
+ offset,
74
+ }: GenericMenuProps) => {
75
+ return (
76
+ <MenuRoot>
77
+ <MenuTrigger asChild>{trigger}</MenuTrigger>
78
+ <MenuContent side={side} sideOffset={offset} {...contentProps}>
79
+ {items.map(
80
+ ({ shortcut, onShortcut, shortcutOptions, ...item }, index) => (
81
+ <React.Fragment key={index}>
82
+ {renderMenuItem(
83
+ item,
84
+ shortcut && (
85
+ <MenuShortcut
86
+ keys={shortcut}
87
+ handler={(event) => onShortcut?.(event)}
88
+ options={shortcutOptions}
89
+ >
90
+ {shortcut}
91
+ </MenuShortcut>
92
+ ),
93
+ )}
94
+ </React.Fragment>
95
+ ),
96
+ )}
97
+ </MenuContent>
98
+ </MenuRoot>
99
+ );
100
+ };
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import { MenuItemType } from "../menu";
3
+ import {
4
+ MenuCheckboxItem,
5
+ MenuItem,
6
+ MenuLabel,
7
+ MenuRadioItem,
8
+ MenuSeparator,
9
+ MenuSub,
10
+ MenuSubContent,
11
+ MenuSubTrigger,
12
+ } from "../menu-primitives";
13
+
14
+ export const renderMenuItem = (item: MenuItemType, children?: any) => {
15
+ switch (item.type) {
16
+ case "item":
17
+ return (
18
+ <MenuItem {...item}>
19
+ {item.label} {children}
20
+ </MenuItem>
21
+ );
22
+ case "checkbox":
23
+ return (
24
+ <MenuCheckboxItem {...item}>
25
+ {item.label} {children}
26
+ </MenuCheckboxItem>
27
+ );
28
+ case "radio":
29
+ return (
30
+ <MenuRadioItem {...item}>
31
+ {item.label} {children}
32
+ </MenuRadioItem>
33
+ );
34
+ case "label":
35
+ return <MenuLabel {...item}>{item.label} </MenuLabel>;
36
+ case "separator":
37
+ return <MenuSeparator {...item} />;
38
+ case "submenu":
39
+ return (
40
+ <MenuSub>
41
+ <MenuSubTrigger {...item}>{item.label}</MenuSubTrigger>
42
+ <MenuSubContent>
43
+ {item.items?.map((subItem, index) => (
44
+ <React.Fragment key={index}>
45
+ {renderMenuItem(subItem)}
46
+ </React.Fragment>
47
+ ))}
48
+ </MenuSubContent>
49
+ </MenuSub>
50
+ );
51
+ default:
52
+ return null;
53
+ }
54
+ };