@noxickon/onyx 2.0.3 → 3.0.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 (871) hide show
  1. package/AI-README.md +4942 -0
  2. package/README.md +222 -80
  3. package/dist/_internal/CustomSvgIcon.d.ts +1 -0
  4. package/dist/_internal/constants.d.ts +1 -0
  5. package/dist/_internal/hooks/useEventCallback.d.ts +1 -0
  6. package/dist/_internal/styles/button.variants.d.ts +8 -0
  7. package/dist/_internal/styles/color.helpers.d.ts +154 -0
  8. package/dist/_internal/styles/index.d.ts +4 -0
  9. package/dist/_internal/styles/link.variants.d.ts +6 -0
  10. package/dist/_internal/styles/status.styles.d.ts +38 -0
  11. package/dist/_internal/utils/Portal/Portal.d.ts +2 -0
  12. package/dist/_internal/utils/Portal/Portal.types.d.ts +5 -0
  13. package/dist/_internal/utils/Portal/index.d.ts +2 -0
  14. package/dist/_internal/utils/Slot/Slot.types.d.ts +6 -0
  15. package/dist/_internal/utils/Slot/createSlot.d.ts +5 -0
  16. package/dist/_internal/utils/Slot/index.d.ts +2 -0
  17. package/dist/_internal/utils/index.d.ts +4 -0
  18. package/dist/_internal/utils/isIconOnly.d.ts +2 -0
  19. package/dist/_internal/utils/pickClasses.d.ts +1 -0
  20. package/dist/chunks/{hooks-CUNBk2tZ.js → hooks-6tQOArBm.js} +6406 -5884
  21. package/dist/chunks/hooks-CNgb50x1.js +31 -0
  22. package/dist/chunks/ui-B0Ma5GdK.js +9 -0
  23. package/dist/chunks/ui-DrKTwQ0M.js +20527 -0
  24. package/dist/contexts/AuthContext/index.d.ts +5 -0
  25. package/dist/contexts/AuthContext/src/AuthContext.d.ts +2 -0
  26. package/dist/contexts/AuthContext/src/AuthContext.types.d.ts +27 -0
  27. package/dist/contexts/AuthContext/src/AuthProvider.d.ts +2 -0
  28. package/dist/contexts/AuthContext/src/query.d.ts +1 -0
  29. package/dist/contexts/AuthContext/src/useAuth.d.ts +1 -0
  30. package/dist/contexts/AuthContext/test/AuthContext.test.d.ts +1 -0
  31. package/dist/contexts/DialogContext/DialogContext.stories.d.ts +9 -0
  32. package/dist/contexts/DialogContext/index.d.ts +3 -0
  33. package/dist/contexts/DialogContext/src/DialogContext.d.ts +2 -0
  34. package/dist/contexts/DialogContext/src/DialogContext.types.d.ts +26 -0
  35. package/dist/contexts/DialogContext/src/DialogProvider.d.ts +2 -0
  36. package/dist/contexts/DialogContext/src/useDialog.d.ts +2 -0
  37. package/dist/contexts/DialogContext/test/DialogProvider.test.d.ts +1 -0
  38. package/dist/contexts/FeatureFlagContext/index.d.ts +5 -0
  39. package/dist/contexts/FeatureFlagContext/src/FeatureContext.d.ts +2 -0
  40. package/dist/contexts/FeatureFlagContext/src/FeatureContext.types.d.ts +28 -0
  41. package/dist/contexts/FeatureFlagContext/src/FeatureFlag.d.ts +2 -0
  42. package/dist/contexts/FeatureFlagContext/src/FeatureProvider.d.ts +2 -0
  43. package/dist/contexts/FeatureFlagContext/src/query.d.ts +1 -0
  44. package/dist/contexts/FeatureFlagContext/src/useFeature.d.ts +1 -0
  45. package/dist/contexts/FeatureFlagContext/test/Feature.test.d.ts +1 -0
  46. package/dist/contexts/contexts.cjs.js +11 -2
  47. package/dist/contexts/contexts.es.js +94 -82
  48. package/dist/contexts/index.d.ts +3 -0
  49. package/dist/forms/Checkbox/Checkbox.stories.d.ts +80 -0
  50. package/dist/forms/Checkbox/index.d.ts +5 -0
  51. package/dist/forms/Checkbox/src/Checkbox.d.ts +2 -0
  52. package/dist/forms/Checkbox/src/Checkbox.types.d.ts +20 -0
  53. package/dist/forms/Checkbox/src/CheckboxGroup.d.ts +2 -0
  54. package/dist/forms/Checkbox/src/CheckboxGroupItem.d.ts +2 -0
  55. package/dist/forms/Checkbox/src/context/CheckboxGroupContext.d.ts +2 -0
  56. package/dist/forms/Checkbox/src/context/CheckboxGroupContext.types.d.ts +6 -0
  57. package/dist/forms/Checkbox/src/context/useCheckboxGroup.d.ts +1 -0
  58. package/dist/forms/Checkbox/test/Checkbox.test.d.ts +1 -0
  59. package/dist/forms/FileUpload/FileUpload.stories.d.ts +67 -0
  60. package/dist/forms/FileUpload/index.d.ts +6 -0
  61. package/dist/forms/FileUpload/src/FileUpload.d.ts +2 -0
  62. package/dist/forms/FileUpload/src/FileUpload.types.d.ts +24 -0
  63. package/dist/forms/FileUpload/src/FileUploadArea.d.ts +2 -0
  64. package/dist/forms/FileUpload/src/FileUploadButton.d.ts +2 -0
  65. package/dist/forms/FileUpload/src/FileUploadOverlay.d.ts +2 -0
  66. package/dist/forms/FileUpload/src/context/FileUploadContext.d.ts +2 -0
  67. package/dist/forms/FileUpload/src/context/FileUploadContext.types.d.ts +17 -0
  68. package/dist/forms/FileUpload/src/context/useFileUploadContext.d.ts +1 -0
  69. package/dist/forms/FileUpload/src/utils.d.ts +1 -0
  70. package/dist/forms/FileUpload/test/FileUpload.test.d.ts +1 -0
  71. package/dist/forms/Form/Form.stories.d.ts +52 -0
  72. package/dist/forms/Form/index.d.ts +9 -0
  73. package/dist/forms/Form/src/Form.d.ts +2 -0
  74. package/dist/forms/Form/src/Form.types.d.ts +18 -0
  75. package/dist/forms/Form/src/FormDescription.d.ts +2 -0
  76. package/dist/forms/Form/src/FormError.d.ts +2 -0
  77. package/dist/forms/Form/src/FormField.d.ts +2 -0
  78. package/dist/forms/Form/src/FormGroup.d.ts +2 -0
  79. package/dist/forms/Form/src/FormGroupTitle.d.ts +2 -0
  80. package/dist/forms/Form/src/FormLabel.d.ts +2 -0
  81. package/dist/forms/Form/src/context/FormFieldContext.d.ts +2 -0
  82. package/dist/forms/Form/src/context/FormFieldContext.types.d.ts +7 -0
  83. package/dist/forms/Form/src/context/useFormFieldContext.d.ts +1 -0
  84. package/dist/forms/Form/test/Form.test.d.ts +1 -0
  85. package/dist/forms/Input/Date/Date.stories.d.ts +91 -0
  86. package/dist/forms/Input/Date/index.d.ts +5 -0
  87. package/dist/forms/Input/Date/src/Date.types.d.ts +23 -0
  88. package/dist/forms/Input/Date/src/DateButton.d.ts +2 -0
  89. package/dist/forms/Input/Date/src/DateContainer.d.ts +2 -0
  90. package/dist/forms/Input/Date/src/DateInput.d.ts +1 -0
  91. package/dist/forms/Input/Date/src/DatePickerButton.d.ts +2 -0
  92. package/dist/forms/Input/Date/src/DatePickerContent.d.ts +1 -0
  93. package/dist/forms/Input/Date/src/context/DateContext.d.ts +2 -0
  94. package/dist/forms/Input/Date/src/context/DateContext.types.d.ts +18 -0
  95. package/dist/forms/Input/Date/src/context/useDateContext.d.ts +1 -0
  96. package/dist/forms/Input/Date/src/date.styles.d.ts +10 -0
  97. package/dist/forms/Input/Date/src/useDateInput.d.ts +16 -0
  98. package/dist/forms/Input/Date/test/Date.test.d.ts +1 -0
  99. package/dist/forms/Input/Number/Number.stories.d.ts +95 -0
  100. package/dist/forms/Input/Number/index.d.ts +7 -0
  101. package/dist/forms/Input/Number/src/Number.types.d.ts +26 -0
  102. package/dist/forms/Input/Number/src/NumberButton.d.ts +2 -0
  103. package/dist/forms/Input/Number/src/NumberContainer.d.ts +2 -0
  104. package/dist/forms/Input/Number/src/NumberDecrementButton.d.ts +1 -0
  105. package/dist/forms/Input/Number/src/NumberIncrementButton.d.ts +1 -0
  106. package/dist/forms/Input/Number/src/NumberInput.d.ts +2 -0
  107. package/dist/forms/Input/Number/src/NumberInput.utils.d.ts +2 -0
  108. package/dist/forms/Input/Number/src/context/NumberContext.d.ts +2 -0
  109. package/dist/forms/Input/Number/src/context/NumberContext.types.d.ts +15 -0
  110. package/dist/forms/Input/Number/src/context/useNumberContext.d.ts +1 -0
  111. package/dist/forms/Input/Number/test/NumberInput.test.d.ts +1 -0
  112. package/dist/forms/Input/Otp/Otp.stories.d.ts +69 -0
  113. package/dist/forms/Input/Otp/index.d.ts +2 -0
  114. package/dist/forms/Input/Otp/src/Otp.types.d.ts +11 -0
  115. package/dist/forms/Input/Otp/src/OtpInput.d.ts +2 -0
  116. package/dist/forms/Input/Otp/test/OtpInput.test.d.ts +1 -0
  117. package/dist/forms/Input/Text/Text.stories.d.ts +84 -0
  118. package/dist/forms/Input/Text/index.d.ts +8 -0
  119. package/dist/forms/Input/Text/src/Text.types.d.ts +31 -0
  120. package/dist/forms/Input/Text/src/TextButton.d.ts +2 -0
  121. package/dist/forms/Input/Text/src/TextClearButton.d.ts +1 -0
  122. package/dist/forms/Input/Text/src/TextContainer.d.ts +2 -0
  123. package/dist/forms/Input/Text/src/TextCounter.d.ts +2 -0
  124. package/dist/forms/Input/Text/src/TextInput.d.ts +2 -0
  125. package/dist/forms/Input/Text/src/TextVisibilityButton.d.ts +1 -0
  126. package/dist/forms/Input/Text/src/context/TextContext.d.ts +2 -0
  127. package/dist/forms/Input/Text/src/context/TextContext.types.d.ts +10 -0
  128. package/dist/forms/Input/Text/src/context/useTextContext.d.ts +1 -0
  129. package/dist/forms/Input/Text/test/TextInput.test.d.ts +1 -0
  130. package/dist/forms/Input/Time/Time.stories.d.ts +62 -0
  131. package/dist/forms/Input/Time/index.d.ts +4 -0
  132. package/dist/forms/Input/Time/src/Time.types.d.ts +17 -0
  133. package/dist/forms/Input/Time/src/TimeButton.d.ts +2 -0
  134. package/dist/forms/Input/Time/src/TimeContainer.d.ts +2 -0
  135. package/dist/forms/Input/Time/src/TimeInput.d.ts +1 -0
  136. package/dist/forms/Input/Time/src/context/TimeContext.d.ts +2 -0
  137. package/dist/forms/Input/Time/src/context/TimeContext.types.d.ts +6 -0
  138. package/dist/forms/Input/Time/src/context/useTimeContext.d.ts +1 -0
  139. package/dist/forms/Input/Time/src/useTimeInput.d.ts +9 -0
  140. package/dist/forms/Input/Time/test/Time.test.d.ts +1 -0
  141. package/dist/forms/Input/_internal/context/BaseInputContext.d.ts +2 -0
  142. package/dist/forms/Input/_internal/context/BaseInputContext.types.d.ts +10 -0
  143. package/dist/forms/Input/_internal/context/useBaseInputContext.d.ts +1 -0
  144. package/dist/forms/Input/_internal/src/BaseInput.d.ts +2 -0
  145. package/dist/forms/Input/_internal/src/BaseInput.types.d.ts +13 -0
  146. package/dist/forms/Input/_internal/src/BaseInputButton.d.ts +2 -0
  147. package/dist/forms/Input/_internal/src/BaseInputContainer.d.ts +2 -0
  148. package/dist/forms/Input/_internal/src/BaseInputCounter.d.ts +2 -0
  149. package/dist/forms/Input/_internal/test/BaseInput.test.d.ts +1 -0
  150. package/dist/forms/Input/index.d.ts +5 -0
  151. package/dist/forms/Radio/Radio.stories.d.ts +61 -0
  152. package/dist/forms/Radio/index.d.ts +6 -0
  153. package/dist/forms/Radio/src/Radio.types.d.ts +16 -0
  154. package/dist/forms/Radio/src/RadioGroup.d.ts +2 -0
  155. package/dist/forms/Radio/src/RadioGroupItem.d.ts +2 -0
  156. package/dist/forms/Radio/src/context/RadioGroupContext.d.ts +2 -0
  157. package/dist/forms/Radio/src/context/RadioGroupContext.types.d.ts +6 -0
  158. package/dist/forms/Radio/src/context/useRadioGroup.d.ts +1 -0
  159. package/dist/forms/Radio/test/Radio.test.d.ts +1 -0
  160. package/dist/forms/Select/Select.stories.d.ts +13 -0
  161. package/dist/forms/Select/index.d.ts +7 -0
  162. package/dist/forms/Select/src/Select.d.ts +2 -0
  163. package/dist/forms/Select/src/Select.types.d.ts +28 -0
  164. package/dist/forms/Select/src/SelectContent.d.ts +2 -0
  165. package/dist/forms/Select/src/SelectGroup.d.ts +2 -0
  166. package/dist/forms/Select/src/SelectItem.d.ts +2 -0
  167. package/dist/forms/Select/src/SelectTrigger.d.ts +2 -0
  168. package/dist/forms/Select/src/context/SelectContext.d.ts +2 -0
  169. package/dist/forms/Select/src/context/SelectContext.types.d.ts +25 -0
  170. package/dist/forms/Select/src/context/useSelectContext.d.ts +1 -0
  171. package/dist/forms/Select/src/extractItemsFromContent.d.ts +2 -0
  172. package/dist/forms/Select/test/Select.test.d.ts +1 -0
  173. package/dist/forms/Switch/Switch.stories.d.ts +9 -0
  174. package/dist/forms/Switch/index.d.ts +2 -0
  175. package/dist/forms/Switch/src/Switch.d.ts +2 -0
  176. package/dist/forms/Switch/src/Switch.types.d.ts +7 -0
  177. package/dist/forms/Switch/test/Switch.test.d.ts +1 -0
  178. package/dist/forms/Textarea/Textarea.stories.d.ts +10 -0
  179. package/dist/forms/Textarea/index.d.ts +2 -0
  180. package/dist/forms/Textarea/src/Textarea.d.ts +2 -0
  181. package/dist/forms/Textarea/src/Textarea.types.d.ts +5 -0
  182. package/dist/forms/Textarea/test/Textarea.test.d.ts +1 -0
  183. package/dist/forms/index.d.ts +8 -0
  184. package/dist/hooks/hooks.cjs.js +1 -1
  185. package/dist/hooks/hooks.es.js +14 -9
  186. package/dist/hooks/index.d.ts +13 -0
  187. package/dist/hooks/useControllableState/UseControllableState.stories.d.ts +6 -0
  188. package/dist/hooks/useControllableState/index.d.ts +2 -0
  189. package/dist/hooks/useControllableState/src/useControllableState.d.ts +2 -0
  190. package/dist/hooks/useControllableState/src/useControllableState.types.d.ts +10 -0
  191. package/dist/hooks/useControllableState/test/useControllableState.test.d.ts +1 -0
  192. package/dist/hooks/useFileUpload/index.d.ts +2 -0
  193. package/dist/hooks/useFileUpload/src/useFileUpload.d.ts +2 -0
  194. package/dist/hooks/useFileUpload/src/useFileUpload.types.d.ts +20 -0
  195. package/dist/hooks/useFileUpload/tests/useFileUpload.test.d.ts +1 -0
  196. package/dist/hooks/useFilterFetch/UseFilterFetch.stories.d.ts +7 -0
  197. package/dist/hooks/useFilterFetch/index.d.ts +2 -0
  198. package/dist/hooks/useFilterFetch/src/useFilterFetch.d.ts +2 -0
  199. package/dist/hooks/useFilterFetch/src/useFilterFetch.types.d.ts +22 -0
  200. package/dist/hooks/useFilterFetch/test/useFilterFetch.test.d.ts +1 -0
  201. package/dist/hooks/useFilterQuery/index.d.ts +2 -0
  202. package/dist/hooks/useFilterQuery/src/useFilterQuery.d.ts +2 -0
  203. package/dist/hooks/useFilterQuery/src/useFilterQuery.types.d.ts +24 -0
  204. package/dist/hooks/useFilterQuery/test/useFilter.test.d.ts +1 -0
  205. package/dist/hooks/useFocus/UseFocus.stories.d.ts +6 -0
  206. package/dist/hooks/useFocus/index.d.ts +2 -0
  207. package/dist/hooks/useFocus/src/useFocus.d.ts +2 -0
  208. package/dist/hooks/useFocus/src/useFocus.types.d.ts +17 -0
  209. package/dist/hooks/useFocus/test/useFocus.test.d.ts +1 -0
  210. package/dist/hooks/useForm/index.d.ts +2 -0
  211. package/dist/hooks/useForm/src/useForm.d.ts +2 -0
  212. package/dist/hooks/useForm/src/useForm.types.d.ts +20 -0
  213. package/dist/hooks/useForm/test/useForm.test.d.ts +1 -0
  214. package/dist/hooks/useFormFetch/UseFormFetch.stories.d.ts +6 -0
  215. package/dist/hooks/useFormFetch/index.d.ts +2 -0
  216. package/dist/hooks/useFormFetch/src/useFormFetch.d.ts +2 -0
  217. package/dist/hooks/useFormFetch/src/useFormFetch.types.d.ts +18 -0
  218. package/dist/hooks/useFormFetch/test/useFormFetch.test.d.ts +1 -0
  219. package/dist/hooks/useFormState/index.d.ts +4 -0
  220. package/dist/hooks/useFormState/src/config/arrayRules.d.ts +8 -0
  221. package/dist/hooks/useFormState/src/config/simpleRules.d.ts +18 -0
  222. package/dist/hooks/useFormState/src/handleRules.d.ts +3 -0
  223. package/dist/hooks/useFormState/src/rulesHelper.d.ts +3 -0
  224. package/dist/hooks/useFormState/src/useFormState.d.ts +2 -0
  225. package/dist/hooks/useFormState/src/useFormState.types.d.ts +37 -0
  226. package/dist/hooks/useFormState/src/validator.d.ts +2 -0
  227. package/dist/hooks/useFormState/test/useFormState.test.d.ts +1 -0
  228. package/dist/hooks/useKeyboard/UseKeyboard.stories.d.ts +6 -0
  229. package/dist/hooks/useKeyboard/index.d.ts +2 -0
  230. package/dist/hooks/useKeyboard/src/useKeyboard.d.ts +2 -0
  231. package/dist/hooks/useKeyboard/src/useKeyboard.types.d.ts +9 -0
  232. package/dist/hooks/useKeyboard/test/useKeyboard.test.d.ts +1 -0
  233. package/dist/hooks/useOverflowDetection/UseOverflowDetection.stories.d.ts +6 -0
  234. package/dist/hooks/useOverflowDetection/index.d.ts +2 -0
  235. package/dist/hooks/useOverflowDetection/src/useOverflowDetection.d.ts +2 -0
  236. package/dist/hooks/useOverflowDetection/src/useOverflowDetection.types.d.ts +8 -0
  237. package/dist/hooks/useOverflowDetection/test/useOverflowDetection.test.d.ts +1 -0
  238. package/dist/hooks/useScrollSpy/UseScrollSpy.stories.d.ts +6 -0
  239. package/dist/hooks/useScrollSpy/index.d.ts +2 -0
  240. package/dist/hooks/useScrollSpy/src/useScrollSpy.d.ts +2 -0
  241. package/dist/hooks/useScrollSpy/src/useScrollSpy.types.d.ts +9 -0
  242. package/dist/hooks/useScrollSpy/test/useScrollSpy.test.d.ts +1 -0
  243. package/dist/hooks/useSize/UseSize.stories.d.ts +6 -0
  244. package/dist/hooks/useSize/index.d.ts +1 -0
  245. package/dist/hooks/useSize/src/useSize.d.ts +6 -0
  246. package/dist/hooks/useSize/test/useSize.test.d.ts +1 -0
  247. package/dist/hooks/useTheme/UseTheme.stories.d.ts +7 -0
  248. package/dist/hooks/useTheme/index.d.ts +2 -0
  249. package/dist/hooks/useTheme/src/useTheme.d.ts +2 -0
  250. package/dist/hooks/useTheme/src/useTheme.types.d.ts +10 -0
  251. package/dist/hooks/useTheme/test/useTheme.test.d.ts +1 -0
  252. package/dist/index.d.ts +3 -1960
  253. package/dist/layouts/AppLayout/AppLayout.stories.d.ts +29 -0
  254. package/dist/layouts/AppLayout/index.d.ts +2 -0
  255. package/dist/layouts/AppLayout/src/AppLayout.d.ts +2 -0
  256. package/dist/layouts/AppLayout/src/AppLayout.types.d.ts +4 -0
  257. package/dist/layouts/AppLayout/test/AppLayout.test.d.ts +1 -0
  258. package/dist/layouts/MainContent/MainContent.stories.d.ts +40 -0
  259. package/dist/layouts/MainContent/index.d.ts +5 -0
  260. package/dist/layouts/MainContent/src/MainContent.d.ts +2 -0
  261. package/dist/layouts/MainContent/src/MainContent.types.d.ts +10 -0
  262. package/dist/layouts/MainContent/src/MainContentBody.d.ts +2 -0
  263. package/dist/layouts/MainContent/src/MainContentHeader.d.ts +2 -0
  264. package/dist/layouts/MainContent/test/MainContent.test.d.ts +1 -0
  265. package/dist/layouts/Sidebar/Sidebar.stories.d.ts +57 -0
  266. package/dist/layouts/Sidebar/index.d.ts +26 -0
  267. package/dist/layouts/Sidebar/src/Sidebar.d.ts +2 -0
  268. package/dist/layouts/Sidebar/src/Sidebar.types.d.ts +75 -0
  269. package/dist/layouts/Sidebar/src/SidebarContent.d.ts +2 -0
  270. package/dist/layouts/Sidebar/src/SidebarFooter.d.ts +2 -0
  271. package/dist/layouts/Sidebar/src/SidebarGroup.d.ts +2 -0
  272. package/dist/layouts/Sidebar/src/SidebarGroupAction.d.ts +2 -0
  273. package/dist/layouts/Sidebar/src/SidebarGroupContent.d.ts +2 -0
  274. package/dist/layouts/Sidebar/src/SidebarGroupLabel.d.ts +2 -0
  275. package/dist/layouts/Sidebar/src/SidebarHeader.d.ts +2 -0
  276. package/dist/layouts/Sidebar/src/SidebarMenu.d.ts +2 -0
  277. package/dist/layouts/Sidebar/src/SidebarMenuAction.d.ts +2 -0
  278. package/dist/layouts/Sidebar/src/SidebarMenuButton.d.ts +2 -0
  279. package/dist/layouts/Sidebar/src/SidebarMenuIcon.d.ts +2 -0
  280. package/dist/layouts/Sidebar/src/SidebarMenuItem.d.ts +2 -0
  281. package/dist/layouts/Sidebar/src/SidebarMenuSkeleton.d.ts +2 -0
  282. package/dist/layouts/Sidebar/src/SidebarMenuSub.d.ts +2 -0
  283. package/dist/layouts/Sidebar/src/SidebarMenuSubButton.d.ts +2 -0
  284. package/dist/layouts/Sidebar/src/SidebarMenuSubItem.d.ts +2 -0
  285. package/dist/layouts/Sidebar/src/SidebarMenuTag.d.ts +2 -0
  286. package/dist/layouts/Sidebar/src/SidebarSeparator.d.ts +2 -0
  287. package/dist/layouts/Sidebar/src/SidebarTrigger.d.ts +2 -0
  288. package/dist/layouts/Sidebar/src/context/MenuItem/MenuItemContext.d.ts +2 -0
  289. package/dist/layouts/Sidebar/src/context/MenuItem/MenuItemContext.types.d.ts +12 -0
  290. package/dist/layouts/Sidebar/src/context/MenuItem/MenuItemProvider.d.ts +2 -0
  291. package/dist/layouts/Sidebar/src/context/MenuItem/useMenuItemContext.d.ts +1 -0
  292. package/dist/layouts/Sidebar/src/context/Sidebar/SidebarContext.d.ts +2 -0
  293. package/dist/layouts/Sidebar/src/context/Sidebar/SidebarContext.types.d.ts +7 -0
  294. package/dist/layouts/Sidebar/src/context/Sidebar/SidebarProvider.d.ts +2 -0
  295. package/dist/layouts/Sidebar/src/context/Sidebar/SidebarProvider.types.d.ts +4 -0
  296. package/dist/layouts/Sidebar/src/context/Sidebar/useSidebarContext.d.ts +1 -0
  297. package/dist/layouts/Sidebar/test/Sidebar.test.d.ts +1 -0
  298. package/dist/layouts/index.d.ts +3 -0
  299. package/dist/layouts/layouts.cjs.js +1 -1
  300. package/dist/layouts/layouts.es.js +406 -668
  301. package/dist/legacy/hooks/useVirtualList/index.d.ts +2 -0
  302. package/dist/legacy/hooks/useVirtualList/src/useVirtualList.d.ts +2 -0
  303. package/dist/legacy/hooks/useVirtualList/src/useVirtualList.types.d.ts +23 -0
  304. package/dist/legacy/hooks/useVirtualList/src/utils/binarySearch.d.ts +1 -0
  305. package/dist/legacy/index.d.ts +6 -0
  306. package/dist/legacy/layouts/Header/Header.stories.d.ts +43 -0
  307. package/dist/legacy/layouts/Header/index.d.ts +1 -0
  308. package/dist/legacy/layouts/Header/src/Header.d.ts +2 -0
  309. package/dist/legacy/layouts/Header/src/Header.types.d.ts +8 -0
  310. package/dist/legacy/layouts/Header/test/Header.test.d.ts +1 -0
  311. package/dist/legacy/layouts/MainContent/MainContent.stories.d.ts +42 -0
  312. package/dist/legacy/layouts/MainContent/index.d.ts +1 -0
  313. package/dist/legacy/layouts/MainContent/src/MainContent.d.ts +2 -0
  314. package/dist/legacy/layouts/MainContent/src/MainContent.types.d.ts +10 -0
  315. package/dist/legacy/layouts/MainContent/test/MainContent.test.d.ts +1 -0
  316. package/dist/legacy/layouts/Sidebar/Sidebar.stories.d.ts +61 -0
  317. package/dist/legacy/layouts/Sidebar/index.d.ts +10 -0
  318. package/dist/legacy/layouts/Sidebar/src/Sidebar.d.ts +2 -0
  319. package/dist/legacy/layouts/Sidebar/src/Sidebar.types.d.ts +37 -0
  320. package/dist/legacy/layouts/Sidebar/src/SidebarBody.d.ts +2 -0
  321. package/dist/legacy/layouts/Sidebar/src/SidebarButton.d.ts +2 -0
  322. package/dist/legacy/layouts/Sidebar/src/SidebarFooter.d.ts +2 -0
  323. package/dist/legacy/layouts/Sidebar/src/SidebarGroup.d.ts +2 -0
  324. package/dist/legacy/layouts/Sidebar/src/SidebarHeader.d.ts +2 -0
  325. package/dist/legacy/layouts/Sidebar/src/SidebarIcon.d.ts +2 -0
  326. package/dist/legacy/layouts/Sidebar/src/SidebarLabel.d.ts +2 -0
  327. package/dist/legacy/layouts/Sidebar/src/SidebarLink.d.ts +2 -0
  328. package/dist/legacy/layouts/Sidebar/src/constants.d.ts +5 -0
  329. package/dist/legacy/layouts/Sidebar/src/context/SidebarContext.d.ts +2 -0
  330. package/dist/legacy/layouts/Sidebar/src/context/SidebarContext.types.d.ts +4 -0
  331. package/dist/legacy/layouts/Sidebar/src/context/useSidebarContext.d.ts +1 -0
  332. package/dist/legacy/layouts/Sidebar/test/Sidebar.test.d.ts +1 -0
  333. package/dist/legacy/legacy.cjs.js +1 -0
  334. package/dist/legacy/legacy.es.js +842 -0
  335. package/dist/legacy/ui/EndlessList/EndlessList.stories.d.ts +27 -0
  336. package/dist/legacy/ui/EndlessList/index.d.ts +6 -0
  337. package/dist/legacy/ui/EndlessList/src/EndlessList.d.ts +2 -0
  338. package/dist/legacy/ui/EndlessList/src/EndlessList.types.d.ts +25 -0
  339. package/dist/legacy/ui/EndlessList/src/EndlessListEmpty.d.ts +2 -0
  340. package/dist/legacy/ui/EndlessList/src/EndlessListError.d.ts +2 -0
  341. package/dist/legacy/ui/EndlessList/src/EndlessListLoader.d.ts +2 -0
  342. package/dist/legacy/ui/EndlessList/src/context/EndlessListContext.d.ts +2 -0
  343. package/dist/legacy/ui/EndlessList/src/context/EndlessListContext.types.d.ts +7 -0
  344. package/dist/legacy/ui/EndlessList/src/context/index.d.ts +3 -0
  345. package/dist/legacy/ui/EndlessList/src/context/useEndlessListContext.d.ts +2 -0
  346. package/dist/legacy/ui/EndlessList/test/EndlessList.test.d.ts +1 -0
  347. package/dist/legacy/ui/Floating/Floating.stories.d.ts +80 -0
  348. package/dist/legacy/ui/Floating/index.d.ts +8 -0
  349. package/dist/legacy/ui/Floating/src/Floating.d.ts +2 -0
  350. package/dist/legacy/ui/Floating/src/Floating.types.d.ts +29 -0
  351. package/dist/legacy/ui/Floating/src/FloatingContent.d.ts +2 -0
  352. package/dist/legacy/ui/Floating/src/FloatingTrigger.d.ts +2 -0
  353. package/dist/legacy/ui/Floating/src/context/FloatingContext.d.ts +2 -0
  354. package/dist/legacy/ui/Floating/src/context/FloatingContext.types.d.ts +17 -0
  355. package/dist/legacy/ui/Floating/src/context/useFloatingContext.d.ts +1 -0
  356. package/dist/legacy/ui/Floating/test/Floating.test.d.ts +1 -0
  357. package/dist/onyx.cjs.js +1 -1
  358. package/dist/onyx.es.js +68 -51
  359. package/dist/pages/Login/Login.stories.d.ts +56 -0
  360. package/dist/pages/Login/index.d.ts +2 -0
  361. package/dist/pages/Login/src/Login.d.ts +2 -0
  362. package/dist/pages/Login/src/Login.types.d.ts +18 -0
  363. package/dist/pages/index.d.ts +1 -0
  364. package/dist/pages/pages.cjs.js +1 -13
  365. package/dist/pages/pages.es.js +94 -126
  366. package/dist/routes/GuestRoute/index.d.ts +2 -0
  367. package/dist/routes/GuestRoute/src/GuestRoute.d.ts +2 -0
  368. package/dist/routes/GuestRoute/src/GuestRoute.types.d.ts +6 -0
  369. package/dist/routes/GuestRoute/test/GuestRoute.test.d.ts +1 -0
  370. package/dist/routes/ProtectedRoute/index.d.ts +2 -0
  371. package/dist/routes/ProtectedRoute/src/ProtectedRoute.d.ts +2 -0
  372. package/dist/routes/ProtectedRoute/src/ProtectedRoute.types.d.ts +6 -0
  373. package/dist/routes/ProtectedRoute/test/ProtectedRoute.test.d.ts +1 -0
  374. package/dist/routes/RoleRoute/index.d.ts +2 -0
  375. package/dist/routes/RoleRoute/src/RoleRoute.d.ts +2 -0
  376. package/dist/routes/RoleRoute/src/RoleRoute.types.d.ts +7 -0
  377. package/dist/routes/RoleRoute/test/RoleRoute.test.d.ts +1 -0
  378. package/dist/routes/index.d.ts +3 -0
  379. package/dist/routes/routes.cjs.js +1 -1
  380. package/dist/routes/routes.es.js +8 -8
  381. package/dist/typography/Description/Description.stories.d.ts +38 -0
  382. package/dist/typography/Description/index.d.ts +2 -0
  383. package/dist/typography/Description/src/Description.d.ts +2 -0
  384. package/dist/typography/Description/src/Description.types.d.ts +5 -0
  385. package/dist/typography/Description/test/Description.test.d.ts +1 -0
  386. package/dist/typography/Error/Error.stories.d.ts +34 -0
  387. package/dist/typography/Error/index.d.ts +2 -0
  388. package/dist/typography/Error/src/Error.d.ts +2 -0
  389. package/dist/typography/Error/src/Error.types.d.ts +2 -0
  390. package/dist/typography/Error/test/Error.test.d.ts +1 -0
  391. package/dist/typography/Heading/Heading.stories.d.ts +326 -0
  392. package/dist/typography/Heading/index.d.ts +2 -0
  393. package/dist/typography/Heading/src/Heading.d.ts +283 -0
  394. package/dist/typography/Heading/src/Heading.types.d.ts +9 -0
  395. package/dist/typography/Heading/test/Heading.test.d.ts +1 -0
  396. package/dist/typography/Label/Label.stories.d.ts +46 -0
  397. package/dist/typography/Label/index.d.ts +2 -0
  398. package/dist/typography/Label/src/Label.d.ts +2 -0
  399. package/dist/typography/Label/src/Label.types.d.ts +6 -0
  400. package/dist/typography/Label/test/Label.test.d.ts +1 -0
  401. package/dist/typography/Legend/Legend.stories.d.ts +42 -0
  402. package/dist/typography/Legend/index.d.ts +2 -0
  403. package/dist/typography/Legend/src/Legend.d.ts +2 -0
  404. package/dist/typography/Legend/src/Legend.types.d.ts +6 -0
  405. package/dist/typography/Legend/test/Legend.test.d.ts +1 -0
  406. package/dist/typography/index.d.ts +5 -0
  407. package/dist/ui/Accordion/Accordion.stories.d.ts +59 -0
  408. package/dist/ui/Accordion/index.d.ts +6 -0
  409. package/dist/ui/Accordion/src/Accordion.d.ts +2 -0
  410. package/dist/ui/Accordion/src/Accordion.types.d.ts +16 -0
  411. package/dist/ui/Accordion/src/AccordionContent.d.ts +2 -0
  412. package/dist/ui/Accordion/src/AccordionItem.d.ts +2 -0
  413. package/dist/ui/Accordion/src/AccordionTrigger.d.ts +2 -0
  414. package/dist/ui/Accordion/src/context/AccordionContext.d.ts +2 -0
  415. package/dist/ui/Accordion/src/context/AccordionContext.types.d.ts +12 -0
  416. package/dist/ui/Accordion/src/context/AccordionItemContext.d.ts +2 -0
  417. package/dist/ui/Accordion/src/context/useAccordionContext.d.ts +1 -0
  418. package/dist/ui/Accordion/src/context/useAccordionItemContext.d.ts +1 -0
  419. package/dist/ui/Accordion/test/Accordion.test.d.ts +1 -0
  420. package/dist/ui/Alert/Alert.stories.d.ts +36 -0
  421. package/dist/ui/Alert/index.d.ts +5 -0
  422. package/dist/ui/Alert/src/Alert.d.ts +2 -0
  423. package/dist/ui/Alert/src/Alert.types.d.ts +8 -0
  424. package/dist/ui/Alert/src/AlertDescription.d.ts +2 -0
  425. package/dist/ui/Alert/src/AlertTitle.d.ts +2 -0
  426. package/dist/ui/Alert/src/alert.styles.d.ts +3 -0
  427. package/dist/ui/Alert/src/context/AlertContext.d.ts +2 -0
  428. package/dist/ui/Alert/src/context/AlertContext.types.d.ts +4 -0
  429. package/dist/ui/Alert/src/context/useAlertContext.d.ts +1 -0
  430. package/dist/ui/Alert/test/Alert.test.d.ts +1 -0
  431. package/dist/ui/AspectRatio/AspectRatio.stories.d.ts +48 -0
  432. package/dist/ui/AspectRatio/index.d.ts +6 -0
  433. package/dist/ui/AspectRatio/src/AspectRatio.d.ts +2 -0
  434. package/dist/ui/AspectRatio/src/AspectRatio.types.d.ts +30 -0
  435. package/dist/ui/AspectRatio/src/AspectRatioFallback.d.ts +2 -0
  436. package/dist/ui/AspectRatio/src/AspectRatioImage.d.ts +2 -0
  437. package/dist/ui/AspectRatio/src/AspectRatioVideo.d.ts +2 -0
  438. package/dist/ui/AspectRatio/src/context/AspectRatioContext.d.ts +2 -0
  439. package/dist/ui/AspectRatio/src/context/AspectRatioContext.types.d.ts +11 -0
  440. package/dist/ui/AspectRatio/src/context/useAspectRatioContext.d.ts +1 -0
  441. package/dist/ui/AspectRatio/test/AspectRatio.test.d.ts +1 -0
  442. package/dist/ui/Avatar/Avatar.stories.d.ts +70 -0
  443. package/dist/ui/Avatar/index.d.ts +7 -0
  444. package/dist/ui/Avatar/src/Avatar.d.ts +2 -0
  445. package/dist/ui/Avatar/src/Avatar.types.d.ts +26 -0
  446. package/dist/ui/Avatar/src/AvatarField.d.ts +2 -0
  447. package/dist/ui/Avatar/src/AvatarFieldContent.d.ts +2 -0
  448. package/dist/ui/Avatar/src/AvatarFieldName.d.ts +2 -0
  449. package/dist/ui/Avatar/src/AvatarFieldSubtitle.d.ts +2 -0
  450. package/dist/ui/Avatar/src/avatar.styles.d.ts +11 -0
  451. package/dist/ui/Avatar/test/Avatar.test.d.ts +1 -0
  452. package/dist/ui/Badge/Badge.stories.d.ts +60 -0
  453. package/dist/ui/Badge/index.d.ts +2 -0
  454. package/dist/ui/Badge/src/Badge.d.ts +2 -0
  455. package/dist/ui/Badge/src/Badge.types.d.ts +11 -0
  456. package/dist/ui/Badge/src/badge.styles.d.ts +9 -0
  457. package/dist/ui/Badge/test/Badge.test.d.ts +1 -0
  458. package/dist/ui/Breadcrumb/Breadcrumb.stories.d.ts +42 -0
  459. package/dist/ui/Breadcrumb/index.d.ts +8 -0
  460. package/dist/ui/Breadcrumb/src/Breadcrumb.d.ts +2 -0
  461. package/dist/ui/Breadcrumb/src/Breadcrumb.types.d.ts +18 -0
  462. package/dist/ui/Breadcrumb/src/BreadcrumbEllipsis.d.ts +2 -0
  463. package/dist/ui/Breadcrumb/src/BreadcrumbItem.d.ts +2 -0
  464. package/dist/ui/Breadcrumb/src/BreadcrumbLink.d.ts +2 -0
  465. package/dist/ui/Breadcrumb/src/BreadcrumbPage.d.ts +2 -0
  466. package/dist/ui/Breadcrumb/src/BreadcrumbSeparator.d.ts +2 -0
  467. package/dist/ui/Breadcrumb/test/Breadcrumb.test.d.ts +1 -0
  468. package/dist/ui/Button/Button.stories.d.ts +74 -0
  469. package/dist/ui/Button/index.d.ts +2 -0
  470. package/dist/ui/Button/src/Button.d.ts +2 -0
  471. package/dist/ui/Button/src/Button.types.d.ts +9 -0
  472. package/dist/ui/Button/test/Button.test.d.ts +1 -0
  473. package/dist/ui/Calendar/Calendar.stories.d.ts +33 -0
  474. package/dist/ui/Calendar/index.d.ts +2 -0
  475. package/dist/ui/Calendar/src/Calendar.d.ts +2 -0
  476. package/dist/ui/Calendar/src/Calendar.types.d.ts +20 -0
  477. package/dist/ui/Calendar/src/CalendarGrid.d.ts +2 -0
  478. package/dist/ui/Calendar/src/CalendarHeader.d.ts +2 -0
  479. package/dist/ui/Calendar/test/Calendar.test.d.ts +1 -0
  480. package/dist/ui/Card/Card.stories.d.ts +73 -0
  481. package/dist/ui/Card/index.d.ts +7 -0
  482. package/dist/ui/Card/src/Card.d.ts +2 -0
  483. package/dist/ui/Card/src/Card.types.d.ts +20 -0
  484. package/dist/ui/Card/src/CardAction.d.ts +2 -0
  485. package/dist/ui/Card/src/CardContent.d.ts +2 -0
  486. package/dist/ui/Card/src/CardFooter.d.ts +2 -0
  487. package/dist/ui/Card/src/CardHeader.d.ts +2 -0
  488. package/dist/ui/Card/test/Card.test.d.ts +1 -0
  489. package/dist/ui/DescriptionList/DescriptionList.stories.d.ts +11 -0
  490. package/dist/ui/DescriptionList/index.d.ts +4 -0
  491. package/dist/ui/DescriptionList/src/DescriptionList.d.ts +2 -0
  492. package/dist/ui/DescriptionList/src/DescriptionList.types.d.ts +11 -0
  493. package/dist/ui/DescriptionList/src/DescriptionListTerm.d.ts +2 -0
  494. package/dist/ui/DescriptionList/src/DescriptionListValue.d.ts +2 -0
  495. package/dist/ui/DescriptionList/test/DescriptionList.test.d.ts +1 -0
  496. package/dist/ui/Dialog/Dialog.stories.d.ts +11 -0
  497. package/dist/ui/Dialog/index.d.ts +6 -0
  498. package/dist/ui/Dialog/src/Dialog.d.ts +2 -0
  499. package/dist/ui/Dialog/src/Dialog.types.d.ts +20 -0
  500. package/dist/ui/Dialog/src/DialogBody.d.ts +2 -0
  501. package/dist/ui/Dialog/src/DialogFooter.d.ts +2 -0
  502. package/dist/ui/Dialog/src/DialogHeader.d.ts +2 -0
  503. package/dist/ui/Dialog/src/context/DialogContext.d.ts +2 -0
  504. package/dist/ui/Dialog/src/context/DialogContext.types.d.ts +7 -0
  505. package/dist/ui/Dialog/src/context/useDialog.d.ts +1 -0
  506. package/dist/ui/Dialog/test/Dialog.test.d.ts +1 -0
  507. package/dist/ui/Dnd/OxDnd.stories.d.ts +50 -0
  508. package/dist/ui/Dnd/index.d.ts +11 -0
  509. package/dist/ui/Dnd/src/DndContext.d.ts +2 -0
  510. package/dist/ui/Dnd/src/DndContext.types.d.ts +9 -0
  511. package/dist/ui/Dnd/src/Draggable.d.ts +2 -0
  512. package/dist/ui/Dnd/src/Draggable.types.d.ts +7 -0
  513. package/dist/ui/Dnd/src/Droppable.d.ts +2 -0
  514. package/dist/ui/Dnd/src/Droppable.types.d.ts +7 -0
  515. package/dist/ui/Dnd/src/context/DndContext.d.ts +2 -0
  516. package/dist/ui/Dnd/src/context/DndContext.types.d.ts +9 -0
  517. package/dist/ui/Dnd/src/context/useDndContext.d.ts +1 -0
  518. package/dist/ui/Dnd/test/Dnd.test.d.ts +1 -0
  519. package/dist/ui/Drawer/Drawer.stories.d.ts +53 -0
  520. package/dist/ui/Drawer/index.d.ts +8 -0
  521. package/dist/ui/Drawer/src/Drawer.d.ts +2 -0
  522. package/dist/ui/Drawer/src/Drawer.types.d.ts +26 -0
  523. package/dist/ui/Drawer/src/DrawerBody.d.ts +2 -0
  524. package/dist/ui/Drawer/src/DrawerContent.d.ts +2 -0
  525. package/dist/ui/Drawer/src/DrawerFooter.d.ts +2 -0
  526. package/dist/ui/Drawer/src/DrawerHeader.d.ts +2 -0
  527. package/dist/ui/Drawer/src/DrawerTrigger.d.ts +2 -0
  528. package/dist/ui/Drawer/src/context/DrawerContext.d.ts +2 -0
  529. package/dist/ui/Drawer/src/context/DrawerContext.types.d.ts +5 -0
  530. package/dist/ui/Drawer/src/context/useDrawerContext.d.ts +1 -0
  531. package/dist/ui/Drawer/test/Drawer.test.d.ts +1 -0
  532. package/dist/ui/Dropdown/Dropdown.stories.d.ts +78 -0
  533. package/dist/ui/Dropdown/index.d.ts +12 -0
  534. package/dist/ui/Dropdown/src/Dropdown.d.ts +2 -0
  535. package/dist/ui/Dropdown/src/Dropdown.types.d.ts +52 -0
  536. package/dist/ui/Dropdown/src/DropdownBody.d.ts +2 -0
  537. package/dist/ui/Dropdown/src/DropdownContent.d.ts +2 -0
  538. package/dist/ui/Dropdown/src/DropdownFooter.d.ts +2 -0
  539. package/dist/ui/Dropdown/src/DropdownHeader.d.ts +2 -0
  540. package/dist/ui/Dropdown/src/DropdownItem.d.ts +2 -0
  541. package/dist/ui/Dropdown/src/DropdownLabel.d.ts +2 -0
  542. package/dist/ui/Dropdown/src/DropdownSeparator.d.ts +2 -0
  543. package/dist/ui/Dropdown/src/DropdownShortcut.d.ts +2 -0
  544. package/dist/ui/Dropdown/src/DropdownTrigger.d.ts +2 -0
  545. package/dist/ui/Dropdown/src/context/DropdownContext.d.ts +2 -0
  546. package/dist/ui/Dropdown/src/context/DropdownContext.types.d.ts +11 -0
  547. package/dist/ui/Dropdown/src/context/useDropdownContext.d.ts +1 -0
  548. package/dist/ui/Dropdown/test/Dropdown.test.d.ts +1 -0
  549. package/dist/ui/EndlessList/EndlessList.stories.d.ts +89 -0
  550. package/dist/ui/EndlessList/index.d.ts +8 -0
  551. package/dist/ui/EndlessList/src/EndlessList.d.ts +2 -0
  552. package/dist/ui/EndlessList/src/EndlessList.types.d.ts +32 -0
  553. package/dist/ui/EndlessList/src/EndlessListEmpty.d.ts +2 -0
  554. package/dist/ui/EndlessList/src/EndlessListError.d.ts +2 -0
  555. package/dist/ui/EndlessList/src/EndlessListItem.d.ts +2 -0
  556. package/dist/ui/EndlessList/src/EndlessListItems.d.ts +2 -0
  557. package/dist/ui/EndlessList/src/EndlessListLoader.d.ts +2 -0
  558. package/dist/ui/EndlessList/src/context/EndlessListContext.d.ts +16 -0
  559. package/dist/ui/EndlessList/src/context/ItemContext.d.ts +10 -0
  560. package/dist/ui/EndlessList/src/context/index.d.ts +4 -0
  561. package/dist/ui/EndlessList/test/EndlessList.test.d.ts +1 -0
  562. package/dist/ui/HoverCard/HoverCard.stories.d.ts +71 -0
  563. package/dist/ui/HoverCard/index.d.ts +5 -0
  564. package/dist/ui/HoverCard/src/HoverCard.d.ts +2 -0
  565. package/dist/ui/HoverCard/src/HoverCard.types.d.ts +21 -0
  566. package/dist/ui/HoverCard/src/HoverCardContent.d.ts +2 -0
  567. package/dist/ui/HoverCard/src/HoverCardTrigger.d.ts +2 -0
  568. package/dist/ui/HoverCard/src/context/HoverCardContext.d.ts +2 -0
  569. package/dist/ui/HoverCard/src/context/HoverCardContext.types.d.ts +14 -0
  570. package/dist/ui/HoverCard/src/context/useHoverCardContext.d.ts +1 -0
  571. package/dist/ui/HoverCard/test/HoverCard.test.d.ts +1 -0
  572. package/dist/ui/Icon/Icon.stories.d.ts +52 -0
  573. package/dist/ui/Icon/index.d.ts +4 -0
  574. package/dist/ui/Icon/src/Icon.d.ts +2 -0
  575. package/dist/ui/Icon/src/Icon.types.d.ts +21 -0
  576. package/dist/ui/Icon/src/IconBox.d.ts +2 -0
  577. package/dist/ui/Icon/src/constants.d.ts +9 -0
  578. package/dist/ui/Icon/src/context/IconBoxContext.d.ts +2 -0
  579. package/dist/ui/Icon/src/context/IconBoxContext.types.d.ts +5 -0
  580. package/dist/ui/Icon/src/context/useIconBoxContext.d.ts +1 -0
  581. package/dist/ui/Icon/src/icon.styles.d.ts +3 -0
  582. package/dist/ui/Icon/test/Icon.test.d.ts +1 -0
  583. package/dist/ui/Image/Image.stories.d.ts +50 -0
  584. package/dist/ui/Image/index.d.ts +2 -0
  585. package/dist/ui/Image/src/Image.d.ts +2 -0
  586. package/dist/ui/Image/src/Image.types.d.ts +9 -0
  587. package/dist/ui/Image/test/Image.test.d.ts +1 -0
  588. package/dist/ui/JsonField/JsonField.stories.d.ts +32 -0
  589. package/dist/ui/JsonField/index.d.ts +4 -0
  590. package/dist/ui/JsonField/src/JsonField.d.ts +2 -0
  591. package/dist/ui/JsonField/src/JsonField.types.d.ts +12 -0
  592. package/dist/ui/JsonField/src/JsonNode.d.ts +2 -0
  593. package/dist/ui/JsonField/test/JsonField.test.d.ts +1 -0
  594. package/dist/ui/Kanban/Kanban.stories.d.ts +49 -0
  595. package/dist/ui/Kanban/index.d.ts +8 -0
  596. package/dist/ui/Kanban/src/Kanban.d.ts +2 -0
  597. package/dist/ui/Kanban/src/Kanban.types.d.ts +30 -0
  598. package/dist/ui/Kanban/src/KanbanCard.d.ts +2 -0
  599. package/dist/ui/Kanban/src/KanbanCardHandle.d.ts +2 -0
  600. package/dist/ui/Kanban/src/KanbanColumn.d.ts +2 -0
  601. package/dist/ui/Kanban/src/KanbanColumnFooter.d.ts +2 -0
  602. package/dist/ui/Kanban/src/KanbanColumnHeader.d.ts +2 -0
  603. package/dist/ui/Kanban/src/context/KanbanCardContext.d.ts +3 -0
  604. package/dist/ui/Kanban/src/context/KanbanColumnContext.d.ts +3 -0
  605. package/dist/ui/Kanban/src/context/KanbanContext.d.ts +3 -0
  606. package/dist/ui/Kanban/src/context/KanbanContext.types.d.ts +23 -0
  607. package/dist/ui/Kanban/src/context/index.d.ts +4 -0
  608. package/dist/ui/Kanban/test/Kanban.test.d.ts +1 -0
  609. package/dist/ui/Link/Link.stories.d.ts +51 -0
  610. package/dist/ui/Link/index.d.ts +2 -0
  611. package/dist/ui/Link/src/Link.d.ts +2 -0
  612. package/dist/ui/Link/src/Link.types.d.ts +7 -0
  613. package/dist/ui/Link/test/Link.test.d.ts +1 -0
  614. package/dist/ui/Masonry/Masonry.stories.d.ts +31 -0
  615. package/dist/ui/Masonry/index.d.ts +2 -0
  616. package/dist/ui/Masonry/src/Masonry.d.ts +2 -0
  617. package/dist/ui/Masonry/src/Masonry.types.d.ts +11 -0
  618. package/dist/ui/Masonry/src/hooks/useMasonry.d.ts +10 -0
  619. package/dist/ui/Masonry/test/Masonry.test.d.ts +1 -0
  620. package/dist/ui/Notifications/Notifications.stories.d.ts +70 -0
  621. package/dist/ui/Notifications/index.d.ts +7 -0
  622. package/dist/ui/Notifications/src/Notifications.d.ts +2 -0
  623. package/dist/ui/Notifications/src/Notifications.types.d.ts +50 -0
  624. package/dist/ui/Notifications/src/NotificationsBody.d.ts +2 -0
  625. package/dist/ui/Notifications/src/NotificationsButton.d.ts +2 -0
  626. package/dist/ui/Notifications/src/NotificationsLink.d.ts +2 -0
  627. package/dist/ui/Notifications/src/NotificationsTrigger.d.ts +2 -0
  628. package/dist/ui/Notifications/src/context/NotificationsContext.d.ts +2 -0
  629. package/dist/ui/Notifications/src/context/NotificationsContext.types.d.ts +12 -0
  630. package/dist/ui/Notifications/src/context/useNotificationsContext.d.ts +1 -0
  631. package/dist/ui/Notifications/test/Notifications.test.d.ts +1 -0
  632. package/dist/ui/PageOutline/PageOutline.stories.d.ts +41 -0
  633. package/dist/ui/PageOutline/index.d.ts +6 -0
  634. package/dist/ui/PageOutline/src/PageOutline.d.ts +2 -0
  635. package/dist/ui/PageOutline/src/PageOutline.types.d.ts +17 -0
  636. package/dist/ui/PageOutline/src/PageOutlineContent.d.ts +2 -0
  637. package/dist/ui/PageOutline/src/PageOutlineHeader.d.ts +2 -0
  638. package/dist/ui/PageOutline/src/PageOutlineItem.d.ts +2 -0
  639. package/dist/ui/PageOutline/src/context/PageOutlineContext.d.ts +11 -0
  640. package/dist/ui/PageOutline/test/PageOutline.test.d.ts +1 -0
  641. package/dist/ui/Pagination/Pagination.stories.d.ts +43 -0
  642. package/dist/ui/Pagination/index.d.ts +8 -0
  643. package/dist/ui/Pagination/src/Pagination.d.ts +2 -0
  644. package/dist/ui/Pagination/src/Pagination.types.d.ts +27 -0
  645. package/dist/ui/Pagination/src/PaginationEllipsis.d.ts +2 -0
  646. package/dist/ui/Pagination/src/PaginationItem.d.ts +2 -0
  647. package/dist/ui/Pagination/src/PaginationLink.d.ts +2 -0
  648. package/dist/ui/Pagination/src/PaginationNext.d.ts +2 -0
  649. package/dist/ui/Pagination/src/PaginationPrevious.d.ts +2 -0
  650. package/dist/ui/Pagination/test/Pagination.test.d.ts +1 -0
  651. package/dist/ui/Popover/Popover.stories.d.ts +66 -0
  652. package/dist/ui/Popover/index.d.ts +5 -0
  653. package/dist/ui/Popover/src/Popover.d.ts +2 -0
  654. package/dist/ui/Popover/src/Popover.types.d.ts +20 -0
  655. package/dist/ui/Popover/src/PopoverContent.d.ts +2 -0
  656. package/dist/ui/Popover/src/PopoverTrigger.d.ts +2 -0
  657. package/dist/ui/Popover/src/context/PopoverContext.d.ts +2 -0
  658. package/dist/ui/Popover/src/context/PopoverContext.types.d.ts +10 -0
  659. package/dist/ui/Popover/src/context/usePopoverContext.d.ts +1 -0
  660. package/dist/ui/Popover/test/Popover.test.d.ts +1 -0
  661. package/dist/ui/Popper/Popper.stories.d.ts +10 -0
  662. package/dist/ui/Popper/index.d.ts +9 -0
  663. package/dist/ui/Popper/src/Popper.d.ts +2 -0
  664. package/dist/ui/Popper/src/Popper.types.d.ts +27 -0
  665. package/dist/ui/Popper/src/Popper.utils.d.ts +10 -0
  666. package/dist/ui/Popper/src/PopperAnchor.d.ts +2 -0
  667. package/dist/ui/Popper/src/PopperArrow.d.ts +1 -0
  668. package/dist/ui/Popper/src/PopperContent.d.ts +2 -0
  669. package/dist/ui/Popper/src/context/PopperContext.d.ts +3 -0
  670. package/dist/ui/Popper/src/context/PopperContext.types.d.ts +14 -0
  671. package/dist/ui/Popper/src/context/usePopperContext.d.ts +2 -0
  672. package/dist/ui/Popper/src/hooks/index.d.ts +2 -0
  673. package/dist/ui/Popper/src/hooks/usePopperState.d.ts +2 -0
  674. package/dist/ui/Popper/src/hooks/usePopperState.types.d.ts +19 -0
  675. package/dist/ui/Popper/test/Popper.test.d.ts +1 -0
  676. package/dist/ui/Progress/Progress.stories.d.ts +59 -0
  677. package/dist/ui/Progress/index.d.ts +4 -0
  678. package/dist/ui/Progress/src/Progress.d.ts +2 -0
  679. package/dist/ui/Progress/src/Progress.types.d.ts +11 -0
  680. package/dist/ui/Progress/src/ProgressCircular.d.ts +2 -0
  681. package/dist/ui/Progress/test/Progress.test.d.ts +1 -0
  682. package/dist/ui/Progress/test/ProgressCircular.test.d.ts +1 -0
  683. package/dist/ui/Separator/Separator.stories.d.ts +36 -0
  684. package/dist/ui/Separator/index.d.ts +2 -0
  685. package/dist/ui/Separator/src/Separator.d.ts +2 -0
  686. package/dist/ui/Separator/src/Separator.types.d.ts +5 -0
  687. package/dist/ui/Separator/test/Separator.test.d.ts +1 -0
  688. package/dist/ui/Skeleton/Skeleton.stories.d.ts +50 -0
  689. package/dist/ui/Skeleton/index.d.ts +2 -0
  690. package/dist/ui/Skeleton/src/Skeleton.d.ts +2 -0
  691. package/dist/ui/Skeleton/src/Skeleton.types.d.ts +5 -0
  692. package/dist/ui/Skeleton/test/Skeleton.test.d.ts +1 -0
  693. package/dist/ui/Slider/Slider.stories.d.ts +79 -0
  694. package/dist/ui/Slider/index.d.ts +2 -0
  695. package/dist/ui/Slider/src/Slider.d.ts +2 -0
  696. package/dist/ui/Slider/src/Slider.types.d.ts +15 -0
  697. package/dist/ui/Slider/test/Slider.test.d.ts +1 -0
  698. package/dist/ui/SortableList/SortableList.stories.d.ts +50 -0
  699. package/dist/ui/SortableList/index.d.ts +5 -0
  700. package/dist/ui/SortableList/src/SortableList.d.ts +2 -0
  701. package/dist/ui/SortableList/src/SortableList.types.d.ts +21 -0
  702. package/dist/ui/SortableList/src/SortableListHandle.d.ts +2 -0
  703. package/dist/ui/SortableList/src/SortableListItem.d.ts +2 -0
  704. package/dist/ui/SortableList/src/context/SortableListContext.d.ts +2 -0
  705. package/dist/ui/SortableList/src/context/SortableListContext.types.d.ts +15 -0
  706. package/dist/ui/SortableList/src/context/SortableListItemContext.d.ts +2 -0
  707. package/dist/ui/SortableList/src/context/index.d.ts +4 -0
  708. package/dist/ui/SortableList/src/context/useSortableListContext.d.ts +2 -0
  709. package/dist/ui/SortableList/test/SortableList.test.d.ts +1 -0
  710. package/dist/ui/Spinner/Spinner.stories.d.ts +36 -0
  711. package/dist/ui/Spinner/index.d.ts +2 -0
  712. package/dist/ui/Spinner/src/Spinner.d.ts +2 -0
  713. package/dist/ui/Spinner/src/Spinner.types.d.ts +5 -0
  714. package/dist/ui/Spinner/test/Spinner.test.d.ts +1 -0
  715. package/dist/ui/StatusDisplay/StatusDisplay.stories.d.ts +62 -0
  716. package/dist/ui/StatusDisplay/index.d.ts +2 -0
  717. package/dist/ui/StatusDisplay/src/StatusDisplay.d.ts +2 -0
  718. package/dist/ui/StatusDisplay/src/StatusDisplay.types.d.ts +18 -0
  719. package/dist/ui/StatusDisplay/test/StatusDisplay.test.d.ts +1 -0
  720. package/dist/ui/Stepper/Stepper.stories.d.ts +11 -0
  721. package/dist/ui/Stepper/index.d.ts +5 -0
  722. package/dist/ui/Stepper/src/Stepper.d.ts +2 -0
  723. package/dist/ui/Stepper/src/Stepper.types.d.ts +29 -0
  724. package/dist/ui/Stepper/src/StepperActions.d.ts +2 -0
  725. package/dist/ui/Stepper/src/StepperConnector.d.ts +2 -0
  726. package/dist/ui/Stepper/src/StepperItem.d.ts +2 -0
  727. package/dist/ui/Stepper/src/context/StepperContext.d.ts +2 -0
  728. package/dist/ui/Stepper/src/context/StepperContext.types.d.ts +10 -0
  729. package/dist/ui/Stepper/src/context/useStepperContext.d.ts +1 -0
  730. package/dist/ui/Stepper/src/stepperHelper.d.ts +131 -0
  731. package/dist/ui/Stepper/test/Stepper.test.d.ts +1 -0
  732. package/dist/ui/Table/Table.stories.d.ts +79 -0
  733. package/dist/ui/Table/index.d.ts +11 -0
  734. package/dist/ui/Table/src/Table.d.ts +2 -0
  735. package/dist/ui/Table/src/Table.types.d.ts +35 -0
  736. package/dist/ui/Table/src/TableBody.d.ts +2 -0
  737. package/dist/ui/Table/src/TableCell.d.ts +2 -0
  738. package/dist/ui/Table/src/TableControls.d.ts +2 -0
  739. package/dist/ui/Table/src/TableFooter.d.ts +2 -0
  740. package/dist/ui/Table/src/TableHead.d.ts +2 -0
  741. package/dist/ui/Table/src/TableHeader.d.ts +2 -0
  742. package/dist/ui/Table/src/TableRow.d.ts +2 -0
  743. package/dist/ui/Table/src/TableSkeletonRow.d.ts +4 -0
  744. package/dist/ui/Table/src/context/TableContext.d.ts +2 -0
  745. package/dist/ui/Table/src/context/TableContext.types.d.ts +20 -0
  746. package/dist/ui/Table/src/context/TableSectionContext.d.ts +6 -0
  747. package/dist/ui/Table/src/context/useTableContext.d.ts +1 -0
  748. package/dist/ui/Table/test/Table.test.d.ts +1 -0
  749. package/dist/ui/Tabs/Tab.stories.d.ts +50 -0
  750. package/dist/ui/Tabs/index.d.ts +6 -0
  751. package/dist/ui/Tabs/src/Tabs.d.ts +2 -0
  752. package/dist/ui/Tabs/src/Tabs.types.d.ts +19 -0
  753. package/dist/ui/Tabs/src/TabsContent.d.ts +2 -0
  754. package/dist/ui/Tabs/src/TabsList.d.ts +2 -0
  755. package/dist/ui/Tabs/src/TabsTrigger.d.ts +2 -0
  756. package/dist/ui/Tabs/src/context/TabContext.d.ts +2 -0
  757. package/dist/ui/Tabs/src/context/TabContext.types.d.ts +5 -0
  758. package/dist/ui/Tabs/src/context/useTabContext.d.ts +1 -0
  759. package/dist/ui/Tabs/src/tabs.styles.d.ts +9 -0
  760. package/dist/ui/Tabs/test/Tabs.test.d.ts +1 -0
  761. package/dist/ui/Tag/Tag.stories.d.ts +34 -0
  762. package/dist/ui/Tag/index.d.ts +2 -0
  763. package/dist/ui/Tag/src/Tag.d.ts +2 -0
  764. package/dist/ui/Tag/src/Tag.types.d.ts +6 -0
  765. package/dist/ui/Tag/test/Tag.test.d.ts +1 -0
  766. package/dist/ui/ThemeSwitcher/ThemeSwitcher.stories.d.ts +35 -0
  767. package/dist/ui/ThemeSwitcher/index.d.ts +2 -0
  768. package/dist/ui/ThemeSwitcher/src/ThemeSwitcher.d.ts +2 -0
  769. package/dist/ui/ThemeSwitcher/src/ThemeSwitcher.types.d.ts +8 -0
  770. package/dist/ui/ThemeSwitcher/test/ThemeSwitcher.test.d.ts +1 -0
  771. package/dist/ui/Timeline/Timeline.stories.d.ts +10 -0
  772. package/dist/ui/Timeline/index.d.ts +4 -0
  773. package/dist/ui/Timeline/src/Timeline.d.ts +2 -0
  774. package/dist/ui/Timeline/src/Timeline.types.d.ts +16 -0
  775. package/dist/ui/Timeline/src/TimelineItem.d.ts +2 -0
  776. package/dist/ui/Timeline/test/Timeline.test.d.ts +1 -0
  777. package/dist/ui/Toast/Toast.stories.d.ts +12 -0
  778. package/dist/ui/Toast/index.d.ts +5 -0
  779. package/dist/ui/Toast/src/Toast.d.ts +2 -0
  780. package/dist/ui/Toast/src/Toast.types.d.ts +29 -0
  781. package/dist/ui/Toast/src/ToastItem.d.ts +2 -0
  782. package/dist/ui/Toast/src/context/ToastContext.d.ts +2 -0
  783. package/dist/ui/Toast/src/context/ToastContext.types.d.ts +28 -0
  784. package/dist/ui/Toast/src/context/ToastProvider.d.ts +2 -0
  785. package/dist/ui/Toast/src/context/useToast.d.ts +2 -0
  786. package/dist/ui/Toast/test/Toast.test.d.ts +1 -0
  787. package/dist/ui/Toggle/Toggle.stories.d.ts +53 -0
  788. package/dist/ui/Toggle/index.d.ts +4 -0
  789. package/dist/ui/Toggle/src/Toggle.d.ts +2 -0
  790. package/dist/ui/Toggle/src/Toggle.types.d.ts +28 -0
  791. package/dist/ui/Toggle/src/ToggleGroup.d.ts +2 -0
  792. package/dist/ui/Toggle/src/context/ToggleGroupContext.d.ts +2 -0
  793. package/dist/ui/Toggle/src/context/ToggleGroupContext.types.d.ts +8 -0
  794. package/dist/ui/Toggle/src/context/useToggleGroup.d.ts +1 -0
  795. package/dist/ui/Toggle/test/Toggle.test.d.ts +1 -0
  796. package/dist/ui/Tooltip/Tooltip.stories.d.ts +9 -0
  797. package/dist/ui/Tooltip/index.d.ts +5 -0
  798. package/dist/ui/Tooltip/src/Tooltip.d.ts +2 -0
  799. package/dist/ui/Tooltip/src/Tooltip.types.d.ts +14 -0
  800. package/dist/ui/Tooltip/src/TooltipProvider.d.ts +2 -0
  801. package/dist/ui/Tooltip/src/context/TooltipContext.d.ts +2 -0
  802. package/dist/ui/Tooltip/src/context/TooltipContext.types.d.ts +11 -0
  803. package/dist/ui/Tooltip/src/context/useOxTooltipContext.d.ts +2 -0
  804. package/dist/ui/Tooltip/test/Tooltip.test.d.ts +1 -0
  805. package/dist/ui/index.d.ts +43 -0
  806. package/dist/ui.css +1 -1
  807. package/dist/utils/builder/index.d.ts +3 -0
  808. package/dist/utils/builder/src/buildMailTo.d.ts +2 -0
  809. package/dist/utils/builder/src/buildUrl.d.ts +2 -0
  810. package/dist/utils/builder/src/builder.types.d.ts +10 -0
  811. package/dist/utils/builder/test/buildMailTo.test.d.ts +1 -0
  812. package/dist/utils/builder/test/buildUrl.test.d.ts +1 -0
  813. package/dist/utils/cn/index.d.ts +1 -0
  814. package/dist/utils/cn/src/cn.d.ts +2 -0
  815. package/dist/utils/cn/test/cn.test.d.ts +1 -0
  816. package/dist/utils/copyToClipboard/index.d.ts +1 -0
  817. package/dist/utils/copyToClipboard/src/copyToClipboard.d.ts +1 -0
  818. package/dist/utils/copyToClipboard/test/copyToClipboard.test.d.ts +1 -0
  819. package/dist/utils/createId/index.d.ts +2 -0
  820. package/dist/utils/createId/src/createId.d.ts +3 -0
  821. package/dist/utils/createId/src/createId.types.d.ts +10 -0
  822. package/dist/utils/createId/test/createId.test.d.ts +1 -0
  823. package/dist/utils/errorHelper/index.d.ts +2 -0
  824. package/dist/utils/errorHelper/src/errorHelper.d.ts +4 -0
  825. package/dist/utils/errorHelper/src/errorHelper.types.d.ts +17 -0
  826. package/dist/utils/errorHelper/test/errorHelper.test.d.ts +1 -0
  827. package/dist/utils/formatter/index.d.ts +6 -0
  828. package/dist/utils/formatter/src/formatBytes.d.ts +2 -0
  829. package/dist/utils/formatter/src/formatCurrency.d.ts +2 -0
  830. package/dist/utils/formatter/src/formatDate.d.ts +2 -0
  831. package/dist/utils/formatter/src/formatNumber.d.ts +2 -0
  832. package/dist/utils/formatter/src/formatTimestamp.d.ts +1 -0
  833. package/dist/utils/formatter/src/formatter.types.d.ts +18 -0
  834. package/dist/utils/formatter/test/formatBytes.test.d.ts +1 -0
  835. package/dist/utils/formatter/test/formatCurrency.test.d.ts +1 -0
  836. package/dist/utils/formatter/test/formatDate.test.d.ts +1 -0
  837. package/dist/utils/formatter/test/formatNumber.test.d.ts +1 -0
  838. package/dist/utils/formatter/test/formatTimestamp.test.d.ts +1 -0
  839. package/dist/utils/hasDataSlot/index.d.ts +1 -0
  840. package/dist/utils/hasDataSlot/src/hasDataSlot.d.ts +3 -0
  841. package/dist/utils/hasDataSlot/test/hasDataSlot.test.d.ts +1 -0
  842. package/dist/utils/index.d.ts +9 -0
  843. package/dist/utils/scrollToElement/index.d.ts +2 -0
  844. package/dist/utils/scrollToElement/src/scrollToElement.d.ts +2 -0
  845. package/dist/utils/scrollToElement/src/scrollToElement.types.d.ts +7 -0
  846. package/dist/utils/scrollToElement/test/scrollToElement.test.d.ts +1 -0
  847. package/dist/utils/utils.cjs.js +1 -1
  848. package/dist/utils/utils.es.js +6 -6
  849. package/dist/utils/validation/index.d.ts +4 -0
  850. package/dist/utils/validation/src/constants.d.ts +57 -0
  851. package/dist/utils/validation/src/validateEmail.d.ts +2 -0
  852. package/dist/utils/validation/src/validatePhone.d.ts +2 -0
  853. package/dist/utils/validation/src/validateUrl.d.ts +2 -0
  854. package/dist/utils/validation/src/validation.types.d.ts +13 -0
  855. package/dist/utils/validation/test/validateEmail.test.d.ts +1 -0
  856. package/dist/utils/validation/test/validatePhone.test.d.ts +1 -0
  857. package/dist/utils/validation/test/validateUrl.test.d.ts +1 -0
  858. package/package.json +62 -37
  859. package/dist/animations.css +0 -217
  860. package/dist/chunks/hooks-UiKjBucd.js +0 -47
  861. package/dist/chunks/query-CIsrxNi-.js +0 -10
  862. package/dist/chunks/query-D2S9cFBP.js +0 -14
  863. package/dist/chunks/ui-DaFpw1V6.js +0 -13291
  864. package/dist/chunks/ui-Dfv80f9y.js +0 -20
  865. package/dist/contexts.d.ts +0 -117
  866. package/dist/hooks.d.ts +0 -192
  867. package/dist/layouts.d.ts +0 -440
  868. package/dist/pages.d.ts +0 -15
  869. package/dist/routes.d.ts +0 -28
  870. package/dist/shared.css +0 -129
  871. package/dist/utils.d.ts +0 -133
