@primitiv-ui/react 0.1.0 → 0.1.2

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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +2 -1
  3. package/src/AccessibleIcon/AccessibleIcon.tsx +6 -2
  4. package/src/AccessibleIcon/__tests__/AccessibleIcon.test.tsx +1 -1
  5. package/src/AccessibleIcon/types.ts +4 -0
  6. package/src/Accordion/Accordion.tsx +34 -12
  7. package/src/Accordion/AccordionContext.ts +1 -1
  8. package/src/Accordion/__tests__/Accordion.reading-direction.test.tsx +1 -1
  9. package/src/Accordion/hooks/useAccordionItem.ts +1 -1
  10. package/src/Accordion/hooks/useAccordionRoot.ts +1 -1
  11. package/src/Accordion/hooks/useAccordionTrigger.ts +2 -2
  12. package/src/Accordion/index.ts +2 -1
  13. package/src/Accordion/types.ts +55 -13
  14. package/src/Alert/Alert.tsx +9 -2
  15. package/src/Alert/__tests__/Alert.test.tsx +1 -1
  16. package/src/Alert/types.ts +1 -0
  17. package/src/Avatar/Avatar.tsx +20 -7
  18. package/src/Avatar/AvatarContext.ts +12 -6
  19. package/src/Breadcrumb/Breadcrumb.tsx +32 -10
  20. package/src/Button/Button.tsx +5 -2
  21. package/src/Button/types.ts +4 -0
  22. package/src/Carousel/Carousel.tsx +30 -14
  23. package/src/Carousel/CarouselContext.ts +7 -3
  24. package/src/Carousel/__tests__/Carousel.asChild.test.tsx +1 -1
  25. package/src/Carousel/__tests__/Carousel.auto-play.test.tsx +1 -1
  26. package/src/Carousel/__tests__/Carousel.basic-rendering.test.tsx +1 -1
  27. package/src/Carousel/__tests__/Carousel.controlled-state.test.tsx +1 -1
  28. package/src/Carousel/__tests__/Carousel.error-handling.test.tsx +1 -1
  29. package/src/Carousel/__tests__/Carousel.ids.test.tsx +1 -1
  30. package/src/Carousel/__tests__/Carousel.imperative-api.test.tsx +2 -2
  31. package/src/Carousel/__tests__/Carousel.indicators.test.tsx +1 -1
  32. package/src/Carousel/__tests__/Carousel.intersection-observer.test.tsx +2 -2
  33. package/src/Carousel/__tests__/Carousel.keyboard-navigation.test.tsx +1 -1
  34. package/src/Carousel/__tests__/Carousel.play-pause.test.tsx +1 -1
  35. package/src/Carousel/__tests__/Carousel.prev-next.test.tsx +1 -1
  36. package/src/Carousel/__tests__/Carousel.reduced-motion.test.tsx +1 -1
  37. package/src/Carousel/__tests__/Carousel.refresh-progress.test.tsx +2 -2
  38. package/src/Carousel/__tests__/Carousel.scroll-snap-change.test.tsx +1 -1
  39. package/src/Carousel/__tests__/Carousel.scroll-sync.test.tsx +1 -1
  40. package/src/Carousel/__tests__/Carousel.slides-per-move.test.tsx +1 -1
  41. package/src/Carousel/__tests__/Carousel.slides-per-page.test.tsx +1 -1
  42. package/src/Carousel/__tests__/Carousel.touch-interaction.test.tsx +1 -1
  43. package/src/Carousel/__tests__/Carousel.transition-modes.test.tsx +1 -1
  44. package/src/Carousel/__tests__/Carousel.translations.test.tsx +1 -1
  45. package/src/Carousel/__tests__/Carousel.uncontrolled-state.test.tsx +1 -1
  46. package/src/Carousel/types.ts +8 -0
  47. package/src/Checkbox/Checkbox.tsx +11 -6
  48. package/src/Checkbox/CheckboxContext.ts +1 -1
  49. package/src/Checkbox/hooks/useCheckboxRoot.ts +1 -1
  50. package/src/Checkbox/index.ts +1 -0
  51. package/src/Checkbox/types.ts +30 -3
  52. package/src/CheckboxCard/CheckboxCard.tsx +13 -11
  53. package/src/CheckboxCard/CheckboxCardContext.ts +19 -6
  54. package/src/CheckboxCard/hooks/useCheckboxCardRoot.ts +2 -2
  55. package/src/CheckboxCard/types.ts +21 -5
  56. package/src/Collapsible/Collapsible.tsx +37 -21
  57. package/src/Collapsible/CollapsibleContext.ts +1 -1
  58. package/src/Collapsible/hooks/useCollapsibleRoot.ts +1 -1
  59. package/src/Collapsible/hooks/useCollapsibleTrigger.ts +1 -1
  60. package/src/Collapsible/index.ts +1 -0
  61. package/src/Collapsible/types.ts +45 -12
  62. package/src/ContextMenu/ContextMenu.tsx +60 -34
  63. package/src/ContextMenu/ContextMenuContext.ts +2 -2
  64. package/src/ContextMenu/ContextMenuSubContext.ts +1 -1
  65. package/src/ContextMenu/__tests__/ContextMenu.reading-direction.test.tsx +1 -1
  66. package/src/ContextMenu/index.ts +2 -1
  67. package/src/ContextMenu/types.ts +160 -17
  68. package/src/DirectionProvider/DirectionProvider.tsx +7 -1
  69. package/src/DirectionProvider/__tests__/DirectionProvider.test.tsx +1 -1
  70. package/src/DirectionProvider/types.ts +1 -0
  71. package/src/Divider/Divider.tsx +4 -1
  72. package/src/Divider/__tests__/Divider.test.tsx +1 -1
  73. package/src/Divider/index.ts +2 -1
  74. package/src/Divider/types.ts +5 -0
  75. package/src/Dropdown/Dropdown.tsx +60 -34
  76. package/src/Dropdown/DropdownContext.ts +2 -2
  77. package/src/Dropdown/DropdownSubContext.ts +1 -1
  78. package/src/Dropdown/__tests__/Dropdown.reading-direction.test.tsx +1 -1
  79. package/src/Dropdown/hooks/useDropdownContent.ts +1 -1
  80. package/src/Dropdown/hooks/useDropdownItem.ts +1 -1
  81. package/src/Dropdown/hooks/useDropdownRoot.ts +2 -2
  82. package/src/Dropdown/hooks/useDropdownTrigger.ts +1 -1
  83. package/src/Dropdown/index.ts +2 -1
  84. package/src/Dropdown/types.ts +153 -25
  85. package/src/EmptyState/EmptyState.tsx +34 -20
  86. package/src/EmptyState/__tests__/EmptyState.Actions.test.tsx +1 -1
  87. package/src/EmptyState/__tests__/EmptyState.Description.test.tsx +1 -1
  88. package/src/EmptyState/__tests__/EmptyState.Media.test.tsx +1 -1
  89. package/src/EmptyState/__tests__/EmptyState.Root.test.tsx +1 -1
  90. package/src/EmptyState/__tests__/EmptyState.Title.test.tsx +1 -1
  91. package/src/EmptyState/types.ts +2 -1
  92. package/src/Field/Field.tsx +24 -10
  93. package/src/Field/FieldContext.ts +1 -1
  94. package/src/Field/types.ts +4 -0
  95. package/src/Fieldset/Fieldset.tsx +26 -10
  96. package/src/Fieldset/types.ts +2 -0
  97. package/src/Input/Input.tsx +6 -3
  98. package/src/Input/__tests__/Input.field-integration.test.tsx +1 -1
  99. package/src/Input/types.ts +4 -0
  100. package/src/InputGroup/InputGroup.tsx +15 -8
  101. package/src/InputGroup/types.ts +9 -0
  102. package/src/MillerColumns/MillerColumns.tsx +28 -8
  103. package/src/MillerColumns/MillerColumnsContext.ts +1 -1
  104. package/src/MillerColumns/hooks/useMillerColumnsItem.ts +2 -2
  105. package/src/MillerColumns/hooks/useMillerColumnsRoot.ts +0 -0
  106. package/src/MillerColumns/index.ts +1 -1
  107. package/src/MillerColumns/types.ts +67 -14
  108. package/src/MillerColumns/useMillerColumnsSelection.ts +1 -1
  109. package/src/Modal/Modal.tsx +25 -11
  110. package/src/Modal/ModalContext.ts +14 -7
  111. package/src/Modal/hooks/useModalRoot.ts +1 -1
  112. package/src/Modal/hooks/useModalTrigger.ts +2 -2
  113. package/src/Modal/types.ts +51 -2
  114. package/src/Portal/Portal.tsx +3 -1
  115. package/src/Portal/types.ts +4 -0
  116. package/src/Progress/Progress.tsx +12 -7
  117. package/src/Progress/ProgressContext.ts +18 -6
  118. package/src/RadioCard/RadioCard.tsx +17 -11
  119. package/src/RadioCard/RadioCardContext.ts +17 -5
  120. package/src/RadioCard/RadioCardItemContext.ts +18 -5
  121. package/src/RadioCard/__tests__/RadioCard.reading-direction.test.tsx +1 -1
  122. package/src/RadioCard/hooks/useRadioCardRoot.ts +1 -1
  123. package/src/RadioCard/types.ts +24 -3
  124. package/src/RadioGroup/RadioGroup.tsx +17 -11
  125. package/src/RadioGroup/RadioGroupContext.ts +1 -1
  126. package/src/RadioGroup/RadioGroupItemContext.ts +1 -1
  127. package/src/RadioGroup/__tests__/RadioGroup.reading-direction.test.tsx +1 -1
  128. package/src/RadioGroup/hooks/useRadioGroupRoot.ts +1 -1
  129. package/src/RadioGroup/index.ts +1 -0
  130. package/src/RadioGroup/types.ts +34 -3
  131. package/src/Select/Select.tsx +23 -8
  132. package/src/Select/__tests__/Select.field-integration.test.tsx +1 -1
  133. package/src/Select/index.ts +1 -1
  134. package/src/Select/types.ts +18 -3
  135. package/src/SkipNav/SkipNav.tsx +7 -2
  136. package/src/SkipNav/__tests__/SkipNav.ids.test.tsx +1 -1
  137. package/src/Slider/Slider.tsx +26 -11
  138. package/src/Slider/SliderContext.ts +13 -6
  139. package/src/Slider/__tests__/Slider.reading-direction.test.tsx +1 -1
  140. package/src/Slider/hooks/useSliderRoot.ts +1 -1
  141. package/src/Slider/types.ts +12 -3
  142. package/src/Status/Status.tsx +9 -2
  143. package/src/Status/__tests__/Status.test.tsx +1 -1
  144. package/src/Status/types.ts +4 -0
  145. package/src/Switch/Switch.tsx +16 -6
  146. package/src/Switch/SwitchContext.ts +13 -5
  147. package/src/Switch/hooks/useSwitchRoot.ts +1 -1
  148. package/src/Switch/types.ts +24 -3
  149. package/src/Table/Table.tsx +51 -25
  150. package/src/Table/__tests__/Table.Body.test.tsx +1 -1
  151. package/src/Table/__tests__/Table.Caption.test.tsx +1 -1
  152. package/src/Table/__tests__/Table.Cell.test.tsx +1 -1
  153. package/src/Table/__tests__/Table.Footer.test.tsx +1 -1
  154. package/src/Table/__tests__/Table.Head.test.tsx +1 -1
  155. package/src/Table/__tests__/Table.Header.test.tsx +1 -1
  156. package/src/Table/__tests__/Table.Root.test.tsx +1 -1
  157. package/src/Table/__tests__/Table.Row.test.tsx +1 -1
  158. package/src/Table/__tests__/Table.ScrollArea.test.tsx +1 -1
  159. package/src/Table/index.ts +2 -1
  160. package/src/Tabs/Tabs.tsx +30 -10
  161. package/src/Tabs/TabsContext.ts +15 -7
  162. package/src/Tabs/__tests__/Tabs.asChild.test.tsx +1 -1
  163. package/src/Tabs/__tests__/Tabs.basic-rendering.test.tsx +1 -1
  164. package/src/Tabs/__tests__/Tabs.change-event-callbacks.test.tsx +1 -1
  165. package/src/Tabs/__tests__/Tabs.controlled-state.test.tsx +1 -1
  166. package/src/Tabs/__tests__/Tabs.error-handling.test.tsx +1 -1
  167. package/src/Tabs/__tests__/Tabs.imperative-api.test.tsx +1 -1
  168. package/src/Tabs/__tests__/Tabs.keyboard-interaction.test.tsx +1 -1
  169. package/src/Tabs/__tests__/Tabs.lazy-mount.test.tsx +1 -1
  170. package/src/Tabs/__tests__/Tabs.mouse-interaction.test.tsx +1 -1
  171. package/src/Tabs/__tests__/Tabs.reading-direction.test.tsx +1 -1
  172. package/src/Tabs/__tests__/Tabs.uncontrolled-state.test.tsx +1 -1
  173. package/src/Tabs/hooks/useTabsContent.ts +1 -1
  174. package/src/Tabs/hooks/useTabsRoot.ts +1 -1
  175. package/src/Tabs/hooks/useTabsTrigger.ts +1 -1
  176. package/src/Tabs/types.ts +35 -1
  177. package/src/Tabs/utils.ts +1 -1
  178. package/src/Textarea/Textarea.tsx +6 -3
  179. package/src/Textarea/__tests__/Textarea.field-integration.test.tsx +1 -1
  180. package/src/Textarea/types.ts +4 -0
  181. package/src/Toggle/Toggle.tsx +11 -4
  182. package/src/Toggle/types.ts +7 -3
  183. package/src/ToggleGroup/ToggleGroup.tsx +23 -13
  184. package/src/ToggleGroup/ToggleGroupContext.ts +1 -1
  185. package/src/ToggleGroup/__tests__/ToggleGroup.reading-direction.test.tsx +1 -1
  186. package/src/ToggleGroup/hooks/useToggleGroupRoot.ts +1 -1
  187. package/src/ToggleGroup/types.ts +45 -5
  188. package/src/Tooltip/Tooltip.tsx +46 -15
  189. package/src/Tooltip/TooltipContext.ts +1 -1
  190. package/src/Tooltip/hooks/useTooltipContent.ts +1 -1
  191. package/src/Tooltip/hooks/useTooltipRoot.ts +1 -1
  192. package/src/Tooltip/hooks/useTooltipTrigger.ts +1 -1
  193. package/src/Tooltip/index.ts +1 -0
  194. package/src/Tooltip/types.ts +50 -2
  195. package/src/Tree/Tree.tsx +58 -12
  196. package/src/Tree/TreeContext.ts +1 -1
  197. package/src/Tree/__tests__/Tree.selection-path.test.tsx +2 -2
  198. package/src/Tree/hooks/useTreeItemKeyboard.ts +1 -1
  199. package/src/Tree/hooks/useTreeRoot.ts +1 -1
  200. package/src/Tree/index.ts +1 -1
  201. package/src/Tree/types.ts +39 -7
  202. package/src/VisuallyHidden/VisuallyHidden.tsx +4 -2
  203. package/src/VisuallyHidden/__tests__/VisuallyHidden.test.tsx +1 -1
  204. package/src/VisuallyHidden/types.ts +4 -0
  205. package/src/index.ts +39 -38
  206. package/src/types.ts +1 -0
  207. package/src/utils/createStrictContext.ts +9 -5
