@noxickon/onyx 4.1.6 → 5.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 (140) hide show
  1. package/AI-README.md +467 -103
  2. package/dist/_internal/styles/checkbox.variants.d.ts +5 -0
  3. package/dist/_internal/styles/index.d.ts +3 -0
  4. package/dist/_internal/styles/radio.variants.d.ts +5 -0
  5. package/dist/_internal/styles/switch.variants.d.ts +9 -0
  6. package/dist/_internal/types.d.ts +1 -0
  7. package/dist/chunks/hooks-B58X4Fdh.js +46 -0
  8. package/dist/chunks/hooks-iUUmqFrq.js +7056 -0
  9. package/dist/chunks/ui-Bz7A98Kq.js +13 -0
  10. package/dist/chunks/ui-CezxuKW0.js +22994 -0
  11. package/dist/contexts/contexts.cjs.js +2 -2
  12. package/dist/contexts/contexts.es.js +55 -55
  13. package/dist/forms/Checkbox/Checkbox.stories.d.ts +10 -3
  14. package/dist/forms/Checkbox/index.d.ts +3 -3
  15. package/dist/forms/Checkbox/src/Checkbox.d.ts +1 -1
  16. package/dist/forms/Checkbox/src/Checkbox.types.d.ts +11 -4
  17. package/dist/forms/Checkbox/src/CheckboxGroup.d.ts +1 -1
  18. package/dist/forms/Checkbox/src/CheckboxGroupItem.d.ts +1 -1
  19. package/dist/forms/Checkbox/src/context/CheckboxGroupContext.types.d.ts +5 -2
  20. package/dist/forms/Input/Date/src/useDateInput.d.ts +2 -2
  21. package/dist/forms/Input/Number/src/Number.types.d.ts +4 -4
  22. package/dist/forms/Input/Number/src/context/NumberContext.types.d.ts +2 -2
  23. package/dist/forms/Input/Time/src/useTimeInput.d.ts +2 -2
  24. package/dist/forms/Radio/Radio.stories.d.ts +14 -3
  25. package/dist/forms/Radio/index.d.ts +2 -2
  26. package/dist/forms/Radio/src/Radio.types.d.ts +9 -7
  27. package/dist/forms/Radio/src/RadioGroup.d.ts +1 -1
  28. package/dist/forms/Radio/src/RadioGroupItem.d.ts +1 -1
  29. package/dist/forms/Radio/src/context/RadioGroupContext.types.d.ts +5 -2
  30. package/dist/forms/Select/Select.stories.d.ts +53 -4
  31. package/dist/forms/Select/index.d.ts +1 -1
  32. package/dist/forms/Select/src/Select.d.ts +1 -1
  33. package/dist/forms/Select/src/Select.types.d.ts +17 -5
  34. package/dist/forms/Switch/Switch.stories.d.ts +1 -0
  35. package/dist/forms/Switch/src/Switch.d.ts +1 -1
  36. package/dist/forms/Switch/src/Switch.types.d.ts +2 -0
  37. package/dist/hooks/hooks.cjs.js +1 -1
  38. package/dist/hooks/hooks.es.js +11 -10
  39. package/dist/hooks/index.d.ts +1 -0
  40. package/dist/hooks/useControllableState/src/useControllableState.types.d.ts +3 -6
  41. package/dist/hooks/useSort/UseSort.stories.d.ts +6 -0
  42. package/dist/hooks/useSort/index.d.ts +2 -0
  43. package/dist/hooks/useSort/src/useSort.d.ts +3 -0
  44. package/dist/hooks/useSort/src/useSort.types.d.ts +20 -0
  45. package/dist/hooks/useSort/test/useSort.test.d.ts +1 -0
  46. package/dist/layouts/layouts.cjs.js +1 -1
  47. package/dist/layouts/layouts.es.js +31 -32
  48. package/dist/legacy/index.d.ts +1 -0
  49. package/dist/legacy/legacy.cjs.js +1 -1
  50. package/dist/legacy/legacy.es.js +766 -604
  51. package/dist/legacy/ui/Floating/Floating.stories.d.ts +1 -1
  52. package/dist/legacy/ui/Floating/index.d.ts +1 -1
  53. package/dist/legacy/ui/Floating/src/Floating.types.d.ts +1 -1
  54. package/dist/legacy/ui/Floating/src/FloatingTrigger.d.ts +1 -1
  55. package/dist/legacy/ui/Toast/Toast.stories.d.ts +9 -0
  56. package/dist/legacy/ui/Toast/index.d.ts +5 -0
  57. package/dist/legacy/ui/Toast/src/Toast.d.ts +2 -0
  58. package/dist/legacy/ui/Toast/src/Toast.types.d.ts +29 -0
  59. package/dist/legacy/ui/Toast/src/ToastItem.d.ts +2 -0
  60. package/dist/legacy/ui/Toast/src/context/ToastContext.d.ts +2 -0
  61. package/dist/legacy/ui/Toast/src/context/ToastContext.types.d.ts +28 -0
  62. package/dist/legacy/ui/Toast/src/context/ToastProvider.d.ts +2 -0
  63. package/dist/legacy/ui/Toast/src/context/useToast.d.ts +2 -0
  64. package/dist/legacy/ui/Toast/test/Toast.test.d.ts +1 -0
  65. package/dist/onyx.cjs.js +1 -1
  66. package/dist/onyx.es.js +19 -18
  67. package/dist/pages/pages.cjs.js +1 -1
  68. package/dist/pages/pages.es.js +37 -37
  69. package/dist/routes/routes.cjs.js +1 -1
  70. package/dist/routes/routes.es.js +3 -3
  71. package/dist/styles.css +1 -0
  72. package/dist/ui/Breadcrumb/Breadcrumb.stories.d.ts +1 -1
  73. package/dist/ui/Breadcrumb/index.d.ts +1 -1
  74. package/dist/ui/Breadcrumb/src/Breadcrumb.types.d.ts +1 -1
  75. package/dist/ui/Breadcrumb/src/BreadcrumbLink.d.ts +1 -1
  76. package/dist/ui/Button/Button.stories.d.ts +2 -2
  77. package/dist/ui/Button/src/Button.d.ts +1 -1
  78. package/dist/ui/Button/src/Button.types.d.ts +1 -1
  79. package/dist/ui/Dropdown/Dropdown.stories.d.ts +23 -3
  80. package/dist/ui/Dropdown/index.d.ts +8 -2
  81. package/dist/ui/Dropdown/src/Dropdown.types.d.ts +31 -4
  82. package/dist/ui/Dropdown/src/DropdownCheckboxItem.d.ts +2 -0
  83. package/dist/ui/Dropdown/src/DropdownGroup.d.ts +2 -0
  84. package/dist/ui/Dropdown/src/DropdownRadioGroup.d.ts +2 -0
  85. package/dist/ui/Dropdown/src/DropdownRadioItem.d.ts +2 -0
  86. package/dist/ui/Dropdown/src/DropdownSubMenu.d.ts +2 -0
  87. package/dist/ui/Dropdown/src/DropdownSubMenuContent.d.ts +2 -0
  88. package/dist/ui/Dropdown/src/DropdownSubMenuTrigger.d.ts +2 -0
  89. package/dist/ui/Dropdown/src/DropdownTrigger.d.ts +1 -1
  90. package/dist/ui/Dropdown/src/context/DropdownContext.types.d.ts +2 -0
  91. package/dist/ui/Dropdown/src/context/DropdownRadioContext.d.ts +2 -0
  92. package/dist/ui/Dropdown/src/context/DropdownRadioContext.types.d.ts +5 -0
  93. package/dist/ui/Dropdown/src/context/DropdownSubMenuContext.d.ts +2 -0
  94. package/dist/ui/Dropdown/src/context/DropdownSubMenuContext.types.d.ts +14 -0
  95. package/dist/ui/Dropdown/src/context/useDropdownRadioContext.d.ts +1 -0
  96. package/dist/ui/Dropdown/src/context/useDropdownSubMenuContext.d.ts +1 -0
  97. package/dist/ui/HoverCard/HoverCard.stories.d.ts +1 -1
  98. package/dist/ui/HoverCard/index.d.ts +1 -1
  99. package/dist/ui/HoverCard/src/HoverCard.types.d.ts +1 -1
  100. package/dist/ui/HoverCard/src/HoverCardTrigger.d.ts +1 -1
  101. package/dist/ui/Link/Link.stories.d.ts +1 -1
  102. package/dist/ui/Link/src/Link.d.ts +1 -1
  103. package/dist/ui/Link/src/Link.types.d.ts +1 -1
  104. package/dist/ui/Pagination/Pagination.stories.d.ts +3 -3
  105. package/dist/ui/Pagination/index.d.ts +3 -3
  106. package/dist/ui/Pagination/src/Pagination.types.d.ts +3 -3
  107. package/dist/ui/Pagination/src/PaginationLink.d.ts +1 -1
  108. package/dist/ui/Pagination/src/PaginationNext.d.ts +1 -1
  109. package/dist/ui/Pagination/src/PaginationPrevious.d.ts +1 -1
  110. package/dist/ui/Popover/Popover.stories.d.ts +1 -1
  111. package/dist/ui/Popover/index.d.ts +1 -1
  112. package/dist/ui/Popover/src/Popover.types.d.ts +1 -1
  113. package/dist/ui/Popover/src/PopoverTrigger.d.ts +1 -1
  114. package/dist/ui/Popper/index.d.ts +1 -1
  115. package/dist/ui/Popper/src/Popper.types.d.ts +1 -1
  116. package/dist/ui/Popper/src/PopperAnchor.d.ts +1 -1
  117. package/dist/ui/Table/Table.stories.d.ts +7 -4
  118. package/dist/ui/Table/index.d.ts +3 -3
  119. package/dist/ui/Table/src/Table.d.ts +1 -1
  120. package/dist/ui/Table/src/Table.types.d.ts +8 -0
  121. package/dist/ui/Table/src/TableHead.d.ts +1 -1
  122. package/dist/ui/Table/src/TableRow.d.ts +1 -1
  123. package/dist/ui/Table/src/context/TableContext.types.d.ts +6 -0
  124. package/dist/ui/Toast/Toast.stories.d.ts +4 -2
  125. package/dist/ui/Toast/index.d.ts +1 -1
  126. package/dist/ui/Toast/src/Toast.d.ts +2 -2
  127. package/dist/ui/Toast/src/Toast.types.d.ts +23 -23
  128. package/dist/ui/Toast/src/context/ToastContext.types.d.ts +15 -23
  129. package/dist/ui/Toast/src/context/ToastProvider.d.ts +2 -2
  130. package/dist/ui/Toast/src/context/useToast.d.ts +2 -1
  131. package/dist/ui.css +1 -1
  132. package/dist/utils/utils.cjs.js +1 -1
  133. package/dist/utils/utils.es.js +6 -6
  134. package/package.json +17 -16
  135. package/dist/chunks/hooks-BMXCuU2h.js +0 -7318
  136. package/dist/chunks/hooks-H39lCrRt.js +0 -31
  137. package/dist/chunks/ui-BBpe54MX.js +0 -9
  138. package/dist/chunks/ui-DaY9hD0b.js +0 -20924
  139. package/dist/ui/Dropdown/src/DropdownLabel.d.ts +0 -2
  140. package/dist/ui/Toast/src/ToastItem.d.ts +0 -2