package/AI-README.md ADDED
@@ -0,0 +1,4942 @@
1
+ # Onyx Component Library - AI Reference Guide
2
+
3
+ **Version:** 3.0.0 • **Updated:** 2025-12-16 • **Built from:** bfdd6f72
4
+
5
+ > This comprehensive reference guide provides detailed information about all components, hooks, contexts, utilities, and patterns in the Onyx component library. Designed for AI assistants and developers to quickly understand component APIs and usage.
6
+
7
+ ## Installation
8
+
9
+ Install Onyx and its peer dependencies:
10
+
11
+ ```bash
12
+ npm install @noxickon/onyx lucide-react
13
+ ```
14
+
15
+ ### Peer Dependencies
16
+
17
+ **Required:**
18
+
19
+ - `react` ^19.0.0
20
+ - `react-dom` ^19.0.0
21
+ - `lucide-react` ^0.500.0
22
+
23
+ **Optional:**
24
+
25
+ - `@apollo/client` ^4.0.0 (if using Apollo features)
26
+ - `graphql` ^16.0.0 (if using GraphQL features)
27
+ - `@mdi/js` ^7.4.47 (alternative icon library)
28
+ - `@mdi/react` ^1.6.1 (alternative icon library)
29
+
30
+ ## Setup
31
+
32
+ Import Onyx components and styles:
33
+
34
+ ```tsx
35
+ import { OxButton, OxCard } from '@noxickon/onyx';
36
+ import { Check } from 'lucide-react';
37
+ import '@noxickon/onyx/styles';
38
+
39
+ function App() {
40
+ return (
41
+ <OxButton variant="primary">
42
+ <OxIcon icon={Check} />
43
+ Click Me
44
+ </OxButton>
45
+ );
46
+ }
47
+ ```
48
+
49
+ ## Package Exports
50
+
51
+ Onyx uses a multi-entry build system for optimal tree-shaking:
52
+
53
+ ```tsx
54
+ // UI Components (main export)
55
+ import { OxButton, OxCard, OxDialog } from '@noxickon/onyx';
56
+
57
+ // Forms
58
+ import { OxCheckbox, OxInput, OxSelect } from '@noxickon/onyx/forms';
59
+
60
+ // Typography
61
+ import { OxHeading, OxLabel } from '@noxickon/onyx/typography';
62
+
63
+ // Contexts
64
+ import { OxAuthProvider, useOxAuth } from '@noxickon/onyx/contexts';
65
+
66
+ // Hooks
67
+ import { useForm, useFilterQuery, useFormState } from '@noxickon/onyx/hooks';
68
+
69
+ // Layouts
70
+ import { OxAppLayout, OxSidebar, OxMainContent } from '@noxickon/onyx/layouts';
71
+
72
+ // Route Guards
73
+ import { OxProtectedRoute, OxGuestRoute, OxRoleRoute } from '@noxickon/onyx/routes';
74
+
75
+ // Utilities
76
+ import { cn, buildUrl, validateEmail } from '@noxickon/onyx/utils';
77
+
78
+ // Legacy Components (deprecated)
79
+ import { OxFloating, useVirtualList } from '@noxickon/onyx/legacy';
80
+
81
+ // Styles
82
+ import '@noxickon/onyx/styles'; // Component styles (required)
83
+ import '@noxickon/onyx/shared'; // Shared utility classes (optional)
84
+ import '@noxickon/onyx/animations'; // Animations (optional)
85
+ ```
86
+
87
+ ---
88
+
89
+ # UI Components (43)
90
+
91
+ ## OxAccordion
92
+
93
+ Collapsible accordion component with single or multiple open items.
94
+
95
+ **Pattern**: Compound Component
96
+ **Sub-components**: `Content`, `Item`, `Trigger`
97
+
98
+ ### Props
99
+
100
+ ```tsx
101
+ interface OxAccordionProps extends ComponentPropsWithRef<'div'> {
102
+ children: ReactNode;
103
+ defaultValue?: string | string[]; // Default open accordion items
104
+ onValueChange?: (value: string | string[]) => void;
105
+ type?: 'single' | 'multiple'; // Single or multiple items can be open
106
+ value?: string | string[]; // Controlled value
107
+ }
108
+
109
+ interface OxAccordionItemProps extends ComponentPropsWithRef<'div'> {
110
+ children: ReactNode;
111
+ disabled?: boolean;
112
+ value: string; // Required - Unique identifier for the item
113
+ }
114
+
115
+ interface OxAccordionTriggerProps extends ComponentPropsWithRef<'button'> {}
116
+ interface OxAccordionContentProps extends ComponentPropsWithRef<'div'> {}
117
+ ```
118
+
119
+ ### Example
120
+
121
+ ```tsx
122
+ <OxAccordion type="multiple" defaultValue={['item-1']}>
123
+ <OxAccordion.Item value="item-1">
124
+ <OxAccordion.Trigger>Is it accessible?</OxAccordion.Trigger>
125
+ <OxAccordion.Content>Yes. It adheres to the WAI-ARIA design pattern.</OxAccordion.Content>
126
+ </OxAccordion.Item>
127
+ </OxAccordion>
128
+ ```
129
+
130
+ ---
131
+
132
+ ## OxAlert
133
+
134
+ Alert component with different types and compound pattern.
135
+
136
+ **Pattern**: Compound Component
137
+ **Sub-components**: `Title`, `Description`
138
+
139
+ ### Props
140
+
141
+ ```tsx
142
+ interface OxAlertProps extends ComponentPropsWithRef<'div'> {
143
+ children: ReactNode;
144
+ variant?: 'default' | 'destructive' | 'success' | 'warning' | 'info';
145
+ }
146
+
147
+ interface OxAlertTitleProps extends ComponentPropsWithRef<'div'> {}
148
+ interface OxAlertDescriptionProps extends ComponentPropsWithRef<'div'> {}
149
+ ```
150
+
151
+ ### Example
152
+
153
+ ```tsx
154
+ <OxAlert variant="success">
155
+ <OxAlert.Title>Success</OxAlert.Title>
156
+ <OxAlert.Description>Your changes have been saved.</OxAlert.Description>
157
+ </OxAlert>
158
+ ```
159
+
160
+ ---
161
+
162
+ ## OxAspectRatio
163
+
164
+ Container that maintains a specific aspect ratio for its content.
165
+
166
+ **Pattern**: Compound Component
167
+ **Sub-components**: `Fallback`, `Image`, `Video`
168
+
169
+ ### Props
170
+
171
+ ```tsx
172
+ interface OxAspectRatioProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
173
+ children: ReactNode;
174
+ isLoading?: boolean;
175
+ ratio: number; // Width/height ratio (e.g., 16/9 = 1.78)
176
+ }
177
+
178
+ interface OxAspectRatioImageProps {
179
+ alt: string;
180
+ className?: string;
181
+ crossOrigin?: '' | 'anonymous' | 'use-credentials';
182
+ loading?: 'eager' | 'lazy';
183
+ objectFit?: 'contain' | 'cover' | 'fill';
184
+ referrerPolicy?: ReferrerPolicy;
185
+ src: string;
186
+ }
187
+
188
+ interface OxAspectRatioVideoProps {
189
+ alt?: string;
190
+ autoPlay?: boolean;
191
+ className?: string;
192
+ controls?: boolean;
193
+ crossOrigin?: '' | 'anonymous' | 'use-credentials';
194
+ loop?: boolean;
195
+ muted?: boolean;
196
+ objectFit?: 'contain' | 'cover' | 'fill';
197
+ playsInline?: boolean;
198
+ src: string;
199
+ }
200
+
201
+ interface OxAspectRatioFallbackProps extends ComponentPropsWithRef<'div'> {
202
+ children: ReactNode;
203
+ }
204
+ ```
205
+
206
+ ### Usage
207
+
208
+ ```tsx
209
+ <OxAspectRatio ratio={16 / 9}>
210
+ <OxAspectRatio.Image src="/image.jpg" alt="Example" objectFit="cover" />
211
+ <OxAspectRatio.Fallback>Loading...</OxAspectRatio.Fallback>
212
+ </OxAspectRatio>
213
+
214
+ <OxAspectRatio ratio={4 / 3}>
215
+ <OxAspectRatio.Video src="/video.mp4" controls autoPlay muted />
216
+ </OxAspectRatio>
217
+ ```
218
+
219
+ ---
220
+
221
+ ## OxAvatar
222
+
223
+ Avatar component with status indicators and loading states.
224
+
225
+ **Pattern**: Simple Component
226
+
227
+ ### Props
228
+
229
+ ```tsx
230
+ interface OxAvatarProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
231
+ alt?: string;
232
+ fallback?: string | ReactNode; // Shown when image fails to load
233
+ isLoading?: boolean; // Shows loading state
234
+ shape?: 'rectangle' | 'circle';
235
+ showStatus?: boolean; // Display status indicator
236
+ size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
237
+ skeleton?: boolean; // Shows skeleton loader
238
+ src?: string;
239
+ status?: 'online' | 'offline' | 'away' | 'busy';
240
+ }
241
+ ```
242
+
243
+ ### Example
244
+
245
+ ```tsx
246
+ <OxAvatar
247
+ src="/avatar.jpg"
248
+ alt="User Name"
249
+ size="lg"
250
+ shape="circle"
251
+ showStatus
252
+ status="online"
253
+ fallback="UN"
254
+ />
255
+ ```
256
+
257
+ ---
258
+
259
+ ## OxBadge
260
+
261
+ Notification badge for displaying counts or status indicators on UI elements. Designed for use with ghost buttons and icons.
262
+
263
+ **Pattern**: Simple Component
264
+
265
+ > **Note:** Badges are optimized for ghost buttons and icons. For colored backgrounds, use the `bgColor` prop for custom solutions. Count badges use subtle backgrounds; dot badges use solid colors for status indicators.
266
+
267
+ ### Props
268
+
269
+ ```tsx
270
+ interface OxBadgeProps extends ComponentPropsWithRef<'span'> {
271
+ children?: ReactNode;
272
+ count?: number;
273
+ max?: number;
274
+ position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
275
+ showZero?: boolean;
276
+ type?: 'dot' | 'count';
277
+ variant?: ColorStyleName;
278
+ }
279
+ ```
280
+
281
+ ### Example
282
+
283
+ ```tsx
284
+ {/* Standalone count badge */}
285
+ <OxBadge count={5} />
286
+
287
+ {/* Badge on button */}
288
+ <OxBadge count={12} position="top-right">
289
+ <OxButton variant="ghost" aria-label="Messages">
290
+ <OxIcon icon={Mail} />
291
+ </OxButton>
292
+ </OxBadge>
293
+
294
+ {/* Overflow handling */}
295
+ <OxBadge count={100} max={99} /> {/* Shows "99+" */}
296
+
297
+ {/* Dot badge for status */}
298
+ <OxBadge type="dot" variant="green" position="top-right">
299
+ <OxIcon icon={Bell} className="size-6" />
300
+ </OxBadge>
301
+ ```
302
+
303
+ ---
304
+
305
+ ## OxTag
306
+
307
+ Inline label component for categorization and metadata display.
308
+
309
+ **Pattern**: Simple Component
310
+
311
+ ### Props
312
+
313
+ ```tsx
314
+ interface OxTagProps extends ComponentPropsWithRef<'span'> {
315
+ children: ReactNode; // Tag content
316
+ color?: ColorStyleName; // Predefined theme color
317
+ }
318
+ ```
319
+
320
+ ### Example
321
+
322
+ ```tsx
323
+ {/* Basic tags */}
324
+ <OxTag color="blue">New</OxTag>
325
+ <OxTag color="green">Active</OxTag>
326
+ <OxTag color="purple">Featured</OxTag>
327
+
328
+ {/* In context */}
329
+ <div className="flex gap-2">
330
+ <OxTag color="purple">React</OxTag>
331
+ <OxTag color="blue">TypeScript</OxTag>
332
+ <OxTag color="green">Tailwind</OxTag>
333
+ </div>
334
+ ```
335
+
336
+ ---
337
+
338
+ ## OxBreadcrumb
339
+
340
+ Breadcrumb navigation with asChild pattern support.
341
+
342
+ **Pattern**: Compound Component
343
+ **Sub-components**: `Ellipsis`, `Item`, `Link`, `Page`, `Separator`
344
+
345
+ ### Props
346
+
347
+ ```tsx
348
+ interface OxBreadcrumbProps extends ComponentPropsWithRef<'ol'> {
349
+ children: ReactNode;
350
+ }
351
+
352
+ interface OxBreadcrumbItemProps extends ComponentPropsWithRef<'li'> {
353
+ children: ReactNode;
354
+ }
355
+
356
+ interface OxBreadcrumbLinkProps extends ComponentPropsWithRef<'a'> {
357
+ asChild?: boolean; // Renders as child component (e.g., Next.js Link)
358
+ children: ReactNode;
359
+ current?: boolean; // Marks as current page
360
+ href?: string;
361
+ }
362
+
363
+ interface OxBreadcrumbPageProps extends ComponentPropsWithRef<'span'> {
364
+ children: ReactNode;
365
+ }
366
+
367
+ interface OxBreadcrumbSeparatorProps extends ComponentPropsWithRef<'li'> {}
368
+ interface OxBreadcrumbEllipsisProps extends ComponentPropsWithRef<'span'> {}
369
+ ```
370
+
371
+ ### Example
372
+
373
+ ```tsx
374
+ <OxBreadcrumb>
375
+ <OxBreadcrumb.Item>
376
+ <OxBreadcrumb.Link href="/">Home</OxBreadcrumb.Link>
377
+ </OxBreadcrumb.Item>
378
+ <OxBreadcrumb.Separator />
379
+ <OxBreadcrumb.Item>
380
+ <OxBreadcrumb.Link href="/products">Products</OxBreadcrumb.Link>
381
+ </OxBreadcrumb.Item>
382
+ <OxBreadcrumb.Separator />
383
+ <OxBreadcrumb.Item>
384
+ <OxBreadcrumb.Page>Current Page</OxBreadcrumb.Page>
385
+ </OxBreadcrumb.Item>
386
+ </OxBreadcrumb>;
387
+
388
+ {
389
+ /* Using asChild with Next.js Link */
390
+ }
391
+ <OxBreadcrumb.Link asChild>
392
+ <Link to="/dashboard">Dashboard</Link>
393
+ </OxBreadcrumb.Link>;
394
+ ```
395
+
396
+ ---
397
+
398
+ ## OxButton
399
+
400
+ Button component with variants, sizes, and loading states.
401
+
402
+ **Pattern**: Simple Component
403
+
404
+ > **Note:** For links styled as buttons, use `OxButton` with `asChild` prop. Use `OxLink` only for text-based links with underline.
405
+
406
+ ### Props
407
+
408
+ ```tsx
409
+ interface OxButtonProps extends ComponentPropsWithRef<'button'> {
410
+ asChild?: boolean; // Renders as child element (useful for Link components)
411
+ fullWidth?: boolean; // Expands to full container width
412
+ isLoading?: boolean; // Shows spinner, disables interaction
413
+ size?: 'sm' | 'md' | 'lg';
414
+ variant?: 'gradient' | 'primary' | 'accent' | 'default' | 'secondary' | 'ghost' | 'danger';
415
+ }
416
+ ```
417
+
418
+ ### Example
419
+
420
+ ```tsx
421
+ <OxButton variant="primary" size="md" isLoading>
422
+ Save Changes
423
+ </OxButton>;
424
+
425
+ {
426
+ /* Render as Link while keeping button styling */
427
+ }
428
+ <OxButton asChild variant="primary">
429
+ <Link to="/dashboard">Dashboard</Link>
430
+ </OxButton>;
431
+ ```
432
+
433
+ ---
434
+
435
+ ## OxCalendar
436
+
437
+ Date picker component.
438
+
439
+ **Pattern**: Simple Component
440
+
441
+ ### Props
442
+
443
+ ```tsx
444
+ interface OxCalendarProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
445
+ onChange?: (value: string) => void;
446
+ value?: string; // Date string
447
+ }
448
+ ```
449
+
450
+ ### Example
451
+
452
+ ```tsx
453
+ <OxCalendar value="2024-01-15" onChange={(date) => console.log(date)} />
454
+ ```
455
+
456
+ ---
457
+
458
+ ## OxCard
459
+
460
+ Card component with hover effects and loading states.
461
+
462
+ **Pattern**: Compound Component
463
+ **Sub-components**: `Action`, `Content`, `Footer`, `Header`
464
+
465
+ ### Props
466
+
467
+ ```tsx
468
+ interface OxCardProps extends ComponentPropsWithRef<'div'> {
469
+ children: ReactNode;
470
+ color?: Exclude<ColorStyleName, 'default'>; // Card accent color
471
+ equalHeight?: boolean; // Makes card take full height
472
+ hoverable?: boolean; // Enables hover effects
473
+ hoverVariant?: 'none' | 'lift' | 'border';
474
+ isLoading?: boolean; // Shows loading state
475
+ padding?: 'none' | 'sm' | 'md';
476
+ }
477
+
478
+ interface OxCardContentProps extends ComponentPropsWithRef<'div'> {
479
+ children: ReactNode;
480
+ flexGrow?: boolean; // Makes content grow to fill space
481
+ }
482
+
483
+ interface OxCardFooterProps extends ComponentPropsWithRef<'div'> {
484
+ children: ReactNode;
485
+ }
486
+
487
+ interface OxCardHeaderProps extends ComponentPropsWithRef<'div'> {}
488
+ interface OxCardActionProps extends ComponentPropsWithRef<'div'> {}
489
+ ```
490
+
491
+ ### Example
492
+
493
+ ```tsx
494
+ <OxCard hoverable hoverVariant="lift" color="blue" isLoading={false}>
495
+ <OxCard.Header>Card Title</OxCard.Header>
496
+ <OxCard.Content flexGrow>Main content here</OxCard.Content>
497
+ <OxCard.Footer>Footer content</OxCard.Footer>
498
+ <OxCard.Action>
499
+ <button>Action</button>
500
+ </OxCard.Action>
501
+ </OxCard>
502
+ ```
503
+
504
+ ---
505
+
506
+ ## OxDescriptionList (beta)
507
+
508
+ Semantic description list component.
509
+
510
+ **Pattern**: Compound Component
511
+ **Sub-components**: `Term`, `Value`
512
+
513
+ ### Props
514
+
515
+ ```tsx
516
+ interface OxDescriptionListProps extends ComponentPropsWithRef<'dl'> {
517
+ children: ReactNode;
518
+ outline?: boolean; // Adds border outline
519
+ }
520
+
521
+ interface OxDescriptionListTermProps extends ComponentPropsWithRef<'dt'> {
522
+ children: ReactNode;
523
+ }
524
+
525
+ interface OxDescriptionListValueProps extends ComponentPropsWithRef<'dd'> {
526
+ children?: ReactNode;
527
+ }
528
+ ```
529
+
530
+ ### Example
531
+
532
+ ```tsx
533
+ <OxDescriptionList outline>
534
+ <OxDescriptionList.Term>Name</OxDescriptionList.Term>
535
+ <OxDescriptionList.Value>John Doe</OxDescriptionList.Value>
536
+ <OxDescriptionList.Term>Email</OxDescriptionList.Term>
537
+ <OxDescriptionList.Value>john@example.com</OxDescriptionList.Value>
538
+ </OxDescriptionList>
539
+ ```
540
+
541
+ ---
542
+
543
+ ## OxDialog
544
+
545
+ Modal dialog component.
546
+
547
+ **Pattern**: Compound Component
548
+ **Sub-components**: `Body`, `Footer`, `Header`
549
+
550
+ ### Props
551
+
552
+ ```tsx
553
+ interface OxDialogProps extends ComponentPropsWithoutRef<'dialog'> {
554
+ children: ReactNode;
555
+ closeOnOutsideClick?: boolean; // Closes on backdrop click
556
+ isOpen: boolean; // Required - Controls visibility
557
+ onClose: () => void; // Required - Close callback
558
+ persistent?: boolean; // Prevents closing on outside click/escape
559
+ showCloseButton?: boolean;
560
+ size?: 'sm' | 'md' | 'lg' | 'xl';
561
+ }
562
+
563
+ interface OxDialogHeaderProps extends ComponentPropsWithRef<'div'> {
564
+ children: ReactNode;
565
+ }
566
+
567
+ interface OxDialogBodyProps extends ComponentPropsWithRef<'div'> {
568
+ children: ReactNode;
569
+ }
570
+
571
+ interface OxDialogFooterProps extends ComponentPropsWithRef<'div'> {
572
+ children: ReactNode;
573
+ }
574
+ ```
575
+
576
+ ### Example
577
+
578
+ ```tsx
579
+ <OxDialog isOpen={open} onClose={() => setOpen(false)} size="md">
580
+ <OxDialog.Header>Confirm Action</OxDialog.Header>
581
+ <OxDialog.Body>Are you sure you want to continue?</OxDialog.Body>
582
+ <OxDialog.Footer>
583
+ <OxButton onClick={() => setOpen(false)}>Cancel</OxButton>
584
+ <OxButton variant="primary">Confirm</OxButton>
585
+ </OxDialog.Footer>
586
+ </OxDialog>
587
+ ```
588
+
589
+ ---
590
+
591
+ ## OxDndContext
592
+
593
+ Drag and drop context provider using @dnd-kit/core.
594
+
595
+ **Pattern**: Compound Component (Context-based)
596
+ **Sub-components**: `Draggable`, `Droppable`
597
+ **Additional Exports**: `useDndContext`
598
+
599
+ ### Props
600
+
601
+ ```tsx
602
+ interface DndDragEvent {
603
+ active: Active; // @dnd-kit Active type
604
+ over: Over | null; // @dnd-kit Over type
605
+ }
606
+
607
+ interface OxDndContextProps {
608
+ children: ReactNode;
609
+ onDragCancel?: (event: DndDragEvent) => void;
610
+ onDragEnd?: (event: DndDragEvent) => void;
611
+ onDragOver?: (event: DndDragEvent) => void;
612
+ onDragStart?: (event: DndDragEvent) => void;
613
+ }
614
+
615
+ interface OxDraggableProps extends Omit<ComponentPropsWithRef<'div'>, 'id'> {
616
+ children: ReactNode;
617
+ data?: Record<string, unknown>; // Custom data passed to drag events
618
+ disabled?: boolean;
619
+ id?: string;
620
+ }
621
+
622
+ interface OxDroppableProps extends Omit<ComponentPropsWithRef<'div'>, 'id'> {
623
+ children: ReactNode;
624
+ data?: Record<string, unknown>; // Custom data for drop zone identification
625
+ disabled?: boolean;
626
+ id?: string;
627
+ }
628
+ ```
629
+
630
+ ### Usage
631
+
632
+ ```tsx
633
+ <OxDndContext
634
+ onDragEnd={({ active, over }) => {
635
+ if (over) {
636
+ console.log(`Dropped ${active.id} onto ${over.id}`);
637
+ }
638
+ }}
639
+ >
640
+ <OxDndContext.Droppable id="drop-zone">
641
+ <OxDndContext.Draggable id="item-1">
642
+ Drag me
643
+ </OxDndContext.Draggable>
644
+ </OxDndContext.Droppable>
645
+ </OxDndContext>
646
+ ```
647
+
648
+ **Note**: For simple reordering within a list, prefer `OxSortableList`. Use `OxDndContext` for complex drag-and-drop scenarios across different containers.
649
+
650
+ ---
651
+
652
+ ## OxDrawer
653
+
654
+ Slide-out drawer component.
655
+
656
+ **Pattern**: Compound Component
657
+ **Sub-components**: `Body`, `Content`, `Footer`, `Header`, `Trigger`
658
+
659
+ ### Props
660
+
661
+ ```tsx
662
+ interface OxDrawerProps {
663
+ children: ReactNode;
664
+ defaultOpen?: boolean;
665
+ onOpenChange?: (open: boolean) => void;
666
+ open?: boolean; // Controlled open state
667
+ }
668
+
669
+ interface OxDrawerTriggerProps extends ComponentPropsWithRef<'button'> {
670
+ children: ReactNode;
671
+ disabled?: boolean;
672
+ }
673
+
674
+ interface OxDrawerContentProps extends ComponentPropsWithRef<'div'> {
675
+ children: ReactNode;
676
+ closeOnOutsideClick?: boolean;
677
+ side?: 'left' | 'right' | 'top' | 'bottom'; // Slide-in direction
678
+ }
679
+
680
+ interface OxDrawerHeaderProps extends ComponentPropsWithRef<'div'> {
681
+ children: ReactNode;
682
+ }
683
+
684
+ interface OxDrawerBodyProps extends ComponentPropsWithRef<'div'> {
685
+ children: ReactNode;
686
+ }
687
+
688
+ interface OxDrawerFooterProps extends ComponentPropsWithRef<'div'> {
689
+ children: ReactNode;
690
+ }
691
+ ```
692
+
693
+ ### Example
694
+
695
+ ```tsx
696
+ <OxDrawer>
697
+ <OxDrawer.Trigger>Open Drawer</OxDrawer.Trigger>
698
+ <OxDrawer.Content side="right">
699
+ <OxDrawer.Header>Drawer Title</OxDrawer.Header>
700
+ <OxDrawer.Body>Drawer content</OxDrawer.Body>
701
+ <OxDrawer.Footer>Footer</OxDrawer.Footer>
702
+ </OxDrawer.Content>
703
+ </OxDrawer>
704
+ ```
705
+
706
+ ---
707
+
708
+ ## OxDropdown
709
+
710
+ Dropdown menu with extensive sub-components.
711
+
712
+ **Pattern**: Compound Component
713
+ **Sub-components**: `Body`, `Content`, `Footer`, `Header`, `Item`, `Label`, `Separator`, `Shortcut`, `Trigger`
714
+
715
+ ### Props
716
+
717
+ ```tsx
718
+ interface OxDropdownProps {
719
+ align?: 'start' | 'center' | 'end';
720
+ children: ReactNode;
721
+ defaultOpen?: boolean;
722
+ disabled?: boolean;
723
+ onOpenChange?: (open: boolean) => void;
724
+ open?: boolean; // Controlled open state
725
+ side?: 'top' | 'bottom' | 'left' | 'right';
726
+ }
727
+
728
+ interface OxDropdownTriggerProps extends ComponentPropsWithRef<'button'> {
729
+ animateIcon?: boolean; // Animates icon on open/close
730
+ asChild?: boolean; // Renders as child component (useful for custom triggers)
731
+ children: ReactNode;
732
+ hideIcon?: boolean;
733
+ icon?: LucideIcon;
734
+ size?: OxButtonProps['size'];
735
+ variant?: OxButtonProps['variant'];
736
+ }
737
+
738
+ interface OxDropdownContentProps extends ComponentPropsWithRef<'div'> {
739
+ children: ReactNode;
740
+ className?: string;
741
+ }
742
+
743
+ interface OxDropdownBodyProps extends ComponentPropsWithRef<'ul'> {
744
+ children: ReactNode;
745
+ }
746
+
747
+ // Item can be either button or link
748
+ type OxDropdownItemProps = OxDropdownItemButtonProps | OxDropdownItemLinkProps;
749
+
750
+ interface OxDropdownItemButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {
751
+ disabled?: boolean;
752
+ }
753
+
754
+ interface OxDropdownItemLinkProps extends ComponentPropsWithRef<'a'> {
755
+ disabled?: boolean; // Disables link navigation
756
+ href: string; // Required for link variant
757
+ }
758
+
759
+ interface OxDropdownLabelProps extends ComponentPropsWithRef<'div'> {
760
+ children: ReactNode;
761
+ }
762
+
763
+ interface OxDropdownShortcutProps extends ComponentPropsWithRef<'span'> {
764
+ children: ReactNode;
765
+ }
766
+
767
+ interface OxDropdownHeaderProps extends ComponentPropsWithRef<'div'> {
768
+ children: ReactNode;
769
+ }
770
+
771
+ interface OxDropdownFooterProps extends ComponentPropsWithRef<'div'> {
772
+ children: ReactNode;
773
+ }
774
+
775
+ interface OxDropdownSeparatorProps extends Omit<OxSeparatorProps, 'orientation' | 'vertical'> {}
776
+ ```
777
+
778
+ ### Example
779
+
780
+ ```tsx
781
+ <OxDropdown side="bottom" align="start">
782
+ <OxDropdown.Trigger>Options</OxDropdown.Trigger>
783
+ <OxDropdown.Content>
784
+ <OxDropdown.Header>Actions</OxDropdown.Header>
785
+ <OxDropdown.Body>
786
+ <OxDropdown.Item onClick={handleEdit}>
787
+ Edit <OxDropdown.Shortcut>⌘E</OxDropdown.Shortcut>
788
+ </OxDropdown.Item>
789
+ <OxDropdown.Item href="/settings">Settings</OxDropdown.Item>
790
+ <OxDropdown.Separator />
791
+ <OxDropdown.Item onClick={handleDelete}>Delete</OxDropdown.Item>
792
+ </OxDropdown.Body>
793
+ </OxDropdown.Content>
794
+ </OxDropdown>
795
+ ```
796
+
797
+ ---
798
+
799
+ ## OxEndlessList
800
+
801
+ Virtualized infinite scroll list using @tanstack/react-virtual.
802
+
803
+ **Pattern**: Compound Component
804
+ **Sub-components**: `Empty`, `Error`, `Item`, `Items`, `Loader`
805
+
806
+ ### Props
807
+
808
+ ```tsx
809
+ interface OxEndlessListProps<TData> extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
810
+ children: ReactNode;
811
+ data: TData[];
812
+ estimateSize: number | ((index: number) => number); // Estimated row height in pixels
813
+ gap?: number;
814
+ getItemKey: (item: TData, index: number) => string | number;
815
+ hasNextPage?: boolean;
816
+ isError?: boolean;
817
+ isLoading?: boolean;
818
+ loadMoreThreshold?: number; // Distance from bottom to trigger load (px)
819
+ onLoadMore?: () => void;
820
+ overscan?: number; // Number of items to render outside visible area
821
+ }
822
+
823
+ interface OxEndlessListItemsProps {
824
+ children: ReactNode;
825
+ className?: string;
826
+ paddingY?: number;
827
+ }
828
+
829
+ interface OxEndlessListItemProps<TData = unknown> {
830
+ children: (item: TData, index: number) => ReactNode; // Render function
831
+ className?: string;
832
+ }
833
+
834
+ interface OxEndlessListLoaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
835
+ children?: ReactNode;
836
+ }
837
+
838
+ interface OxEndlessListEmptyProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
839
+ children?: ReactNode;
840
+ }
841
+
842
+ interface OxEndlessListErrorProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
843
+ children?: ReactNode;
844
+ }
845
+ ```
846
+
847
+ ### Usage
848
+
849
+ ```tsx
850
+ <OxEndlessList
851
+ data={items}
852
+ estimateSize={50}
853
+ getItemKey={(item) => item.id}
854
+ hasNextPage={hasMore}
855
+ isLoading={isLoading}
856
+ onLoadMore={fetchMore}
857
+ >
858
+ <OxEndlessList.Items>
859
+ <OxEndlessList.Item>
860
+ {(item, index) => <div>{item.name}</div>}
861
+ </OxEndlessList.Item>
862
+ </OxEndlessList.Items>
863
+ <OxEndlessList.Loader>Loading more...</OxEndlessList.Loader>
864
+ <OxEndlessList.Empty>No items found</OxEndlessList.Empty>
865
+ <OxEndlessList.Error>Failed to load</OxEndlessList.Error>
866
+ </OxEndlessList>
867
+ ```
868
+
869
+ ---
870
+
871
+ ## OxFloating ⚠️ DEPRECATED
872
+
873
+ > **Deprecated**: Moved to `@noxickon/onyx/legacy`. Use `OxPopper` or higher-level components (OxPopover, OxDropdown, OxTooltip) instead.
874
+
875
+ Low-level floating UI primitive.
876
+
877
+ **Import**: `import { OxFloating } from '@noxickon/onyx/legacy';`
878
+ **Pattern**: Compound Component (Primitive)
879
+ **Sub-components**: `Content`, `Trigger`
880
+ **Additional Exports**: `OxFloatingContext`, `useOxFloatingContext`
881
+
882
+ ### Props
883
+
884
+ ```tsx
885
+ interface OxFloatingProps {
886
+ align?: 'start' | 'center' | 'end';
887
+ animationDuration?: number; // Animation duration in ms
888
+ ariaHaspopup?: 'menu' | 'dialog' | 'listbox' | 'tree' | 'grid' | true;
889
+ children: ReactNode;
890
+ defaultOpen?: boolean;
891
+ disabled?: boolean;
892
+ hoverDelay?: number; // Delay before showing on hover (ms)
893
+ id?: string;
894
+ offset?: number; // Distance from trigger element
895
+ onOpenChange?: (open: boolean) => void;
896
+ open?: boolean; // Controlled open state
897
+ position?: 'top' | 'bottom' | 'left' | 'right';
898
+ trigger?: 'hover' | 'click' | 'manual' | 'focus'; // Interaction type
899
+ useAriaControls?: boolean;
900
+ }
901
+
902
+ interface OxFloatingTriggerProps extends ComponentPropsWithRef<'div'> {
903
+ asChild?: boolean; // Renders as child component
904
+ children: ReactNode;
905
+ }
906
+
907
+ interface OxFloatingContentProps extends ComponentPropsWithoutRef<'div'> {
908
+ children: ReactNode;
909
+ portal?: boolean; // Renders in portal
910
+ }
911
+ ```
912
+
913
+ **Note**: Base component for Popover, Dropdown, and Tooltip. Use higher-level components instead when possible.
914
+
915
+ ---
916
+
917
+ ## OxHoverCard
918
+
919
+ Card that appears on hover with configurable delays.
920
+
921
+ **Pattern**: Compound Component
922
+ **Sub-components**: `Content`, `Trigger`
923
+
924
+ ### Props
925
+
926
+ ```tsx
927
+ type OxPopperSide = 'top' | 'right' | 'bottom' | 'left';
928
+ type OxPopperAlign = 'start' | 'center' | 'end';
929
+
930
+ interface OxHoverCardProps {
931
+ align?: OxPopperAlign;
932
+ children: ReactNode;
933
+ closeDelay?: number; // Delay before closing (ms)
934
+ defaultOpen?: boolean;
935
+ disabled?: boolean;
936
+ onOpenChange?: (open: boolean) => void;
937
+ open?: boolean; // Controlled open state
938
+ openDelay?: number; // Delay before opening (ms)
939
+ side?: OxPopperSide;
940
+ }
941
+
942
+ interface OxHoverCardTriggerProps extends ComponentPropsWithoutRef<'div'> {
943
+ asChild?: boolean;
944
+ children: ReactNode;
945
+ }
946
+
947
+ interface OxHoverCardContentProps extends ComponentPropsWithoutRef<'div'> {
948
+ children: ReactNode;
949
+ forceMount?: boolean; // Keep mounted when closed
950
+ }
951
+ ```
952
+
953
+ ### Usage
954
+
955
+ ```tsx
956
+ <OxHoverCard openDelay={200} closeDelay={100}>
957
+ <OxHoverCard.Trigger asChild>
958
+ <OxButton>Hover me</OxButton>
959
+ </OxHoverCard.Trigger>
960
+ <OxHoverCard.Content>
961
+ <p>Additional information appears here</p>
962
+ </OxHoverCard.Content>
963
+ </OxHoverCard>
964
+ ```
965
+
966
+ ---
967
+
968
+ ## OxIcon
969
+
970
+ Icon component with Lucide icon support.
971
+
972
+ **Pattern**: Compound Component
973
+ **Sub-components**: `Box`
974
+
975
+ ### Props
976
+
977
+ ```tsx
978
+ interface OxIconProps {
979
+ children?: React.ReactNode;
980
+ className?: string;
981
+ icon?: LucideIcon; // Lucide icon component
982
+ path?: string; // SVG path for custom icon
983
+ placeholder?: boolean; // Shows placeholder icon
984
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | number;
985
+ }
986
+
987
+ interface OxIconBoxProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
988
+ children: ReactNode;
989
+ color?: ColorStyleName; // Background color
990
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
991
+ }
992
+ ```
993
+
994
+ ### Example
995
+
996
+ ```tsx
997
+ import { Check } from 'lucide-react';
998
+
999
+ <OxIcon icon={Check} size="lg" />
1000
+ <OxIcon path="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
1001
+
1002
+ <OxIcon.Box color="blue" size="lg">
1003
+ <OxIcon icon={Check} />
1004
+ </OxIcon.Box>
1005
+ ```
1006
+
1007
+ ---
1008
+
1009
+ ## OxJsonField (alpha)
1010
+
1011
+ JSON data display with syntax highlighting.
1012
+
1013
+ **Pattern**: Compound Component
1014
+ **Sub-components**: `Node`
1015
+
1016
+ ### Props
1017
+
1018
+ ```tsx
1019
+ type OxJsonValue =
1020
+ | string
1021
+ | number
1022
+ | boolean
1023
+ | null
1024
+ | undefined
1025
+ | OxJsonValue[]
1026
+ | { [key: string]: OxJsonValue };
1027
+
1028
+ interface OxJsonFieldProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1029
+ value: string | OxJsonValue; // Required - JSON to display
1030
+ }
1031
+
1032
+ interface OxJsonNodeProps {
1033
+ data: OxJsonValue;
1034
+ level: number; // Nesting level for indentation
1035
+ trailingComma?: boolean;
1036
+ }
1037
+ ```
1038
+
1039
+ ### Example
1040
+
1041
+ ```tsx
1042
+ <OxJsonField value={{ name: "John", age: 30, active: true }} />
1043
+ <OxJsonField value='{"key": "value"}' />
1044
+ ```
1045
+
1046
+ ---
1047
+
1048
+ ## OxKanban
1049
+
1050
+ Kanban board for drag-and-drop card management across columns.
1051
+
1052
+ **Pattern**: Compound Component
1053
+ **Sub-components**: `Card`, `Card.Handle`, `Column`, `Column.Footer`, `Column.Header`
1054
+
1055
+ ### Props
1056
+
1057
+ ```tsx
1058
+ interface OxKanbanProps extends ComponentPropsWithRef<'div'> {
1059
+ children: ReactNode;
1060
+ columnGap?: number;
1061
+ disabled?: boolean;
1062
+ onMove: (cardId: string, fromColumn: string, toColumn: string, newIndex: number) => void;
1063
+ onReorder?: (cardId: string, column: string, fromIndex: number, toIndex: number) => void;
1064
+ }
1065
+
1066
+ interface OxKanbanColumnProps extends ComponentPropsWithRef<'div'> {
1067
+ children?: ReactNode;
1068
+ disabled?: boolean;
1069
+ emptyState?: ReactNode; // Shown when column has no cards
1070
+ gap?: number;
1071
+ heading?: ReactNode;
1072
+ id: string; // Unique column identifier
1073
+ }
1074
+
1075
+ interface OxKanbanColumnHeaderProps extends ComponentPropsWithRef<'div'> {
1076
+ children: ReactNode;
1077
+ }
1078
+
1079
+ interface OxKanbanColumnFooterProps extends ComponentPropsWithRef<'div'> {
1080
+ children: ReactNode;
1081
+ }
1082
+
1083
+ interface OxKanbanCardProps extends ComponentPropsWithRef<'div'> {
1084
+ children: ReactNode;
1085
+ disabled?: boolean;
1086
+ id: string; // Unique card identifier
1087
+ }
1088
+
1089
+ interface OxKanbanCardHandleProps extends ComponentPropsWithRef<'button'> {
1090
+ children?: ReactNode;
1091
+ }
1092
+ ```
1093
+
1094
+ ### Usage
1095
+
1096
+ ```tsx
1097
+ <OxKanban
1098
+ onMove={(cardId, from, to, index) => moveCard(cardId, from, to, index)}
1099
+ onReorder={(cardId, column, from, to) => reorderCard(cardId, column, from, to)}
1100
+ >
1101
+ <OxKanban.Column id="todo">
1102
+ <OxKanban.Column.Header>To Do</OxKanban.Column.Header>
1103
+ <OxKanban.Card id="task-1">
1104
+ <OxKanban.Card.Handle />
1105
+ <span>Task 1</span>
1106
+ </OxKanban.Card>
1107
+ <OxKanban.Column.Footer>
1108
+ <OxButton>Add task</OxButton>
1109
+ </OxKanban.Column.Footer>
1110
+ </OxKanban.Column>
1111
+ <OxKanban.Column id="done" emptyState="No completed tasks">
1112
+ <OxKanban.Column.Header>Done</OxKanban.Column.Header>
1113
+ </OxKanban.Column>
1114
+ </OxKanban>
1115
+ ```
1116
+
1117
+ ---
1118
+
1119
+ ## OxLink
1120
+
1121
+ Link component for text-based navigation with hover underline.
1122
+
1123
+ **Pattern**: Simple Component
1124
+
1125
+ > **Note:** For button-styled links (e.g., call-to-action buttons), use `OxButton` with `asChild` instead. `OxLink` is for inline and text-based links only.
1126
+
1127
+ ### Props
1128
+
1129
+ ```tsx
1130
+ interface OxLinkProps extends ComponentPropsWithRef<'a'> {
1131
+ asChild?: boolean; // Renders as child element (useful for routing libraries)
1132
+ disabled?: boolean; // Disables link navigation
1133
+ size?: 'sm' | 'md' | 'lg';
1134
+ variant?: 'primary' | 'secondary' | 'accent'; // primary = violet text, secondary = white text
1135
+ }
1136
+ ```
1137
+
1138
+ ### Example
1139
+
1140
+ ```tsx
1141
+ <OxLink href="/about" variant="primary">
1142
+ About Us
1143
+ </OxLink>;
1144
+
1145
+ {
1146
+ /* Use with React Router */
1147
+ }
1148
+ <OxLink asChild>
1149
+ <Link to="/dashboard">Dashboard</Link>
1150
+ </OxLink>;
1151
+ ```
1152
+
1153
+ ---
1154
+
1155
+ ## OxMasonry
1156
+
1157
+ Responsive masonry layout with configurable columns.
1158
+
1159
+ **Pattern**: Simple Component
1160
+
1161
+ ### Props
1162
+
1163
+ ```tsx
1164
+ type Breakpoint = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
1165
+
1166
+ type ResponsiveColumns = {
1167
+ default: number;
1168
+ } & Partial<Record<Breakpoint, number>>;
1169
+
1170
+ interface OxMasonryProps {
1171
+ children: ReactNode;
1172
+ className?: string;
1173
+ columns: number | ResponsiveColumns; // Fixed columns or responsive breakpoints
1174
+ gap?: number;
1175
+ }
1176
+ ```
1177
+
1178
+ ### Usage
1179
+
1180
+ ```tsx
1181
+ // Fixed columns
1182
+ <OxMasonry columns={3} gap={16}>
1183
+ <div>Item 1</div>
1184
+ <div>Item 2</div>
1185
+ <div>Item 3</div>
1186
+ </OxMasonry>
1187
+
1188
+ // Responsive columns
1189
+ <OxMasonry
1190
+ columns={{ default: 1, sm: 2, md: 3, lg: 4 }}
1191
+ gap={24}
1192
+ >
1193
+ {items.map(item => <Card key={item.id}>{item.content}</Card>)}
1194
+ </OxMasonry>
1195
+ ```
1196
+
1197
+ ---
1198
+
1199
+ ## OxNotifications
1200
+
1201
+ Notification center component.
1202
+
1203
+ **Pattern**: Compound Component
1204
+ **Sub-components**: `Body`, `Button`, `Link`, `Trigger`
1205
+
1206
+ ### Props
1207
+
1208
+ ```tsx
1209
+ interface OxNotificationItemProps {
1210
+ icon?: LucideIcon;
1211
+ id: string; // Required - Unique ID
1212
+ img?: string;
1213
+ message?: string;
1214
+ path?: string; // SVG path
1215
+ read: boolean; // Required
1216
+ timestamp: Date; // Required
1217
+ title: string; // Required
1218
+ type?: 'default' | 'info' | 'success' | 'warning' | 'error';
1219
+ }
1220
+
1221
+ interface OxNotificationsProps extends ComponentPropsWithRef<'div'> {
1222
+ children?: ReactNode;
1223
+ disabled?: boolean;
1224
+ emptyMessage?: string;
1225
+ items?: OxNotificationItemProps[];
1226
+ onItemClick?: (item: OxNotificationItemProps) => void;
1227
+ onMarkAllRead?: () => void;
1228
+ unreadCount?: number;
1229
+ }
1230
+
1231
+ interface OxNotificationsTriggerProps extends ComponentPropsWithRef<'button'> {
1232
+ children?: ReactNode;
1233
+ customIcon?: LucideIcon;
1234
+ unreadCount?: number; // Badge count
1235
+ }
1236
+
1237
+ interface OxNotificationsBodyProps extends ComponentPropsWithRef<'ul'> {
1238
+ children?: ReactNode;
1239
+ }
1240
+
1241
+ interface OxNotificationsButtonProps extends Omit<
1242
+ ComponentPropsWithRef<'button'>,
1243
+ 'children' | 'type' | 'onClick'
1244
+ > {
1245
+ children?: ReactNode;
1246
+ icon?: LucideIcon;
1247
+ img?: string;
1248
+ message?: string;
1249
+ path?: string;
1250
+ timestamp?: Date;
1251
+ title?: string;
1252
+ type?: 'default' | 'info' | 'success' | 'warning' | 'error';
1253
+ unread?: boolean;
1254
+ }
1255
+
1256
+ interface OxNotificationsLinkProps extends Omit<
1257
+ ComponentPropsWithRef<'a'>,
1258
+ 'children' | 'type' | 'onClick'
1259
+ > {
1260
+ children?: ReactNode;
1261
+ href: string; // Required
1262
+ icon?: LucideIcon;
1263
+ img?: string;
1264
+ message?: string;
1265
+ path?: string;
1266
+ timestamp?: Date;
1267
+ title?: string;
1268
+ type?: 'default' | 'info' | 'success' | 'warning' | 'error';
1269
+ unread?: boolean;
1270
+ }
1271
+ ```
1272
+
1273
+ ### Example
1274
+
1275
+ ```tsx
1276
+ <OxNotifications
1277
+ items={notifications}
1278
+ unreadCount={5}
1279
+ onItemClick={(item) => console.log(item)}
1280
+ onMarkAllRead={() => console.log('Mark all read')}
1281
+ >
1282
+ <OxNotifications.Trigger unreadCount={5} />
1283
+ <OxNotifications.Body>
1284
+ <OxNotifications.Button title="New message" message="You have a new message" />
1285
+ <OxNotifications.Link href="/notifications" title="View all" />
1286
+ </OxNotifications.Body>
1287
+ </OxNotifications>
1288
+ ```
1289
+
1290
+ ---
1291
+
1292
+ ## OxPageOutline
1293
+
1294
+ Table of contents / page outline component with scroll spy.
1295
+
1296
+ **Pattern**: Compound Component
1297
+ **Sub-components**: `Content`, `Header`, `Item`
1298
+
1299
+ ### Props
1300
+
1301
+ ```tsx
1302
+ type OxPageOutlineLevel = 1 | 2 | 3;
1303
+
1304
+ interface OxPageOutlineProps extends ComponentPropsWithRef<'nav'> {
1305
+ children: ReactNode;
1306
+ scrollOffset?: number; // Offset for scroll position detection (px)
1307
+ }
1308
+
1309
+ interface OxPageOutlineHeaderProps extends ComponentPropsWithRef<'div'> {
1310
+ children: ReactNode;
1311
+ }
1312
+
1313
+ interface OxPageOutlineContentProps extends ComponentPropsWithRef<'div'> {
1314
+ children: ReactNode;
1315
+ }
1316
+
1317
+ interface OxPageOutlineItemProps extends ComponentPropsWithRef<'a'> {
1318
+ children: ReactNode;
1319
+ href: string; // Anchor link (e.g., "#section-1")
1320
+ level?: OxPageOutlineLevel; // Indentation level (1-3)
1321
+ }
1322
+ ```
1323
+
1324
+ ### Usage
1325
+
1326
+ ```tsx
1327
+ <OxPageOutline scrollOffset={80}>
1328
+ <OxPageOutline.Header>On this page</OxPageOutline.Header>
1329
+ <OxPageOutline.Content>
1330
+ <OxPageOutline.Item href="#introduction" level={1}>Introduction</OxPageOutline.Item>
1331
+ <OxPageOutline.Item href="#getting-started" level={1}>Getting Started</OxPageOutline.Item>
1332
+ <OxPageOutline.Item href="#installation" level={2}>Installation</OxPageOutline.Item>
1333
+ <OxPageOutline.Item href="#configuration" level={2}>Configuration</OxPageOutline.Item>
1334
+ <OxPageOutline.Item href="#api" level={1}>API Reference</OxPageOutline.Item>
1335
+ </OxPageOutline.Content>
1336
+ </OxPageOutline>
1337
+ ```
1338
+
1339
+ ---
1340
+
1341
+ ## OxPagination
1342
+
1343
+ Pagination component with routing support.
1344
+
1345
+ **Pattern**: Compound Component
1346
+ **Sub-components**: `Ellipsis`, `Item`, `Link`, `Next`, `Previous`
1347
+
1348
+ ### Props
1349
+
1350
+ ```tsx
1351
+ interface OxPaginationProps extends ComponentPropsWithRef<'nav'> {
1352
+ children: ReactNode;
1353
+ }
1354
+
1355
+ interface OxPaginationItemProps extends ComponentPropsWithRef<'li'> {
1356
+ children: ReactNode;
1357
+ }
1358
+
1359
+ interface OxPaginationLinkProps extends ComponentPropsWithRef<'a'> {
1360
+ asChild?: boolean; // Renders as child component (for routing libraries)
1361
+ children: ReactNode;
1362
+ disabled?: boolean;
1363
+ href?: string;
1364
+ isActive?: boolean; // Marks as active page
1365
+ }
1366
+
1367
+ interface OxPaginationPreviousProps extends ComponentPropsWithRef<'a'> {
1368
+ asChild?: boolean; // Renders as child component
1369
+ children?: ReactNode;
1370
+ disabled?: boolean;
1371
+ href?: string;
1372
+ }
1373
+
1374
+ interface OxPaginationNextProps extends ComponentPropsWithRef<'a'> {
1375
+ asChild?: boolean; // Renders as child component
1376
+ children?: ReactNode;
1377
+ disabled?: boolean;
1378
+ href?: string;
1379
+ }
1380
+
1381
+ interface OxPaginationEllipsisProps extends ComponentPropsWithRef<'span'> {}
1382
+ ```
1383
+
1384
+ ### Example
1385
+
1386
+ ```tsx
1387
+ <OxPagination>
1388
+ <OxPagination.Item>
1389
+ <OxPagination.Previous href="?page=1" />
1390
+ </OxPagination.Item>
1391
+ <OxPagination.Item>
1392
+ <OxPagination.Link href="?page=1">1</OxPagination.Link>
1393
+ </OxPagination.Item>
1394
+ <OxPagination.Item>
1395
+ <OxPagination.Link href="?page=2" isActive>
1396
+ 2
1397
+ </OxPagination.Link>
1398
+ </OxPagination.Item>
1399
+ <OxPagination.Item>
1400
+ <OxPagination.Ellipsis />
1401
+ </OxPagination.Item>
1402
+ <OxPagination.Item>
1403
+ <OxPagination.Next href="?page=3" />
1404
+ </OxPagination.Item>
1405
+ </OxPagination>
1406
+ ```
1407
+
1408
+ ---
1409
+
1410
+ ## OxPopover
1411
+
1412
+ Popover component built on Floating.
1413
+
1414
+ **Pattern**: Compound Component
1415
+ **Sub-components**: `Content`, `Trigger`
1416
+
1417
+ ### Props
1418
+
1419
+ ```tsx
1420
+ interface OxPopoverProps extends ComponentPropsWithRef<'div'> {
1421
+ align?: 'start' | 'center' | 'end';
1422
+ children: React.ReactNode;
1423
+ defaultOpen?: boolean;
1424
+ disabled?: boolean;
1425
+ onOpenChange?: (open: boolean) => void;
1426
+ open?: boolean; // Controlled open state
1427
+ side?: 'top' | 'bottom' | 'left' | 'right';
1428
+ }
1429
+
1430
+ interface OxPopoverTriggerProps extends ComponentPropsWithRef<'button'> {
1431
+ asChild?: boolean; // Renders as child component
1432
+ children: React.ReactNode;
1433
+ }
1434
+
1435
+ interface OxPopoverContentProps extends ComponentPropsWithRef<'div'> {
1436
+ children: React.ReactNode;
1437
+ showCloseButton?: boolean;
1438
+ }
1439
+ ```
1440
+
1441
+ ### Example
1442
+
1443
+ ```tsx
1444
+ <OxPopover side="bottom">
1445
+ <OxPopover.Trigger>Click me</OxPopover.Trigger>
1446
+ <OxPopover.Content showCloseButton>Popover content here</OxPopover.Content>
1447
+ </OxPopover>
1448
+ ```
1449
+
1450
+ ---
1451
+
1452
+ ## OxPopper
1453
+
1454
+ Low-level positioning primitive for floating elements. Built on @floating-ui/react.
1455
+
1456
+ **Pattern**: Compound Component (Primitive)
1457
+ **Sub-components**: `Anchor`, `Arrow`, `Content`
1458
+ **Additional Exports**: `usePopperState`, `usePopperContext`, `usePopperContentContext`
1459
+
1460
+ ### Props
1461
+
1462
+ ```tsx
1463
+ type OxPopperSide = 'top' | 'right' | 'bottom' | 'left';
1464
+ type OxPopperAlign = 'start' | 'center' | 'end';
1465
+ type OxPopperSticky = 'partial' | 'always';
1466
+
1467
+ interface OxPopperProps {
1468
+ children: ReactNode;
1469
+ }
1470
+
1471
+ interface OxPopperAnchorProps extends ComponentPropsWithoutRef<'div'> {
1472
+ asChild?: boolean;
1473
+ children?: ReactNode;
1474
+ virtualRef?: RefObject<Measurable | null>; // For virtual anchor positioning
1475
+ }
1476
+
1477
+ interface OxPopperContentProps extends ComponentPropsWithoutRef<'div'> {
1478
+ align?: OxPopperAlign;
1479
+ alignOffset?: number;
1480
+ arrowPadding?: number;
1481
+ avoidCollisions?: boolean;
1482
+ children: ReactNode;
1483
+ collisionPadding?: number;
1484
+ hideWhenDetached?: boolean; // Hide when anchor is out of view
1485
+ onPlaced?: () => void;
1486
+ side?: OxPopperSide;
1487
+ sideOffset?: number;
1488
+ sticky?: OxPopperSticky; // How content sticks to viewport edges
1489
+ }
1490
+ ```
1491
+
1492
+ ### Usage
1493
+
1494
+ ```tsx
1495
+ <OxPopper>
1496
+ <OxPopper.Anchor asChild>
1497
+ <button>Anchor element</button>
1498
+ </OxPopper.Anchor>
1499
+ <OxPopper.Content side="bottom" align="start" sideOffset={8}>
1500
+ <OxPopper.Arrow />
1501
+ <div>Positioned content</div>
1502
+ </OxPopper.Content>
1503
+ </OxPopper>
1504
+ ```
1505
+
1506
+ **Note**: This is a low-level primitive. Prefer `OxPopover`, `OxDropdown`, or `OxTooltip` for common use cases.
1507
+
1508
+ ---
1509
+
1510
+ ## OxProgress
1511
+
1512
+ Progress bar component with linear and circular variants.
1513
+
1514
+ **Pattern**: Compound Component
1515
+ **Sub-components**: `Circular`
1516
+
1517
+ ### Props
1518
+
1519
+ ```tsx
1520
+ interface OxProgressProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1521
+ buffer?: number; // Buffer value for buffering state
1522
+ max?: number;
1523
+ value?: number;
1524
+ }
1525
+
1526
+ interface OxProgressCircularProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1527
+ max?: number;
1528
+ showPercentage?: boolean; // Shows percentage text in center
1529
+ value?: number;
1530
+ }
1531
+ ```
1532
+
1533
+ ### Example
1534
+
1535
+ ```tsx
1536
+ <OxProgress value={60} max={100} />
1537
+ <OxProgress value={30} buffer={60} max={100} />
1538
+
1539
+ <OxProgress.Circular value={75} max={100} showPercentage />
1540
+ ```
1541
+
1542
+ ---
1543
+
1544
+ ## OxSeparator
1545
+
1546
+ Divider component.
1547
+
1548
+ **Pattern**: Simple Component
1549
+
1550
+ ### Props
1551
+
1552
+ ```tsx
1553
+ interface OxSeparatorProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1554
+ decorative?: boolean; // Marks as decorative (aria-hidden)
1555
+ orientation?: 'horizontal' | 'vertical';
1556
+ }
1557
+ ```
1558
+
1559
+ ### Example
1560
+
1561
+ ```tsx
1562
+ <OxSeparator orientation="horizontal" />
1563
+ <OxSeparator orientation="vertical" decorative />
1564
+ ```
1565
+
1566
+ ---
1567
+
1568
+ ## OxSkeleton
1569
+
1570
+ Loading skeleton placeholder.
1571
+
1572
+ **Pattern**: Simple Component
1573
+
1574
+ ### Props
1575
+
1576
+ ```tsx
1577
+ interface OxSkeletonProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1578
+ animate?: boolean; // Enables pulse animation
1579
+ shape?: 'rectangle' | 'circle';
1580
+ }
1581
+ ```
1582
+
1583
+ ### Example
1584
+
1585
+ ```tsx
1586
+ <OxSkeleton animate shape="rectangle" />
1587
+ <OxSkeleton shape="circle" />
1588
+ ```
1589
+
1590
+ ---
1591
+
1592
+ ## OxSlider
1593
+
1594
+ Slider component with range support.
1595
+
1596
+ **Pattern**: Simple Component
1597
+
1598
+ ### Props
1599
+
1600
+ ```tsx
1601
+ interface OxSliderProps extends Omit<
1602
+ ComponentPropsWithRef<'div'>,
1603
+ 'onChange' | 'defaultValue' | 'children'
1604
+ > {
1605
+ defaultValue?: number | [number, number]; // Single value or range
1606
+ disabled?: boolean;
1607
+ marks?: boolean | number[]; // Shows marks at positions
1608
+ max?: number;
1609
+ min?: number;
1610
+ onChange?: (value: number | [number, number]) => void;
1611
+ onChangeCommitted?: (value: number | [number, number]) => void; // Called when user releases
1612
+ orientation?: 'horizontal' | 'vertical';
1613
+ showValue?: boolean; // Shows current value
1614
+ step?: number;
1615
+ value?: number | [number, number]; // Controlled value
1616
+ }
1617
+ ```
1618
+
1619
+ ### Example
1620
+
1621
+ ```tsx
1622
+ {
1623
+ /* Single value slider */
1624
+ }
1625
+ <OxSlider min={0} max={100} value={50} onChange={setValue} />;
1626
+
1627
+ {
1628
+ /* Range slider */
1629
+ }
1630
+ <OxSlider value={[20, 80]} onChange={setRange} />;
1631
+
1632
+ {
1633
+ /* With marks */
1634
+ }
1635
+ <OxSlider marks={[0, 25, 50, 75, 100]} showValue />;
1636
+ ```
1637
+
1638
+ ---
1639
+
1640
+ ## OxSortableList
1641
+
1642
+ Sortable list with drag-and-drop reordering. Built on @dnd-kit.
1643
+
1644
+ **Pattern**: Compound Component
1645
+ **Sub-components**: `Handle`, `Item`
1646
+
1647
+ ### Props
1648
+
1649
+ ```tsx
1650
+ type OxSortableListDirection = 'vertical' | 'horizontal' | 'grid';
1651
+
1652
+ interface OxSortableListProps extends ComponentPropsWithRef<'div'> {
1653
+ children: ReactNode;
1654
+ columns?: number; // For grid direction
1655
+ direction?: OxSortableListDirection;
1656
+ disabled?: boolean;
1657
+ gap?: number;
1658
+ onReorder: (fromIndex: number, toIndex: number) => void;
1659
+ }
1660
+
1661
+ interface OxSortableListItemProps extends ComponentPropsWithRef<'div'> {
1662
+ children: ReactNode;
1663
+ disabled?: boolean;
1664
+ }
1665
+
1666
+ interface OxSortableListHandleProps extends ComponentPropsWithRef<'button'> {
1667
+ children?: ReactNode;
1668
+ }
1669
+ ```
1670
+
1671
+ ### Usage
1672
+
1673
+ ```tsx
1674
+ const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
1675
+
1676
+ const handleReorder = (from: number, to: number) => {
1677
+ const newItems = [...items];
1678
+ const [moved] = newItems.splice(from, 1);
1679
+ newItems.splice(to, 0, moved);
1680
+ setItems(newItems);
1681
+ };
1682
+
1683
+ <OxSortableList direction="vertical" gap={8} onReorder={handleReorder}>
1684
+ {items.map((item, index) => (
1685
+ <OxSortableList.Item key={item}>
1686
+ <OxSortableList.Handle />
1687
+ <span>{item}</span>
1688
+ </OxSortableList.Item>
1689
+ ))}
1690
+ </OxSortableList>
1691
+
1692
+ // Grid layout
1693
+ <OxSortableList direction="grid" columns={3} gap={16} onReorder={handleReorder}>
1694
+ {items.map(item => (
1695
+ <OxSortableList.Item key={item}>{item}</OxSortableList.Item>
1696
+ ))}
1697
+ </OxSortableList>
1698
+ ```
1699
+
1700
+ ---
1701
+
1702
+ ## OxSpinner
1703
+
1704
+ Loading spinner.
1705
+
1706
+ **Pattern**: Simple Component
1707
+
1708
+ ### Props
1709
+
1710
+ ```tsx
1711
+ interface OxSpinnerProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
1712
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | number;
1713
+ }
1714
+ ```
1715
+
1716
+ ### Example
1717
+
1718
+ ```tsx
1719
+ <OxSpinner size="lg" />
1720
+ <OxSpinner size={48} />
1721
+ ```
1722
+
1723
+ ---
1724
+
1725
+ ## OxStatusDisplay (beta)
1726
+
1727
+ Status display for errors and states.
1728
+
1729
+ **Pattern**: Simple Component
1730
+
1731
+ ### Props
1732
+
1733
+ ```tsx
1734
+ type OxStatusType =
1735
+ | 'loading'
1736
+ | 'empty'
1737
+ | 'offline'
1738
+ | 'success'
1739
+ | 'warning'
1740
+ | 'info'
1741
+ | 401
1742
+ | 403
1743
+ | 404
1744
+ | 408
1745
+ | 429
1746
+ | 500
1747
+ | 502
1748
+ | 503
1749
+ | 504; // HTTP status codes
1750
+
1751
+ interface OxStatusDisplayProps extends ComponentPropsWithRef<'div'> {
1752
+ action?: ReactNode; // Custom action element
1753
+ inline?: boolean;
1754
+ message?: string;
1755
+ onBack?: () => void; // Back button callback
1756
+ title?: string;
1757
+ type: OxStatusType; // Required
1758
+ }
1759
+ ```
1760
+
1761
+ ### Example
1762
+
1763
+ ```tsx
1764
+ <OxStatusDisplay type={404} title="Page Not Found" message="The page you're looking for doesn't exist." />
1765
+ <OxStatusDisplay type="loading" />
1766
+ <OxStatusDisplay type={500} onBack={() => navigate(-1)} />
1767
+ ```
1768
+
1769
+ ---
1770
+
1771
+ ## OxStepper (experimental)
1772
+
1773
+ Multi-step navigation component.
1774
+
1775
+ **Pattern**: Compound Component
1776
+ **Sub-components**: `Actions`, `Item`
1777
+
1778
+ ### Props
1779
+
1780
+ ```tsx
1781
+ interface OxStepperProps extends ComponentPropsWithRef<'div'> {
1782
+ children: ReactNode;
1783
+ color?: ColorStyleName;
1784
+ currentStep?: number; // Current active step index
1785
+ onStepChange?: (step: number) => void;
1786
+ orientation?: 'horizontal' | 'vertical';
1787
+ type?: 'linear' | 'non-linear'; // Linear or non-linear navigation
1788
+ }
1789
+
1790
+ interface OxStepperItemProps extends ComponentPropsWithRef<'div'> {
1791
+ children: ReactNode;
1792
+ description?: string;
1793
+ icon?: LucideIcon;
1794
+ state?: 'completed' | 'current' | 'upcoming' | 'error' | 'warning';
1795
+ stepIndex?: number; // Auto-assigned
1796
+ title: string; // Required
1797
+ }
1798
+
1799
+ interface OxStepperActionsProps extends ComponentPropsWithRef<'div'> {
1800
+ children: ReactNode;
1801
+ }
1802
+ ```
1803
+
1804
+ ### Example
1805
+
1806
+ ```tsx
1807
+ <OxStepper currentStep={1} type="linear" orientation="horizontal">
1808
+ <OxStepper.Item title="Account" description="Create account" state="completed" />
1809
+ <OxStepper.Item title="Profile" description="Add profile" state="current" />
1810
+ <OxStepper.Item title="Finish" description="Complete setup" state="upcoming" />
1811
+ <OxStepper.Actions>
1812
+ <OxButton>Previous</OxButton>
1813
+ <OxButton variant="primary">Next</OxButton>
1814
+ </OxStepper.Actions>
1815
+ </OxStepper>
1816
+ ```
1817
+
1818
+ ---
1819
+
1820
+ ## OxTable
1821
+
1822
+ Table component with selection and loading states.
1823
+
1824
+ **Pattern**: Compound Component
1825
+ **Sub-components**: `Body`, `Cell`, `Controls`, `Footer`, `Head`, `Header`, `Row`, `SkeletonRow`
1826
+
1827
+ ### Props
1828
+
1829
+ ```tsx
1830
+ interface OxTableProps extends ComponentPropsWithRef<'table'> {
1831
+ allRowIds?: string[]; // All row IDs for selection
1832
+ children: ReactNode;
1833
+ draggable?: boolean; // Enables row reordering via drag and drop
1834
+ isLoading?: boolean; // Shows loading skeleton
1835
+ onRowReorder?: (newOrder: string[]) => void; // Callback when rows are reordered
1836
+ onSelectionChange?: (selectedRows: string[]) => void;
1837
+ selectable?: boolean; // Enables row selection with checkboxes
1838
+ selectedRows?: string[];
1839
+ skeletonColumns?: number;
1840
+ skeletonRows?: number;
1841
+ }
1842
+
1843
+ interface OxTableCellProps extends ComponentPropsWithoutRef<'td'> {
1844
+ children?: ReactNode;
1845
+ }
1846
+
1847
+ interface OxTableHeadProps extends ComponentPropsWithRef<'th'> {
1848
+ children?: ReactNode;
1849
+ }
1850
+
1851
+ interface OxTableRowProps extends ComponentPropsWithRef<'tr'> {
1852
+ children: ReactNode;
1853
+ rowId?: string; // Required for selection
1854
+ }
1855
+
1856
+ interface OxTableBodyProps extends ComponentPropsWithRef<'tbody'> {
1857
+ children: ReactNode;
1858
+ }
1859
+
1860
+ interface OxTableFooterProps extends ComponentPropsWithRef<'tfoot'> {
1861
+ children: ReactNode;
1862
+ }
1863
+
1864
+ interface OxTableControlsProps extends ComponentPropsWithRef<'div'> {
1865
+ children: ReactNode;
1866
+ }
1867
+
1868
+ interface OxTableHeaderProps extends ComponentPropsWithRef<'thead'> {
1869
+ children: ReactNode;
1870
+ }
1871
+ ```
1872
+
1873
+ ### Example
1874
+
1875
+ ```tsx
1876
+ <OxTable selectable selectedRows={selected} onSelectionChange={setSelected}>
1877
+ <OxTable.Header>
1878
+ <OxTable.Row>
1879
+ <OxTable.Head>Name</OxTable.Head>
1880
+ <OxTable.Head>Email</OxTable.Head>
1881
+ </OxTable.Row>
1882
+ </OxTable.Header>
1883
+ <OxTable.Body>
1884
+ <OxTable.Row rowId="1">
1885
+ <OxTable.Cell>John Doe</OxTable.Cell>
1886
+ <OxTable.Cell>john@example.com</OxTable.Cell>
1887
+ </OxTable.Row>
1888
+ </OxTable.Body>
1889
+ </OxTable>
1890
+ ```
1891
+
1892
+ ---
1893
+
1894
+ ## OxTabs
1895
+
1896
+ Tabs component with bordered and pills variants.
1897
+
1898
+ **Pattern**: Compound Component
1899
+ **Sub-components**: `Content`, `List`, `Trigger`
1900
+
1901
+ ### Props
1902
+
1903
+ ```tsx
1904
+ interface OxTabsProps extends ComponentPropsWithRef<'div'> {
1905
+ children: ReactNode;
1906
+ defaultValue?: string;
1907
+ onValueChange?: (value: string) => void;
1908
+ value?: string; // Controlled active tab
1909
+ variant?: 'bordered' | 'pills';
1910
+ }
1911
+
1912
+ interface OxTabsListProps extends ComponentPropsWithRef<'div'> {
1913
+ children: ReactNode;
1914
+ }
1915
+
1916
+ interface OxTabsTriggerProps extends ComponentPropsWithRef<'button'> {
1917
+ children: ReactNode;
1918
+ value: string; // Required - Tab identifier
1919
+ }
1920
+
1921
+ interface OxTabsContentProps extends ComponentPropsWithRef<'div'> {
1922
+ children: ReactNode;
1923
+ value: string; // Required - Tab identifier
1924
+ }
1925
+ ```
1926
+
1927
+ ### Example
1928
+
1929
+ ```tsx
1930
+ <OxTabs defaultValue="account" variant="bordered">
1931
+ <OxTabs.List>
1932
+ <OxTabs.Trigger value="account">Account</OxTabs.Trigger>
1933
+ <OxTabs.Trigger value="password">Password</OxTabs.Trigger>
1934
+ </OxTabs.List>
1935
+ <OxTabs.Content value="account">Account settings</OxTabs.Content>
1936
+ <OxTabs.Content value="password">Password settings</OxTabs.Content>
1937
+ </OxTabs>
1938
+ ```
1939
+
1940
+ ---
1941
+
1942
+ ## OxTimeline (alpha)
1943
+
1944
+ Timeline component.
1945
+
1946
+ **Pattern**: Compound Component
1947
+ **Sub-components**: `Item`
1948
+
1949
+ ### Props
1950
+
1951
+ ```tsx
1952
+ interface OxTimelineProps extends ComponentPropsWithRef<'ol'> {
1953
+ children: ReactNode;
1954
+ }
1955
+
1956
+ interface OxTimelineItemProps extends ComponentPropsWithRef<'li'> {
1957
+ align?: 'left' | 'right';
1958
+ color?: ColorStyleName;
1959
+ description?: string;
1960
+ icon?: LucideIcon;
1961
+ label: string; // Required
1962
+ showSeparator?: boolean; // Shows connecting line
1963
+ timestamp?: string;
1964
+ }
1965
+ ```
1966
+
1967
+ ### Example
1968
+
1969
+ ```tsx
1970
+ <OxTimeline>
1971
+ <OxTimeline.Item
1972
+ label="Created"
1973
+ description="Project initialized"
1974
+ timestamp="2024-01-01"
1975
+ color="blue"
1976
+ />
1977
+ <OxTimeline.Item
1978
+ label="Updated"
1979
+ description="Files modified"
1980
+ timestamp="2024-01-15"
1981
+ color="green"
1982
+ />
1983
+ </OxTimeline>
1984
+ ```
1985
+
1986
+ ---
1987
+
1988
+ ## OxToast (beta)
1989
+
1990
+ Toast notification system.
1991
+
1992
+ **Pattern**: Context-based Component
1993
+ **Additional Exports**: `OxToastProvider`, `useOxToast`
1994
+
1995
+ ### Props
1996
+
1997
+ ```tsx
1998
+ interface OxToastData {
1999
+ color?: ColorStyleName;
2000
+ customContent?: ReactNode;
2001
+ description?: string;
2002
+ duration?: number; // Auto-dismiss duration in ms
2003
+ icon?: LucideIcon;
2004
+ id: string; // Required - Unique ID
2005
+ isRemoving?: boolean; // Internal removal state
2006
+ path?: string; // SVG path
2007
+ title: string; // Required
2008
+ type: StatusType; // Required
2009
+ }
2010
+
2011
+ interface OxToastProps {
2012
+ align: 'left' | 'center' | 'right'; // Required
2013
+ onRemove: (id: string) => void; // Required
2014
+ position: 'top' | 'bottom'; // Required
2015
+ toasts: OxToastData[]; // Required
2016
+ }
2017
+ ```
2018
+
2019
+ ### Hook
2020
+
2021
+ ```tsx
2022
+ const { showToast } = useOxToast();
2023
+
2024
+ showToast({
2025
+ title: 'Success!',
2026
+ description: 'Your changes have been saved.',
2027
+ type: 'success',
2028
+ duration: 5000,
2029
+ });
2030
+ ```
2031
+
2032
+ ### Example
2033
+
2034
+ ```tsx
2035
+ // Wrap app
2036
+ <OxToastProvider>
2037
+ <App />
2038
+ </OxToastProvider>;
2039
+
2040
+ // Use in component
2041
+ function MyComponent() {
2042
+ const { showToast } = useOxToast();
2043
+
2044
+ return <button onClick={() => showToast({ title: 'Hello', type: 'info' })}>Show Toast</button>;
2045
+ }
2046
+ ```
2047
+
2048
+ ---
2049
+
2050
+ ## OxToggle
2051
+
2052
+ Toggle button component with groups.
2053
+
2054
+ **Pattern**: Compound Component
2055
+ **Sub-components**: `Group`
2056
+
2057
+ ### Props
2058
+
2059
+ ```tsx
2060
+ interface OxToggleProps extends Omit<ComponentPropsWithRef<'button'>, 'onChange'> {
2061
+ children?: ReactNode;
2062
+ onPressedChange?: (pressed: boolean) => void;
2063
+ pressed?: boolean; // Controlled pressed state
2064
+ size?: 'sm' | 'md' | 'lg';
2065
+ value?: string; // For use in groups
2066
+ }
2067
+
2068
+ interface OxToggleGroupSingleProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
2069
+ children: ReactNode;
2070
+ disabled?: boolean;
2071
+ name?: string;
2072
+ onValueChange?: (value: string) => void;
2073
+ size?: 'sm' | 'md' | 'lg';
2074
+ type?: 'single'; // Single selection
2075
+ value?: string; // Controlled selected value
2076
+ }
2077
+
2078
+ interface OxToggleGroupMultipleProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
2079
+ children: ReactNode;
2080
+ disabled?: boolean;
2081
+ name?: string;
2082
+ onValueChange?: (value: string[]) => void;
2083
+ size?: 'sm' | 'md' | 'lg';
2084
+ type: 'multiple'; // Required - Multiple selection
2085
+ value?: string[]; // Controlled selected values
2086
+ }
2087
+ ```
2088
+
2089
+ ### Example
2090
+
2091
+ ```tsx
2092
+ {
2093
+ /* Single toggle */
2094
+ }
2095
+ <OxToggle pressed={bold} onPressedChange={setBold}>
2096
+ Bold
2097
+ </OxToggle>;
2098
+
2099
+ {
2100
+ /* Toggle group - single selection */
2101
+ }
2102
+ <OxToggle.Group type="single" value={alignment} onValueChange={setAlignment}>
2103
+ <OxToggle value="left">Left</OxToggle>
2104
+ <OxToggle value="center">Center</OxToggle>
2105
+ <OxToggle value="right">Right</OxToggle>
2106
+ </OxToggle.Group>;
2107
+
2108
+ {
2109
+ /* Toggle group - multiple selection */
2110
+ }
2111
+ <OxToggle.Group type="multiple" value={formats} onValueChange={setFormats}>
2112
+ <OxToggle value="bold">Bold</OxToggle>
2113
+ <OxToggle value="italic">Italic</OxToggle>
2114
+ <OxToggle value="underline">Underline</OxToggle>
2115
+ </OxToggle.Group>;
2116
+ ```
2117
+
2118
+ ---
2119
+
2120
+ ## OxTooltip
2121
+
2122
+ Tooltip component.
2123
+
2124
+ **Pattern**: Simple Component
2125
+
2126
+ ### Props
2127
+
2128
+ ```tsx
2129
+ interface OxTooltipProps {
2130
+ align?: 'start' | 'center' | 'end';
2131
+ children: ReactNode; // Required - Trigger element
2132
+ className?: string;
2133
+ content: ReactNode; // Required - Tooltip content
2134
+ disabled?: boolean;
2135
+ hoverDelay?: number; // Delay before showing (ms)
2136
+ interactive?: boolean; // Keep tooltip open when hovering over it
2137
+ position?: 'top' | 'bottom' | 'left' | 'right';
2138
+ trigger?: 'hover' | 'click' | 'focus';
2139
+ }
2140
+ ```
2141
+
2142
+ ### Example
2143
+
2144
+ ```tsx
2145
+ <OxTooltip content="Click to save" position="top">
2146
+ <button>Save</button>
2147
+ </OxTooltip>
2148
+
2149
+ <OxTooltip content="Error occurred" position="bottom">
2150
+ <OxIcon icon={AlertCircle} />
2151
+ </OxTooltip>
2152
+ ```
2153
+
2154
+ ---
2155
+
2156
+ # Form Components (8)
2157
+
2158
+ ## OxCheckbox
2159
+
2160
+ Checkbox component with group support.
2161
+
2162
+ **Pattern**: Compound Component
2163
+ **Sub-components**: `Group`, `GroupItem`
2164
+
2165
+ ### Props
2166
+
2167
+ ```tsx
2168
+ type OxCheckedState = boolean | 'indeterminate';
2169
+
2170
+ interface OxCheckboxProps extends Omit<
2171
+ ComponentPropsWithoutRef<'input'>,
2172
+ 'type' | 'value' | 'children' | 'checked' | 'size' | 'defaultChecked'
2173
+ > {
2174
+ checked?: OxCheckedState; // Can be boolean or 'indeterminate'
2175
+ defaultChecked?: OxCheckedState;
2176
+ error?: boolean; // Error state styling
2177
+ onCheckedChange?: (checked: OxCheckedState) => void;
2178
+ value?: string;
2179
+ }
2180
+
2181
+ interface OxCheckboxGroupProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2182
+ children: ReactNode;
2183
+ disabled?: boolean; // Disables all checkboxes in group
2184
+ name: string; // Required
2185
+ onChange?: (value: (string | number)[]) => void;
2186
+ value?: (string | number)[]; // Controlled selected values
2187
+ }
2188
+
2189
+ interface OxCheckboxGroupItemProps extends Omit<
2190
+ ComponentPropsWithoutRef<'input'>,
2191
+ 'type' | 'size' | 'children' | 'checked' | 'defaultChecked' | 'value'
2192
+ > {
2193
+ error?: boolean;
2194
+ value: string | number; // Required
2195
+ }
2196
+ ```
2197
+
2198
+ ### Example
2199
+
2200
+ ```tsx
2201
+ {
2202
+ /* Single checkbox */
2203
+ }
2204
+ <OxCheckbox checked={agreed} onCheckedChange={setAgreed} />;
2205
+
2206
+ {
2207
+ /* Indeterminate state */
2208
+ }
2209
+ <OxCheckbox checked="indeterminate" />;
2210
+
2211
+ {
2212
+ /* Checkbox group */
2213
+ }
2214
+ <OxCheckbox.Group name="features" value={selected} onChange={setSelected}>
2215
+ <OxCheckbox.GroupItem value="feature1" />
2216
+ <OxCheckbox.GroupItem value="feature2" />
2217
+ </OxCheckbox.Group>;
2218
+ ```
2219
+
2220
+ ---
2221
+
2222
+ ## OxFileUpload (experimental)
2223
+
2224
+ File upload component with drag-and-drop.
2225
+
2226
+ **Pattern**: Compound Component
2227
+ **Sub-components**: `Area`, `Button`, `Overlay`
2228
+
2229
+ ### Props
2230
+
2231
+ ```tsx
2232
+ interface OxFileUploadProps extends Omit<ComponentPropsWithRef<'div'>, 'onError'> {
2233
+ accept?: string[]; // Allowed file types (e.g., ['.jpg', '.png', 'image/*'])
2234
+ children: ReactNode; // Required
2235
+ disabled?: boolean;
2236
+ maxFiles?: number; // Maximum number of files
2237
+ maxSize?: string; // Max file size (e.g., '5MB', '1GB')
2238
+ minSize?: string; // Min file size
2239
+ multiple?: boolean; // Allow multiple files
2240
+ onError?: (error: string) => void; // Validation error callback
2241
+ onFileSelect?: (files: File[]) => void; // Files selected callback
2242
+ }
2243
+
2244
+ interface OxFileUploadAreaProps extends ComponentPropsWithRef<'div'> {
2245
+ children: ReactNode;
2246
+ }
2247
+
2248
+ interface OxFileUploadButtonProps extends ComponentPropsWithRef<'button'> {
2249
+ children: ReactNode;
2250
+ size?: 'sm' | 'md';
2251
+ variant?: 'primary' | 'secondary' | 'ghost' | 'link' | 'danger';
2252
+ }
2253
+
2254
+ interface OxFileUploadOverlayProps extends ComponentPropsWithRef<'div'> {
2255
+ children: ReactNode;
2256
+ }
2257
+ ```
2258
+
2259
+ ### Example
2260
+
2261
+ ```tsx
2262
+ <OxFileUpload
2263
+ accept={['image/*']}
2264
+ maxSize="5MB"
2265
+ multiple
2266
+ onFileSelect={(files) => console.log(files)}
2267
+ onError={(error) => console.error(error)}
2268
+ >
2269
+ <OxFileUpload.Area>
2270
+ <p>Drag files here or click to browse</p>
2271
+ <OxFileUpload.Button>Select Files</OxFileUpload.Button>
2272
+ </OxFileUpload.Area>
2273
+ <OxFileUpload.Overlay>Drop files here</OxFileUpload.Overlay>
2274
+ </OxFileUpload>
2275
+ ```
2276
+
2277
+ ---
2278
+
2279
+ ## OxForm
2280
+
2281
+ Form container with field management.
2282
+
2283
+ **Pattern**: Compound Component
2284
+ **Sub-components**: `Group`, `Field`, `Label`, `Description`, `Error`, `GroupTitle`
2285
+
2286
+ ### Props
2287
+
2288
+ ```tsx
2289
+ interface OxFormProps extends ComponentPropsWithRef<'form'> {
2290
+ children: ReactNode; // Required
2291
+ fullWidth?: boolean; // Makes form full width
2292
+ }
2293
+
2294
+ interface OxFormGroupProps extends ComponentPropsWithRef<'div'> {
2295
+ children: ReactNode;
2296
+ layout?: 'grid'; // Optional grid layout
2297
+ }
2298
+
2299
+ interface OxFormFieldProps extends ComponentPropsWithRef<'div'> {
2300
+ children: ReactNode;
2301
+ disabled?: boolean; // Disables all form controls within
2302
+ error?: boolean | string; // Error state or message
2303
+ id?: string; // Field ID for label association
2304
+ labelPosition?: 'start' | 'end'; // Position of label relative to control (default: 'start')
2305
+ orientation?: 'vertical' | 'horizontal'; // Layout direction
2306
+ required?: boolean; // Marks field as required
2307
+ }
2308
+
2309
+ interface OxFormLabelProps extends ComponentPropsWithRef<'label'> {
2310
+ children: ReactNode; // Required
2311
+ disabled?: boolean;
2312
+ required?: boolean; // Shows required indicator (red asterisk)
2313
+ }
2314
+
2315
+ interface OxFormDescriptionProps extends ComponentPropsWithRef<'div'> {
2316
+ children: ReactNode; // Required
2317
+ disabled?: boolean;
2318
+ }
2319
+
2320
+ interface OxFormErrorProps extends ComponentPropsWithRef<'div'> {}
2321
+
2322
+ interface OxFormGroupTitleProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
2323
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div';
2324
+ children: ReactNode; // Required
2325
+ level?: 1 | 2 | 3 | 4 | 5 | 6 | 7; // Heading level for styling
2326
+ }
2327
+ ```
2328
+
2329
+ ### Example
2330
+
2331
+ ```tsx
2332
+ <OxForm>
2333
+ <OxForm.Group>
2334
+ <OxForm.GroupTitle level={2}>Account Information</OxForm.GroupTitle>
2335
+ <OxForm.Field orientation="vertical">
2336
+ <OxForm.Label required>Email</OxForm.Label>
2337
+ <OxForm.Description>Your email address</OxForm.Description>
2338
+ <input type="email" />
2339
+ <OxForm.Error>Email is required</OxForm.Error>
2340
+ </OxForm.Field>
2341
+ </OxForm.Group>
2342
+ </OxForm>
2343
+ ```
2344
+
2345
+ ---
2346
+
2347
+ ## Input Components
2348
+
2349
+ ### OxTextInput
2350
+
2351
+ Text input with validation and various types.
2352
+
2353
+ **Pattern**: Compound Component
2354
+ **Parts**: `Container`, input element, `Button`, `ClearButton`, `Counter`, `VisibilityButton`
2355
+
2356
+ ### Props
2357
+
2358
+ ```tsx
2359
+ type OxTextInputType = 'email' | 'password' | 'search' | 'tel' | 'text' | 'url';
2360
+
2361
+ interface OxTextInputContainerProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2362
+ defaultValue?: string;
2363
+ disabled?: boolean;
2364
+ error?: boolean;
2365
+ onChange?: (value: string) => void;
2366
+ required?: boolean;
2367
+ type?: OxTextInputType;
2368
+ validationMessage?: string; // Custom error message shown below input
2369
+ value?: string; // Controlled value
2370
+ }
2371
+
2372
+ // Input element props
2373
+ interface OxTextInputProps {
2374
+ [key: `data-${string}`]?: string | undefined;
2375
+ 'aria-describedby'?: string;
2376
+ 'aria-label'?: string;
2377
+ 'aria-labelledby'?: string;
2378
+ autoComplete?: string;
2379
+ className?: string;
2380
+ id?: string;
2381
+ maxLength?: number;
2382
+ minLength?: number;
2383
+ name?: string;
2384
+ pattern?: string; // Validation regex
2385
+ placeholder?: string;
2386
+ readOnly?: boolean;
2387
+ spellCheck?: boolean;
2388
+ }
2389
+
2390
+ interface OxTextInputButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {}
2391
+
2392
+ interface OxTextInputCounterProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
2393
+ currentLength?: number;
2394
+ disabled?: boolean;
2395
+ maxLength: number; // Required
2396
+ }
2397
+ ```
2398
+
2399
+ ### Example
2400
+
2401
+ ```tsx
2402
+ <OxTextInput.Container
2403
+ type="email"
2404
+ value={email}
2405
+ onChange={setEmail}
2406
+ error={!!emailError}
2407
+ validationMessage="Please enter a valid email"
2408
+ >
2409
+ <OxTextInput placeholder="Enter email" maxLength={100} />
2410
+ <OxTextInput.ClearButton />
2411
+ <OxTextInput.Counter maxLength={100} />
2412
+ </OxTextInput.Container>;
2413
+
2414
+ {
2415
+ /* Password input */
2416
+ }
2417
+ <OxTextInput.Container type="password">
2418
+ <OxTextInput placeholder="Password" />
2419
+ <OxTextInput.VisibilityButton />
2420
+ </OxTextInput.Container>;
2421
+ ```
2422
+
2423
+ ---
2424
+
2425
+ ### OxNumberInput
2426
+
2427
+ Numeric input with increment/decrement controls.
2428
+
2429
+ **Pattern**: Compound Component
2430
+ **Parts**: `Container`, input element, `Button`, `IncrementButton`, `DecrementButton`
2431
+
2432
+ ### Props
2433
+
2434
+ ```tsx
2435
+ interface OxNumberInputContainerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
2436
+ defaultValue?: number;
2437
+ disabled?: boolean;
2438
+ error?: boolean;
2439
+ locale?: string; // Locale for number formatting
2440
+ max?: number; // Maximum value
2441
+ maximumFractionDigits?: number; // Max decimal places
2442
+ min?: number; // Minimum value
2443
+ minimumFractionDigits?: number; // Min decimal places
2444
+ onChange?: (value: number | undefined) => void;
2445
+ required?: boolean;
2446
+ steps?: number; // Increment/decrement step value
2447
+ useGrouping?: boolean; // Use thousand separators
2448
+ validationMessage?: string; // Custom error message shown below input
2449
+ value?: number; // Controlled value
2450
+ }
2451
+
2452
+ interface OxNumberInputProps {
2453
+ 'aria-label'?: string;
2454
+ 'aria-labelledby'?: string;
2455
+ className?: string;
2456
+ id?: string;
2457
+ placeholder?: string;
2458
+ }
2459
+
2460
+ interface OxNumberInputButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {}
2461
+ ```
2462
+
2463
+ ### Example
2464
+
2465
+ ```tsx
2466
+ <OxNumberInput.Container
2467
+ value={quantity}
2468
+ onChange={setQuantity}
2469
+ min={0}
2470
+ max={100}
2471
+ steps={5}
2472
+ useGrouping
2473
+ >
2474
+ <OxNumberInput.DecrementButton />
2475
+ <OxNumberInput placeholder="Quantity" />
2476
+ <OxNumberInput.IncrementButton />
2477
+ </OxNumberInput.Container>
2478
+ ```
2479
+
2480
+ ---
2481
+
2482
+ ### OxDateInput
2483
+
2484
+ Date input with picker.
2485
+
2486
+ **Pattern**: Compound Component
2487
+ **Parts**: `Container`, `Button`, `PickerButton`
2488
+
2489
+ ### Props
2490
+
2491
+ ```tsx
2492
+ interface OxDateInputContainerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
2493
+ defaultOpen?: boolean; // Default open state of picker
2494
+ defaultValue?: string; // Date string
2495
+ disabled?: boolean;
2496
+ error?: boolean;
2497
+ onChange?: (value: string) => void;
2498
+ onOpenChange?: (open: boolean) => void;
2499
+ open?: boolean; // Controlled open state
2500
+ pickOnly?: boolean; // Only allow picking from calendar, no manual input
2501
+ readOnly?: boolean;
2502
+ required?: boolean;
2503
+ validationMessage?: string; // Custom error message shown below input
2504
+ value?: string; // Controlled value
2505
+ }
2506
+
2507
+ interface OxDateInputButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {}
2508
+
2509
+ // Picker button - opens calendar
2510
+ interface OxDatePickerButtonProps extends Omit<
2511
+ ComponentPropsWithRef<'button'>,
2512
+ 'type' | 'children'
2513
+ > {}
2514
+ ```
2515
+
2516
+ ### Example
2517
+
2518
+ ```tsx
2519
+ <OxDateInput.Container value={date} onChange={setDate}>
2520
+ <OxDateInput.PickerButton />
2521
+ </OxDateInput.Container>;
2522
+
2523
+ {
2524
+ /* Pick-only mode (no manual input) */
2525
+ }
2526
+ <OxDateInput.Container pickOnly>
2527
+ <OxDateInput.PickerButton />
2528
+ </OxDateInput.Container>;
2529
+ ```
2530
+
2531
+ ---
2532
+
2533
+ ### OxTimeInput
2534
+
2535
+ Time input component.
2536
+
2537
+ **Pattern**: Compound Component
2538
+ **Parts**: `Container`, `Button`
2539
+
2540
+ ### Props
2541
+
2542
+ ```tsx
2543
+ interface OxTimeInputContainerProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2544
+ defaultValue?: string; // Time string
2545
+ disabled?: boolean;
2546
+ error?: boolean;
2547
+ onChange?: (value: string) => void;
2548
+ required?: boolean;
2549
+ validationMessage?: string; // Custom error message shown below input
2550
+ value?: string; // Controlled value
2551
+ }
2552
+
2553
+ interface OxTimeInputButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {}
2554
+ ```
2555
+
2556
+ ### Example
2557
+
2558
+ ```tsx
2559
+ <OxTimeInput.Container value={time} onChange={setTime}>
2560
+ <input type="time" />
2561
+ </OxTimeInput.Container>
2562
+ ```
2563
+
2564
+ ---
2565
+
2566
+ ### OxOtpInput
2567
+
2568
+ One-Time Password input.
2569
+
2570
+ **Pattern**: Simple Component
2571
+
2572
+ ### Props
2573
+
2574
+ ```tsx
2575
+ type OxOtpInputType = 'numeric' | 'alphanumeric' | 'text';
2576
+
2577
+ interface OxOtpInputProps {
2578
+ className?: string;
2579
+ disabled?: boolean;
2580
+ error?: boolean;
2581
+ length?: number; // Number of digits/characters
2582
+ onComplete?: (value: string) => void; // Called when all digits filled
2583
+ onValueChange?: (value: string) => void; // Called on any change
2584
+ placeholder?: string;
2585
+ type?: OxOtpInputType; // Type of characters allowed
2586
+ }
2587
+ ```
2588
+
2589
+ ### Example
2590
+
2591
+ ```tsx
2592
+ <OxOtpInput
2593
+ length={6}
2594
+ type="numeric"
2595
+ onComplete={(code) => verifyCode(code)}
2596
+ onValueChange={(value) => console.log(value)}
2597
+ />
2598
+ ```
2599
+
2600
+ ---
2601
+
2602
+ ## OxRadio
2603
+
2604
+ Radio button group.
2605
+
2606
+ **Pattern**: Compound Component (Namespace - no standalone component)
2607
+ **Sub-components**: `Group`, `Item`
2608
+
2609
+ ### Props
2610
+
2611
+ ```tsx
2612
+ interface OxRadioGroupProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2613
+ children: ReactNode; // Required
2614
+ defaultValue?: string | number;
2615
+ disabled?: boolean; // Disables all radio buttons
2616
+ error?: boolean;
2617
+ name?: string;
2618
+ onChange?: (value: string | number) => void;
2619
+ required?: boolean;
2620
+ value?: string | number; // Controlled selected value
2621
+ }
2622
+
2623
+ interface OxRadioItemProps extends Omit<
2624
+ ComponentPropsWithoutRef<'input'>,
2625
+ 'type' | 'size' | 'required'
2626
+ > {
2627
+ error?: boolean;
2628
+ onCheckedChange?: (checked: boolean) => void; // Called when this item is checked
2629
+ value?: string | number;
2630
+ }
2631
+ ```
2632
+
2633
+ ### Example
2634
+
2635
+ ```tsx
2636
+ <OxRadio.Group name="plan" value={plan} onChange={setPlan}>
2637
+ <OxRadio.Item value="basic" />
2638
+ <OxRadio.Item value="pro" />
2639
+ <OxRadio.Item value="enterprise" />
2640
+ </OxRadio.Group>
2641
+ ```
2642
+
2643
+ **Note**: No standalone `OxRadio` component - only `OxRadio.Group` and `OxRadio.Item`.
2644
+
2645
+ ---
2646
+
2647
+ ## OxSelect
2648
+
2649
+ Select dropdown with single and multi-select.
2650
+
2651
+ **Pattern**: Compound Component
2652
+ **Sub-components**: `Trigger`, `Content`, `Group`, `Item`
2653
+
2654
+ ### Props
2655
+
2656
+ ```tsx
2657
+ interface OxSelectProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'> {
2658
+ defaultOpen?: boolean;
2659
+ defaultValue?: string | number | null | Array<string | number | null>;
2660
+ disabled?: boolean;
2661
+ error?: boolean;
2662
+ id?: string;
2663
+ isLoading?: boolean; // Shows loading state
2664
+ multiple?: boolean; // Enable multi-select
2665
+ onChange?: (value: string | number | null | Array<string | number | null>) => void;
2666
+ onOpenChange?: (open: boolean) => void;
2667
+ open?: boolean; // Controlled open state
2668
+ required?: boolean;
2669
+ value?: string | number | null | Array<string | number | null>; // Controlled value
2670
+ }
2671
+
2672
+ interface OxSelectTriggerProps extends ComponentPropsWithRef<'button'> {
2673
+ displayAsTag?: boolean; // Display selected items as tags (multi-select)
2674
+ placeholder?: string;
2675
+ tagColor?: ColorStyleName;
2676
+ }
2677
+
2678
+ interface OxSelectContentProps extends ComponentPropsWithRef<'ul'> {}
2679
+
2680
+ interface OxSelectGroupProps extends ComponentPropsWithRef<'div'> {
2681
+ label?: ReactNode; // Group label
2682
+ }
2683
+
2684
+ interface OxSelectItemProps extends Omit<ComponentPropsWithRef<'button'>, 'value'> {
2685
+ value: string | number | null; // Required
2686
+ }
2687
+ ```
2688
+
2689
+ ### Example
2690
+
2691
+ ```tsx
2692
+ {
2693
+ /* Single select */
2694
+ }
2695
+ <OxSelect value={country} onChange={setCountry}>
2696
+ <OxSelect.Trigger placeholder="Select country" />
2697
+ <OxSelect.Content>
2698
+ <OxSelect.Item value="us">United States</OxSelect.Item>
2699
+ <OxSelect.Item value="uk">United Kingdom</OxSelect.Item>
2700
+ </OxSelect.Content>
2701
+ </OxSelect>;
2702
+
2703
+ {
2704
+ /* Multi-select with badges */
2705
+ }
2706
+ <OxSelect multiple value={tags} onChange={setTags}>
2707
+ <OxSelect.Trigger displayAsTag tagColor="blue" />
2708
+ <OxSelect.Content>
2709
+ <OxSelect.Group label="Categories">
2710
+ <OxSelect.Item value="react">React</OxSelect.Item>
2711
+ <OxSelect.Item value="typescript">TypeScript</OxSelect.Item>
2712
+ </OxSelect.Group>
2713
+ </OxSelect.Content>
2714
+ </OxSelect>;
2715
+ ```
2716
+
2717
+ ---
2718
+
2719
+ ## OxSwitch
2720
+
2721
+ Toggle switch for boolean values.
2722
+
2723
+ **Pattern**: Simple Component
2724
+
2725
+ ### Props
2726
+
2727
+ ```tsx
2728
+ interface OxSwitchProps extends Omit<
2729
+ ComponentPropsWithRef<'button'>,
2730
+ 'type' | 'size' | 'onChange' | 'children'
2731
+ > {
2732
+ checked?: boolean; // Controlled checked state
2733
+ error?: boolean;
2734
+ onChange?: (checked: boolean) => void;
2735
+ required?: boolean;
2736
+ }
2737
+ ```
2738
+
2739
+ ### Example
2740
+
2741
+ ```tsx
2742
+ <OxSwitch checked={enabled} onChange={setEnabled} />
2743
+ ```
2744
+
2745
+ ---
2746
+
2747
+ ## OxTextarea
2748
+
2749
+ Multi-line text input.
2750
+
2751
+ **Pattern**: Simple Component
2752
+
2753
+ ### Props
2754
+
2755
+ ```tsx
2756
+ interface OxTextareaProps extends Omit<ComponentPropsWithRef<'textarea'>, 'children'> {
2757
+ error?: boolean;
2758
+ showMaxLength?: boolean; // Show character count indicator
2759
+ }
2760
+ ```
2761
+
2762
+ ### Example
2763
+
2764
+ ```tsx
2765
+ <OxTextarea placeholder="Enter description" maxLength={500} showMaxLength rows={5} />
2766
+ ```
2767
+
2768
+ ---
2769
+
2770
+ # Layout Components (3)
2771
+
2772
+ ## OxAppLayout
2773
+
2774
+ Top-level application layout wrapper.
2775
+
2776
+ **Pattern**: Simple Wrapper
2777
+
2778
+ ### Props
2779
+
2780
+ ```tsx
2781
+ interface OxAppLayoutProps extends ComponentPropsWithRef<'div'> {
2782
+ children: ReactNode; // Required
2783
+ className?: string;
2784
+ }
2785
+ ```
2786
+
2787
+ ### Example
2788
+
2789
+ ```tsx
2790
+ <OxSidebarProvider>
2791
+ <OxAppLayout>
2792
+ <OxSidebar>...</OxSidebar>
2793
+ <OxMainContent>...</OxMainContent>
2794
+ </OxAppLayout>
2795
+ </OxSidebarProvider>
2796
+ ```
2797
+
2798
+ **Notes**:
2799
+
2800
+ - Responsive grid layout (single column on mobile, two-column on desktop)
2801
+ - Mobile breakpoint: 640px
2802
+ - Requires `OxSidebarProvider` in component tree
2803
+ - Max width: `max-w-16xl`
2804
+
2805
+ ---
2806
+
2807
+ ## OxMainContent
2808
+
2809
+ Main content area with header and body.
2810
+
2811
+ **Pattern**: Compound Component
2812
+ **Sub-components**: `Header`, `Body`
2813
+
2814
+ ### Props
2815
+
2816
+ ```tsx
2817
+ interface OxMainContentProps extends ComponentPropsWithRef<'main'> {
2818
+ children: ReactNode; // Required
2819
+ className?: string;
2820
+ }
2821
+
2822
+ interface OxMainContentHeaderProps extends ComponentPropsWithRef<'div'> {
2823
+ children: ReactNode; // Required
2824
+ className?: string;
2825
+ }
2826
+
2827
+ interface OxMainContentBodyProps extends ComponentPropsWithRef<'div'> {
2828
+ children: ReactNode; // Required
2829
+ className?: string;
2830
+ }
2831
+ ```
2832
+
2833
+ ### Example
2834
+
2835
+ ```tsx
2836
+ <OxMainContent>
2837
+ <OxMainContent.Header>
2838
+ <h1>Page Title</h1>
2839
+ </OxMainContent.Header>
2840
+ <OxMainContent.Body>Page content here</OxMainContent.Body>
2841
+ </OxMainContent>
2842
+ ```
2843
+
2844
+ ---
2845
+
2846
+ ## OxSidebar
2847
+
2848
+ Comprehensive sidebar navigation system.
2849
+
2850
+ **Pattern**: Complex Compound Component
2851
+ **Main Exports**: `OxSidebar`, `OxSidebarMenu`, `OxSidebarGroup`, `OxSidebarProvider`, `useOxSidebar`
2852
+
2853
+ ### Sidebar Sub-components
2854
+
2855
+ - `OxSidebar.Header` - Top section
2856
+ - `OxSidebar.Content` - Main scrollable area
2857
+ - `OxSidebar.Footer` - Bottom section
2858
+ - `OxSidebar.Separator` - Visual divider
2859
+ - `OxSidebar.Trigger` - Toggle button (mobile)
2860
+
2861
+ ### Menu Sub-components
2862
+
2863
+ - `OxSidebarMenu.Item` - Menu item wrapper
2864
+ - `OxSidebarMenu.Button` - Clickable button/link (polymorphic)
2865
+ - `OxSidebarMenu.Icon` - Icon for menu items
2866
+ - `OxSidebarMenu.Tag` - Tag/counter
2867
+ - `OxSidebarMenu.Action` - Action button
2868
+ - `OxSidebarMenu.Skeleton` - Loading skeleton
2869
+ - `OxSidebarMenu.Sub` - Submenu container
2870
+ - `OxSidebarMenu.SubItem` - Submenu item wrapper
2871
+ - `OxSidebarMenu.SubButton` - Submenu button
2872
+
2873
+ ### Group Sub-components
2874
+
2875
+ - `OxSidebarGroup.Label` - Group heading
2876
+ - `OxSidebarGroup.Action` - Group action button
2877
+ - `OxSidebarGroup.Content` - Group content container
2878
+
2879
+ ### Props
2880
+
2881
+ ```tsx
2882
+ // Provider
2883
+ interface OxSidebarProviderProps {
2884
+ children: ReactNode; // Required
2885
+ }
2886
+
2887
+ // Root Sidebar
2888
+ interface OxSidebarProps extends ComponentPropsWithoutRef<'aside'> {
2889
+ children: ReactNode; // Required
2890
+ className?: string;
2891
+ }
2892
+
2893
+ // Menu Item
2894
+ interface OxSidebarMenuItemProps extends ComponentPropsWithRef<'li'> {
2895
+ children: ReactNode;
2896
+ className?: string;
2897
+ defaultOpen?: boolean; // Initial open state for submenu
2898
+ hasSub?: boolean; // Indicates if item has submenu
2899
+ }
2900
+
2901
+ // Menu Button (Polymorphic - renders as link or button)
2902
+ type OxSidebarMenuButtonProps =
2903
+ | {
2904
+ children: ReactNode;
2905
+ href: string; // Required for link variant
2906
+ disabled?: boolean;
2907
+ className?: string;
2908
+ onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
2909
+ }
2910
+ | {
2911
+ children: ReactNode;
2912
+ href?: never;
2913
+ type?: 'button';
2914
+ disabled?: boolean;
2915
+ className?: string;
2916
+ onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
2917
+ };
2918
+ ```
2919
+
2920
+ ### Hook
2921
+
2922
+ ```tsx
2923
+ const { isMobile, mobileOpen, openSidebar, closeSidebar, toggleSidebar } = useOxSidebar();
2924
+
2925
+ // Returns:
2926
+ // - isMobile: boolean (viewport < 640px)
2927
+ // - mobileOpen: boolean (current mobile open state)
2928
+ // - openSidebar: () => void
2929
+ // - closeSidebar: () => void
2930
+ // - toggleSidebar: () => void
2931
+ ```
2932
+
2933
+ ### Example
2934
+
2935
+ ```tsx
2936
+ <OxSidebarProvider>
2937
+ <OxAppLayout>
2938
+ <OxSidebar>
2939
+ <OxSidebar.Header>
2940
+ <img src="/logo.png" alt="Logo" />
2941
+ </OxSidebar.Header>
2942
+
2943
+ <OxSidebar.Content>
2944
+ <OxSidebarMenu>
2945
+ {/* Simple menu item */}
2946
+ <OxSidebarMenu.Item>
2947
+ <OxSidebarMenu.Button href="/dashboard">
2948
+ <OxSidebarMenu.Icon icon={Home} />
2949
+ Dashboard
2950
+ </OxSidebarMenu.Button>
2951
+ </OxSidebarMenu.Item>
2952
+
2953
+ {/* Menu item with submenu */}
2954
+ <OxSidebarMenu.Item hasSub defaultOpen>
2955
+ <OxSidebarMenu.Button>
2956
+ <OxSidebarMenu.Icon icon={Settings} />
2957
+ Settings
2958
+ <OxSidebarMenu.Tag>3</OxSidebarMenu.Tag>
2959
+ </OxSidebarMenu.Button>
2960
+ <OxSidebarMenu.Sub>
2961
+ <OxSidebarMenu.SubItem>
2962
+ <OxSidebarMenu.SubButton>Profile</OxSidebarMenu.SubButton>
2963
+ </OxSidebarMenu.SubItem>
2964
+ </OxSidebarMenu.Sub>
2965
+ </OxSidebarMenu.Item>
2966
+ </OxSidebarMenu>
2967
+
2968
+ <OxSidebarGroup>
2969
+ <OxSidebarGroup.Label>Projects</OxSidebarGroup.Label>
2970
+ <OxSidebarGroup.Content>{/* Group items */}</OxSidebarGroup.Content>
2971
+ </OxSidebarGroup>
2972
+ </OxSidebar.Content>
2973
+
2974
+ <OxSidebar.Footer>User info</OxSidebar.Footer>
2975
+ </OxSidebar>
2976
+
2977
+ <OxMainContent>...</OxMainContent>
2978
+ </OxAppLayout>
2979
+ </OxSidebarProvider>
2980
+ ```
2981
+
2982
+ **Notes**:
2983
+
2984
+ - Responsive: Drawer on mobile (< 640px), fixed sidebar on desktop
2985
+ - Width: 256px on desktop
2986
+ - Automatically manages submenu state
2987
+ - MenuButton with `hasSub` automatically shows chevron and toggles submenu
2988
+ - Polymorphic MenuButton (renders as `<a>` if href provided, otherwise `<button>`)
2989
+
2990
+ ---
2991
+
2992
+ # Typography Components (5)
2993
+
2994
+ ## OxDescription
2995
+
2996
+ Helper text component.
2997
+
2998
+ **Pattern**: Simple Component
2999
+
3000
+ ### Props
3001
+
3002
+ ```tsx
3003
+ interface OxDescriptionProps extends ComponentPropsWithRef<'div'> {
3004
+ children: ReactNode; // Required
3005
+ disabled?: boolean; // Applies disabled styling
3006
+ }
3007
+ ```
3008
+
3009
+ ### Example
3010
+
3011
+ ```tsx
3012
+ <OxDescription>This field is required for verification.</OxDescription>
3013
+ <OxDescription disabled>This field is disabled.</OxDescription>
3014
+ ```
3015
+
3016
+ ---
3017
+
3018
+ ## OxError
3019
+
3020
+ Error message component.
3021
+
3022
+ **Pattern**: Simple Component
3023
+
3024
+ ### Props
3025
+
3026
+ ```tsx
3027
+ interface OxErrorProps extends ComponentPropsWithRef<'div'> {
3028
+ children?: ReactNode; // Returns null if not provided
3029
+ }
3030
+ ```
3031
+
3032
+ ### Example
3033
+
3034
+ ```tsx
3035
+ <OxError>Email is required</OxError>
3036
+ <OxError>
3037
+ <AlertCircle /> Invalid format
3038
+ </OxError>
3039
+ ```
3040
+
3041
+ **Notes**:
3042
+
3043
+ - Renders with `role="alert"`
3044
+ - Returns `null` if no children
3045
+ - Auto-styles SVG children with proper sizing
3046
+
3047
+ ---
3048
+
3049
+ ## OxHeading
3050
+
3051
+ Heading component with 7 visual levels.
3052
+
3053
+ **Pattern**: Simple Component
3054
+
3055
+ ### Props
3056
+
3057
+ ```tsx
3058
+ interface OxHeadingProps extends HTMLAttributes<HTMLElement> {
3059
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div'; // Element to render (default: 'h2')
3060
+ children: ReactNode; // Required
3061
+ level?: 1 | 2 | 3 | 4 | 5 | 6 | 7; // Visual styling level
3062
+ }
3063
+ ```
3064
+
3065
+ **Level Styles**:
3066
+
3067
+ - 1: `text-2xl font-bold`
3068
+ - 2: `text-xl font-semibold` (default)
3069
+ - 3: `text-lg font-semibold`
3070
+ - 4: `text-base font-semibold`
3071
+ - 5: `text-sm font-semibold`
3072
+ - 6: `text-sm font-medium`
3073
+ - 7: `text-sm`
3074
+
3075
+ ### Example
3076
+
3077
+ ```tsx
3078
+ <OxHeading as="h1" level={1}>Page Title</OxHeading>
3079
+ <OxHeading as="h2">Section Title</OxHeading>
3080
+ <OxHeading as="div" level={3}>Custom Element</OxHeading>
3081
+ ```
3082
+
3083
+ **Notes**:
3084
+
3085
+ - Semantic level derived from `as` prop if `level` not provided
3086
+ - Adds `role="heading"` and `aria-level` when `as="div"`
3087
+ - No ref support
3088
+
3089
+ ---
3090
+
3091
+ ## OxLabel
3092
+
3093
+ Form label component.
3094
+
3095
+ **Pattern**: Simple Component
3096
+
3097
+ ### Props
3098
+
3099
+ ```tsx
3100
+ interface OxLabelProps extends ComponentPropsWithRef<'label'> {
3101
+ children: ReactNode; // Required
3102
+ disabled?: boolean;
3103
+ required?: boolean; // Shows red asterisk (*)
3104
+ }
3105
+ ```
3106
+
3107
+ ### Example
3108
+
3109
+ ```tsx
3110
+ <OxLabel htmlFor="email" required>Email Address</OxLabel>
3111
+ <OxLabel disabled>Disabled Field</OxLabel>
3112
+ ```
3113
+
3114
+ **Notes**:
3115
+
3116
+ - Cursor changes to `pointer` when `htmlFor` provided and not disabled
3117
+ - Required indicator: red asterisk appended when `required={true}`
3118
+
3119
+ ---
3120
+
3121
+ ## OxLegend
3122
+
3123
+ Fieldset legend component.
3124
+
3125
+ **Pattern**: Simple Component
3126
+
3127
+ ### Props
3128
+
3129
+ ```tsx
3130
+ interface OxLegendProps extends ComponentPropsWithRef<'legend'> {
3131
+ children: ReactNode; // Required
3132
+ disabled?: boolean;
3133
+ required?: boolean; // Shows red asterisk (*)
3134
+ }
3135
+ ```
3136
+
3137
+ ### Example
3138
+
3139
+ ```tsx
3140
+ <fieldset>
3141
+ <OxLegend required>Personal Information</OxLegend>
3142
+ ...
3143
+ </fieldset>
3144
+ ```
3145
+
3146
+ **Notes**:
3147
+
3148
+ - Use with `<fieldset>` elements
3149
+ - Similar to Label but larger font size (`text-base` vs `text-sm`)
3150
+
3151
+ ---
3152
+
3153
+ # Contexts (3)
3154
+
3155
+ ## OxAuthContext
3156
+
3157
+ User authentication and authorization.
3158
+
3159
+ **Exports**: `OxAuthProvider`, `useOxAuth`, `OxAuthContext`, `DEFAULT_GET_CURRENT_USER`
3160
+
3161
+ ### Props
3162
+
3163
+ ```tsx
3164
+ interface OxAuthProviderProps {
3165
+ adminRole?: string; // Default: 'ADMIN'
3166
+ children: ReactNode;
3167
+ getCurrentUserQuery?: DocumentNode; // Custom GraphQL query
3168
+ options?: Parameters<typeof useQuery>[1]; // Apollo options
3169
+ pollInterval?: number; // Default: 300000 (5 minutes)
3170
+ }
3171
+
3172
+ type OxUser = {
3173
+ id: string;
3174
+ role: string;
3175
+ email?: string;
3176
+ username?: string;
3177
+ } | null;
3178
+
3179
+ type OxAuthContextType = {
3180
+ error: ErrorLike | null;
3181
+ isAdmin: boolean; // Computed from user.role === adminRole
3182
+ isLoggedIn: boolean; // Computed from !!user
3183
+ loading: boolean;
3184
+ refreshUser: RefetchFunction; // Apollo refetch
3185
+ user: OxUser;
3186
+ };
3187
+ ```
3188
+
3189
+ ### Example
3190
+
3191
+ ```tsx
3192
+ // Wrap app
3193
+ <OxAuthProvider adminRole="ADMIN" pollInterval={300000}>
3194
+ <App />
3195
+ </OxAuthProvider>;
3196
+
3197
+ // Use in component
3198
+ function MyComponent() {
3199
+ const { user, isLoggedIn, isAdmin, loading, refreshUser } = useOxAuth();
3200
+
3201
+ if (loading) return <Spinner />;
3202
+ if (!isLoggedIn) return <Login />;
3203
+
3204
+ return <Dashboard user={user} />;
3205
+ }
3206
+ ```
3207
+
3208
+ **Notes**:
3209
+
3210
+ - Apollo GraphQL integration with auto-polling
3211
+ - Default query fetches: id, username, email, role
3212
+ - Throws error if hook used outside provider
3213
+
3214
+ ---
3215
+
3216
+ ## OxDialogContext
3217
+
3218
+ Modal dialog management.
3219
+
3220
+ **Exports**: `OxDialogProvider`, `useOxDialog`
3221
+
3222
+ ### Props
3223
+
3224
+ ```tsx
3225
+ interface OxDialogProviderProps {
3226
+ children: ReactNode;
3227
+ maxDialogs?: number; // Default: 3
3228
+ }
3229
+
3230
+ interface OxDialogOptions {
3231
+ className?: string;
3232
+ closeOnOutsideClick?: boolean;
3233
+ persistent?: boolean;
3234
+ showCloseButton?: boolean;
3235
+ size?: OxDialogSize;
3236
+ }
3237
+
3238
+ // Callable API
3239
+ interface OxDialogContextApi {
3240
+ // Shorthand
3241
+ (content: ReactNode, options?: OxDialogOptions): string; // Returns dialog ID
3242
+
3243
+ // Methods
3244
+ dismiss: () => void; // Close top dialog
3245
+ dismissAll: () => void; // Close all dialogs
3246
+ open: (content: ReactNode, options?: OxDialogOptions) => string;
3247
+ }
3248
+ ```
3249
+
3250
+ ### Example
3251
+
3252
+ ```tsx
3253
+ // Wrap app
3254
+ <OxDialogProvider maxDialogs={3}>
3255
+ <App />
3256
+ </OxDialogProvider>;
3257
+
3258
+ // Use in component
3259
+ function MyComponent() {
3260
+ const dialog = useOxDialog();
3261
+
3262
+ const showConfirm = () => {
3263
+ dialog(
3264
+ <div>
3265
+ <h2>Confirm Action</h2>
3266
+ <button onClick={dialog.dismiss}>Cancel</button>
3267
+ </div>,
3268
+ { size: 'md', showCloseButton: true }
3269
+ );
3270
+ };
3271
+
3272
+ return <button onClick={showConfirm}>Show Dialog</button>;
3273
+ }
3274
+ ```
3275
+
3276
+ **Notes**:
3277
+
3278
+ - Stack-based management (LIFO)
3279
+ - Auto body scroll lock when dialogs open
3280
+ - Max dialog limit prevents too many concurrent dialogs
3281
+
3282
+ ---
3283
+
3284
+ ## OxFeatureFlagContext
3285
+
3286
+ Feature flag system with dev mode.
3287
+
3288
+ **Exports**: `OxFeatureProvider`, `OxFeatureFlag`, `useOxFeature`, `DEFAULT_GET_FEATURES`
3289
+
3290
+ ### Props
3291
+
3292
+ ```tsx
3293
+ interface OxFeatureProviderProps {
3294
+ children: ReactNode;
3295
+ enableDevMode?: boolean; // Default: false (enables all features)
3296
+ getFeaturesQuery?: DocumentNode; // Custom GraphQL query
3297
+ options?: Parameters<typeof useQuery>[1]; // Apollo options
3298
+ pollInterval?: number; // Default: 300000 (5 minutes)
3299
+ }
3300
+
3301
+ type FeatureFlags = Record<string, boolean>;
3302
+
3303
+ type OxFeatureContextType = {
3304
+ enableDevMode: boolean;
3305
+ error: ErrorLike | null;
3306
+ features: FeatureFlags;
3307
+ isEnabled: (featureName: string) => boolean;
3308
+ loading: boolean;
3309
+ refreshFeatures: RefetchFunction;
3310
+ };
3311
+
3312
+ interface OxFeatureFlagProps {
3313
+ children: ReactNode;
3314
+ className?: string;
3315
+ fallback?: ReactNode; // Rendered when feature disabled
3316
+ name: string; // Required - Feature flag name
3317
+ }
3318
+ ```
3319
+
3320
+ ### Example
3321
+
3322
+ ```tsx
3323
+ // Wrap app
3324
+ <OxFeatureProvider enableDevMode={false}>
3325
+ <App />
3326
+ </OxFeatureProvider>;
3327
+
3328
+ // Use hook
3329
+ function MyComponent() {
3330
+ const { isEnabled, features } = useOxFeature();
3331
+
3332
+ if (isEnabled('new-dashboard')) {
3333
+ return <NewDashboard />;
3334
+ }
3335
+ return <OldDashboard />;
3336
+ }
3337
+
3338
+ // Use component
3339
+ <OxFeatureFlag name="beta-feature" fallback={<ComingSoon />}>
3340
+ <BetaFeature />
3341
+ </OxFeatureFlag>;
3342
+ ```
3343
+
3344
+ **Notes**:
3345
+
3346
+ - Dev mode enables ALL features and skips GraphQL query
3347
+ - Apollo integration with auto-polling
3348
+ - Declarative `OxFeatureFlag` component for conditional rendering
3349
+
3350
+ ---
3351
+
3352
+ # Hooks (13)
3353
+
3354
+ ## useControllableState
3355
+
3356
+ Manages state that can be both controlled and uncontrolled.
3357
+
3358
+ ### Signature
3359
+
3360
+ ```tsx
3361
+ function useControllableState<T>(params: {
3362
+ defaultValue?: T;
3363
+ name?: string; // Default: 'Component'
3364
+ onChange?: (value: T | undefined) => void;
3365
+ value?: T;
3366
+ }): [
3367
+ T | undefined, // Current value
3368
+ (value: T | undefined | ((prev: T | undefined) => T | undefined)) => void, // Setter
3369
+ ];
3370
+ ```
3371
+
3372
+ ### Example
3373
+
3374
+ ```tsx
3375
+ function MyComponent({ value, defaultValue, onChange }) {
3376
+ const [internalValue, setValue] = useControllableState({
3377
+ value,
3378
+ defaultValue,
3379
+ onChange,
3380
+ });
3381
+
3382
+ return <input value={internalValue} onChange={(e) => setValue(e.target.value)} />;
3383
+ }
3384
+ ```
3385
+
3386
+ **Notes**:
3387
+
3388
+ - Provides dev warnings when switching between modes
3389
+ - Uses `Object.is()` for efficient comparison
3390
+ - Follows Radix UI patterns
3391
+
3392
+ ---
3393
+
3394
+ ## useFileUpload
3395
+
3396
+ Handles file uploads with validation and progress.
3397
+
3398
+ ### Signature
3399
+
3400
+ ```tsx
3401
+ function useFileUpload<T extends Record<string, unknown>>(options: {
3402
+ endpoint: string; // Required
3403
+ headers?: Record<string, string>;
3404
+ initialData: T; // Required
3405
+ validationRules?: ValidatorConfig;
3406
+ }): UseFileUploadReturn<T>;
3407
+
3408
+ // Returns UseFormStateReturn<T> + additional:
3409
+ {
3410
+ cancel: () => void;
3411
+ isUploading: boolean;
3412
+ upload: (options?: {
3413
+ onBefore?: () => void;
3414
+ onCancel?: (error: unknown) => void;
3415
+ onError?: (error: unknown) => void;
3416
+ onFinish?: () => void;
3417
+ onSuccess?: (response: AxiosResponse) => void;
3418
+ onUpload?: (progressEvent: AxiosProgressEvent) => void;
3419
+ skipValidation?: boolean;
3420
+ }) => void;
3421
+ }
3422
+ ```
3423
+
3424
+ ### Example
3425
+
3426
+ ```tsx
3427
+ function FileUploadForm() {
3428
+ const { data, setData, upload, isUploading, cancel, errors } = useFileUpload({
3429
+ endpoint: '/api/upload',
3430
+ initialData: { file: null, description: '' },
3431
+ validationRules: {
3432
+ file: ['required', 'file', 'fileSize:5MB'],
3433
+ description: ['required', 'minLength:10'],
3434
+ },
3435
+ });
3436
+
3437
+ return (
3438
+ <form
3439
+ onSubmit={(e) => {
3440
+ e.preventDefault();
3441
+ upload();
3442
+ }}
3443
+ >
3444
+ <input type="file" onChange={(e) => setData('file', e.target.files[0])} />
3445
+ <input value={data.description} onChange={(e) => setData('description', e.target.value)} />
3446
+ <button type="submit" disabled={isUploading}>
3447
+ Upload
3448
+ </button>
3449
+ {isUploading && <button onClick={cancel}>Cancel</button>}
3450
+ </form>
3451
+ );
3452
+ }
3453
+ ```
3454
+
3455
+ **Notes**:
3456
+
3457
+ - Axios `multipart/form-data` uploads
3458
+ - Upload progress tracking
3459
+ - Cancellation via `AbortController`
3460
+ - Pre-upload validation
3461
+
3462
+ ---
3463
+
3464
+ ## useFilterFetch
3465
+
3466
+ Manages filter state with REST API fetch requests.
3467
+
3468
+ ### Signature
3469
+
3470
+ ```tsx
3471
+ function useFilterFetch<T extends Record<string, any>, TResponse = unknown>(options: {
3472
+ headers?: Record<string, string>;
3473
+ initialData: T; // Required - initial filter values
3474
+ method?: 'GET' | 'POST'; // Default: 'GET'
3475
+ url: string; // Required - API endpoint
3476
+ validationRules?: ValidatorConfig;
3477
+ }): UseFilterFetchReturn<T, TResponse>;
3478
+
3479
+ interface UseFilterFetchReturn<T, TResponse> {
3480
+ data: TResponse | undefined; // Response data
3481
+ error: unknown;
3482
+ errors: Record<keyof T, string[]>; // Validation errors per field
3483
+ filter: T; // Current filter values
3484
+ isDirty: boolean;
3485
+ isLoading: boolean;
3486
+ isValid: boolean;
3487
+ query: (options?: FilterFetchQueryOptions<TResponse>) => void;
3488
+ refetch: () => void; // Re-run with current filters
3489
+ reset: () => void;
3490
+ setFilter: (key: keyof T, value: T[keyof T]) => void;
3491
+ validate: () => boolean;
3492
+ }
3493
+
3494
+ interface FilterFetchQueryOptions<TResponse> {
3495
+ onBefore?: () => void;
3496
+ onError?: (error: unknown) => void;
3497
+ onFinish?: () => void;
3498
+ onSuccess?: (response: TResponse) => void;
3499
+ skipValidation?: boolean;
3500
+ }
3501
+ ```
3502
+
3503
+ ### Example
3504
+
3505
+ ```tsx
3506
+ function ProductList() {
3507
+ const { data, filter, setFilter, query, isLoading } = useFilterFetch<
3508
+ { category: string; search: string },
3509
+ Product[]
3510
+ >({
3511
+ url: '/api/products',
3512
+ initialData: { category: '', search: '' },
3513
+ });
3514
+
3515
+ return (
3516
+ <div>
3517
+ <input
3518
+ value={filter.search}
3519
+ onChange={(e) => setFilter('search', e.target.value)}
3520
+ onKeyDown={(e) => e.key === 'Enter' && query()}
3521
+ />
3522
+ <select
3523
+ value={filter.category}
3524
+ onChange={(e) => {
3525
+ setFilter('category', e.target.value);
3526
+ query();
3527
+ }}
3528
+ >
3529
+ <option value="">All</option>
3530
+ <option value="electronics">Electronics</option>
3531
+ </select>
3532
+ {isLoading ? <Spinner /> : data?.map(product => <ProductCard key={product.id} {...product} />)}
3533
+ </div>
3534
+ );
3535
+ }
3536
+ ```
3537
+
3538
+ **Notes**:
3539
+
3540
+ - Similar to `useFilterQuery` but for REST APIs instead of GraphQL
3541
+ - Supports GET (query params) and POST (body) methods
3542
+ - Built on `useFormState` for validation and state management
3543
+
3544
+ ---
3545
+
3546
+ ## useFilterQuery
3547
+
3548
+ Manages filter state with GraphQL queries.
3549
+
3550
+ ### Signature
3551
+
3552
+ ```tsx
3553
+ function useFilterQuery<T extends Record<string, any>, TResponse = unknown>(options: {
3554
+ query: DocumentNode; // Required
3555
+ headers?: Record<string, string>;
3556
+ initialData: T; // Required
3557
+ validationRules?: ValidatorConfig;
3558
+ options?: Parameters<typeof useLazyQuery<TResponse>>[1];
3559
+ }): UseFilterQueryReturn<T, TResponse>;
3560
+
3561
+ // Returns:
3562
+ {
3563
+ data: TResponse | undefined; // Query response
3564
+ error: unknown;
3565
+ filter: T; // Filter values
3566
+ setFilter: (data: Partial<T>) => void | ((path: string, value: any) => void);
3567
+ isLoading: boolean;
3568
+ query: (options?: QueryOptions<TResponse>) => void;
3569
+ refetch: () => void;
3570
+ // + UseFormState methods (errors, validate, etc.)
3571
+ }
3572
+ ```
3573
+
3574
+ ### Example
3575
+
3576
+ ```tsx
3577
+ const GET_USERS = gql`
3578
+ query GetUsers($filters: UserFilters) {
3579
+ users(filters: $filters) {
3580
+ id
3581
+ name
3582
+ }
3583
+ }
3584
+ `;
3585
+
3586
+ function UserFilter() {
3587
+ const { filter, setFilter, query, data, isLoading } = useFilterQuery({
3588
+ query: GET_USERS,
3589
+ initialData: { name: '', role: '' },
3590
+ });
3591
+
3592
+ return (
3593
+ <div>
3594
+ <input value={filter.name} onChange={(e) => setFilter('name', e.target.value)} />
3595
+ <button onClick={() => query()}>Search</button>
3596
+ {isLoading && <Spinner />}
3597
+ {data?.users.map((user) => (
3598
+ <div key={user.id}>{user.name}</div>
3599
+ ))}
3600
+ </div>
3601
+ );
3602
+ }
3603
+ ```
3604
+
3605
+ **Notes**:
3606
+
3607
+ - Apollo `useLazyQuery` integration
3608
+ - Default fetch policy: `network-only`
3609
+ - Passes filters as `{ filters: data }` to query
3610
+
3611
+ ---
3612
+
3613
+ ## useFocus
3614
+
3615
+ Manages focus within a container.
3616
+
3617
+ ### Signature
3618
+
3619
+ ```tsx
3620
+ function useFocus(params: {
3621
+ containerRef: RefObject<HTMLElement | null>; // Required
3622
+ options?: {
3623
+ autoFocus?: boolean; // Default: false
3624
+ enabled?: boolean; // Default: true
3625
+ restoreFocus?: boolean; // Default: false
3626
+ trapFocus?: boolean; // Default: false
3627
+ };
3628
+ }): {
3629
+ focusFirst: () => void;
3630
+ focusLast: () => void;
3631
+ getCurrentFocus: () => HTMLElement | null;
3632
+ getFocusableElements: () => HTMLElement[];
3633
+ };
3634
+ ```
3635
+
3636
+ ### Example
3637
+
3638
+ ```tsx
3639
+ function Modal() {
3640
+ const containerRef = useRef(null);
3641
+ const { focusFirst } = useFocus({
3642
+ containerRef,
3643
+ options: { autoFocus: true, trapFocus: true, restoreFocus: true },
3644
+ });
3645
+
3646
+ return (
3647
+ <div ref={containerRef}>
3648
+ <button>First</button>
3649
+ <button>Second</button>
3650
+ <button>Last</button>
3651
+ </div>
3652
+ );
3653
+ }
3654
+ ```
3655
+
3656
+ **Notes**:
3657
+
3658
+ - Auto-focus on mount
3659
+ - Circular Tab navigation with `trapFocus`
3660
+ - Focus restoration on unmount
3661
+ - Shift+Tab support
3662
+
3663
+ ---
3664
+
3665
+ ## useForm
3666
+
3667
+ Form state with GraphQL mutations.
3668
+
3669
+ ### Signature
3670
+
3671
+ ```tsx
3672
+ function useForm<T extends Record<string, any>, TResponse = unknown>(options: {
3673
+ operation: DocumentNode; // Required - GraphQL mutation
3674
+ headers?: Record<string, string>;
3675
+ initialData: T; // Required
3676
+ validationRules?: ValidatorConfig;
3677
+ options?: Parameters<typeof useMutation<TResponse>>[1];
3678
+ }): UseFormReturn<T, TResponse>;
3679
+
3680
+ // Returns UseFormStateReturn<T> + additional:
3681
+ {
3682
+ isLoading: boolean;
3683
+ submit: (options?: {
3684
+ onBefore?: () => void;
3685
+ onError?: (error: unknown) => void;
3686
+ onFinish?: () => void;
3687
+ onSuccess?: (response: any) => void;
3688
+ skipValidation?: boolean;
3689
+ }) => void;
3690
+ transform: (fn: (data: T) => unknown) => Omit<UseFormReturn<T, TResponse>, 'transform'>;
3691
+ }
3692
+ ```
3693
+
3694
+ ### Example
3695
+
3696
+ ```tsx
3697
+ const CREATE_USER = gql`
3698
+ mutation CreateUser($input: UserInput!) {
3699
+ createUser(input: $input) {
3700
+ id
3701
+ name
3702
+ }
3703
+ }
3704
+ `;
3705
+
3706
+ function UserForm() {
3707
+ const { data, setData, submit, isLoading, errors } = useForm({
3708
+ operation: CREATE_USER,
3709
+ initialData: { name: '', email: '' },
3710
+ validationRules: {
3711
+ name: ['required', 'minLength:2'],
3712
+ email: ['required', 'email'],
3713
+ },
3714
+ });
3715
+
3716
+ return (
3717
+ <form
3718
+ onSubmit={(e) => {
3719
+ e.preventDefault();
3720
+ submit();
3721
+ }}
3722
+ >
3723
+ <input value={data.name} onChange={(e) => setData('name', e.target.value)} />
3724
+ {errors.name && <OxError>{errors.name}</OxError>}
3725
+ <button type="submit" disabled={isLoading}>
3726
+ Submit
3727
+ </button>
3728
+ </form>
3729
+ );
3730
+ }
3731
+ ```
3732
+
3733
+ **Notes**:
3734
+
3735
+ - Apollo `useMutation` integration
3736
+ - Passes data as `{ input: data }`
3737
+ - `transform()` for pre-submission data transformation
3738
+ - Pre-submission validation
3739
+
3740
+ ---
3741
+
3742
+ ## useFormFetch
3743
+
3744
+ Form state management with REST API submission via fetch.
3745
+
3746
+ ### Signature
3747
+
3748
+ ```tsx
3749
+ function useFormFetch<T extends Record<string, any>, TResponse = unknown>(options: {
3750
+ headers?: Record<string, string>;
3751
+ initialData: T; // Required
3752
+ method?: 'DELETE' | 'PATCH' | 'POST' | 'PUT'; // Default: 'POST'
3753
+ url: string; // Required - API endpoint
3754
+ validationRules?: ValidatorConfig;
3755
+ }): UseFormFetchReturn<T, TResponse>;
3756
+
3757
+ interface UseFormFetchReturn<T, TResponse> extends UseFormStateReturn<T> {
3758
+ isLoading: boolean;
3759
+ submit: (options?: FormFetchSubmitOptions<TResponse>) => void;
3760
+ transform: (fn: (data: T) => unknown) => Omit<UseFormFetchReturn<T, TResponse>, 'transform'>;
3761
+ }
3762
+
3763
+ interface FormFetchSubmitOptions<TResponse> {
3764
+ onBefore?: () => void;
3765
+ onError?: (error: unknown) => void;
3766
+ onFinish?: () => void;
3767
+ onSuccess?: (response: TResponse) => void;
3768
+ skipValidation?: boolean;
3769
+ }
3770
+ ```
3771
+
3772
+ ### Example
3773
+
3774
+ ```tsx
3775
+ function CreateUserForm() {
3776
+ const { data, setData, submit, errors, isLoading } = useFormFetch<
3777
+ { email: string; name: string },
3778
+ { id: string }
3779
+ >({
3780
+ url: '/api/users',
3781
+ method: 'POST',
3782
+ initialData: { email: '', name: '' },
3783
+ validationRules: {
3784
+ email: ['required', 'email'],
3785
+ name: ['required', 'minLength:2'],
3786
+ },
3787
+ });
3788
+
3789
+ return (
3790
+ <form onSubmit={(e) => { e.preventDefault(); submit({ onSuccess: (res) => navigate(`/users/${res.id}`) }); }}>
3791
+ <input value={data.name} onChange={(e) => setData('name', e.target.value)} />
3792
+ {errors.name && <span>{errors.name[0]}</span>}
3793
+ <input value={data.email} onChange={(e) => setData('email', e.target.value)} />
3794
+ {errors.email && <span>{errors.email[0]}</span>}
3795
+ <button type="submit" disabled={isLoading}>Create</button>
3796
+ </form>
3797
+ );
3798
+ }
3799
+
3800
+ // With data transformation
3801
+ const { submit, transform } = useFormFetch({ ... });
3802
+ transform((data) => ({ ...data, timestamp: Date.now() })).submit();
3803
+ ```
3804
+
3805
+ **Notes**:
3806
+
3807
+ - Similar to `useForm` but for REST APIs instead of GraphQL
3808
+ - Supports all HTTP methods (POST, PUT, PATCH, DELETE)
3809
+ - `transform()` allows modifying data before submission
3810
+ - Prevents duplicate submissions while loading
3811
+
3812
+ ---
3813
+
3814
+ ## useFormState
3815
+
3816
+ Core form state management with Zod validation.
3817
+
3818
+ ### Signature
3819
+
3820
+ ```tsx
3821
+ function useFormState<T extends Record<string, unknown>>(options: {
3822
+ initialData: T; // Required (cannot contain 'root' key)
3823
+ validationRules?: ValidatorConfig;
3824
+ }): {
3825
+ data: T;
3826
+ setData: {
3827
+ (data: Partial<T>): void; // Set multiple fields
3828
+ (path: string, value: any): void; // Set single field by path
3829
+ };
3830
+ errors: Record<string, string | string[]>;
3831
+ hasErrors: boolean;
3832
+ isDirty: boolean;
3833
+ clearError: (field: string) => void;
3834
+ clearErrors: () => void;
3835
+ setError: (field: string, error: string | string[]) => void;
3836
+ hasError: (field: string) => boolean;
3837
+ reset: () => void;
3838
+ validate: () => boolean;
3839
+ };
3840
+ ```
3841
+
3842
+ ### Built-in Validation Rules
3843
+
3844
+ **Simple Rules**:
3845
+
3846
+ - `'nullable'`, `'required'`, `'string'`, `'email'`, `'url'`, `'number'`, `'integer'`, `'positive'`, `'negative'`, `'ipv4'`, `'boolean'`, `'date'`, `'array'`, `'object'`, `'file'`
3847
+
3848
+ **Parametrized Rules**:
3849
+
3850
+ - `'min:${number}'`, `'max:${number}'`, `'minLength:${number}'`, `'maxLength:${number}'`, `'pattern:${string}'`, `'fileSize:${string}'` (e.g., '5MB'), `'fileType:${string}'` (e.g., 'image/\*'), `'arrayMinLength:${number}'`, `'arrayMaxLength:${number}'`
3851
+
3852
+ **Array Rules**:
3853
+
3854
+ - `'arrayEach:string'`, `'arrayEach:number'`, `'arrayEach:email'`, `'arrayEach:url'`, `'arrayEach:file'`, `'arrayEach:fileSize:${string}'`, `'arrayEach:fileType:${string}'`
3855
+
3856
+ **Custom Validators**:
3857
+
3858
+ ```tsx
3859
+ import { validator } from '@/hooks';
3860
+
3861
+ const customRule = validator((value) => value !== 'forbidden', 'This value is not allowed');
3862
+ ```
3863
+
3864
+ ### Example
3865
+
3866
+ ```tsx
3867
+ function ContactForm() {
3868
+ const { data, setData, errors, validate, isDirty } = useFormState({
3869
+ initialData: { name: '', email: '', age: 0 },
3870
+ validationRules: {
3871
+ name: ['required', 'minLength:2'],
3872
+ email: ['required', 'email'],
3873
+ age: ['required', 'number', 'min:18'],
3874
+ },
3875
+ });
3876
+
3877
+ const handleSubmit = () => {
3878
+ if (validate()) {
3879
+ console.log('Valid data:', data);
3880
+ }
3881
+ };
3882
+
3883
+ return (
3884
+ <form>
3885
+ <input value={data.name} onChange={(e) => setData('name', e.target.value)} />
3886
+ {errors.name && <span>{errors.name}</span>}
3887
+ <button onClick={handleSubmit}>Submit</button>
3888
+ </form>
3889
+ );
3890
+ }
3891
+ ```
3892
+
3893
+ **Notes**:
3894
+
3895
+ - Zod v4 validation
3896
+ - Nested path support (dot notation)
3897
+ - File size: B, KB, MB, GB, TB
3898
+ - File type wildcards: `image/*`
3899
+
3900
+ ---
3901
+
3902
+ ## useKeyboard
3903
+
3904
+ Keyboard event handling.
3905
+
3906
+ ### Signature
3907
+
3908
+ ```tsx
3909
+ function useKeyboard(options: {
3910
+ allowRepeat?: boolean; // Default: false
3911
+ enabled?: boolean; // Default: true
3912
+ onArrowDown?: () => void;
3913
+ onArrowUp?: () => void;
3914
+ onEnter?: () => void;
3915
+ onEscape?: () => void;
3916
+ onTab?: () => void;
3917
+ }): void;
3918
+ ```
3919
+
3920
+ ### Example
3921
+
3922
+ ```tsx
3923
+ function SearchBox() {
3924
+ const [results, setResults] = useState([]);
3925
+ const [selectedIndex, setSelectedIndex] = useState(0);
3926
+
3927
+ useKeyboard({
3928
+ onArrowDown: () => setSelectedIndex((i) => Math.min(i + 1, results.length - 1)),
3929
+ onArrowUp: () => setSelectedIndex((i) => Math.max(i - 1, 0)),
3930
+ onEnter: () => selectResult(results[selectedIndex]),
3931
+ onEscape: () => closeResults(),
3932
+ });
3933
+
3934
+ return <div>...</div>;
3935
+ }
3936
+ ```
3937
+
3938
+ **Notes**:
3939
+
3940
+ - Document-level listeners
3941
+ - Prevents default for all keys except Tab
3942
+ - Key repeat control
3943
+
3944
+ ---
3945
+
3946
+ ## useOverflowDetection
3947
+
3948
+ Detects overflow and hides overflowing elements.
3949
+
3950
+ ### Signature
3951
+
3952
+ ```tsx
3953
+ function useOverflowDetection(options?: {
3954
+ selector?: string; // Default: '[data-ox-state="selected"]'
3955
+ }): {
3956
+ overflowAmount: number; // Number of hidden items
3957
+ checkOverflow: () => void;
3958
+ handleResize: (node: HTMLDivElement | null) => () => void; // Ref callback with cleanup
3959
+ };
3960
+ ```
3961
+
3962
+ ### Example
3963
+
3964
+ ```tsx
3965
+ function TagList({ tags }) {
3966
+ const { overflowAmount, handleResize } = useOverflowDetection();
3967
+
3968
+ return (
3969
+ <div ref={handleResize}>
3970
+ {tags.map((tag) => (
3971
+ <span key={tag} data-ox-state="selected">
3972
+ {tag}
3973
+ </span>
3974
+ ))}
3975
+ {overflowAmount > 0 && <span>+{overflowAmount} more</span>}
3976
+ </div>
3977
+ );
3978
+ }
3979
+ ```
3980
+
3981
+ **Notes**:
3982
+
3983
+ - ResizeObserver integration
3984
+ - Automatically hides overflow from end
3985
+ - Returns hidden element count
3986
+
3987
+ ---
3988
+
3989
+ ## useScrollSpy
3990
+
3991
+ Tracks active section based on scroll position using IntersectionObserver.
3992
+
3993
+ ### Signature
3994
+
3995
+ ```tsx
3996
+ function useScrollSpy(
3997
+ sectionIds: string[], // Array of element IDs to observe
3998
+ options?: UseScrollSpyOptions
3999
+ ): UseScrollSpyReturn;
4000
+
4001
+ interface UseScrollSpyOptions {
4002
+ root?: Element | null; // Scroll container (default: viewport)
4003
+ rootMargin?: string; // Margin around root (default: '0px')
4004
+ threshold?: number | number[]; // Visibility threshold (default: 0)
4005
+ }
4006
+
4007
+ interface UseScrollSpyReturn {
4008
+ activeId: string; // Currently visible section ID
4009
+ setActiveId: (id: string) => void; // Manually set active section
4010
+ }
4011
+ ```
4012
+
4013
+ ### Example
4014
+
4015
+ ```tsx
4016
+ function TableOfContents() {
4017
+ const sectionIds = ['intro', 'features', 'installation', 'api'];
4018
+ const { activeId } = useScrollSpy(sectionIds, { rootMargin: '-100px 0px -50% 0px' });
4019
+
4020
+ return (
4021
+ <nav>
4022
+ {sectionIds.map(id => (
4023
+ <a
4024
+ key={id}
4025
+ href={`#${id}`}
4026
+ className={activeId === id ? 'active' : ''}
4027
+ >
4028
+ {id}
4029
+ </a>
4030
+ ))}
4031
+ </nav>
4032
+ );
4033
+ }
4034
+ ```
4035
+
4036
+ **Notes**:
4037
+
4038
+ - Uses IntersectionObserver for efficient scroll tracking
4039
+ - Automatically updates as user scrolls through sections
4040
+ - Commonly used with `OxPageOutline` component
4041
+
4042
+ ---
4043
+
4044
+ ## useSize
4045
+
4046
+ Tracks element dimensions using ResizeObserver.
4047
+
4048
+ ### Signature
4049
+
4050
+ ```tsx
4051
+ function useSize(element: Element | null): Size | undefined;
4052
+
4053
+ interface Size {
4054
+ height: number;
4055
+ width: number;
4056
+ }
4057
+ ```
4058
+
4059
+ ### Example
4060
+
4061
+ ```tsx
4062
+ function ResponsiveComponent() {
4063
+ const [ref, setRef] = useState<HTMLDivElement | null>(null);
4064
+ const size = useSize(ref);
4065
+
4066
+ return (
4067
+ <div ref={setRef}>
4068
+ {size && (
4069
+ <p>Width: {size.width}px, Height: {size.height}px</p>
4070
+ )}
4071
+ {size && size.width < 400 ? <CompactView /> : <FullView />}
4072
+ </div>
4073
+ );
4074
+ }
4075
+ ```
4076
+
4077
+ **Notes**:
4078
+
4079
+ - Returns `undefined` when element is null
4080
+ - Updates automatically on resize
4081
+ - Values are rounded to nearest integer
4082
+
4083
+ ---
4084
+
4085
+ ## useTheme
4086
+
4087
+ Theme management with localStorage persistence.
4088
+
4089
+ **Export alias**: `useOxTheme`
4090
+
4091
+ ### Signature
4092
+
4093
+ ```tsx
4094
+ function useTheme(options?: UseThemeOptions): UseThemeReturn;
4095
+
4096
+ type Theme = 'light' | 'dark';
4097
+
4098
+ interface UseThemeOptions {
4099
+ defaultTheme?: Theme; // Default: 'light'
4100
+ storageKey?: string; // localStorage key (default: 'ox-theme')
4101
+ }
4102
+
4103
+ interface UseThemeReturn {
4104
+ setTheme: (theme: Theme) => void;
4105
+ theme: Theme;
4106
+ toggleTheme: () => void;
4107
+ }
4108
+ ```
4109
+
4110
+ ### Example
4111
+
4112
+ ```tsx
4113
+ function ThemeToggle() {
4114
+ const { theme, toggleTheme } = useTheme();
4115
+
4116
+ return (
4117
+ <button onClick={toggleTheme}>
4118
+ {theme === 'light' ? '🌙' : '☀️'}
4119
+ </button>
4120
+ );
4121
+ }
4122
+
4123
+ // With custom storage key
4124
+ const { theme, setTheme } = useTheme({
4125
+ defaultTheme: 'dark',
4126
+ storageKey: 'my-app-theme',
4127
+ });
4128
+ ```
4129
+
4130
+ **Notes**:
4131
+
4132
+ - Persists theme preference to localStorage
4133
+ - Syncs across browser tabs
4134
+ - Respects system preference as initial default
4135
+
4136
+ ---
4137
+
4138
+ # Route Guards (3)
4139
+
4140
+ ## OxGuestRoute
4141
+
4142
+ Protects routes for unauthenticated users only (e.g., login, signup).
4143
+
4144
+ ### Props
4145
+
4146
+ ```tsx
4147
+ interface OxGuestRouteProps {
4148
+ children: ReactNode; // Required - Shown when NOT authenticated
4149
+ onAuthenticated?: ReactNode; // Fallback when authenticated
4150
+ onLoading?: ReactNode; // Fallback during auth check
4151
+ }
4152
+ ```
4153
+
4154
+ ### Example
4155
+
4156
+ ```tsx
4157
+ <OxGuestRoute onLoading={<Spinner />} onAuthenticated={<Navigate to="/dashboard" />}>
4158
+ <LoginPage />
4159
+ </OxGuestRoute>
4160
+ ```
4161
+
4162
+ ---
4163
+
4164
+ ## OxProtectedRoute
4165
+
4166
+ Protects routes requiring authentication.
4167
+
4168
+ ### Props
4169
+
4170
+ ```tsx
4171
+ interface OxProtectedRouteProps {
4172
+ children: ReactNode; // Required - Shown when authenticated
4173
+ onLoading?: ReactNode; // Fallback during auth check
4174
+ onUnauthenticated?: ReactNode; // Fallback when NOT authenticated
4175
+ }
4176
+ ```
4177
+
4178
+ ### Example
4179
+
4180
+ ```tsx
4181
+ <OxProtectedRoute onLoading={<Spinner />} onUnauthenticated={<Navigate to="/login" />}>
4182
+ <Dashboard />
4183
+ </OxProtectedRoute>
4184
+ ```
4185
+
4186
+ ---
4187
+
4188
+ ## OxRoleRoute
4189
+
4190
+ Protects routes requiring specific user roles.
4191
+
4192
+ ### Props
4193
+
4194
+ ```tsx
4195
+ interface OxRoleRouteProps {
4196
+ children: ReactNode; // Required - Shown when user has role
4197
+ onLoading?: ReactNode; // Fallback during auth check
4198
+ onUnauthorized?: ReactNode; // Fallback when unauthorized or not authenticated
4199
+ roles?: string[]; // Default: ['admin'] - Allowed roles (OR logic)
4200
+ }
4201
+ ```
4202
+
4203
+ ### Example
4204
+
4205
+ ```tsx
4206
+ {
4207
+ /* Admin only */
4208
+ }
4209
+ <OxRoleRoute>
4210
+ <AdminPanel />
4211
+ </OxRoleRoute>;
4212
+
4213
+ {
4214
+ /* Admin or moderator */
4215
+ }
4216
+ <OxRoleRoute roles={['admin', 'moderator']} onUnauthorized={<AccessDenied />}>
4217
+ <ModerationTools />
4218
+ </OxRoleRoute>;
4219
+ ```
4220
+
4221
+ **Notes**:
4222
+
4223
+ - User must have at least ONE of the specified roles
4224
+ - Empty roles array always shows `onUnauthorized`
4225
+ - Default role: `'admin'`
4226
+
4227
+ ---
4228
+
4229
+ # Utilities (9)
4230
+
4231
+ ## Builder
4232
+
4233
+ URL and mailto link construction.
4234
+
4235
+ ### Functions
4236
+
4237
+ ```tsx
4238
+ // Build URL with query params
4239
+ function buildUrl(
4240
+ path: string,
4241
+ params?: Record<string, string | number | boolean | null | undefined>,
4242
+ options?: {
4243
+ baseUrl?: string;
4244
+ fragment?: string; // Auto-prefixes with # if needed
4245
+ }
4246
+ ): string;
4247
+
4248
+ // Build mailto link
4249
+ function buildMailTo(
4250
+ email: string | string[],
4251
+ options?: {
4252
+ bcc?: string | string[];
4253
+ body?: string;
4254
+ cc?: string | string[];
4255
+ subject?: string;
4256
+ }
4257
+ ): string;
4258
+ ```
4259
+
4260
+ ### Example
4261
+
4262
+ ```tsx
4263
+ buildUrl(
4264
+ '/api/users',
4265
+ { id: 123, active: true },
4266
+ {
4267
+ baseUrl: 'https://api.example.com',
4268
+ fragment: 'section-1',
4269
+ }
4270
+ );
4271
+ // "https://api.example.com/api/users?id=123&active=true#section-1"
4272
+
4273
+ buildMailTo(['john@example.com', 'jane@example.com'], {
4274
+ subject: 'Meeting Request',
4275
+ cc: 'manager@example.com',
4276
+ });
4277
+ // "mailto:john@example.com,jane@example.com?cc=manager@example.com&subject=Meeting+Request"
4278
+ ```
4279
+
4280
+ ---
4281
+
4282
+ ## cn
4283
+
4284
+ Tailwind CSS class name merging.
4285
+
4286
+ ### Function
4287
+
4288
+ ```tsx
4289
+ function cn(...inputs: ClassValue[]): string;
4290
+ ```
4291
+
4292
+ ### Example
4293
+
4294
+ ```tsx
4295
+ cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive });
4296
+ // "px-4 py-2 bg-blue-500 text-white" (if isActive)
4297
+
4298
+ cn('px-2', 'px-4');
4299
+ // "px-4" (tailwind-merge resolves conflicts)
4300
+ ```
4301
+
4302
+ ---
4303
+
4304
+ ## copyToClipboard
4305
+
4306
+ Cross-browser clipboard copying.
4307
+
4308
+ ### Function
4309
+
4310
+ ```tsx
4311
+ async function copyToClipboard(text: string): Promise<boolean>;
4312
+ ```
4313
+
4314
+ ### Example
4315
+
4316
+ ```tsx
4317
+ const success = await copyToClipboard('Hello, World!');
4318
+ if (success) {
4319
+ console.log('Copied!');
4320
+ }
4321
+ ```
4322
+
4323
+ **Notes**:
4324
+
4325
+ - Modern Clipboard API with fallback
4326
+ - Never throws errors (returns false)
4327
+ - Requires HTTPS for modern API
4328
+
4329
+ ---
4330
+
4331
+ ## createId
4332
+
4333
+ Unique ID generation.
4334
+
4335
+ ### Functions
4336
+
4337
+ ```tsx
4338
+ // Overloaded function
4339
+ function createId(): string;
4340
+ function createId(prefix: string): string;
4341
+ function createId(prefix: string, options: { length?: number; separator?: string }): string;
4342
+ function createId(options: { length?: number; separator?: string }): string;
4343
+
4344
+ function generateRandomString(length: number): string;
4345
+ ```
4346
+
4347
+ ### Example
4348
+
4349
+ ```tsx
4350
+ createId();
4351
+ // "ox_lz8k3xa1abc123de"
4352
+
4353
+ createId('user');
4354
+ // "user_lz8k3xb2xyz456gh"
4355
+
4356
+ createId('order', { length: 12, separator: '-' });
4357
+ // "order-lz8k3xc3abcdefgh1234"
4358
+
4359
+ generateRandomString(8);
4360
+ // "x7k2m9p4"
4361
+ ```
4362
+
4363
+ **Notes**:
4364
+
4365
+ - Format: `{prefix}{separator}{timestamp}{counter}{randomString}`
4366
+ - Default prefix: `'ox'`, separator: `'_'`, length: `8`
4367
+ - Uses crypto.getRandomValues when available
4368
+
4369
+ ---
4370
+
4371
+ ## errorHelper
4372
+
4373
+ GraphQL and form error handling.
4374
+
4375
+ ### Functions
4376
+
4377
+ ```tsx
4378
+ function parseGraphQLErrors(errors: OxGraphQLError[]): OxParsedError[];
4379
+
4380
+ function handleFormErrors(errors: OxParsedError[], formState: OxFormState): void;
4381
+
4382
+ function handleGraphQLFormErrors(errors: OxGraphQLError[], formState: OxFormState): void;
4383
+ ```
4384
+
4385
+ ### Example
4386
+
4387
+ ```tsx
4388
+ const graphqlErrors = [
4389
+ {
4390
+ message: 'Invalid email',
4391
+ extensions: { code: 'VALIDATION_ERROR', field: 'email' },
4392
+ },
4393
+ ];
4394
+
4395
+ const parsed = parseGraphQLErrors(graphqlErrors);
4396
+ // [{ message: 'Invalid email', code: 'VALIDATION_ERROR', field: 'email' }]
4397
+
4398
+ handleFormErrors(parsed, formState);
4399
+ // Calls formState.setError('email', 'Invalid email')
4400
+
4401
+ // Or combined:
4402
+ handleGraphQLFormErrors(graphqlErrors, formState);
4403
+ ```
4404
+
4405
+ ---
4406
+
4407
+ ## formatter
4408
+
4409
+ Data formatting utilities.
4410
+
4411
+ ### Functions
4412
+
4413
+ ```tsx
4414
+ // Bytes to human-readable
4415
+ function formatBytes(
4416
+ bytes: number,
4417
+ options?: {
4418
+ binary?: boolean; // Use 1024 base (default: false)
4419
+ decimals?: number; // Default: 1
4420
+ locale?: string; // Default: 'en-US'
4421
+ }
4422
+ ): string;
4423
+
4424
+ // Currency formatting
4425
+ function formatCurrency(
4426
+ amount: number,
4427
+ options?: {
4428
+ currency?: string; // Default: 'USD'
4429
+ locale?: string; // Default: 'en-US'
4430
+ }
4431
+ ): string;
4432
+
4433
+ // Date formatting
4434
+ function formatDate(
4435
+ date: Date | string | number,
4436
+ options?: {
4437
+ format?: 'short' | 'medium' | 'long' | 'full'; // Default: 'medium'
4438
+ locale?: string; // Default: 'en-US'
4439
+ }
4440
+ ): string;
4441
+
4442
+ // Number formatting
4443
+ function formatNumber(
4444
+ number: number,
4445
+ options?: {
4446
+ compact?: boolean; // Compact notation (e.g., 1.2K)
4447
+ decimals?: number; // Default: 2
4448
+ locale?: string; // Default: 'en-US'
4449
+ }
4450
+ ): string;
4451
+
4452
+ // Relative time
4453
+ function formatTimestamp(date: Date): string;
4454
+ ```
4455
+
4456
+ ### Example
4457
+
4458
+ ```tsx
4459
+ formatBytes(1234567);
4460
+ // "1.2 MB"
4461
+
4462
+ formatCurrency(1234.56, { currency: 'EUR', locale: 'de-DE' });
4463
+ // "1.234,56 €"
4464
+
4465
+ formatDate(new Date('2024-01-15'), { format: 'long' });
4466
+ // "January 15, 2024"
4467
+
4468
+ formatNumber(1234567, { compact: true });
4469
+ // "1.23M"
4470
+
4471
+ formatTimestamp(new Date(Date.now() - 5 * 60 * 1000));
4472
+ // "5m ago"
4473
+ ```
4474
+
4475
+ ---
4476
+
4477
+ ## hasDataSlot
4478
+
4479
+ React slot validation type guard.
4480
+
4481
+ ### Function
4482
+
4483
+ ```tsx
4484
+ function hasDataSlot(
4485
+ element: React.ReactNode,
4486
+ slot: string
4487
+ ): element is React.ReactElement<{ 'data-ox-slot': string }>;
4488
+ ```
4489
+
4490
+ ### Example
4491
+
4492
+ ```tsx
4493
+ const children = [
4494
+ <div data-ox-slot="header">Header</div>,
4495
+ <div data-ox-slot="content">Content</div>,
4496
+ ];
4497
+
4498
+ const headerSlot = children.find((child) => hasDataSlot(child, 'header'));
4499
+ // TypeScript knows headerSlot has data-ox-slot prop
4500
+ ```
4501
+
4502
+ **Notes**:
4503
+
4504
+ - Type guard for TypeScript narrowing
4505
+ - Validates React element and slot attribute
4506
+
4507
+ ---
4508
+
4509
+ ## scrollToElement
4510
+
4511
+ Promise-based smooth scrolling.
4512
+
4513
+ ### Function
4514
+
4515
+ ```tsx
4516
+ function scrollToElement(
4517
+ target: string | Element,
4518
+ options?: {
4519
+ behavior?: 'smooth' | 'instant' | 'auto';
4520
+ block?: 'start' | 'center' | 'end' | 'nearest';
4521
+ inline?: 'start' | 'center' | 'end' | 'nearest';
4522
+ offset?: number; // Pixels from element position
4523
+ timeout?: number; // Default: 5000ms
4524
+ }
4525
+ ): Promise<void>;
4526
+ ```
4527
+
4528
+ ### Example
4529
+
4530
+ ```tsx
4531
+ await scrollToElement('#my-section');
4532
+ await scrollToElement('.target', { offset: -100 }); // 100px above
4533
+ await scrollToElement(element, { behavior: 'smooth', block: 'center' });
4534
+ ```
4535
+
4536
+ **Notes**:
4537
+
4538
+ - Smart selector parsing
4539
+ - Promise resolves when scroll completes
4540
+ - Rejects if element not found or timeout
4541
+
4542
+ ---
4543
+
4544
+ ## validation
4545
+
4546
+ Input validation utilities.
4547
+
4548
+ ### Functions
4549
+
4550
+ ```tsx
4551
+ // Email validation
4552
+ function validateEmail(
4553
+ email: string,
4554
+ options?: {
4555
+ allowLocalhost?: boolean;
4556
+ requireTld?: boolean; // Default: true
4557
+ }
4558
+ ): boolean;
4559
+
4560
+ // URL validation
4561
+ function validateUrl(
4562
+ url: string,
4563
+ options?: {
4564
+ allowLocalhost?: boolean; // Default: false (blocks 127.0.0.1, 192.168.x.x, etc.)
4565
+ protocols?: string[]; // Default: ['http:', 'https:']
4566
+ requireProtocol?: boolean; // Default: false (auto-adds https://)
4567
+ }
4568
+ ): boolean;
4569
+
4570
+ // Phone validation
4571
+ function validatePhone(
4572
+ phone: string,
4573
+ options?: {
4574
+ allowedCountries?: string[]; // e.g., ['US', 'CA', 'UK']
4575
+ strict?: boolean; // Default: false (requires E.164 format with +)
4576
+ }
4577
+ ): boolean;
4578
+ ```
4579
+
4580
+ ### Example
4581
+
4582
+ ```tsx
4583
+ validateEmail('user@example.com');
4584
+ // true
4585
+
4586
+ validateUrl('https://example.com');
4587
+ // true
4588
+
4589
+ validateUrl('example.com', { requireProtocol: false });
4590
+ // true (auto-adds https://)
4591
+
4592
+ validatePhone('+14155552671');
4593
+ // true
4594
+
4595
+ validatePhone('(415) 555-2671');
4596
+ // true (non-strict mode)
4597
+
4598
+ validatePhone('+14155552671', { strict: true });
4599
+ // true
4600
+
4601
+ validatePhone('(415) 555-2671', { strict: true });
4602
+ // false (strict requires E.164)
4603
+
4604
+ validatePhone('+14155552671', { allowedCountries: ['US', 'CA'] });
4605
+ // true
4606
+ ```
4607
+
4608
+ **Notes**:
4609
+
4610
+ - Email: RFC 5321 compliant, max 254 chars
4611
+ - URL: Max 2083 chars (IE compatibility)
4612
+ - Phone: Supports 50+ country codes, 7-15 digits
4613
+ - Phone strict mode: E.164 format (+prefix, no formatting)
4614
+
4615
+ ---
4616
+
4617
+ # Common Patterns
4618
+
4619
+ ## asChild Pattern
4620
+
4621
+ The `asChild` prop enables polymorphic rendering using Radix Slot. When `asChild={true}`, the component renders as its child element while preserving the component's styling and functionality.
4622
+
4623
+ **Components with asChild**:
4624
+
4625
+ - `OxBreadcrumb.Link`
4626
+ - `OxButton`
4627
+ - `OxDropdown.Trigger`
4628
+ - `OxFloating.Trigger` _(deprecated - use OxPopper.Anchor)_
4629
+ - `OxHoverCard.Trigger`
4630
+ - `OxLink`
4631
+ - `OxPagination.Link`, `OxPagination.Next`, `OxPagination.Previous`
4632
+ - `OxPopover.Trigger`
4633
+
4634
+ **Example**:
4635
+
4636
+ ```tsx
4637
+ {
4638
+ /* Render as Next.js Link while keeping button styling */
4639
+ }
4640
+ <OxButton asChild variant="primary">
4641
+ <Link to="/dashboard">Dashboard</Link>
4642
+ </OxButton>;
4643
+ ```
4644
+
4645
+ ---
4646
+
4647
+ ## Compound Components
4648
+
4649
+ Components using the compound pattern provide sub-components accessed via dot notation. This allows flexible composition while maintaining type safety.
4650
+
4651
+ **Compound Components**:
4652
+
4653
+ - UI: Accordion, Alert, Breadcrumb, Card, DescriptionList, Dialog, Drawer, Dropdown, Floating, Icon, JsonField, Notifications, Pagination, Popover, Progress, Stepper, Table, Tabs, Timeline, Toggle
4654
+ - Forms: Checkbox, FileUpload, Form, Input (all variants), Radio, Select
4655
+ - Layouts: MainContent, Sidebar (+ Menu, Group)
4656
+ - Typography: (simple components)
4657
+
4658
+ ---
4659
+
4660
+ ## Controlled vs Uncontrolled
4661
+
4662
+ Many components support both controlled and uncontrolled modes:
4663
+
4664
+ **Controlled** (parent manages state):
4665
+
4666
+ ```tsx
4667
+ <OxSlider value={value} onChange={setValue} />
4668
+ ```
4669
+
4670
+ **Uncontrolled** (component manages state):
4671
+
4672
+ ```tsx
4673
+ <OxSlider defaultValue={50} />
4674
+ ```
4675
+
4676
+ **Components**:
4677
+
4678
+ - Accordion, Dialog, Drawer, Dropdown, Floating, Popover, Slider, Tabs, Toggle
4679
+
4680
+ ---
4681
+
4682
+ ## Loading States
4683
+
4684
+ Components with built-in loading states:
4685
+
4686
+ - Avatar (`isLoading`, `skeleton`)
4687
+ - Button (`isLoading`)
4688
+ - Card (`isLoading`)
4689
+ - Select (`isLoading`)
4690
+ - Table (`isLoading` with skeleton rows)
4691
+
4692
+ ---
4693
+
4694
+ ## Validation
4695
+
4696
+ Form components support validation via `useFormState` hook:
4697
+
4698
+ **Built-in Rules**: `'required'`, `'email'`, `'url'`, `'min:N'`, `'max:N'`, `'minLength:N'`, `'maxLength:N'`, `'pattern:regex'`, `'fileSize:5MB'`, `'fileType:image/*'`
4699
+
4700
+ **Example**:
4701
+
4702
+ ```tsx
4703
+ const { data, errors, validate } = useFormState({
4704
+ initialData: { email: '' },
4705
+ validationRules: {
4706
+ email: ['required', 'email'],
4707
+ },
4708
+ });
4709
+ ```
4710
+
4711
+ ---
4712
+
4713
+ ## Color Customization
4714
+
4715
+ Components accepting `ColorStyleName`:
4716
+
4717
+ - Tag, Card, Icon.Box, Progress, Skeleton, Spinner, Stepper, Timeline
4718
+
4719
+ **Available Colors**: purple, lime, red, yellow, green, blue, indigo, pink, amber, emerald, teal, cyan, sky, violet, fuchsia, orange, rose, gray
4720
+
4721
+ ---
4722
+
4723
+ ## Size Variants
4724
+
4725
+ Common size props:
4726
+
4727
+ - **XS-3XL**: Avatar, Icon, Spinner (`'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'`)
4728
+ - **SM-LG**: Button, Link, Toggle (`'sm' | 'md' | 'lg'`)
4729
+ - **SM-XL**: Dialog (`'sm' | 'md' | 'lg' | 'xl'`)
4730
+
4731
+ ---
4732
+
4733
+ # Best Practices
4734
+
4735
+ ## Import Optimization
4736
+
4737
+ Use specific imports for better tree-shaking:
4738
+
4739
+ ```tsx
4740
+ // Good - specific imports
4741
+ import { OxButton, OxCard } from '@noxickon/onyx';
4742
+ import { useForm } from '@noxickon/onyx/hooks';
4743
+
4744
+ // Avoid - barrel imports everything
4745
+ import * as Onyx from '@noxickon/onyx';
4746
+ ```
4747
+
4748
+ ## Form Handling
4749
+
4750
+ Use `useForm` for GraphQL forms, `useFormState` for local forms:
4751
+
4752
+ ```tsx
4753
+ // GraphQL form
4754
+ const { data, submit, errors } = useForm({
4755
+ operation: CREATE_USER_MUTATION,
4756
+ initialData: { name: '', email: '' },
4757
+ validationRules: { email: ['required', 'email'] },
4758
+ });
4759
+
4760
+ // Local form
4761
+ const { data, validate } = useFormState({
4762
+ initialData: { search: '' },
4763
+ validationRules: { search: ['minLength:3'] },
4764
+ });
4765
+ ```
4766
+
4767
+ ## Route Protection
4768
+
4769
+ Layer route guards for complex authorization:
4770
+
4771
+ ```tsx
4772
+ {
4773
+ /* Guest route wrapping protected content */
4774
+ }
4775
+ <OxGuestRoute onAuthenticated={<Navigate to="/dashboard" />}>
4776
+ <LoginPage />
4777
+ </OxGuestRoute>;
4778
+
4779
+ {
4780
+ /* Protected route with role guard */
4781
+ }
4782
+ <OxProtectedRoute onUnauthenticated={<Navigate to="/login" />}>
4783
+ <OxRoleRoute roles={['admin', 'moderator']} onUnauthorized={<AccessDenied />}>
4784
+ <AdminPanel />
4785
+ </OxRoleRoute>
4786
+ </OxProtectedRoute>;
4787
+ ```
4788
+
4789
+ ## Accessibility
4790
+
4791
+ All components are WCAG compliant. Ensure proper labels and ARIA attributes:
4792
+
4793
+ ```tsx
4794
+ <OxForm.Field>
4795
+ <OxForm.Label htmlFor="email" required>
4796
+ Email
4797
+ </OxForm.Label>
4798
+ <input id="email" aria-describedby="email-description email-error" />
4799
+ <OxForm.Description id="email-description">Your email address</OxForm.Description>
4800
+ <OxForm.Error id="email-error">Email is required</OxForm.Error>
4801
+ </OxForm.Field>
4802
+ ```
4803
+
4804
+ ---
4805
+
4806
+ # Type Definitions
4807
+
4808
+ ## Common Types
4809
+
4810
+ ```tsx
4811
+ // Lucide icon type
4812
+ import type { LucideIcon } from 'lucide-react';
4813
+
4814
+ // Color names from theme
4815
+ type ColorStyleName =
4816
+ | 'purple'
4817
+ | 'lime'
4818
+ | 'red'
4819
+ | 'yellow'
4820
+ | 'green'
4821
+ | 'blue'
4822
+ | 'indigo'
4823
+ | 'pink'
4824
+ | 'amber'
4825
+ | 'emerald'
4826
+ | 'teal'
4827
+ | 'cyan'
4828
+ | 'sky'
4829
+ | 'violet'
4830
+ | 'fuchsia'
4831
+ | 'orange'
4832
+ | 'rose'
4833
+ | 'gray';
4834
+
4835
+ type StatusType = 'default' | 'info' | 'success' | 'warning' | 'error';
4836
+
4837
+ // Validation errors
4838
+ type ValidationErrors = Record<string, string | string[]>;
4839
+ type ValidationError = string | string[];
4840
+
4841
+ // Form state
4842
+ interface OxFormState {
4843
+ setError: (field: string, error: string | string[]) => void;
4844
+ }
4845
+
4846
+ // User type (AuthContext)
4847
+ type OxUser = {
4848
+ id: string;
4849
+ role: string;
4850
+ email?: string;
4851
+ username?: string;
4852
+ } | null;
4853
+ ```
4854
+
4855
+ ---
4856
+
4857
+ # Maintenance Guide
4858
+
4859
+ ## For Library Maintainers
4860
+
4861
+ This AI-README.md serves as the **single source of truth** for external API documentation. Update it whenever you make changes to the public API.
4862
+
4863
+ ### When to Update
4864
+
4865
+ Update this document when:
4866
+
4867
+ - ✅ Adding/removing a component, hook, or utility
4868
+ - ✅ Changing public props or API signatures
4869
+ - ✅ Modifying component behavior or usage patterns
4870
+ - ✅ Releasing a new version
4871
+
4872
+ Do NOT update for:
4873
+
4874
+ - ❌ Internal refactoring without API changes
4875
+ - ❌ Documentation typo fixes (unless they affect accuracy)
4876
+ - ❌ Build/test configuration changes
4877
+
4878
+ ### Update Workflow
4879
+
4880
+ 1. **Make code changes** in the source files.
4881
+ 2. **Update AI-README.md** immediately:
4882
+ - Update affected component/hook sections.
4883
+ - Update the version header (date, version if applicable, commit after commit).
4884
+ 3. **Verify accuracy** by comparing with actual type definitions.
4885
+ 4. **Commit together** with code changes.
4886
+
4887
+ ### Version Header Maintenance
4888
+
4889
+ After making changes:
4890
+
4891
+ ```bash
4892
+ # Update the header manually:
4893
+ # Version: Check package.json "version" field
4894
+ # Updated: Today's date (YYYY-MM-DD format)
4895
+ # Built from: Run `git rev-parse --short HEAD` after committing
4896
+ ```
4897
+
4898
+ ### Structure Consistency
4899
+
4900
+ Every component should follow this pattern:
4901
+
4902
+ ````markdown
4903
+ ## OxComponentName
4904
+
4905
+ Brief one-line description.
4906
+
4907
+ **Pattern**: Standalone | Compound Component
4908
+ **Sub-components**: `SubComp1`, `SubComp2` (if compound)
4909
+
4910
+ ### Props
4911
+
4912
+ ```tsx
4913
+ interface OxComponentNameProps {
4914
+ // Full TypeScript interface
4915
+ }
4916
+ ```
4917
+ ````
4918
+
4919
+ ### Example
4920
+
4921
+ ```tsx
4922
+ <OxComponentName prop="value">Content</OxComponentName>
4923
+ ```
4924
+
4925
+ ```
4926
+
4927
+ ---
4928
+
4929
+ ### Quality Checklist
4930
+
4931
+ Before releasing:
4932
+ - Version header matches package.json
4933
+ - All new components documented
4934
+ - All examples tested and accurate
4935
+ - TypeScript interfaces match source code
4936
+ - No internal file paths exposed
4937
+ - Only Ox-prefixed exports documented
4938
+
4939
+ ---
4940
+
4941
+ This AI-README provides comprehensive reference documentation for all Onyx components, hooks, contexts, utilities, and patterns. All information is extracted from the actual source code with accurate prop definitions and usage examples.
4942
+ ```