@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,9 +1,13 @@
1
1
  import { ComponentProps, ReactNode, Ref } from "react";
2
2
 
3
3
  import { CheckedState } from "../Checkbox/types";
4
- import { Direction } from "../DirectionProvider";
4
+ import { Direction } from "../DirectionProvider/index.ts";
5
5
 
6
- type DropdownRootBaseProps = {
6
+ /**
7
+ * Shared base for both {@link DropdownRootProps} variants — `children` plus
8
+ * the reading-direction control.
9
+ */
10
+ export type DropdownRootBaseProps = {
7
11
  children?: ReactNode;
8
12
  /**
9
13
  * Reading direction for the menu. Affects which arrow key opens / closes
@@ -14,22 +18,42 @@ type DropdownRootBaseProps = {
14
18
  dir?: Direction;
15
19
  };
16
20
 
17
- type DropdownRootUncontrolledProps = DropdownRootBaseProps & {
21
+ /**
22
+ * Uncontrolled variant of {@link DropdownRootProps}: the component owns the
23
+ * open state. Pass `defaultOpen` (or omit it); `onOpenChange` is optional
24
+ * and `open` is forbidden.
25
+ */
26
+ export type DropdownRootUncontrolledProps = DropdownRootBaseProps & {
18
27
  defaultOpen?: boolean;
19
28
  open?: never;
20
29
  onOpenChange?: (open: boolean) => void;
21
30
  };
22
31
 
23
- type DropdownRootControlledProps = DropdownRootBaseProps & {
32
+ /**
33
+ * Controlled variant of {@link DropdownRootProps}: the parent owns the open
34
+ * state. Pass `open` and `onOpenChange` together; `defaultOpen` is
35
+ * forbidden.
36
+ */
37
+ export type DropdownRootControlledProps = DropdownRootBaseProps & {
24
38
  defaultOpen?: never;
25
39
  open: boolean;
26
40
  onOpenChange: (open: boolean) => void;
27
41
  };
28
42
 
43
+ /**
44
+ * Props for {@link Dropdown.Root} — the controlled/uncontrolled discriminated
45
+ * union pairing {@link DropdownRootUncontrolledProps} with
46
+ * {@link DropdownRootControlledProps}, plus the shared `children` and `dir`.
47
+ */
29
48
  export type DropdownRootProps =
30
49
  | DropdownRootUncontrolledProps
31
50
  | DropdownRootControlledProps;
32
51
 
52
+ /**
53
+ * Props for {@link Dropdown.Trigger} — the button that opens the menu. Extends
54
+ * the native `<button>` props (minus the ARIA attributes Dropdown owns) and
55
+ * adds `asChild` for rendering a custom element.
56
+ */
33
57
  export type DropdownTriggerProps = Omit<
34
58
  ComponentProps<"button">,
35
59
  "aria-haspopup" | "aria-expanded" | "aria-controls"
@@ -39,6 +63,11 @@ export type DropdownTriggerProps = Omit<
39
63
  asChild?: boolean;
40
64
  };
41
65
 
66
+ /**
67
+ * Props for {@link Dropdown.Content} — the popover menu surface. Extends the
68
+ * native `<menu>` props (minus the `role`/`popover`/`id` Dropdown manages) and
69
+ * adds `asChild` for rendering a custom element.
70
+ */
42
71
  export type DropdownContentProps = Omit<
43
72
  ComponentProps<"menu">,
44
73
  "role" | "popover" | "id"
@@ -48,6 +77,11 @@ export type DropdownContentProps = Omit<
48
77
  asChild?: boolean;
49
78
  };
50
79
 
80
+ /**
81
+ * Props for {@link Dropdown.Item} — a selectable menu item. Extends the native
82
+ * `<li>` props and adds `disabled`, `asChild`, and an `onSelect` callback that
83
+ * fires on activation (click, Enter, or Space).
84
+ */
51
85
  export type DropdownItemProps = Omit<
52
86
  ComponentProps<"li">,
53
87
  "role" | "tabIndex" | "onSelect"
@@ -64,12 +98,21 @@ export type DropdownItemProps = Omit<
64
98
  onSelect?: (event: Event) => void;
65
99
  };
