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