@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon Revill
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@primitiv-ui/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
+ "description": "Headless, accessible React components built on the WAI-ARIA authoring patterns. Zero styles ship with this package — bring your own (CSS, Tailwind, CSS-in-JS, design tokens).",
4
5
  "type": "module",
5
6
  "main": "./src/index.ts",
6
7
  "types": "./src/index.ts",
@@ -1,5 +1,5 @@
1
1
  import { Children, cloneElement, ReactElement } from "react";
2
- import { VisuallyHidden } from "../VisuallyHidden";
2
+ import { VisuallyHidden } from "../VisuallyHidden/index.ts";
3
3
  import { AccessibleIconProps } from "./types";
4
4
 
5
5
  type DecorativeIconProps = { "aria-hidden": string; focusable: string };
@@ -26,7 +26,10 @@ type DecorativeIconProps = { "aria-hidden": string; focusable: string };
26
26
  * </button>
27
27
  * ```
28
28
  */
29
- export function AccessibleIcon({ label, children }: AccessibleIconProps) {
29
+ export function AccessibleIcon({
30
+ label,
31
+ children,
32
+ }: AccessibleIconProps): ReactElement {
30
33
  const icon = Children.only(children) as ReactElement<DecorativeIconProps>;
31
34
 
32
35
  return (
@@ -37,4 +40,5 @@ export function AccessibleIcon({ label, children }: AccessibleIconProps) {
37
40
  );
38
41
  }
39
42
 
43
+ /** @internal */
40
44
  AccessibleIcon.displayName = "AccessibleIcon";
@@ -1,4 +1,4 @@
1
- import { AccessibleIcon } from "..";
1
+ import { AccessibleIcon } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("AccessibleIcon component", () => {
@@ -1,5 +1,9 @@
1
1
  import { ReactElement } from "react";
2
2
 
3
+ /**
4
+ * Props for {@link AccessibleIcon} — a single icon element plus the
5
+ * visually-hidden `label` announced as its accessible name.
6
+ */
3
7
  export type AccessibleIconProps = {
4
8
  /** Text announced by assistive technology as the icon's accessible name. */
5
9
  label: string;
@@ -1,7 +1,8 @@
1
1
  import { Ref, useEffect } from "react";
2
+ import type { ReactElement } from "react";
2
3
 
3
- import { useDirection } from "../DirectionProvider";
4
- import { Slot } from "../Slot";
4
+ import { useDirection } from "../DirectionProvider/index.ts";
5
+ import { Slot } from "../Slot/index.ts";
5
6
 
6
7
  import type {
7
8
  AccordionRootProps,
@@ -21,7 +22,7 @@ import {
21
22
  useAccordionItem,
22
23
  useAccordionItemContext,
23
24
  useAccordionRoot,
24
- } from "./hooks";
25
+ } from "./hooks/index.ts";
25
26
  import { useAccordionTrigger } from "./hooks/useAccordionTrigger";
26
27
 
27
28
  /**
@@ -78,7 +79,7 @@ export function AccordionRoot({
78
79
  orientation = "vertical",
79
80
  dir,
80
81
  ...rest
81
- }: AccordionRootProps) {
82
+ }: AccordionRootProps): ReactElement {
82
83
  const resolvedDir = dir ?? useDirection();
83
84
  const { contextValue } = useAccordionRoot(
84
85
  controlledValue,
@@ -98,6 +99,7 @@ export function AccordionRoot({
98
99
  );
99
100
  }
100
101
 
102
+ /** @internal */
101
103
  AccordionRoot.displayName = "AccordionRoot";
102
104
 
103
105
  /**
@@ -124,7 +126,7 @@ export function AccordionItem({
124
126
  children,
125
127
  value,
126
128
  ...rest
127
- }: AccordionItemProps) {
129
+ }: AccordionItemProps): ReactElement {
128
130
  const { contextValue } = useAccordionItem(value);
129
131
 
130
132
  return (
@@ -134,6 +136,7 @@ export function AccordionItem({
134
136
  );
135
137
  }
136
138
 
139
+ /** @internal */
137
140
  AccordionItem.displayName = "AccordionItem";
138
141
 
139
142
  /**
@@ -156,13 +159,14 @@ export function AccordionHeader({
156
159
  children,
157
160
  level = 3,
158
161
  ...rest
159
- }: AccordionHeaderProps) {
162
+ }: AccordionHeaderProps): ReactElement {
160
163
  useAccordionHeaderContext();
161
164
  const HeadingTag: HeadingTag = `h${level}`;
162
165
 
163
166
  return <HeadingTag {...rest}>{children}</HeadingTag>;
164
167
  }
165
168
 
169
+ /** @internal */
166
170
  AccordionHeader.displayName = "AccordionHeader";
167
171
 
168
172
  /**
@@ -229,16 +233,14 @@ AccordionHeader.displayName = "AccordionHeader";
229
233
  * </Accordion.Trigger>
230
234
  * ```