package/AI-README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Onyx Component Library - AI Reference Guide
2
2
 
3
- **Version:** 3.0.0 • **Updated:** 2025-12-16 • **Built from:** bfdd6f72
3
+ **Version:** 3.0.0 • **Updated:** 2026-02-04 • **Built from:** a0a8ed34
4
4
 
5
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
6
 
@@ -90,7 +90,7 @@ import '@noxickon/onyx/animations'; // Animations (optional)
90
90
 
91
91
  ---
92
92
 
93
- # UI Components (43)
93
+ # UI Components (45)
94
94
 
95
95
  ## OxAccordion
96
96
 
@@ -226,7 +226,8 @@ interface OxAspectRatioFallbackProps extends ComponentPropsWithRef<'div'> {
226
226
 
227
227
  Avatar component with status indicators and loading states.
228
228
 
229
- **Pattern**: Simple Component
229
+ **Pattern**: Simple Component + Compound Component (OxAvatarField)
230
+ **Sub-components**: `OxAvatarField`, `OxAvatarField.Content`, `OxAvatarField.Name`, `OxAvatarField.Subtitle`
230
231
 
231
232
  ### Props
232
233
 
@@ -242,11 +243,31 @@ interface OxAvatarProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
242
243
  src?: string;
243
244
  status?: 'online' | 'offline' | 'away' | 'busy';
244
245
  }
246
+
247
+ interface OxAvatarFieldProps extends ComponentPropsWithRef<'div'> {
248
+ children: ReactNode;
249
+ orientation?: 'horizontal' | 'vertical'; // Layout direction
250
+ }
251
+
252
+ interface OxAvatarFieldContentProps extends ComponentPropsWithRef<'div'> {
253
+ children: ReactNode;
254
+ }
255
+
256
+ interface OxAvatarFieldNameProps extends ComponentPropsWithRef<'span'> {
257
+ children: ReactNode;
258
+ }
259
+
260
+ interface OxAvatarFieldSubtitleProps extends ComponentPropsWithRef<'span'> {
261
+ children: ReactNode;
262
+ }
245
263
  ```
246
264
 
247
265
  ### Example
248
266
 
249
267
  ```tsx
268
+ {
269
+ /* Basic avatar */
270
+ }
250
271
  <OxAvatar
251
272
  src="/avatar.jpg"
252
273
  alt="User Name"
@@ -255,7 +276,18 @@ interface OxAvatarProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
255
276
  showStatus