66
100
 
101
+ /**
102
+ * Props for {@link Dropdown.Separator} — a non-interactive divider between
103
+ * groups of items. Extends the native `<li>` props and adds `asChild`.
104
+ */
67
105
  export type DropdownSeparatorProps = Omit<ComponentProps<"li">, "role"> & {
68
106
  children?: ReactNode;
69
107
  ref?: Ref<HTMLLIElement>;
70
108
  asChild?: boolean;
71
109
  };
72
110
 
111
+ /**
112
+ * Props for {@link Dropdown.ItemIndicator} — the check/dot rendered inside a
113
+ * checkbox or radio item. Extends the native `<span>` props and adds
114
+ * `forceMount` to keep it mounted while unchecked for enter/exit animation.
115
+ */
73
116
  export type DropdownItemIndicatorProps = ComponentProps<"span"> & {
74
117
  children?: ReactNode;
75
118
  ref?: Ref<HTMLSpanElement>;
@@ -83,19 +126,31 @@ export type DropdownItemIndicatorProps = ComponentProps<"span"> & {
83
126
  forceMount?: boolean;
84
127
  };
85
128
 
129
+ /**
130
+ * Props for {@link Dropdown.Group} — a labelled grouping of related items.
131
+ * Extends the native `<li>` props and adds `asChild`.
132
+ */
86
133
  export type DropdownGroupProps = Omit<ComponentProps<"li">, "role"> & {
87
134
  children?: ReactNode;
88
135
  ref?: Ref<HTMLLIElement>;
89
136
  asChild?: boolean;
90
137
  };
91
138
 
139
+ /**
140
+ * Props for {@link Dropdown.Label} — an accessible label for a
141
+ * {@link Dropdown.Group}. Extends the native `<li>` props and adds `asChild`.
142
+ */
92
143
  export type DropdownLabelProps = ComponentProps<"li"> & {
93
144
  children?: ReactNode;
94
145
  ref?: Ref<HTMLLIElement>;
95
146
  asChild?: boolean;
96
147
  };
97
148
 
98
- type DropdownCheckboxItemBaseProps = Omit<
149
+ /**
150
+ * Shared base for both {@link DropdownCheckboxItemProps} variants — the native
151
+ * `<li>` props plus `disabled`, `asChild`, and the `onSelect` callback.
152
+ */
153
+ export type DropdownCheckboxItemBaseProps = Omit<
99
154
  ComponentProps<"li">,
100
155
  "role" | "tabIndex" | "aria-checked" | "defaultChecked" | "onSelect"
101
156
  > & {
@@ -110,44 +165,88 @@ type DropdownCheckboxItemBaseProps = Omit<
110
165
  onSelect?: (event: Event) => void;
111
166
  };
112
167
 
113
- type DropdownCheckboxItemUncontrolledProps = DropdownCheckboxItemBaseProps & {
114
- defaultChecked?: CheckedState;
115
- checked?: never;
116
- onCheckedChange?: (checked: boolean) => void;
117
- };
168
+ /**
169
+ * Uncontrolled variant of {@link DropdownCheckboxItemProps}: the component owns
170
+ * the checked state. Pass `defaultChecked` (or omit it); `onCheckedChange` is
171
+ * optional and the controlled `checked` prop is forbidden.
172
+ */
173
+ export type DropdownCheckboxItemUncontrolledProps =
174
+ DropdownCheckboxItemBaseProps & {
175
+ defaultChecked?: CheckedState;
176
+ checked?: never;
177
+ onCheckedChange?: (checked: boolean) => void;
178
+ };
118
179
 
119
- type DropdownCheckboxItemControlledProps = DropdownCheckboxItemBaseProps & {
120
- defaultChecked?: never;
121
- checked: CheckedState;
122
- onCheckedChange: (checked: boolean) => void;
123
- };
180
+ /**
181
+ * Controlled variant of {@link DropdownCheckboxItemProps}: the parent owns the
182
+ * checked state. Pass `checked` and `onCheckedChange` together;
183
+ * `defaultChecked` is forbidden.
184
+ */
185
+ export type DropdownCheckboxItemControlledProps =
186
+ DropdownCheckboxItemBaseProps & {
187
+ defaultChecked?: never;
188
+ checked: CheckedState;
189
+ onCheckedChange: (checked: boolean) => void;
190
+ };
124
191
 
192
+ /**
193
+ * Props for {@link Dropdown.CheckboxItem} — a togglable menu item. The
194
+ * controlled/uncontrolled discriminated union pairing
195
+ * {@link DropdownCheckboxItemUncontrolledProps} with
196
+ * {@link DropdownCheckboxItemControlledProps}.
197
+ */
125
198
  export type DropdownCheckboxItemProps =
126
199
  | DropdownCheckboxItemUncontrolledProps
127
200
  | DropdownCheckboxItemControlledProps;
128
201
 
129
- type DropdownRadioGroupBaseProps = Omit<ComponentProps<"li">, "role"> & {
202
+ /**
203
+ * Shared base for both {@link DropdownRadioGroupProps} variants — the native
204
+ * `<li>` props plus `asChild`.
205
+ */
206
+ export type DropdownRadioGroupBaseProps = Omit<ComponentProps<"li">, "role"> & {
130
207
  children?: ReactNode;
131
208
  ref?: Ref<HTMLLIElement>;
132
209
  asChild?: boolean;
133
210
  };
134
211
 
135
- type DropdownRadioGroupUncontrolledProps = DropdownRadioGroupBaseProps & {
136
- defaultValue?: string;
137
- value?: never;
138
- onValueChange?: (value: string) => void;
139
- };
212
+ /**
213
+ * Uncontrolled variant of {@link DropdownRadioGroupProps}: the component owns
214
+ * the selected value. Pass `defaultValue` (or omit it); `onValueChange` is
215
+ * optional and the controlled `value` prop is forbidden.
216
+ */
217
+ export type DropdownRadioGroupUncontrolledProps =
218
+ DropdownRadioGroupBaseProps & {
219
+ defaultValue?: string;
220
+ value?: never;
221
+ onValueChange?: (value: string) => void;
222
+ };
140
223
 
141
- type DropdownRadioGroupControlledProps = DropdownRadioGroupBaseProps & {
224
+ /**
225
+ * Controlled variant of {@link DropdownRadioGroupProps}: the parent owns the
226
+ * selected value. Pass `value` and `onValueChange` together; `defaultValue` is
227
+ * forbidden.
228
+ */
229
+ export type DropdownRadioGroupControlledProps = DropdownRadioGroupBaseProps & {
142
230
  defaultValue?: never;
143
231
  value: string;
144
232
  onValueChange: (value: string) => void;
145
233
  };
146
234
 
235
+ /**
236
+ * Props for {@link Dropdown.RadioGroup} — a single-select group of radio items.
237
+ * The controlled/uncontrolled discriminated union pairing
238
+ * {@link DropdownRadioGroupUncontrolledProps} with
239
+ * {@link DropdownRadioGroupControlledProps}.
240
+ */
147
241
  export type DropdownRadioGroupProps =
148
242
  | DropdownRadioGroupUncontrolledProps
149
243
  | DropdownRadioGroupControlledProps;
150
244
 
245
+ /**
246
+ * Props for {@link Dropdown.RadioItem} — one option within a
247
+ * {@link Dropdown.RadioGroup}. Extends the native `<li>` props and adds the
248
+ * required `value`, plus `disabled`, `asChild`, and `onSelect`.
249
+ */
151
250
  export type DropdownRadioItemProps = Omit<
152
251
  ComponentProps<"li">,
153
252
  "role" | "tabIndex" | "aria-checked" | "onSelect"
@@ -160,26 +259,50 @@ export type DropdownRadioItemProps = Omit<
160
259
  onSelect?: (event: Event) => void;
161
260
  };
162
261
 
163
- type DropdownSubBaseProps = {
262
+ /**
263
+ * Shared base for both {@link DropdownSubProps} variants — just the submenu
264
+ * `children`.
265
+ */
266
+ export type DropdownSubBaseProps = {
164
267
  children?: ReactNode;
165
268
  };
166
269
 
167
- type DropdownSubUncontrolledProps = DropdownSubBaseProps & {
270
+ /**
271
+ * Uncontrolled variant of {@link DropdownSubProps}: the component owns the
272
+ * submenu open state. Pass `defaultOpen` (or omit it); `onOpenChange` is
273
+ * optional and the controlled `open` prop is forbidden.
274
+ */
275
+ export type DropdownSubUncontrolledProps = DropdownSubBaseProps & {
168
276
  defaultOpen?: boolean;
169
277
  open?: never;
170
278
  onOpenChange?: (open: boolean) => void;
171
279
  };
172
280
 
173
- type DropdownSubControlledProps = DropdownSubBaseProps & {
281
+ /**
282
+ * Controlled variant of {@link DropdownSubProps}: the parent owns the submenu
283
+ * open state. Pass `open` and `onOpenChange` together; `defaultOpen` is
284
+ * forbidden.
285
+ */
286
+ export type DropdownSubControlledProps = DropdownSubBaseProps & {
174
287
  defaultOpen?: never;
175
288
  open: boolean;
176
289
  onOpenChange: (open: boolean) => void;
177
290
  };
178
291
 
292
+ /**
293
+ * Props for {@link Dropdown.Sub} — the root of a nested submenu. The
294
+ * controlled/uncontrolled discriminated union pairing
295
+ * {@link DropdownSubUncontrolledProps} with {@link DropdownSubControlledProps}.
296
+ */
179
297
  export type DropdownSubProps =
180
298
  | DropdownSubUncontrolledProps
181
299
  | DropdownSubControlledProps;
182
300
 
301
+ /**
302
+ * Props for {@link Dropdown.SubTrigger} — the item that opens a submenu.
303
+ * Extends the native `<li>` props (minus the ARIA attributes Dropdown owns) and
304
+ * adds `disabled` and `asChild`.
305
+ */
183
306
  export type DropdownSubTriggerProps = Omit<
184
307
  ComponentProps<"li">,
185
308
  "role" | "tabIndex" | "aria-haspopup" | "aria-expanded" | "aria-controls"
@@ -190,6 +313,11 @@ export type DropdownSubTriggerProps = Omit<
190
313
  disabled?: boolean;
191
314
  };
192
315
 
316
+ /**
317
+ * Props for {@link Dropdown.SubContent} — the popover surface of a submenu.
318
+ * Extends the native `<menu>` props (minus the `role`/`popover`/`id` Dropdown
319
+ * manages) and adds `asChild`.
320
+ */
193
321
  export type DropdownSubContentProps = Omit<
194
322
  ComponentProps<"menu">,
195
323
  "role" | "popover" | "id"
@@ -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 {
3
5
  EmptyStateActionsProps,
4
6
  EmptyStateDescriptionProps,
@@ -34,11 +36,11 @@ import {
34
36
  * )}
35
37
  * ```
36
38
  */
37
- function EmptyStateRoot({
39
+ export function EmptyStateRoot({
38
40
  asChild = false,
39
41
  children,
40
42
  ...rest
41
- }: EmptyStateRootProps) {
43
+ }: EmptyStateRootProps): ReactElement {
42
44
  const rootProps = { role: "status", ...rest };
43
45
 
44
46
  if (asChild) {
@@ -48,6 +50,7 @@ function EmptyStateRoot({
48
50
  return <div {...rootProps}>{children}</div>;
49
51
  }
50
52
 
53
+ /** @internal */
51
54
  EmptyStateRoot.displayName = "EmptyStateRoot";
52
55
 
53
56
  /**
@@ -72,11 +75,11 @@ EmptyStateRoot.displayName = "EmptyStateRoot";
72
75
  * </EmptyState.Media>
73
76
  * ```
74
77
  */
75
- function EmptyStateMedia({
78
+ export function EmptyStateMedia({
76
79
  asChild = false,
77
80
  children,
78
81
  ...rest
79
- }: EmptyStateMediaProps) {
82
+ }: EmptyStateMediaProps): ReactElement {
80
83
  const mediaProps = { "aria-hidden": true, ...rest };
81
84
 
82
85
  if (asChild) {
@@ -86,6 +89,7 @@ function EmptyStateMedia({
86
89
  return <div {...mediaProps}>{children}</div>;
87
90
  }
88
91
 
92
+ /** @internal */
89
93
  EmptyStateMedia.displayName = "EmptyStateMedia";
90
94
 
91
95
  /**
@@ -107,11 +111,11 @@ EmptyStateMedia.displayName = "EmptyStateMedia";
107
111
  * </EmptyState.Title>
108
112
  * ```
109
113
  */
110
- function EmptyStateTitle({
114
+ export function EmptyStateTitle({
111
115
  asChild = false,
112
116
  children,
113
117
  ...rest
114
- }: EmptyStateTitleProps) {
118
+ }: EmptyStateTitleProps): ReactElement {
115
119
  if (asChild) {
116
120
  return <Slot {...rest}>{children}</Slot>;
117
121
  }
@@ -119,6 +123,7 @@ function EmptyStateTitle({
119
123
  return <p {...rest}>{children}</p>;
120
124
  }
121
125
 
126
+ /** @internal */
122
127
  EmptyStateTitle.displayName = "EmptyStateTitle";
123
128
 
124
129
  /**
@@ -137,11 +142,11 @@ EmptyStateTitle.displayName = "EmptyStateTitle";
137
142
  * <EmptyState.Description>Try adjusting your filters.</EmptyState.Description>
138
143
  * ```
139
144
  */
140
- function EmptyStateDescription({
145
+ export function EmptyStateDescription({
141
146
  asChild = false,
142
147
  children,
143
148
  ...rest
144
- }: EmptyStateDescriptionProps) {
149
+ }: EmptyStateDescriptionProps): ReactElement {
145
150
  if (asChild) {
146
151
  return <Slot {...rest}>{children}</Slot>;
147
152
  }
@@ -149,6 +154,7 @@ function EmptyStateDescription({
149
154
  return <p {...rest}>{children}</p>;
150
155
  }
151
156
 
157
+ /** @internal */
152
158
  EmptyStateDescription.displayName = "EmptyStateDescription";
153
159
 
154
160
  /**
@@ -171,11 +177,11 @@ EmptyStateDescription.displayName = "EmptyStateDescription";
171
177
  * </EmptyState.Actions>
172
178
  * ```
173
179
  */
174
- function EmptyStateActions({
180
+ export function EmptyStateActions({
175
181
  asChild = false,
176
182
  children,
177
183
  ...rest
178
- }: EmptyStateActionsProps) {
184
+ }: EmptyStateActionsProps): ReactElement {
179
185
  if (asChild) {
180
186
  return <Slot {...rest}>{children}</Slot>;
181
187
  }
@@ -183,24 +189,23 @@ function EmptyStateActions({
183
189
  return <div {...rest}>{children}</div>;
184
190
  }
185
191
 
192
+ /** @internal */
186
193
  EmptyStateActions.displayName = "EmptyStateActions";
187
194
 
188
- type EmptyStateCompound = typeof EmptyStateRoot & {
195
+ /** Type of the {@link EmptyState} compound — the Root callable plus its sub-components. */
196
+ export type EmptyStateCompound = typeof EmptyStateRoot & {
197
+ /** The `<div role="status">` live region wrapping the placeholder. */
189
198
  Root: typeof EmptyStateRoot;
199
+ /** The decorative icon/illustration slot. */
190
200
  Media: typeof EmptyStateMedia;
201
+ /** The headline. */
191
202
  Title: typeof EmptyStateTitle;
203
+ /** The supporting copy. */
192
204
  Description: typeof EmptyStateDescription;
205
+ /** The recovery-action slot. */
193
206
  Actions: typeof EmptyStateActions;
194
207
  };
195
208
 
196
- const EmptyState: EmptyStateCompound = Object.assign(EmptyStateRoot, {
197
- Root: EmptyStateRoot,
198
- Media: EmptyStateMedia,
199
- Title: EmptyStateTitle,
200
- Description: EmptyStateDescription,
201
- Actions: EmptyStateActions,
202
- });
203
-
204
209
  /**
205
210
  * Headless, accessible **Empty State** — a stateless compound component for
206
211
  * the placeholder shown when a collection, search, or view has no content.
@@ -240,6 +245,15 @@ const EmptyState: EmptyStateCompound = Object.assign(EmptyStateRoot, {
240
245
  * )}
241
246
  * ```
242
247
  */
248
+ const EmptyState: EmptyStateCompound = Object.assign(EmptyStateRoot, {
249
+ Root: EmptyStateRoot,
250
+ Media: EmptyStateMedia,
251
+ Title: EmptyStateTitle,
252
+ Description: EmptyStateDescription,
253
+ Actions: EmptyStateActions,
254
+ });
255
+
256
+ /** @internal */
243
257
  EmptyState.displayName = "EmptyState";
244
258
 
245
259
  export { EmptyState };
@@ -1,4 +1,4 @@
1
- import { EmptyState } from "..";
1
+ import { EmptyState } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("EmptyState.Actions component", () => {
@@ -1,4 +1,4 @@
1
- import { EmptyState } from "..";
1
+ import { EmptyState } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("EmptyState.Description component", () => {
@@ -1,4 +1,4 @@
1
- import { EmptyState } from "..";
1
+ import { EmptyState } from "../index.ts";
2
2
  import { render } from "@testing-library/react";
3
3
 
4
4
  describe("EmptyState.Media component", () => {
@@ -1,4 +1,4 @@
1
- import { EmptyState } from "..";
1
+ import { EmptyState } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("EmptyState.Root component", () => {
@@ -1,4 +1,4 @@
1
- import { EmptyState } from "..";
1
+ import { EmptyState } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("EmptyState.Title component", () => {
@@ -1,6 +1,7 @@
1
1
  import { ComponentProps } from "react";
2
2
 
3
- type WithAsChild = {
3
+ /** Mixin adding the `asChild` opt-in to a sub-component's props. */
4
+ export type WithAsChild = {
4
5
  /** Render the consumer's own element instead of the default, via `Slot`. */
5
6
  asChild?: boolean;
6
7
  };
@@ -1,8 +1,9 @@
1
1
  import { useId, useMemo } from "react";
2
+ import type { ReactElement } from "react";
2
3
 
3
- import { Slot } from "../Slot";
4
+ import { Slot } from "../Slot/index.ts";
4
5
  import { FieldContext } from "./FieldContext";
5
- import { useFieldContext } from "./hooks";
6
+ import { useFieldContext } from "./hooks/index.ts";
6
7
  import {
7
8
  FieldDescriptionProps,
8
9
  FieldErrorTextProps,
@@ -45,7 +46,7 @@ import {
45
46
  * </Field.Root>
46
47
  * ```
47
48
  */
48
- function FieldRoot({
49
+ export function FieldRoot({
49
50
  id: idProp,
50
51
  invalid = false,
51
52
  disabled = false,
@@ -53,7 +54,7 @@ function FieldRoot({
53
54
  asChild = false,
54
55
  children,
55
56
  ...rest
56
- }: FieldRootProps) {
57
+ }: FieldRootProps): ReactElement {
57
58
  const autoId = useId();
58
59
  const id = idProp ?? autoId;
59
60
  const descriptionId = `${id}-description`;
@@ -83,6 +84,7 @@ function FieldRoot({
83
84
  );
84
85
  }
85
86
 
87
+ /** @internal */
86
88
  FieldRoot.displayName = "FieldRoot";
87
89
 
88
90
  /**
@@ -94,7 +96,11 @@ FieldRoot.displayName = "FieldRoot";
94
96
  *
95
97
  * @throws If rendered outside a `<Field.Root>`.
96
98
  */
97
- function FieldLabel({ asChild = false, children, ...rest }: FieldLabelProps) {
99
+ export function FieldLabel({
100
+ asChild = false,
101
+ children,
102
+ ...rest
103
+ }: FieldLabelProps): ReactElement {
98
104
  const { id } = useFieldContext();
99
105
  const labelProps = { ...rest, htmlFor: id };
100
106
 
@@ -104,6 +110,7 @@ function FieldLabel({ asChild = false, children, ...rest }: FieldLabelProps) {
104
110
  return <label {...labelProps}>{children}</label>;
105
111
  }
106
112
 
113
+ /** @internal */
107
114
  FieldLabel.displayName = "FieldLabel";
108
115
 
109
116
  /**
@@ -117,11 +124,11 @@ FieldLabel.displayName = "FieldLabel";
117
124
  *
118
125
  * @throws If rendered outside a `<Field.Root>`.
119
126
  */
120
- function FieldDescription({
127
+ export function FieldDescription({
121
128
  asChild = false,
122
129
  children,
123
130
  ...rest
124
- }: FieldDescriptionProps) {
131
+ }: FieldDescriptionProps): ReactElement {
125
132
  const { descriptionId } = useFieldContext();
126
133
  const descriptionProps = { ...rest, id: descriptionId };
127
134
 
@@ -131,6 +138,7 @@ function FieldDescription({
131
138
  return <div {...descriptionProps}>{children}</div>;
132
139
  }
133
140
 
141
+ /** @internal */
134
142
  FieldDescription.displayName = "FieldDescription";
135
143
 
136
144
  /**
@@ -151,11 +159,11 @@ FieldDescription.displayName = "FieldDescription";
151
159
  *
152
160
  * @throws If rendered outside a `<Field.Root>`.
153
161
  */
154
- function FieldErrorText({
162
+ export function FieldErrorText({
155
163
  asChild = false,
156
164
  children,
157
165
  ...rest
158
- }: FieldErrorTextProps) {
166
+ }: FieldErrorTextProps): ReactElement | null {
159
167
  const { errorId, invalid } = useFieldContext();
160
168
  if (!invalid) return null;
161
169
  const errorProps = { ...rest, id: errorId, role: "alert" as const };
@@ -166,12 +174,18 @@ function FieldErrorText({
166
174
  return <div {...errorProps}>{children}</div>;
167
175
  }
168
176
 
177
+ /** @internal */
169
178
  FieldErrorText.displayName = "FieldErrorText";
170
179
 
171
- type TFieldCompound = typeof FieldRoot & {
180
+ /** Type of the {@link Field} compound — the Root callable plus its sub-components. */
181
+ export type TFieldCompound = typeof FieldRoot & {
182
+ /** The wrapper that owns shared field state and context. */
172
183
  Root: typeof FieldRoot;
184
+ /** The field's label. */
173
185
  Label: typeof FieldLabel;
186
+ /** The field's supporting helper text. */
174
187
  Description: typeof FieldDescription;
188
+ /** The error message shown when invalid. */
175
189
  ErrorText: typeof FieldErrorText;
176
190
  };
177
191
 
@@ -1,4 +1,4 @@
1
- import { createStrictContext } from "../utils";
1
+ import { createStrictContext } from "../utils/index.ts";
2
2
 
3
3
  export type FieldContextValue = {
4
4
  /** Stable id for the control wired to this field. */
@@ -1,5 +1,6 @@
1
1
  import { ComponentProps, ReactNode } from "react";
2
2
 
3
+ /** Props for `Field.Root`, the wrapper that owns shared field state. */
3
4
  export type FieldRootProps = ComponentProps<"div"> & {
4
5
  /** Stable id wired to the control via {@link FieldLabel}'s `htmlFor`. Auto-generated via `useId` when omitted. */
5
6
  id?: string;
@@ -14,18 +15,21 @@ export type FieldRootProps = ComponentProps<"div"> & {
14
15
  children?: ReactNode;
15
16
  };
16
17
 
18
+ /** Props for `Field.Label`, the field's `<label>`. */
17
19
  export type FieldLabelProps = ComponentProps<"label"> & {
18
20
  /** Renders the consumer element instead of `<label>` via Slot. */
19
21
  asChild?: boolean;
20
22
  children?: ReactNode;
21
23
  };
22
24
 
25
+ /** Props for `Field.Description`, the field's supporting helper text. */
23
26
  export type FieldDescriptionProps = ComponentProps<"div"> & {
24
27
  /** Renders the consumer element instead of `<div>` via Slot. */
25
28
  asChild?: boolean;
26
29
  children?: ReactNode;
27
30
  };
28
31
 
32
+ /** Props for `Field.ErrorText`, the error message shown when invalid. */
29
33
  export type FieldErrorTextProps = ComponentProps<"div"> & {
30
34
  /** Renders the consumer element instead of `<div>` via Slot. */
31
35
  asChild?: boolean;