231
235
  */
232
- export function AccordionTrigger<
233
- T extends HTMLElement = HTMLButtonElement,
234
- >({
236
+ export function AccordionTrigger<T extends HTMLElement = HTMLButtonElement>({
235
237
  ref,
236
238
  children,
237
239
  onClick,
238
240
  disabled = false,
239
241
  asChild = false,
240
242
  ...rest
241
- }: AccordionTriggerProps<T>) {
243
+ }: AccordionTriggerProps<T>): ReactElement {
242
244
  // Cast the external ref to match the internal button ref's element type —
243
245
  // RefObject<T> is invariant in React's types, but at runtime the callback
244
246
  // receives whatever DOM element is actually rendered (button or asChild).
@@ -261,6 +263,7 @@ export function AccordionTrigger<
261
263
  );
262
264
  }
263
265
 
266
+ /** @internal */
264
267
  AccordionTrigger.displayName = "AccordionTrigger";
265
268
 
266
269
  /**
@@ -306,7 +309,7 @@ export function AccordionContent({
306
309
  children,
307
310
  forceMount = false,
308
311
  ...rest
309
- }: AccordionContentProps) {
312
+ }: AccordionContentProps): ReactElement {
310
313
  const { panelId, buttonId, itemId, isExpanded } = useAccordionItemContext();
311
314
  const { registerPanel, unregisterPanel } = useAccordionContext();
312
315
 
@@ -330,6 +333,7 @@ export function AccordionContent({
330
333
  );
331
334
  }
332
335
 
336
+ /** @internal */
333
337
  AccordionContent.displayName = "AccordionContent";
334
338
 
335
339
  /**
@@ -373,7 +377,7 @@ AccordionContent.displayName = "AccordionContent";
373
377
  export function AccordionTriggerIcon({
374
378
  children,
375
379
  ...rest
376
- }: AccordionTriggerIconProps) {
380
+ }: AccordionTriggerIconProps): ReactElement {
377
381
  const { isExpanded } = useAccordionItemContext();
378
382
 
379
383
  return (
@@ -387,8 +391,10 @@ export function AccordionTriggerIcon({
387
391
  );
388
392
  }
389
393
 
394
+ /** @internal */
390
395
  AccordionTriggerIcon.displayName = "AccordionTriggerIcon";
391
396
 