256
277
  status="online"
257
278
  fallback="UN"
258
- />
279
+ />;
280
+
281
+ {
282
+ /* Avatar with field layout */
283
+ }
284
+ <OxAvatarField orientation="horizontal">
285
+ <OxAvatar src="/avatar.jpg" alt="John Doe" size="md" />
286
+ <OxAvatarField.Content>
287
+ <OxAvatarField.Name>John Doe</OxAvatarField.Name>
288
+ <OxAvatarField.Subtitle>Software Engineer</OxAvatarField.Subtitle>
289
+ </OxAvatarField.Content>
290
+ </OxAvatarField>;
259
291
  ```
260
292
 
261
293
  ---
@@ -266,7 +298,7 @@ Notification badge for displaying counts or status indicators on UI elements. De
266
298
 
267
299
  **Pattern**: Simple Component
268
300
 
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.
301
+ > **Note:** Badges are optimized for ghost buttons and icons. Count badges use subtle backgrounds; dot badges use solid colors for status indicators. Use the `variant` prop to change colors.
270
302
 
271
303
  ### Props
272
304
 
@@ -341,7 +373,7 @@ interface OxTagProps extends ComponentPropsWithRef<'span'> {
341
373
 
342
374
  ## OxBreadcrumb
343
375
 
344
- Breadcrumb navigation with asChild pattern support.
376
+ Breadcrumb navigation with asSlot pattern support.
345
377
 
346
378
  **Pattern**: Compound Component
347
379
  **Sub-components**: `Ellipsis`, `Item`, `Link`, `Page`, `Separator`
@@ -358,7 +390,7 @@ interface OxBreadcrumbItemProps extends ComponentPropsWithRef<'li'> {
358
390
  }
359
391
 
360
392
  interface OxBreadcrumbLinkProps extends ComponentPropsWithRef<'a'> {
361
- asChild?: boolean; // Renders as child component (e.g., Next.js Link)
393
+ asSlot?: boolean; // Renders as child component (e.g., Next.js Link)
362
394
  children: ReactNode;
363
395
  current?: boolean; // Marks as current page
364
396
  href?: string;
@@ -390,9 +422,9 @@ interface OxBreadcrumbEllipsisProps extends ComponentPropsWithRef<'span'> {}
390
422
  </OxBreadcrumb>;
391
423
 
392
424
  {
393
- /* Using asChild with Next.js Link */
425
+ /* Using asSlot with Next.js Link */
394
426
  }
395
- <OxBreadcrumb.Link asChild>
427
+ <OxBreadcrumb.Link asSlot>
396
428
  <Link to="/dashboard">Dashboard</Link>
397
429
  </OxBreadcrumb.Link>;
398
430
  ```
@@ -405,13 +437,13 @@ Button component with variants, sizes, and loading states.
405
437
 
406
438
  **Pattern**: Simple Component
407
439
 
408
- > **Note:** For links styled as buttons, use `OxButton` with `asChild` prop. Use `OxLink` only for text-based links with underline.
440
+ > **Note:** For links styled as buttons, use `OxButton` with `asSlot` prop. Use `OxLink` only for text-based links with underline.
409
441
 
410
442
  ### Props
411
443
 
412
444
  ```tsx
413
445
  interface OxButtonProps extends ComponentPropsWithRef<'button'> {
414
- asChild?: boolean; // Renders as child element (useful for Link components)
446
+ asSlot?: boolean; // Renders as child element (useful for Link components)
415
447
  fullWidth?: boolean; // Expands to full container width
416
448
  isLoading?: boolean; // Shows spinner, disables interaction
417
449
  size?: 'sm' | 'md' | 'lg';
@@ -429,7 +461,7 @@ interface OxButtonProps extends ComponentPropsWithRef<'button'> {
429
461
  {
430
462
  /* Render as Link while keeping button styling */
431
463
  }
432
- <OxButton asChild variant="primary">
464
+ <OxButton asSlot variant="primary">
433
465
  <Link to="/dashboard">Dashboard</Link>
434
466
  </OxButton>;
435
467
  ```