@@ -1,7 +1,7 @@
1
1
  import { render, screen } from "@testing-library/react";
2
2
  import userEvent from "@testing-library/user-event";
3
3
 
4
- import { DirectionProvider } from "../../DirectionProvider";
4
+ import { DirectionProvider } from "../../DirectionProvider/index.ts";
5
5
  import { RadioGroup } from "../RadioGroup";
6
6
 
7
7
  describe("RadioGroup reading direction", () => {
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useMemo } from "react";
2
2
 
3
- import { useCollection, useControllableState } from "../../hooks";
3
+ import { useCollection, useControllableState } from "../../hooks/index.ts";
4
4
 
5
5
  type UseRadioGroupRootArgs = {
6
6
  defaultValue?: string;
@@ -1 +1,2 @@
1
1
  export * from "./RadioGroup";
2
+ export * from "./types";
@@ -10,7 +10,12 @@ export type RadioGroupOrientation = "horizontal" | "vertical" | "both";
10
10
  /** Reading direction — swaps the horizontal arrow pair when `"rtl"`. */
11
11
  export type RadioGroupReadingDirection = "ltr" | "rtl";
12
12
 
13
- type RadioGroupRootBaseProps = Omit<ComponentProps<"div">, "role"> & {
13
+ /**
14
+ * Shared base for both {@link RadioGroupRootProps} variants — the native
15
+ * `<div>` attributes (minus `role`) plus the `asChild` escape hatch,
16
+ * orientation, reading direction, and a typed `ref`.
17
+ */
18
+ export type RadioGroupRootBaseProps = Omit<ComponentProps<"div">, "role"> & {
14
19
  children?: ReactNode;
15
20
  ref?: Ref<HTMLDivElement>;
16
21
  asChild?: boolean;
@@ -18,22 +23,43 @@ type RadioGroupRootBaseProps = Omit<ComponentProps<"div">, "role"> & {
18
23
  dir?: RadioGroupReadingDirection;
19
24
  };
20
25
 
21
- type RadioGroupRootUncontrolledProps = RadioGroupRootBaseProps & {
26
+ /**
27
+ * Uncontrolled variant of {@link RadioGroupRootProps}: the component owns
28
+ * the selected value. Pass `defaultValue` (or omit it); `onValueChange` is
29
+ * optional and `value` is forbidden.
30
+ */
31
+ export type RadioGroupRootUncontrolledProps = RadioGroupRootBaseProps & {
22
32
  defaultValue?: string;
23
33
  value?: never;
24
34
  onValueChange?: (value: string) => void;
25
35
  };
26
36
 
27
- type RadioGroupRootControlledProps = RadioGroupRootBaseProps & {
37
+ /**
38
+ * Controlled variant of {@link RadioGroupRootProps}: the parent owns the
39
+ * selected value. Pass `value` and `onValueChange` together; `defaultValue`
40
+ * is forbidden.
41
+ */
42
+ export type RadioGroupRootControlledProps = RadioGroupRootBaseProps & {
28
43
  defaultValue?: never;
29
44
  value: string;
30
45
  onValueChange: (value: string) => void;
31
46
  };
32
47
 
48
+ /**
49
+ * Props for {@link RadioGroup.Root}. A discriminated union of
50
+ * {@link RadioGroupRootUncontrolledProps} and
51
+ * {@link RadioGroupRootControlledProps}, so TypeScript accepts exactly one
52
+ * state mode.
53
+ */
33
54
  export type RadioGroupRootProps =
34
55
  | RadioGroupRootUncontrolledProps
35
56
  | RadioGroupRootControlledProps;
36
57
 
58
+ /**
59
+ * Props for {@link RadioGroup.Item} — the radio button. `value` identifies
60
+ * the option; all native `<button>` attributes (minus the component-owned
61
+ * ones) plus the `asChild` escape hatch and a typed `ref` are passed through.
62
+ */
37
63
  export type RadioGroupItemProps = Omit<
38
64
  ComponentProps<"button">,
39
65
  "type" | "role" | "aria-checked" | "value"
@@ -44,6 +70,11 @@ export type RadioGroupItemProps = Omit<
44
70
  asChild?: boolean;
45
71
  };
46
72
 
73
+ /**
74
+ * Props for {@link RadioGroup.Indicator} — all `<span>` attributes plus
75
+ * `forceMount` (keep mounted while unselected for exit animations) and the
76
+ * `asChild` escape hatch.
77
+ */
47
78
  export type RadioGroupIndicatorProps = ComponentProps<"span"> & {
48
79
  children?: ReactNode;
49
80
  forceMount?: boolean;
@@ -1,7 +1,8 @@
1
1
  import { ChangeEvent, Children, isValidElement, ReactNode } from "react";
2
+ import type { ReactElement } from "react";
2
3
 
3
- import { useFieldProps } from "../Field/hooks";
4
- import { Slot } from "../Slot";
4
+ import { useFieldProps } from "../Field/hooks/index.ts";
5
+ import { Slot } from "../Slot/index.ts";
5
6
 
6
7
  import {
7
8
  SelectGroupProps,
@@ -51,7 +52,7 @@ function hasPlaceholderChild(children: ReactNode): boolean {
51
52
  * ids first, then field-supplied description / error ids). Outside a
52
53
  * `<Field.Root>`, behaviour is unchanged.
53
54
  */
54
- function SelectRoot({
55
+ export function SelectRoot({
55
56
  children,
56
57
  asChild = false,
57
58
  onChange,
@@ -59,7 +60,7 @@ function SelectRoot({
59
60
  value,
60
61
  defaultValue,
61
62
  ...consumer
62
- }: SelectRootProps) {
63
+ }: SelectRootProps): ReactElement {
63
64
  const merged = useFieldProps(consumer);
64
65
 
65
66
  const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
@@ -95,6 +96,7 @@ function SelectRoot({
95
96
  return <select {...rootProps}>{children}</select>;
96
97
  }
97
98
 
99
+ /** @internal */
98
100
  SelectRoot.displayName = "SelectRoot";
99
101
 
100
102
  /**
@@ -104,10 +106,14 @@ SelectRoot.displayName = "SelectRoot";
104
106
  * Native `<option>` only renders text; rich content (icons, descriptions)
105
107
  * is not supported.
106
108
  */
107
- function SelectOption({ children, ...rest }: SelectOptionProps) {
109
+ export function SelectOption({
110
+ children,
111
+ ...rest
112
+ }: SelectOptionProps): ReactElement {
108
113
  return <option {...rest}>{children}</option>;
109
114
  }
110
115
 
116
+ /** @internal */
111
117
  SelectOption.displayName = "SelectOption";
112
118
 
113
119
  /**
@@ -115,10 +121,14 @@ SelectOption.displayName = "SelectOption";
115
121
  * native `<optgroup>` element. The `label` is shown by the browser as a
116
122
  * non-selectable heading and is announced as the group's accessible name.
117
123
  */
118
- function SelectGroup({ children, ...rest }: SelectGroupProps) {
124
+ export function SelectGroup({
125
+ children,
126
+ ...rest
127
+ }: SelectGroupProps): ReactElement {
119
128
  return <optgroup {...rest}>{children}</optgroup>;
120
129
  }
121
130
 
131
+ /** @internal */
122
132
  SelectGroup.displayName = "SelectGroup";
123
133
 
124
134
  /**
@@ -131,7 +141,10 @@ SelectGroup.displayName = "SelectGroup";
131
141
  * Pair with `required` on {@link Select.Root} to make the browser's
132
142
  * native form validation catch an unchosen value at submission.
133
143
  */
134
- function SelectPlaceholder({ children, ...rest }: SelectPlaceholderProps) {
144
+ export function SelectPlaceholder({
145
+ children,
146
+ ...rest
147
+ }: SelectPlaceholderProps): ReactElement {
135
148
  return (
136
149
  <option {...rest} value="" disabled hidden>
137
150
  {children}
@@ -139,9 +152,11 @@ function SelectPlaceholder({ children, ...rest }: SelectPlaceholderProps) {
139
152
  );
140
153
  }
141
154
 
155
+ /** @internal */
142
156
  SelectPlaceholder.displayName = "SelectPlaceholder";
143
157
 
144
- type TSelectCompound = typeof SelectRoot & {
158
+ /** Type of the {@link Select} compound: the root callable plus its attached sub-components. */
159
+ export type TSelectCompound = typeof SelectRoot & {
145
160
  Root: typeof SelectRoot;
146
161
  Option: typeof SelectOption;
147
162
  Group: typeof SelectGroup;
@@ -1,6 +1,6 @@
1
1
  import { render, screen } from "@testing-library/react";
2
2
 
3
- import { Field } from "../../Field";
3
+ import { Field } from "../../Field/index.ts";
4
4
  import { Select } from "../Select";
5
5
 
6
6
  function renderSelect(children?: React.ReactNode) {
@@ -1,2 +1,2 @@
1
- export { Select } from "./Select";
1
+ export * from "./Select";
2
2
  export * from "./types";
@@ -1,6 +1,11 @@
1
1
  import { ChangeEventHandler, ComponentProps, ReactNode, Ref } from "react";
2
2
 
3
- type SelectRootBaseProps = Omit<
3
+ /**
4
+ * Shared base for both {@link SelectRootProps} variants — the native
5
+ * `<select>` attributes (minus the state-owning ones), the `asChild`
6
+ * escape hatch, and the raw `onChange` passthrough.
7
+ */
8
+ export type SelectRootBaseProps = Omit<
4
9
  ComponentProps<"select">,
5
10
  "value" | "defaultValue" | "multiple" | "onChange"
6
11
  > & {
@@ -22,13 +27,23 @@ type SelectRootBaseProps = Omit<
22
27
  asChild?: boolean;
23
28
  };
24
29
 
25
- type SelectRootUncontrolledProps = SelectRootBaseProps & {
30
+ /**
31
+ * Uncontrolled variant of {@link SelectRootProps}: the browser owns the
32
+ * selection. Pass `defaultValue` (or omit it); `onValueChange` is optional
33
+ * and `value` is forbidden.
34
+ */
35
+ export type SelectRootUncontrolledProps = SelectRootBaseProps & {
26
36
  defaultValue?: string;
27
37
  value?: never;
28
38
  onValueChange?: (value: string) => void;
29
39
  };
30
40
 
31
- type SelectRootControlledProps = SelectRootBaseProps & {
41
+ /**
42
+ * Controlled variant of {@link SelectRootProps}: the parent owns the
43
+ * selection. Pass `value` and `onValueChange` together; `defaultValue` is
44
+ * forbidden.
45
+ */
46
+ export type SelectRootControlledProps = SelectRootBaseProps & {
32
47
  defaultValue?: never;
33
48
  value: string;
34
49
  onValueChange: (value: string) => void;
@@ -1,3 +1,5 @@
1
+ import type { ReactElement } from "react";
2
+
1
3
  import { SkipNavContentProps, SkipNavLinkProps } from "./types";
2
4
 
3
5
  const DEFAULT_CONTENT_ID = "primitiv-skip-nav";
@@ -34,7 +36,7 @@ function SkipNavLink({
34
36
  children,
35
37
  contentId = DEFAULT_CONTENT_ID,
36
38
  ...rest
37
- }: SkipNavLinkProps) {
39
+ }: SkipNavLinkProps): ReactElement {
38
40
  return (
39
41
  <a href={`#${contentId}`} {...rest}>
40
42
  {children}
@@ -63,7 +65,10 @@ SkipNavLink.displayName = "SkipNavLink";
63
65
  * </SkipNav.Content>
64
66
  * ```
65
67
  */
66
- function SkipNavContent({ children, ...rest }: SkipNavContentProps) {
68
+ function SkipNavContent({
69
+ children,
70
+ ...rest
71
+ }: SkipNavContentProps): ReactElement {
67
72
  return (
68
73
  <div id={DEFAULT_CONTENT_ID} tabIndex={-1} {...rest}>
69
74
  {children}
@@ -1,4 +1,4 @@
1
- import { SkipNav } from "..";
1
+ import { SkipNav } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("SkipNav id wiring", () => {
@@ -1,8 +1,14 @@
1
- import { useDirection } from "../DirectionProvider";
2
- import { Slot, composeEventHandlers, composeRefs } from "../Slot";
1
+ import type { ReactElement } from "react";
2
+
3
+ import { useDirection } from "../DirectionProvider/index.ts";
4
+ import { Slot, composeEventHandlers, composeRefs } from "../Slot/index.ts";
3
5
 
4
6
  import { SliderContext } from "./SliderContext";
5
- import { useSliderContext, useSliderRoot, useSliderThumb } from "./hooks";
7
+ import {
8
+ useSliderContext,
9
+ useSliderRoot,
10
+ useSliderThumb,
11
+ } from "./hooks/index.ts";
6
12
  import type {
7
13
  SliderRangeProps,
8
14
  SliderRootProps,
@@ -68,7 +74,7 @@ import { getRangeStyle } from "./utils";
68
74
  * </Slider.Root>
69
75
  * ```
70
76
  */
71
- function SliderRoot({
77
+ export function SliderRoot({
72
78
  min = 0,
73
79
  max = 100,
74
80
  step = 1,
@@ -87,7 +93,7 @@ function SliderRoot({
87
93
  ref,
88
94
  children,
89
95
  ...rest
90
- }: SliderRootProps) {
96
+ }: SliderRootProps): ReactElement {
91
97
  const resolvedDir = dir ?? useDirection();
92
98
  const {
93
99
  contextValue,
@@ -136,6 +142,7 @@ function SliderRoot({
136
142
  );
137
143
  }
138
144
 
145
+ /** @internal */
139
146
  SliderRoot.displayName = "SliderRoot";
140
147
 
141
148
  /**
@@ -147,7 +154,11 @@ SliderRoot.displayName = "SliderRoot";
147
154
  *
148
155
  * @throws if rendered outside a `Slider.Root`.
149
156
  */
150
- function SliderTrack({ children, asChild = false, ...rest }: SliderTrackProps) {
157
+ export function SliderTrack({
158
+ children,
159
+ asChild = false,
160
+ ...rest
161
+ }: SliderTrackProps): ReactElement {
151
162
  const { orientation, disabled } = useSliderContext();
152
163
  const trackProps = {
153
164
  ...rest,
@@ -161,6 +172,7 @@ function SliderTrack({ children, asChild = false, ...rest }: SliderTrackProps) {
161
172
  );
162
173
  }
163
174
 
175
+ /** @internal */
164
176
  SliderTrack.displayName = "SliderTrack";
165
177
 
166
178
  /**
@@ -173,12 +185,12 @@ SliderTrack.displayName = "SliderTrack";
173
185
  *
174
186
  * @throws if rendered outside a `Slider.Root`.
175
187
  */
176
- function SliderRange({
188
+ export function SliderRange({
177
189
  style,
178
190
  asChild = false,
179
191
  children,
180
192
  ...rest
181
- }: SliderRangeProps) {
193
+ }: SliderRangeProps): ReactElement {
182
194
  const { values, min, max, orientation, dir, inverted, disabled } =
183
195
  useSliderContext();
184
196
  const rangeProps = {
@@ -197,6 +209,7 @@ function SliderRange({
197
209
  );
198
210
  }
199
211
 
212
+ /** @internal */
200
213
  SliderRange.displayName = "SliderRange";
201
214
 
202
215
  /**
@@ -220,14 +233,14 @@ SliderRange.displayName = "SliderRange";
220
233
  *
221
234
  * @throws if rendered outside a `Slider.Root`.
222
235
  */
223
- function SliderThumb({
236
+ export function SliderThumb({
224
237
  style,
225
238
  ref: forwardedRef,
226
239
  onKeyDown,
227
240
  asChild = false,
228
241
  children,
229
242
  ...rest
230
- }: SliderThumbProps) {
243
+ }: SliderThumbProps): ReactElement {
231
244
  const {
232
245
  ref,
233
246
  value,
@@ -260,9 +273,11 @@ function SliderThumb({
260
273
  );
261
274
  }
262
275
 
276
+ /** @internal */
263
277
  SliderThumb.displayName = "SliderThumb";
264
278
 
265
- type TSliderCompound = typeof SliderRoot & {
279
+ /** Static-property shape of the compound {@link Slider} export: the callable {@link SliderRoot} plus its namespaced sub-components. */
280
+ export type TSliderCompound = typeof SliderRoot & {
266
281
  Root: typeof SliderRoot;
267
282
  Track: typeof SliderTrack;
268
283
  Range: typeof SliderRange;
@@ -1,7 +1,9 @@
1
- import { createStrictContext } from "../utils";
1
+ import type { Context } from "react";
2
+ import { createStrictContext } from "../utils/index.ts";
2
3
 
3
4
  import type { SliderDirection, SliderOrientation } from "./types";
4
5
 
6
+ /** Shared state published by `Slider.Root` to its sub-components: the current values, range/step bounds, orientation and direction, thumb registration, and value-commit callbacks. */
5
7
  export type SliderContextValue = {
6
8
  values: number[];
7
9
  min: number;
@@ -17,8 +19,13 @@ export type SliderContextValue = {
17
19
  commit: (values: number[]) => void;
18
20
  };
19
21
 
20
- export const [SliderContext, useSliderContext] =
21
- createStrictContext<SliderContextValue>(
22
- "Slider sub-components must be rendered inside a <Slider.Root>.",
23
- "SliderContext",
24
- );
22
+ const sliderContextPair = createStrictContext<SliderContextValue>(
23
+ "Slider sub-components must be rendered inside a <Slider.Root>.",
24
+ "SliderContext",
25
+ );
26
+
27
+ /** React context carrying the {@link SliderContextValue} shared by the slider's sub-components. */
28
+ export const SliderContext: Context<SliderContextValue | null> =
29
+ sliderContextPair[0];
30
+ /** Hook returning the {@link SliderContextValue}; throws when used outside a `<Slider.Root>`. */
31
+ export const useSliderContext: () => SliderContextValue = sliderContextPair[1];
@@ -1,7 +1,7 @@
1
1
  import { fireEvent, render, screen } from "@testing-library/react";
2
2
  import userEvent from "@testing-library/user-event";
3
3
 
4
- import { DirectionProvider } from "../../DirectionProvider";
4
+ import { DirectionProvider } from "../../DirectionProvider/index.ts";
5
5
  import { Slider } from "../Slider";
6
6
 
7
7
  import { rtlKeyboardCases } from "./Slider.fixtures";
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useMemo, useRef } from "react";
2
2
  import type { PointerEvent as ReactPointerEvent } from "react";
3
3
 
4
- import { useCollection, useControllableState } from "../../hooks";
4
+ import { useCollection, useControllableState } from "../../hooks/index.ts";
5
5
  import type { SliderContextValue } from "../SliderContext";
6
6
  import type { SliderDirection, SliderOrientation } from "../types";
7
7
  import { clamp, getClosestThumbIndex, getPointerValue } from "../utils";
@@ -1,9 +1,12 @@
1
1
  import type { ComponentProps } from "react";
2
2
 
3
+ /** Layout axis of the slider track. */
3
4
  export type SliderOrientation = "horizontal" | "vertical";
5
+ /** Reading direction of the slider, affecting which end is the minimum. */
4
6
  export type SliderDirection = "ltr" | "rtl";
5
7
 
6
- type SliderRootSharedProps = Omit<
8
+ /** Props common to both controlled and uncontrolled `Slider.Root`: range/step bounds, orientation, direction, and the native `<span>` attributes. */
9
+ export type SliderRootSharedProps = Omit<
7
10
  ComponentProps<"span">,
8
11
  "defaultValue" | "dir"
9
12
  > & {
@@ -19,30 +22,36 @@ type SliderRootSharedProps = Omit<
19
22
  asChild?: boolean;
20
23
  };
21
24
 
22
- type SliderRootUncontrolledProps = SliderRootSharedProps & {
25
+ /** Uncontrolled `Slider.Root` props: seed with `defaultValue`; `value` is disallowed. */
26
+ export type SliderRootUncontrolledProps = SliderRootSharedProps & {
23
27
  defaultValue?: number[];
24
28
  value?: never;
25
29
  onValueChange?: (value: number[]) => void;
26
30
  onValueCommit?: (value: number[]) => void;
27
31
  };
28
32
 
29
- type SliderRootControlledProps = SliderRootSharedProps & {
33
+ /** Controlled `Slider.Root` props: drive with `value`; `defaultValue` is disallowed. */
34
+ export type SliderRootControlledProps = SliderRootSharedProps & {
30
35
  defaultValue?: never;
31
36
  value: number[];
32
37
  onValueChange?: (value: number[]) => void;
33
38
  onValueCommit?: (value: number[]) => void;
34
39
  };
35
40
 
41
+ /** Props for `Slider.Root` — the discriminated union of controlled ({@link SliderRootControlledProps}) and uncontrolled ({@link SliderRootUncontrolledProps}) modes. */
36
42
  export type SliderRootProps =
37
43
  | SliderRootUncontrolledProps
38
44
  | SliderRootControlledProps;
39
45
 
46
+ /** Props for `Slider.Track` — the full-length rail; native `<span>` props plus `asChild`. */
40
47
  export type SliderTrackProps = ComponentProps<"span"> & {
41
48
  asChild?: boolean;
42
49
  };
50
+ /** Props for `Slider.Range` — the filled segment between the minimum and the active thumb; native `<span>` props plus `asChild`. */
43
51
  export type SliderRangeProps = ComponentProps<"span"> & {
44
52
  asChild?: boolean;
45
53
  };
54
+ /** Props for `Slider.Thumb` — a draggable handle; native `<span>` props plus `asChild`. */
46
55
  export type SliderThumbProps = ComponentProps<"span"> & {
47
56
  asChild?: boolean;
48
57
  };
@@ -1,4 +1,6 @@
1
- import { Slot } from "../Slot";
1
+ import type { ReactElement } from "react";
2
+
3
+ import { Slot } from "../Slot/index.ts";
2
4
  import { StatusProps } from "./types";
3
5
 
4
6
  /**
@@ -31,7 +33,11 @@ import { StatusProps } from "./types";
31
33
  * </Status>
32
34
  * ```
33
35
  */
34
- export function Status({ asChild = false, children, ...rest }: StatusProps) {
36
+ export function Status({
37
+ asChild = false,
38
+ children,
39
+ ...rest
40
+ }: StatusProps): ReactElement {
35
41
  const rootProps = { role: "status", ...rest };
36
42
 
37
43
  if (asChild) {
@@ -41,4 +47,5 @@ export function Status({ asChild = false, children, ...rest }: StatusProps) {
41
47
  return <div {...rootProps}>{children}</div>;
42
48
  }
43
49
 
50
+ /** @internal */
44
51
  Status.displayName = "Status";
@@ -1,4 +1,4 @@
1
- import { Status } from "..";
1
+ import { Status } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("Status component", () => {
@@ -1,5 +1,9 @@
1
1
  import { ComponentProps } from "react";
2
2
 
3
+ /**
4
+ * Props for {@link Status} — all native `<div>` attributes plus the
5
+ * `asChild` escape hatch.
6
+ */
3
7
  export type StatusProps = ComponentProps<"div"> & {
4
8
  asChild?: boolean;
5
9
  };
@@ -1,9 +1,10 @@
1
1
  import { useMemo } from "react";
2
+ import type { ReactElement } from "react";
2
3
 
3
- import { Slot, composeEventHandlers } from "../Slot";
4
+ import { Slot, composeEventHandlers } from "../Slot/index.ts";
4
5
 
5
6
  import { SwitchContext } from "./SwitchContext";
6
- import { useSwitchContext, useSwitchRoot } from "./hooks";
7
+ import { useSwitchContext, useSwitchRoot } from "./hooks/index.ts";
7
8
  import { SwitchRootProps, SwitchThumbProps } from "./types";
8
9
 
9
10
  /**
@@ -48,7 +49,7 @@ import { SwitchRootProps, SwitchThumbProps } from "./types";
48
49
  * </Switch.Root>
49
50
  * ```
50
51
  */
51
- function SwitchRoot({
52
+ export function SwitchRoot({
52
53
  defaultChecked,
53
54
  checked,
54
55
  onCheckedChange,
@@ -58,7 +59,7 @@ function SwitchRoot({
58
59
  children,
59
60
  ref,
60
61
  ...rest
61
- }: SwitchRootProps) {
62
+ }: SwitchRootProps): ReactElement {
62
63
  const { checked: isChecked, toggle } = useSwitchRoot({
63
64
  defaultChecked,
64
65
  checked,
@@ -88,6 +89,7 @@ function SwitchRoot({
88
89
  );
89
90
  }
90
91
 
92
+ /** @internal */
91
93
  SwitchRoot.displayName = "SwitchRoot";
92
94
 
93
95
  /**
@@ -111,7 +113,11 @@ SwitchRoot.displayName = "SwitchRoot";
111
113
  *
112
114
  * @throws if rendered outside a `Switch.Root`.
113
115
  */
114
- function SwitchThumb({ children, asChild = false, ...rest }: SwitchThumbProps) {
116
+ export function SwitchThumb({
117
+ children,
118
+ asChild = false,
119
+ ...rest
120
+ }: SwitchThumbProps): ReactElement {
115
121
  const { checked } = useSwitchContext();
116
122
  const thumbProps = {
117
123
  ...rest,
@@ -124,10 +130,14 @@ function SwitchThumb({ children, asChild = false, ...rest }: SwitchThumbProps) {
124
130
  return <span {...thumbProps}>{children}</span>;
125
131
  }
126
132
 
133
+ /** @internal */
127
134
  SwitchThumb.displayName = "SwitchThumb";
128
135
 
129
- type TSwitchCompound = typeof SwitchRoot & {
136
+ /** Type of the {@link Switch} compound — the Root callable plus its sub-components. */
137
+ export type TSwitchCompound = typeof SwitchRoot & {
138
+ /** The root toggle button, owning checked state and context. */
130
139
  Root: typeof SwitchRoot;
140
+ /** The sliding thumb indicator. */
131
141
  Thumb: typeof SwitchThumb;
132
142
  };
133
143
 
@@ -1,10 +1,18 @@
1
- import { createStrictContext } from "../utils";
1
+ import type { Context } from "react";
2
+ import { createStrictContext } from "../utils/index.ts";
2
3
 
4
+ /** Value shared from `Switch.Root` to `Switch.Thumb` through context. */
3
5
  export type SwitchContextValue = {
6
+ /** Whether the switch is currently checked. */
4
7
  checked: boolean;
5
8
  };
6
9
 
7
- export const [SwitchContext, useSwitchContext] =
8
- createStrictContext<SwitchContextValue>(
9
- "Switch.Thumb must be rendered inside a <Switch.Root>.",
10
- );
10
+ const switchContextPair = createStrictContext<SwitchContextValue>(
11
+ "Switch.Thumb must be rendered inside a <Switch.Root>.",
12
+ );
13
+
14
+ /** React context carrying the {@link SwitchContextValue} for `Switch.Thumb`. */
15
+ export const SwitchContext: Context<SwitchContextValue | null> =
16
+ switchContextPair[0];
17
+ /** Read the nearest {@link SwitchContextValue}; throws outside `Switch.Root`. */
18
+ export const useSwitchContext: () => SwitchContextValue = switchContextPair[1];
@@ -1,6 +1,6 @@
1
1
  import { useCallback } from "react";
2
2
 
3
- import { useControllableState } from "../../hooks";
3
+ import { useControllableState } from "../../hooks/index.ts";
4
4
 
5
5
  type UseSwitchRootArgs = {
6
6
  defaultChecked?: boolean;