397
+ /** @internal */
392
398
  type AccordionCompound = typeof AccordionRoot & {
393
399
  Root: typeof AccordionRoot;
394
400
  Item: typeof AccordionItem;
@@ -398,6 +404,22 @@ type AccordionCompound = typeof AccordionRoot & {
398
404
  TriggerIcon: typeof AccordionTriggerIcon;
399
405
  };
400
406
 
407
+ /**
408
+ * Headless, accessible **Accordion** — a compound component for a vertically
409
+ * (or horizontally) stacked set of collapsible sections, following the
410
+ * [WAI-ARIA Accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/)
411
+ * with zero styles.
412
+ *
413
+ * `Accordion` is both callable (an alias of {@link AccordionRoot | `Accordion.Root`})
414
+ * and carries its sub-components as static properties:
415
+ *
416
+ * - {@link AccordionRoot | `Accordion.Root`} — state owner and context provider.
417
+ * - {@link AccordionItem | `Accordion.Item`} — one collapsible section.
418
+ * - {@link AccordionHeader | `Accordion.Header`} — heading wrapper for the trigger.
419
+ * - {@link AccordionTrigger | `Accordion.Trigger`} — button that toggles the section.
420
+ * - {@link AccordionContent | `Accordion.Content`} — the collapsible panel.
421
+ * - {@link AccordionTriggerIcon | `Accordion.TriggerIcon`} — decorative state indicator.
422
+ */
401
423
  const AccordionCompound: AccordionCompound = Object.assign(AccordionRoot, {
402
424
  Root: AccordionRoot,
403
425
  Item: AccordionItem,
@@ -1,4 +1,4 @@
1
- import { createStrictContext } from "../utils";
1
+ import { createStrictContext } from "../utils/index.ts";
2
2
  import { AccordionContextValue, AccordionItemContextValue } from "./types";
3
3
 
4
4
  export const [AccordionContext, useAccordionContext] =
@@ -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 { Accordion } from "../Accordion";
6
6
 
7
7
  describe("Accordion reading direction tests", () => {
@@ -1,6 +1,6 @@
1
1
  import { useId, useMemo } from "react";
2
2
 
3
- import { deriveId } from "../../utils";
3
+ import { deriveId } from "../../utils/index.ts";
4
4
 
5
5
  import { useAccordionContext } from "./useAccordionContext";
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { useRef, useMemo, useCallback, useId, useEffect } from "react";
2
2
 
3
- import { useCollection, useControllableState } from "../../hooks";
3
+ import { useCollection, useControllableState } from "../../hooks/index.ts";
4
4
 
5
5
  import type { AccordionReadingDirection } from "../types";
6
6
 
@@ -1,7 +1,7 @@
1
1
  import { useMemo, useRef, useEffect, MouseEvent, KeyboardEvent } from "react";
2
2
 
3
- import { useRovingTabindex } from "../../hooks";
4
- import { composeRefs } from "../../Slot";
3
+ import { useRovingTabindex } from "../../hooks/index.ts";
4
+ import { composeRefs } from "../../Slot/index.ts";
5
5
 
6
6
  import { AccordionTriggerProps } from "../types";
7
7
 
@@ -1 +1,2 @@
1
- export * from './Accordion';
1
+ export * from "./Accordion";
2
+ export * from "./types";
@@ -1,81 +1,123 @@
1
1
  import { ComponentProps, ReactNode, Ref } from "react";
2
2
  import { HeadingLevel } from "../types";
3
3
 
4
- type AccordionRootBaseProps = ComponentProps<"div"> & {
4
+ /** Props shared by both control modes of `Accordion.Root`. */
5
+ export type AccordionRootBaseProps = ComponentProps<"div"> & {
6
+ /** Allow more than one section to be expanded at a time. */
5
7
  multiple?: boolean;
8
+ /** Layout axis, controlling arrow-key navigation. Defaults to `"vertical"`. */
6
9
  orientation?: "vertical" | "horizontal";
10
+ /** Reading direction, controlling left/right key semantics. */
7
11
  dir?: AccordionReadingDirection;
8
12
  };
9
13
 
10
- type AccordionRootUncontrolledProps = AccordionRootBaseProps & {
14
+ /** `Accordion.Root` props for the uncontrolled (self-managed) expanded state. */
15
+ export type AccordionRootUncontrolledProps = AccordionRootBaseProps & {
16
+ /** Initially expanded item value when uncontrolled. */
11
17
  defaultValue?: string;
12
18
  value?: never;
13
19
  onValueChange?: never;
14
20
  };
15
21
 
16
- type AccordionRootControlledProps = AccordionRootBaseProps & {
22
+ /** `Accordion.Root` props for the controlled expanded state. */
23
+ export type AccordionRootControlledProps = AccordionRootBaseProps & {
17
24
  defaultValue?: never;
25
+ /** Controlled set of expanded item values. */
18
26
  value: string[];
27
+ /** Called whenever the set of expanded item values changes. */
19
28
  onValueChange: (values: string[]) => void;
20
29
  };
21
30
 
31
+ /** Reading direction for an accordion. */
22
32
  export type AccordionReadingDirection = "ltr" | "rtl";
23
33
 
34
+ /** Props for `Accordion.Root`, in either the controlled or uncontrolled mode. */
24
35
  export type AccordionRootProps =
25
36
  | AccordionRootUncontrolledProps
26
37
  | AccordionRootControlledProps;
27
38
 
39
+ /** Props for `Accordion.Item` — a single collapsible section. */
28
40
  export type AccordionItemProps = ComponentProps<"div"> & {
41
+ /** Section contents — typically a `Header` + `Content` pair. */
29
42
  children: ReactNode;
43
+ /** Stable value identifying the item; auto-generated via `useId()` when omitted. */
30
44
  value?: string; // Optional - if not provided, useId() will generate one
31
45
  };
32
46
 
33
- export type AccordionTriggerProps<
34
- T extends HTMLElement = HTMLButtonElement,
35
- > = Omit<ComponentProps<"button">, "disabled" | "ref"> & {
36
- children: ReactNode;
37
- disabled?: boolean;
38
- asChild?: boolean;
39
- /** Ref to the rendered element. Defaults to `HTMLButtonElement`; when using
40
- * `asChild`, specify the child's element type (e.g. `HTMLAnchorElement`). */
41
- ref?: Ref<T>;
42
- };
47
+ /** Props for `Accordion.Trigger` — the button that toggles a section. */
48
+ export type AccordionTriggerProps<T extends HTMLElement = HTMLButtonElement> =
49
+ Omit<ComponentProps<"button">, "disabled" | "ref"> & {
50
+ /** Trigger label / contents. */
51
+ children: ReactNode;
52
+ /** Disable the trigger, removing it from keyboard navigation. */
53
+ disabled?: boolean;
54
+ /** Render into the consumer's own element instead of a `<button>`. */
55
+ asChild?: boolean;
56
+ /** Ref to the rendered element. Defaults to `HTMLButtonElement`; when using
57
+ * `asChild`, specify the child's element type (e.g. `HTMLAnchorElement`). */
58
+ ref?: Ref<T>;
59
+ };
43
60
 
61
+ /** Props for `Accordion.Header` — the heading wrapping a trigger. */
44
62
  export type AccordionHeaderProps = ComponentProps<"h3"> & {
63
+ /** Header contents — typically an `Accordion.Trigger`. */
45
64
  children: ReactNode;
65
+ /** Heading level rendered (`h1`–`h6`). Defaults to `3`. */
46
66
  level?: HeadingLevel;
47
67
  };
48
68
 
69
+ /** Props for `Accordion.Content` — the collapsible panel. */
49
70
  export type AccordionContentProps = ComponentProps<"div"> & {
71
+ /** Panel contents. */
50
72
  children: ReactNode;
73
+ /** Keep the panel mounted even while collapsed. */
51
74
  forceMount?: boolean;
52
75
  };
53
76
 
77
+ /** Props for `Accordion.TriggerIcon` — a decorative open/closed indicator. */
54
78
  export type AccordionTriggerIconProps = ComponentProps<"span"> & {
79
+ /** Icon contents. */
55
80
  children: ReactNode;
56
81
  };
57
82
 
83
+ /** Context value published by `Accordion.Root` to coordinate its sections. */
58
84
  export type AccordionContextValue = {
85
+ /** Generated id namespacing the accordion's element ids. */
59
86
  accordionId: string;
87
+ /** Set of currently expanded item values. */
60
88
  expandedItems: Set<string>;
89
+ /** Layout axis used for arrow-key navigation. */
61
90
  orientation: "vertical" | "horizontal";
91
+ /** Reading direction used for left/right key semantics. */
62
92
  dir: AccordionReadingDirection;
93
+ /** Toggles the expanded state of the given item. */
63
94
  toggleItem: (itemId: string) => void;
95
+ /** Registers a trigger element so roving focus can reach it. */
64
96
  registerTrigger: (
65
97
  itemId: string,
66
98
  element: HTMLButtonElement | null,
67
99
  disabled?: boolean,
68
100
  ) => void;
101
+ /** Ordered ids of registered triggers, used for focus movement. */
69
102
  registeredTriggerItemIds: string[];
103
+ /** Set of item ids whose triggers are disabled. */
70
104
  disabledItemIds: Set<string>;
105
+ /** Moves focus to the given item's trigger. */
71
106
  focusTrigger: (itemId: string) => void;
107
+ /** Registers a content panel as mounted. */
72
108
  registerPanel: (itemId: string) => void;
109
+ /** Removes a previously registered content panel. */
73
110
  unregisterPanel: (itemId: string) => void;
74
111
  };
75
112
 
113
+ /** Context value published by `Accordion.Item` to its header and content. */
76
114
  export type AccordionItemContextValue = {
115
+ /** Id of the trigger button. */
77
116
  buttonId: string;
117
+ /** Id of the content panel. */
78
118
  panelId: string;
119
+ /** Stable value identifying this item. */
79
120
  itemId: string;
121
+ /** Whether this item is currently expanded. */
80
122
  isExpanded: boolean;
81
123
  };
@@ -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 { AlertProps } from "./types";
3
5
 
4
6
  /**
@@ -30,7 +32,11 @@ import { AlertProps } from "./types";
30
32
  * </Alert>
31
33
  * ```
32
34
  */
33
- export function Alert({ asChild = false, children, ...rest }: AlertProps) {
35
+ export function Alert({
36
+ asChild = false,
37
+ children,
38
+ ...rest
39
+ }: AlertProps): ReactElement {
34
40
  const rootProps = { role: "alert", ...rest };
35
41
 
36
42
  if (asChild) {
@@ -40,4 +46,5 @@ export function Alert({ asChild = false, children, ...rest }: AlertProps) {
40
46
  return <div {...rootProps}>{children}</div>;
41
47
  }
42
48
 
49
+ /** @internal */
43
50
  Alert.displayName = "Alert";
@@ -1,4 +1,4 @@
1
- import { Alert } from "..";
1
+ import { Alert } from "../index.ts";
2
2
  import { render, screen } from "@testing-library/react";
3
3
 
4
4
  describe("Alert component", () => {
@@ -1,5 +1,6 @@
1
1
  import { ComponentProps } from "react";
2
2
 
3
+ /** Props for the `Alert` — a live-region `<div role="alert">`; native `<div>` props plus `asChild`. */
3
4
  export type AlertProps = ComponentProps<"div"> & {
4
5
  asChild?: boolean;
5
6
  };
@@ -1,9 +1,10 @@
1
1
  import { useEffect, useMemo, useState } from "react";
2
+ import type { ReactElement } from "react";
2
3
 
3
- import { Slot } from "../Slot";
4
+ import { Slot } from "../Slot/index.ts";
4
5
 
5
6
  import { AvatarContext } from "./AvatarContext";
6
- import { useAvatarContext, useAvatarImage } from "./hooks";
7
+ import { useAvatarContext, useAvatarImage } from "./hooks/index.ts";
7
8
  import {
8
9
  AvatarFallbackProps,
9
10
  AvatarImageLoadingStatus,
@@ -22,7 +23,11 @@ import {
22
23
  * **`asChild` prop.** Pass `asChild` to render the consumer's own element as
23
24
  * the container, with the `data-status` hook merged in.
24
25
  */
25
- function AvatarRoot({ asChild = false, children, ...rest }: AvatarRootProps) {
26
+ export function AvatarRoot({
27
+ asChild = false,
28
+ children,
29
+ ...rest
30
+ }: AvatarRootProps): ReactElement {
26
31
  const [status, setStatus] = useState<AvatarImageLoadingStatus>("idle");
27
32
 
28
33
  const contextValue = useMemo(() => ({ status, setStatus }), [status]);
@@ -40,6 +45,7 @@ function AvatarRoot({ asChild = false, children, ...rest }: AvatarRootProps) {
40
45
  );
41
46
  }
42
47
 
48
+ /** @internal */
43
49
  AvatarRoot.displayName = "AvatarRoot";
44
50
 
45
51
  /**
@@ -55,7 +61,11 @@ AvatarRoot.displayName = "AvatarRoot";
55
61
  *
56
62
  * @throws if rendered outside an `Avatar.Root`.
57
63
  */
58
- function AvatarImage({ asChild = false, children, ...rest }: AvatarImageProps) {
64
+ export function AvatarImage({
65
+ asChild = false,
66
+ children,
67
+ ...rest
68
+ }: AvatarImageProps): ReactElement {
59
69
  const { status, setStatus } = useAvatarContext();
60
70
  const { ref, onLoad, onError } = useAvatarImage(setStatus);
61
71
 
@@ -77,6 +87,7 @@ function AvatarImage({ asChild = false, children, ...rest }: AvatarImageProps) {
77
87
  return <img {...imageProps} ref={ref} />;
78
88
  }
79
89
 
90
+ /** @internal */
80
91
  AvatarImage.displayName = "AvatarImage";
81
92
 
82
93
  /**
@@ -92,12 +103,12 @@ AvatarImage.displayName = "AvatarImage";
92
103
  *
93
104
  * @throws if rendered outside an `Avatar.Root`.
94
105
  */
95
- function AvatarFallback({
106
+ export function AvatarFallback({
96
107
  delayMs,
97
108
  asChild = false,
98
109
  children,
99
110
  ...rest
100
- }: AvatarFallbackProps) {
111
+ }: AvatarFallbackProps): ReactElement | null {
101
112
  const { status } = useAvatarContext();
102
113
  const [delayElapsed, setDelayElapsed] = useState(delayMs === undefined);
103
114
 
@@ -122,9 +133,11 @@ function AvatarFallback({
122
133
  return <span {...fallbackProps}>{children}</span>;
123
134
  }
124
135
 
136
+ /** @internal */
125
137
  AvatarFallback.displayName = "AvatarFallback";
126
138
 
127
- type TAvatarCompound = typeof AvatarRoot & {
139
+ /** Static-property shape of the compound {@link Avatar} export: the callable {@link AvatarRoot} plus its namespaced sub-components. */
140
+ export type TAvatarCompound = typeof AvatarRoot & {
128
141
  Root: typeof AvatarRoot;
129
142
  Image: typeof AvatarImage;
130
143
  Fallback: typeof AvatarFallback;
@@ -1,4 +1,5 @@
1
- import { createStrictContext } from "../utils";
1
+ import type { Context } from "react";
2
+ import { createStrictContext } from "../utils/index.ts";
2
3
 
3
4
  import { AvatarImageLoadingStatus } from "./types";
4
5
 
@@ -13,8 +14,13 @@ export type AvatarContextValue = {
13
14
  setStatus: (status: AvatarImageLoadingStatus) => void;
14
15
  };
15
16
 
16
- export const [AvatarContext, useAvatarContext] =
17
- createStrictContext<AvatarContextValue>(
18
- "Avatar.Image and Avatar.Fallback must be rendered inside an <Avatar.Root>.",
19
- "AvatarContext",
20
- );
17
+ const avatarContextPair = createStrictContext<AvatarContextValue>(
18
+ "Avatar.Image and Avatar.Fallback must be rendered inside an <Avatar.Root>.",
19
+ "AvatarContext",
20
+ );
21
+
22
+ /** React context carrying the {@link AvatarContextValue} shared by the avatar's sub-components. */
23
+ export const AvatarContext: Context<AvatarContextValue | null> =
24
+ avatarContextPair[0];
25
+ /** Hook returning the {@link AvatarContextValue}; throws when used outside an `<Avatar.Root>`. */
26
+ export const useAvatarContext: () => AvatarContextValue = avatarContextPair[1];