@@ -712,7 +744,7 @@ interface OxDrawerFooterProps extends ComponentPropsWithRef<'div'> {
712
744
  Dropdown menu with extensive sub-components.
713
745
 
714
746
  **Pattern**: Compound Component
715
- **Sub-components**: `Body`, `Content`, `Footer`, `Header`, `Item`, `Label`, `Separator`, `Shortcut`, `Trigger`
747
+ **Sub-components**: `Body`, `CheckboxItem`, `Content`, `Footer`, `Group`, `Header`, `Item`, `RadioGroup`, `RadioItem`, `Separator`, `Shortcut`, `SubMenu`, `SubMenuContent`, `SubMenuTrigger`, `Trigger`
716
748
 
717
749
  ### Props
718
750
 
@@ -720,6 +752,7 @@ Dropdown menu with extensive sub-components.
720
752
  interface OxDropdownProps {
721
753
  align?: 'start' | 'center' | 'end';
722
754
  children: ReactNode;
755
+ closeOnOutsideClick?: boolean; // Close when clicking outside
723
756
  defaultOpen?: boolean;
724
757
  disabled?: boolean;
725
758
  onOpenChange?: (open: boolean) => void;
@@ -729,7 +762,7 @@ interface OxDropdownProps {
729
762
 
730
763
  interface OxDropdownTriggerProps extends ComponentPropsWithRef<'button'> {
731
764
  animateIcon?: boolean; // Animates icon on open/close
732
- asChild?: boolean; // Renders as child component (useful for custom triggers)
765
+ asSlot?: boolean; // Renders as child component (useful for custom triggers)
733
766
  children: ReactNode;
734
767
  hideIcon?: boolean;
735
768
  icon?: LucideIcon;
@@ -754,14 +787,50 @@ interface OxDropdownItemButtonProps extends Omit<ComponentPropsWithRef<'button'>
754
787
  }
755
788
 
756
789
  interface OxDropdownItemLinkProps extends ComponentPropsWithRef<'a'> {
757
- disabled?: boolean; // Disables link navigation
790
+ disabled?: boolean;
758
791
  href: string; // Required for link variant
759
792
  }
760
793
 
761
- interface OxDropdownLabelProps extends ComponentPropsWithRef<'div'> {
794
+ interface OxDropdownCheckboxItemProps extends Omit<
795
+ ComponentPropsWithRef<'button'>,
796
+ 'type' | 'onChange'
797
+ > {
798
+ checked?: boolean;
799
+ closeOnSelect?: boolean; // Close dropdown when selected
800
+ defaultChecked?: boolean;
801
+ onCheckedChange?: (checked: boolean) => void;
802
+ }
803
+
804
+ interface OxDropdownRadioGroupProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
805
+ children: ReactNode;
806
+ closeOnSelect?: boolean; // Close dropdown when item selected
807
+ defaultValue?: string;
808
+ onValueChange?: (value: string) => void;
809
+ value?: string;
810
+ }
811
+
812
+ interface OxDropdownRadioItemProps extends Omit<ComponentPropsWithRef<'button'>, 'type' | 'value'> {
813
+ value: string; // Required
814
+ }
815
+
816
+ interface OxDropdownGroupProps extends ComponentPropsWithRef<'div'> {
817
+ children: ReactNode;
818
+ label?: string; // Group label
819
+ }
820
+
821
+ interface OxDropdownSubMenuProps {
762
822
  children: ReactNode;
763
823
  }
764
824
 
825
+ interface OxDropdownSubMenuTriggerProps extends Omit<ComponentPropsWithRef<'button'>, 'type'> {
826
+ disabled?: boolean;
827
+ }
828
+
829
+ interface OxDropdownSubMenuContentProps extends ComponentPropsWithRef<'div'> {
830
+ children: ReactNode;
831
+ className?: string;
832
+ }
833
+
765
834
  interface OxDropdownShortcutProps extends ComponentPropsWithRef<'span'> {
766
835
  children: ReactNode;
767
836
  }
@@ -790,6 +859,33 @@ interface OxDropdownSeparatorProps extends Omit<OxSeparatorProps, 'orientation'
790
859
  </OxDropdown.Item>
791
860
  <OxDropdown.Item href="/settings">Settings</OxDropdown.Item>
792
861
  <OxDropdown.Separator />
862
+
863
+ {/* Checkbox items */}
864
+ <OxDropdown.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
865
+ Show Grid
866
+ </OxDropdown.CheckboxItem>
867
+
868
+ {/* Radio group */}
869
+ <OxDropdown.RadioGroup value={view} onValueChange={setView}>
870
+ <OxDropdown.RadioItem value="list">List View</OxDropdown.RadioItem>
871
+ <OxDropdown.RadioItem value="grid">Grid View</OxDropdown.RadioItem>
872
+ </OxDropdown.RadioGroup>
873
+
874
+ {/* Grouped items */}
875
+ <OxDropdown.Group label="More Actions">
876
+ <OxDropdown.Item>Archive</OxDropdown.Item>
877
+ <OxDropdown.Item>Export</OxDropdown.Item>
878
+ </OxDropdown.Group>
879
+
880
+ {/* Submenu */}
881
+ <OxDropdown.SubMenu>
882
+ <OxDropdown.SubMenuTrigger>Share</OxDropdown.SubMenuTrigger>
883
+ <OxDropdown.SubMenuContent>
884
+ <OxDropdown.Item>Copy Link</OxDropdown.Item>
885
+ <OxDropdown.Item>Email</OxDropdown.Item>
886
+ </OxDropdown.SubMenuContent>
887
+ </OxDropdown.SubMenu>
888
+
793
889
  <OxDropdown.Item onClick={handleDelete}>Delete</OxDropdown.Item>
794
890
  </OxDropdown.Body>
795
891
  </OxDropdown.Content>
@@ -900,7 +996,7 @@ interface OxFloatingProps {
900
996
  }
901
997
 
902
998
  interface OxFloatingTriggerProps extends ComponentPropsWithRef<'div'> {
903
- asChild?: boolean; // Renders as child component
999
+ asSlot?: boolean; // Renders as child component
904
1000
  children: ReactNode;
905
1001
  }
906
1002
 
@@ -940,7 +1036,7 @@ interface OxHoverCardProps {
940
1036
  }
941
1037
 
942
1038
  interface OxHoverCardTriggerProps extends ComponentPropsWithoutRef<'div'> {
943
- asChild?: boolean;
1039
+ asSlot?: boolean;
944
1040
  children: ReactNode;
945
1041
  }
946
1042
 
@@ -954,7 +1050,7 @@ interface OxHoverCardContentProps extends ComponentPropsWithoutRef<'div'> {
954
1050
 
955
1051
  ```tsx
956
1052
  <OxHoverCard openDelay={200} closeDelay={100}>
957
- <OxHoverCard.Trigger asChild>
1053
+ <OxHoverCard.Trigger asSlot>
958
1054
  <OxButton>Hover me</OxButton>
959
1055
  </OxHoverCard.Trigger>
960
1056
  <OxHoverCard.Content>
@@ -1006,6 +1102,40 @@ import { Check } from 'lucide-react';
1006
1102
 
1007
1103
  ---
1008
1104
 
1105
+ ## OxImage
1106
+
1107
+ Image component with loading states and fallback support.
1108
+
1109
+ **Pattern**: Simple Component
1110
+
1111
+ ### Props
1112
+
1113
+ ```tsx
1114
+ interface OxImageProps extends Omit<ComponentPropsWithRef<'img'>, 'onLoad' | 'onError'> {
1115
+ alt: string; // Required - Alt text for accessibility
1116
+ fallback?: ReactNode; // Content shown when image fails to load
1117
+ objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
1118
+ onLoadComplete?: () => void; // Called when image loads successfully
1119
+ onLoadError?: () => void; // Called when image fails to load
1120
+ src: string; // Required - Image source URL
1121
+ }
1122
+ ```
1123
+
1124
+ ### Example
1125
+
1126
+ ```tsx
1127
+ <OxImage
1128
+ src="/photo.jpg"
1129
+ alt="Profile photo"
1130
+ objectFit="cover"
1131
+ onLoadComplete={() => console.log('Loaded')}
1132
+ onLoadError={() => console.log('Failed')}
1133
+ fallback={<OxSkeleton shape="rectangle" />}
1134
+ />
1135
+ ```
1136
+
1137
+ ---
1138
+
1009
1139
  ## OxJsonField (alpha)
1010
1140
 
1011
1141
  JSON data display with syntax highlighting.
@@ -1122,13 +1252,13 @@ Link component for text-based navigation with hover underline.
1122
1252
 
1123
1253
  **Pattern**: Simple Component
1124
1254
 
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.
1255
+ > **Note:** For button-styled links (e.g., call-to-action buttons), use `OxButton` with `asSlot` instead. `OxLink` is for inline and text-based links only.
1126
1256
 
1127
1257
  ### Props
1128
1258
 
1129
1259
  ```tsx
1130
1260
  interface OxLinkProps extends ComponentPropsWithRef<'a'> {
1131
- asChild?: boolean; // Renders as child element (useful for routing libraries)
1261
+ asSlot?: boolean; // Renders as child element (useful for routing libraries)
1132
1262
  disabled?: boolean; // Disables link navigation
1133
1263
  size?: 'sm' | 'md' | 'lg';
1134
1264
  variant?: 'primary' | 'secondary' | 'accent'; // primary = violet text, secondary = white text
@@ -1145,7 +1275,7 @@ interface OxLinkProps extends ComponentPropsWithRef<'a'> {
1145
1275
  {
1146
1276
  /* Use with React Router */
1147
1277
  }
1148
- <OxLink asChild>
1278
+ <OxLink asSlot>
1149
1279
  <Link to="/dashboard">Dashboard</Link>
1150
1280
  </OxLink>;
1151
1281
  ```
@@ -1367,7 +1497,7 @@ interface OxPaginationItemProps extends ComponentPropsWithRef<'li'> {
1367
1497
  }
1368
1498
 
1369
1499
  interface OxPaginationLinkProps extends ComponentPropsWithRef<'a'> {
1370
- asChild?: boolean; // Renders as child component (for routing libraries)
1500
+ asSlot?: boolean; // Renders as child component (for routing libraries)
1371
1501
  children: ReactNode;
1372
1502
  disabled?: boolean;
1373
1503
  href?: string;
@@ -1375,14 +1505,14 @@ interface OxPaginationLinkProps extends ComponentPropsWithRef<'a'> {
1375
1505
  }
1376
1506
 
1377
1507
  interface OxPaginationPreviousProps extends ComponentPropsWithRef<'a'> {
1378
- asChild?: boolean; // Renders as child component
1508
+ asSlot?: boolean; // Renders as child component
1379
1509
  children?: ReactNode;
1380
1510
  disabled?: boolean;
1381
1511
  href?: string;
1382
1512
  }
1383
1513
 
1384
1514
  interface OxPaginationNextProps extends ComponentPropsWithRef<'a'> {
1385
- asChild?: boolean; // Renders as child component
1515
+ asSlot?: boolean; // Renders as child component
1386
1516
  children?: ReactNode;
1387
1517
  disabled?: boolean;
1388
1518
  href?: string;
@@ -1419,7 +1549,7 @@ interface OxPaginationEllipsisProps extends ComponentPropsWithRef<'span'> {}
1419
1549
 
1420
1550
  ## OxPopover
1421
1551
 
1422
- Popover component built on Floating.
1552
+ Popover component built on Popper.
1423
1553
 
1424
1554
  **Pattern**: Compound Component
1425
1555
  **Sub-components**: `Content`, `Trigger`
@@ -1427,9 +1557,10 @@ Popover component built on Floating.
1427
1557
  ### Props
1428
1558
 
1429
1559
  ```tsx
1430
- interface OxPopoverProps extends ComponentPropsWithRef<'div'> {
1560
+ interface OxPopoverProps {
1431
1561
  align?: 'start' | 'center' | 'end';
1432
- children: React.ReactNode;
1562
+ children: ReactNode;
1563
+ closeOnOutsideClick?: boolean; // Close when clicking outside
1433
1564
  defaultOpen?: boolean;
1434
1565
  disabled?: boolean;
1435
1566
  onOpenChange?: (open: boolean) => void;
@@ -1437,13 +1568,13 @@ interface OxPopoverProps extends ComponentPropsWithRef<'div'> {
1437
1568
  side?: 'top' | 'bottom' | 'left' | 'right';
1438
1569
  }
1439
1570
 
1440
- interface OxPopoverTriggerProps extends ComponentPropsWithRef<'button'> {
1441
- asChild?: boolean; // Renders as child component
1442
- children: React.ReactNode;
1571
+ interface OxPopoverTriggerProps extends ComponentPropsWithoutRef<'button'> {
1572
+ asSlot?: boolean; // Renders as child component
1573
+ children: ReactNode;
1443
1574
  }
1444
1575
 
1445
- interface OxPopoverContentProps extends ComponentPropsWithRef<'div'> {
1446
- children: React.ReactNode;
1576
+ interface OxPopoverContentProps extends ComponentPropsWithoutRef<'div'> {
1577
+ children: ReactNode;
1447
1578
  showCloseButton?: boolean;
1448
1579
  }
1449
1580
  ```
@@ -1451,7 +1582,7 @@ interface OxPopoverContentProps extends ComponentPropsWithRef<'div'> {
1451
1582
  ### Example
1452
1583
 
1453
1584
  ```tsx
1454
- <OxPopover side="bottom">
1585
+ <OxPopover side="bottom" closeOnOutsideClick>
1455
1586
  <OxPopover.Trigger>Click me</OxPopover.Trigger>
1456
1587
  <OxPopover.Content showCloseButton>Popover content here</OxPopover.Content>
1457
1588
  </OxPopover>
@@ -1479,7 +1610,7 @@ interface OxPopperProps {
1479
1610
  }
1480
1611
 
1481
1612
  interface OxPopperAnchorProps extends ComponentPropsWithoutRef<'div'> {
1482
- asChild?: boolean;
1613
+ asSlot?: boolean;
1483
1614
  children?: ReactNode;
1484
1615
  virtualRef?: RefObject<Measurable | null>; // For virtual anchor positioning
1485
1616
  }
@@ -1503,7 +1634,7 @@ interface OxPopperContentProps extends ComponentPropsWithoutRef<'div'> {
1503
1634
 
1504
1635
  ```tsx
1505
1636
  <OxPopper>
1506
- <OxPopper.Anchor asChild>
1637
+ <OxPopper.Anchor asSlot>
1507
1638
  <button>Anchor element</button>
1508
1639
  </OxPopper.Anchor>
1509
1640
  <OxPopper.Content side="bottom" align="start" sideOffset={8}>
@@ -1949,6 +2080,43 @@ interface OxTabsContentProps extends ComponentPropsWithRef<'div'> {
1949
2080
 
1950
2081
  ---
1951
2082
 
2083
+ ## OxThemeSwitcher
2084
+
2085
+ Theme toggle button for switching between light, dark, and system themes.
2086
+
2087
+ **Pattern**: Simple Component
2088
+
2089
+ ### Props
2090
+
2091
+ ```tsx
2092
+ type Theme = 'light' | 'dark' | 'system';
2093
+ type ThemeSwitcherSize = 'sm' | 'md' | 'lg';
2094
+
2095
+ interface OxThemeSwitcherProps extends Omit<ComponentPropsWithRef<'button'>, 'onChange'> {
2096
+ onThemeChange?: (theme: Theme) => void; // Called when theme changes
2097
+ size?: ThemeSwitcherSize;
2098
+ theme?: Theme; // Controlled theme value
2099
+ }
2100
+ ```
2101
+
2102
+ ### Example
2103
+
2104
+ ```tsx
2105
+ {
2106
+ /* Uncontrolled - uses useTheme hook internally */
2107
+ }
2108
+ <OxThemeSwitcher size="md" />;
2109
+
2110
+ {
2111
+ /* Controlled */
2112
+ }
2113
+ <OxThemeSwitcher theme={currentTheme} onThemeChange={setCurrentTheme} size="lg" />;
2114
+ ```
2115
+
2116
+ **Note**: Works with the `useTheme` hook for theme management.
2117
+
2118
+ ---
2119
+
1952
2120
  ## OxTimeline (alpha)
1953
2121
 
1954
2122
  Timeline component.
@@ -1995,63 +2163,123 @@ interface OxTimelineItemProps extends ComponentPropsWithRef<'li'> {
1995
2163
 
1996
2164
  ---
1997
2165
 
1998
- ## OxToast (beta)
2166
+ ## OxToast
1999
2167
 
2000
- Toast notification system.
2168
+ Toast notification system built on Sonner.
2001
2169
 
2002
2170
  **Pattern**: Context-based Component
2003
- **Additional Exports**: `OxToastProvider`, `useOxToast`
2171
+ **Additional Exports**: `OxToastProvider`, `useOxToast`, `toast`
2004
2172
 
2005
2173
  ### Props
2006
2174
 
2007
2175
  ```tsx
2008
- interface OxToastData {
2009
- color?: ColorStyleName;
2010
- customContent?: ReactNode;
2176
+ type OxToastPosition =
2177
+ | 'top-left'
2178
+ | 'top-center'
2179
+ | 'top-right'
2180
+ | 'bottom-left'
2181
+ | 'bottom-center'
2182
+ | 'bottom-right';
2183
+
2184
+ interface OxToastOptions {
2185
+ action?: {
2186
+ label: string;
2187
+ onClick: () => void;
2188
+ };
2189
+ cancel?: {
2190
+ label: string;
2191
+ onClick?: () => void;
2192
+ };
2011
2193
  description?: string;
2012
2194
  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
2195
+ icon?: LucideIcon | ReactNode;
2196
+ onAutoClose?: () => void;
2197
+ onDismiss?: () => void;
2019
2198
  }
2020
2199
 
2021
- interface OxToastProps {
2022
- align: 'left' | 'center' | 'right'; // Required
2023
- onRemove: (id: string) => void; // Required
2024
- position: 'top' | 'bottom'; // Required
2025
- toasts: OxToastData[]; // Required
2200
+ interface OxToastProviderProps {
2201
+ children: ReactNode;
2202
+ closeButton?: boolean; // Show close button on toasts
2203
+ expand?: boolean; // Expand toasts on hover
2204
+ gap?: number; // Gap between toasts
2205
+ offset?: string | number; // Offset from viewport edge
2206
+ position?: OxToastPosition; // Default: 'bottom-right'
2207
+ richColors?: boolean; // Use rich semantic colors
2208
+ theme?: 'light' | 'dark' | 'system';
2209
+ visibleToasts?: number; // Max visible toasts
2210
+ }
2211
+ ```
2212
+
2213
+ ### Hook API
2214
+
2215
+ ```tsx
2216
+ interface OxToastContextApi {
2217
+ (title: string, options?: OxToastOptions): string | number; // Default toast
2218
+ success: (title: string, options?: OxToastOptions) => string | number;
2219
+ error: (title: string, options?: OxToastOptions) => string | number;
2220
+ warning: (title: string, options?: OxToastOptions) => string | number;
2221
+ info: (title: string, options?: OxToastOptions) => string | number;
2222
+ loading: (title: string, options?: OxToastOptions) => string | number;
2223
+ destructive: (title: string, options?: OxToastOptions) => string | number;
2224
+ custom: (content: ReactNode, options?: { duration?: number }) => string | number;
2225
+ promise: <T>(
2226
+ promise: Promise<T>,
2227
+ messages: {
2228
+ loading: string;
2229
+ success: string | ((data: T) => string);
2230
+ error: string | ((error: unknown) => string);
2231
+ }
2232
+ ) => Promise<T>;
2233
+ dismiss: (id?: string | number) => void; // Dismiss specific or all toasts
2026
2234
  }
2027
2235
  ```
2028
2236
 
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
2237
  ### Example
2043
2238
 
2044
2239
  ```tsx
2045
- // Wrap app
2046
- <OxToastProvider>
2240
+ // Wrap app with provider
2241
+ <OxToastProvider position="bottom-right" richColors>
2047
2242
  <App />
2048
2243
  </OxToastProvider>;
2049
2244
 
2050
- // Use in component
2245
+ // Use hook in component
2051
2246
  function MyComponent() {
2052
- const { showToast } = useOxToast();
2247
+ const toast = useOxToast();
2053
2248
 
2054
- return <button onClick={() => showToast({ title: 'Hello', type: 'info' })}>Show Toast</button>;
2249
+ return (
2250
+ <div>
2251
+ <button onClick={() => toast('Default notification')}>Default</button>
2252
+ <button onClick={() => toast.success('Changes saved!')}>Success</button>
2253
+ <button onClick={() => toast.error('Something went wrong')}>Error</button>
2254
+ <button onClick={() => toast.warning('Please review')}>Warning</button>
2255
+ <button onClick={() => toast.info('New update available')}>Info</button>
2256
+
2257
+ {/* With description and action */}
2258
+ <button
2259
+ onClick={() =>
2260
+ toast.success('File uploaded', {
2261
+ description: 'Your file has been uploaded successfully.',
2262
+ action: { label: 'View', onClick: () => navigate('/files') },
2263
+ })
2264
+ }
2265
+ >
2266
+ With Action
2267
+ </button>
2268
+
2269
+ {/* Promise toast */}
2270
+ <button
2271
+ onClick={() =>
2272
+ toast.promise(saveData(), {
2273
+ loading: 'Saving...',
2274
+ success: 'Data saved!',
2275
+ error: 'Failed to save',
2276
+ })
2277
+ }
2278
+ >
2279
+ Promise
2280
+ </button>
2281
+ </div>
2282
+ );
2055
2283
  }
2056
2284
  ```
2057
2285
 
@@ -2188,12 +2416,18 @@ interface OxCheckboxProps extends Omit<
2188
2416
  value?: string;
2189
2417
  }
2190
2418
 
2191
- interface OxCheckboxGroupProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2419
+ interface OxCheckboxGroupProps extends Omit<
2420
+ ComponentPropsWithoutRef<'div'>,
2421
+ 'defaultValue' | 'onChange'
2422
+ > {
2192
2423
  children: ReactNode;
2424
+ defaultValue?: string[]; // Uncontrolled default values
2193
2425
  disabled?: boolean; // Disables all checkboxes in group
2426
+ error?: boolean; // Error state styling
2194
2427
  name: string; // Required
2195
- onChange?: (value: (string | number)[]) => void;
2196
- value?: (string | number)[]; // Controlled selected values
2428
+ onValueChange?: (value: string[]) => void; // Called when selection changes
2429
+ orientation?: 'horizontal' | 'vertical'; // Layout direction
2430
+ value?: string[]; // Controlled selected values
2197
2431
  }
2198
2432
 
2199
2433
  interface OxCheckboxGroupItemProps extends Omit<
@@ -2201,7 +2435,7 @@ interface OxCheckboxGroupItemProps extends Omit<
2201
2435
  'type' | 'size' | 'children' | 'checked' | 'defaultChecked' | 'value'
2202
2436
  > {
2203
2437
  error?: boolean;
2204
- value: string | number; // Required
2438
+ value: string; // Required
2205
2439
  }
2206
2440
  ```
2207
2441
 
@@ -2221,7 +2455,12 @@ interface OxCheckboxGroupItemProps extends Omit<
2221
2455
  {
2222
2456
  /* Checkbox group */
2223
2457
  }
2224
- <OxCheckbox.Group name="features" value={selected} onChange={setSelected}>
2458
+ <OxCheckbox.Group
2459
+ name="features"
2460
+ value={selected}
2461
+ onValueChange={setSelected}
2462
+ orientation="vertical"
2463
+ >
2225
2464
  <OxCheckbox.GroupItem value="feature1" />
2226
2465
  <OxCheckbox.GroupItem value="feature2" />
2227
2466
  </OxCheckbox.Group>;
@@ -2561,8 +2800,11 @@ Numeric input with increment/decrement controls.
2561
2800
  ### Props
2562
2801
 
2563
2802
  ```tsx
2564
- interface OxNumberInputContainerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
2565
- defaultValue?: number;
2803
+ interface OxNumberInputContainerProps extends Omit<
2804
+ ComponentPropsWithRef<'div'>,
2805
+ 'defaultValue' | 'onChange'
2806
+ > {
2807
+ defaultValue?: number | null;
2566
2808
  disabled?: boolean;
2567
2809
  error?: boolean;
2568
2810
  locale?: string; // Locale for number formatting
@@ -2570,12 +2812,12 @@ interface OxNumberInputContainerProps extends Omit<ComponentPropsWithRef<'div'>,
2570
2812
  maximumFractionDigits?: number; // Max decimal places
2571
2813
  min?: number; // Minimum value
2572
2814
  minimumFractionDigits?: number; // Min decimal places
2573
- onChange?: (value: number | undefined) => void;
2815
+ onChange?: (value: number | null) => void;
2574
2816
  required?: boolean;
2575
2817
  steps?: number; // Increment/decrement step value
2576
2818
  useGrouping?: boolean; // Use thousand separators
2577
2819
  validationMessage?: string; // Custom error message shown below input
2578
- value?: number; // Controlled value
2820
+ value?: number | null; // Controlled value
2579
2821
  }
2580
2822
 
2581
2823
  interface OxNumberInputProps {
@@ -2740,29 +2982,28 @@ Radio button group.
2740
2982
  ```tsx
2741
2983
  interface OxRadioGroupProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onChange'> {
2742
2984
  children: ReactNode; // Required
2743
- defaultValue?: string | number;
2985
+ defaultValue?: string; // Uncontrolled default value
2744
2986
  disabled?: boolean; // Disables all radio buttons
2745
2987
  error?: boolean;
2746
2988
  name?: string;
2747
- onChange?: (value: string | number) => void;
2989
+ onValueChange?: (value: string) => void; // Called when selection changes
2990
+ orientation?: 'horizontal' | 'vertical'; // Layout direction
2748
2991
  required?: boolean;
2749
- value?: string | number; // Controlled selected value
2992
+ value?: string; // Controlled selected value
2750
2993
  }
2751
2994
 
2752
- interface OxRadioItemProps extends Omit<
2995
+ interface OxRadioGroupItemProps extends Omit<
2753
2996
  ComponentPropsWithoutRef<'input'>,
2754
- 'type' | 'size' | 'required'
2997
+ 'type' | 'size' | 'required' | 'value' | 'name'
2755
2998
  > {
2756
- error?: boolean;
2757
- onCheckedChange?: (checked: boolean) => void; // Called when this item is checked
2758
- value?: string | number;
2999
+ value: string; // Required - unique value for this option
2759
3000
  }
2760
3001
  ```
2761
3002
 
2762
3003
  ### Example
2763
3004
 
2764
3005
  ```tsx
2765
- <OxRadio.Group name="plan" value={plan} onChange={setPlan}>
3006
+ <OxRadio.Group name="plan" value={plan} onValueChange={setPlan} orientation="vertical">
2766
3007
  <OxRadio.Item value="basic" />
2767
3008
  <OxRadio.Item value="pro" />
2768
3009
  <OxRadio.Item value="enterprise" />
@@ -2783,21 +3024,44 @@ Select dropdown with single and multi-select.
2783
3024
  ### Props
2784
3025
 
2785
3026
  ```tsx
2786
- interface OxSelectProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'> {
3027
+ type OxSelectValue = string | number | null;
3028
+
3029
+ // Single select
3030
+ interface OxSelectSingleProps extends Omit<ComponentPropsWithRef<'div'>, 'defaultValue'> {
3031
+ children: ReactNode;
2787
3032
  defaultOpen?: boolean;
2788
- defaultValue?: string | number | null | Array<string | number | null>;
3033
+ defaultValue?: OxSelectValue;
2789
3034
  disabled?: boolean;
2790
3035
  error?: boolean;
2791
3036
  id?: string;
2792
3037
  isLoading?: boolean; // Shows loading state
2793
- multiple?: boolean; // Enable multi-select
2794
- onChange?: (value: string | number | null | Array<string | number | null>) => void;
3038
+ multiple?: false; // Single select (default)
2795
3039
  onOpenChange?: (open: boolean) => void;
3040
+ onValueChange?: (value: OxSelectValue) => void;
2796
3041
  open?: boolean; // Controlled open state
2797
3042
  required?: boolean;
2798
- value?: string | number | null | Array<string | number | null>; // Controlled value
3043
+ value?: OxSelectValue; // Controlled value
2799
3044
  }
2800
3045
 
3046
+ // Multi-select
3047
+ interface OxSelectMultipleProps extends Omit<ComponentPropsWithRef<'div'>, 'defaultValue'> {
3048
+ children: ReactNode;
3049
+ defaultOpen?: boolean;
3050
+ defaultValue?: OxSelectValue[];
3051
+ disabled?: boolean;
3052
+ error?: boolean;
3053
+ id?: string;
3054
+ isLoading?: boolean;
3055
+ multiple: true; // Required for multi-select
3056
+ onOpenChange?: (open: boolean) => void;
3057
+ onValueChange?: (value: OxSelectValue[]) => void;
3058
+ open?: boolean;
3059
+ required?: boolean;
3060
+ value?: OxSelectValue[];
3061
+ }
3062
+
3063
+ type OxSelectProps = OxSelectSingleProps | OxSelectMultipleProps;
3064
+
2801
3065
  interface OxSelectTriggerProps extends ComponentPropsWithRef<'button'> {
2802
3066
  displayAsTag?: boolean; // Display selected items as tags (multi-select)
2803
3067
  placeholder?: string;
@@ -2811,7 +3075,7 @@ interface OxSelectGroupProps extends ComponentPropsWithRef<'div'> {
2811
3075
  }
2812
3076
 
2813
3077
  interface OxSelectItemProps extends Omit<ComponentPropsWithRef<'button'>, 'value'> {
2814
- value: string | number | null; // Required
3078
+ value: OxSelectValue; // Required
2815
3079
  }
2816
3080
  ```
2817
3081
 
@@ -2821,7 +3085,7 @@ interface OxSelectItemProps extends Omit<ComponentPropsWithRef<'button'>, 'value
2821
3085
  {
2822
3086
  /* Single select */
2823
3087
  }
2824
- <OxSelect value={country} onChange={setCountry}>
3088
+ <OxSelect value={country} onValueChange={setCountry}>
2825
3089
  <OxSelect.Trigger placeholder="Select country" />
2826
3090
  <OxSelect.Content>
2827
3091
  <OxSelect.Item value="us">United States</OxSelect.Item>
@@ -2832,7 +3096,7 @@ interface OxSelectItemProps extends Omit<ComponentPropsWithRef<'button'>, 'value
2832
3096
  {
2833
3097
  /* Multi-select with badges */
2834
3098
  }
2835
- <OxSelect multiple value={tags} onChange={setTags}>
3099
+ <OxSelect multiple value={tags} onValueChange={setTags}>
2836
3100
  <OxSelect.Trigger displayAsTag tagColor="blue" />
2837
3101
  <OxSelect.Content>
2838
3102
  <OxSelect.Group label="Categories">
@@ -3523,7 +3787,7 @@ function MyComponent() {
3523
3787
 
3524
3788
  ---
3525
3789
 
3526
- # Hooks (13)
3790
+ # Hooks (14)
3527
3791
 
3528
3792
  ## useControllableState
3529
3793
 
@@ -4266,6 +4530,105 @@ function ResponsiveComponent() {
4266
4530
 
4267
4531
  ---
4268
4532
 
4533
+ ## useSort
4534
+
4535
+ Client-side and server-side sorting with flexible API.
4536
+
4537
+ ### Signature
4538
+
4539
+ ```tsx
4540
+ // Client-side (with data)
4541
+ function useSort<T, K extends string = string>(
4542
+ data: T[],
4543
+ options?: UseSortOptions<K>
4544
+ ): UseSortReturnWithData<T, K>;
4545
+
4546
+ // Server-side (state only)
4547
+ function useSort<K extends string = string>(options?: UseSortOptions<K>): UseSortReturnStateOnly<K>;
4548
+
4549
+ type SortDirection = 'asc' | 'desc';
4550
+
4551
+ interface SortState<K extends string = string> {
4552
+ direction: SortDirection;
4553
+ key: K;
4554
+ }
4555
+
4556
+ interface UseSortOptions<K extends string = string> {
4557
+ defaultDirection?: SortDirection;
4558
+ defaultKey?: K;
4559
+ }
4560
+
4561
+ interface UseSortReturnBase<K extends string = string> {
4562
+ clearSort: () => void;
4563
+ setSortState: (state: SortState<K> | null) => void;
4564
+ sortState: SortState<K> | null;
4565
+ toggleSort: (key: K) => void;
4566
+ }
4567
+
4568
+ interface UseSortReturnWithData<T, K extends string = string> extends UseSortReturnBase<K> {
4569
+ sortedData: T[];
4570
+ }
4571
+
4572
+ type UseSortReturnStateOnly<K extends string = string> = UseSortReturnBase<K>;
4573
+ ```
4574
+
4575
+ ### Example
4576
+
4577
+ ```tsx
4578
+ // Client-side sorting
4579
+ function UsersTable() {
4580
+ const { sortedData, sortState, toggleSort, clearSort } = useSort(users, {
4581
+ defaultKey: 'name',
4582
+ defaultDirection: 'asc',
4583
+ });
4584
+
4585
+ return (
4586
+ <table>
4587
+ <thead>
4588
+ <tr>
4589
+ <th onClick={() => toggleSort('name')}>Name</th>
4590
+ <th onClick={() => toggleSort('age')}>Age</th>
4591
+ </tr>
4592
+ </thead>
4593
+ <tbody>
4594
+ {sortedData.map((user) => (
4595
+ <tr key={user.id}>
4596
+ <td>{user.name}</td>
4597
+ <td>{user.age}</td>
4598
+ </tr>
4599
+ ))}
4600
+ </tbody>
4601
+ </table>
4602
+ );
4603
+ }
4604
+
4605
+ // Server-side sorting
4606
+ function ServerSideTable() {
4607
+ const { sortState, toggleSort, clearSort } = useSort({
4608
+ defaultKey: 'name',
4609
+ defaultDirection: 'asc',
4610
+ });
4611
+
4612
+ useEffect(() => {
4613
+ fetchUsers({
4614
+ sortBy: sortState?.key,
4615
+ sortOrder: sortState?.direction,
4616
+ });
4617
+ }, [sortState]);
4618
+
4619
+ return <table>{/* ... */}</table>;
4620
+ }
4621
+ ```
4622
+
4623
+ **Notes**:
4624
+
4625
+ - Toggle cycle: none → asc → desc → none
4626
+ - Supports nested paths (e.g., `profile.score`)
4627
+ - `sortedData` is memoized for performance
4628
+ - Uses `es-toolkit` for sorting
4629
+
4630
+ ---
4631
+
4269
4632
  ## useTheme
4270
4633
 
4271
4634
  Theme management with localStorage persistence.
@@ -4697,7 +5060,7 @@ formatTimestamp(new Date(Date.now() - 5 * 60 * 1000));
4697
5060
 
4698
5061
  ## hasDataSlot
4699
5062
 
4700
- React slot validation type guard.
5063
+ React slot validation type guard for slot-based component composition.
4701
5064
 
4702
5065
  ### Function
4703
5066
 
@@ -4724,6 +5087,7 @@ const headerSlot = children.find((child) => hasDataSlot(child, 'header'));
4724
5087
 
4725
5088
  - Type guard for TypeScript narrowing
4726
5089
  - Validates React element and slot attribute
5090
+ - Used for slot-based component composition (NOT related to `asSlot` prop)
4727
5091
 
4728
5092
  ---
4729
5093
 
@@ -4837,11 +5201,11 @@ validatePhone('+14155552671', { allowedCountries: ['US', 'CA'] });
4837
5201
 
4838
5202
  # Common Patterns
4839
5203
 
4840
- ## asChild Pattern
5204
+ ## asSlot Pattern
4841
5205
 
4842
- 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.
5206
+ The `asSlot` prop enables polymorphic rendering using Radix Slot. When `asSlot={true}`, the component renders as its child element while preserving the component's styling and functionality.
4843
5207
 
4844
- **Components with asChild**:
5208
+ **Components with asSlot**:
4845
5209
 
4846
5210
  - `OxBreadcrumb.Link`
4847
5211
  - `OxButton`
@@ -4858,7 +5222,7 @@ The `asChild` prop enables polymorphic rendering using Radix Slot. When `asChild
4858
5222
  {
4859
5223
  /* Render as Next.js Link while keeping button styling */
4860
5224
  }
4861
- <OxButton asChild variant="primary">
5225
+ <OxButton asSlot variant="primary">
4862
5226
  <Link to="/dashboard">Dashboard</Link>
4863
5227
  </OxButton>;
4864
5228
  ```