@primitiv-ui/react 0.1.28 → 0.1.29

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 (307) hide show
  1. package/README.md +4 -0
  2. package/package.json +6 -1
  3. package/src/AccessibleIcon/AccessibleIcon.tsx +32 -9
  4. package/src/AccessibleIcon/__tests__/AccessibleIcon.test.tsx +5 -0
  5. package/src/AccessibleIcon/types.ts +15 -2
  6. package/src/Accordion/Accordion.tsx +25 -4
  7. package/src/Accordion/__tests__/Accordion.asChild.test.tsx +46 -0
  8. package/src/Accordion/__tests__/Accordion.basic-rendering.test.tsx +15 -0
  9. package/src/Accordion/__tests__/Accordion.disabled-items.test.tsx +42 -0
  10. package/src/Accordion/__tests__/Accordion.error-handling.test.tsx +33 -0
  11. package/src/Accordion/hooks/useAccordionRoot.ts +44 -7
  12. package/src/Accordion/hooks/useAccordionTrigger.ts +9 -1
  13. package/src/Accordion/types.ts +72 -21
  14. package/src/Alert/Alert.tsx +36 -7
  15. package/src/Alert/__tests__/Alert.test.tsx +5 -0
  16. package/src/Alert/types.ts +18 -2
  17. package/src/Avatar/Avatar.tsx +99 -15
  18. package/src/Avatar/__tests__/Avatar.basic-rendering.test.tsx +10 -0
  19. package/src/Avatar/__tests__/Avatar.fallback.test.tsx +30 -0
  20. package/src/Avatar/__tests__/Avatar.image-loading.test.tsx +35 -0
  21. package/src/Avatar/hooks/useAvatarImage.ts +16 -0
  22. package/src/Avatar/types.ts +15 -3
  23. package/src/Breadcrumb/Breadcrumb.tsx +136 -18
  24. package/src/Breadcrumb/README.md +47 -0
  25. package/src/Breadcrumb/__tests__/Breadcrumb.basic-rendering.test.tsx +11 -0
  26. package/src/Breadcrumb/__tests__/Breadcrumb.ellipsis.test.tsx +110 -0
  27. package/src/Breadcrumb/types.ts +73 -7
  28. package/src/Button/Button.tsx +2 -0
  29. package/src/Button/__tests__/Button.basic-rendering.test.tsx +6 -0
  30. package/src/Button/types.ts +21 -0
  31. package/src/Carousel/Carousel.tsx +263 -15
  32. package/src/Carousel/README.md +749 -72
  33. package/src/Carousel/__tests__/Carousel.autoplay-status.test.tsx +239 -0
  34. package/src/Carousel/__tests__/Carousel.drag-status.test.tsx +292 -0
  35. package/src/Carousel/__tests__/Carousel.dynamic-slides.test.tsx +38 -0
  36. package/src/Carousel/__tests__/Carousel.indicators.test.tsx +101 -0
  37. package/src/Carousel/__tests__/Carousel.infinite.test.tsx +1453 -0
  38. package/src/Carousel/__tests__/Carousel.instant-scroll.test.tsx +124 -0
  39. package/src/Carousel/__tests__/Carousel.intersection-observer.test.tsx +88 -0
  40. package/src/Carousel/__tests__/Carousel.loop.test.tsx +163 -0
  41. package/src/Carousel/__tests__/Carousel.loopEngine.test.ts +77 -0
  42. package/src/Carousel/__tests__/Carousel.mouse-drag.test.tsx +504 -0
  43. package/src/Carousel/__tests__/Carousel.multi-slide-bounds.test.tsx +91 -0
  44. package/src/Carousel/__tests__/Carousel.orientation.test.tsx +207 -0
  45. package/src/Carousel/__tests__/Carousel.overscroll.test.tsx +532 -0
  46. package/src/Carousel/__tests__/Carousel.page-snap-points.test.tsx +50 -0
  47. package/src/Carousel/__tests__/Carousel.progress-text.test.tsx +76 -0
  48. package/src/Carousel/__tests__/Carousel.reduced-motion.test.tsx +3 -6
  49. package/src/Carousel/__tests__/Carousel.refresh-progress.test.tsx +2 -5
  50. package/src/Carousel/__tests__/Carousel.scroll-margin.test.tsx +167 -0
  51. package/src/Carousel/__tests__/Carousel.scroll-progress.test.tsx +518 -0
  52. package/src/Carousel/__tests__/Carousel.scroll-snap-change.test.tsx +32 -11
  53. package/src/Carousel/__tests__/Carousel.scroll-sync.test.tsx +237 -24
  54. package/src/Carousel/__tests__/Carousel.scroll-to-index.test.tsx +115 -0
  55. package/src/Carousel/__tests__/Carousel.slide-snap.test.tsx +172 -0
  56. package/src/Carousel/__tests__/Carousel.slides-per-move.test.tsx +179 -1
  57. package/src/Carousel/__tests__/Carousel.slides-per-page.test.tsx +91 -7
  58. package/src/Carousel/__tests__/Carousel.snap-type.test.tsx +35 -0
  59. package/src/Carousel/__tests__/Carousel.transition-modes.test.tsx +30 -5
  60. package/src/Carousel/__tests__/Carousel.translations.test.tsx +23 -0
  61. package/src/Carousel/__tests__/Carousel.wheel.test.tsx +160 -0
  62. package/src/Carousel/hooks/index.ts +1 -0
  63. package/src/Carousel/hooks/useCarouselLoop.ts +869 -0
  64. package/src/Carousel/hooks/useCarouselRoot.ts +338 -42
  65. package/src/Carousel/hooks/useCarouselSlide.ts +44 -9
  66. package/src/Carousel/hooks/useCarouselViewport.ts +649 -46
  67. package/src/Carousel/loopEngine.ts +54 -0
  68. package/src/Carousel/types.ts +457 -35
  69. package/src/Checkbox/Checkbox.tsx +9 -1
  70. package/src/Checkbox/__tests__/Checkbox.basic-rendering.test.tsx +14 -0
  71. package/src/Checkbox/hooks/useCheckboxInput.ts +4 -0
  72. package/src/Checkbox/types.ts +19 -0
  73. package/src/CheckboxCard/CheckboxCard.tsx +13 -4
  74. package/src/CheckboxCard/__tests__/CheckboxCard.basic-rendering.test.tsx +7 -0
  75. package/src/CheckboxCard/types.ts +65 -17
  76. package/src/Collapsible/Collapsible.tsx +49 -3
  77. package/src/Collapsible/README.md +40 -0
  78. package/src/Collapsible/__tests__/Collapsible.asChild.test.tsx +89 -0
  79. package/src/Collapsible/__tests__/Collapsible.basic-rendering.test.tsx +27 -0
  80. package/src/Collapsible/__tests__/Collapsible.collapsedHeight.test.tsx +140 -0
  81. package/src/Collapsible/hooks/useCollapsibleTrigger.ts +3 -1
  82. package/src/Collapsible/types.ts +89 -22
  83. package/src/ContextMenu/ContextMenu.tsx +270 -4
  84. package/src/ContextMenu/types.ts +148 -6
  85. package/src/DirectionProvider/DirectionProvider.tsx +41 -9
  86. package/src/DirectionProvider/__tests__/DirectionProvider.test.tsx +5 -0
  87. package/src/DirectionProvider/types.ts +28 -3
  88. package/src/Divider/Divider.tsx +24 -10
  89. package/src/Divider/__tests__/Divider.test.tsx +5 -0
  90. package/src/Divider/types.ts +10 -3
  91. package/src/Drawer/Drawer.tsx +315 -0
  92. package/src/Drawer/README.md +124 -0
  93. package/src/Drawer/__tests__/Drawer.behavior.test.tsx +100 -0
  94. package/src/Drawer/__tests__/Drawer.focus-trap.test.tsx +55 -0
  95. package/src/Drawer/__tests__/Drawer.rendering.test.tsx +111 -0
  96. package/src/Drawer/__tests__/Drawer.side.test.tsx +69 -0
  97. package/src/Drawer/__tests__/dialog-polyfill.ts +39 -0
  98. package/src/Drawer/index.ts +2 -0
  99. package/src/Drawer/types.ts +66 -0
  100. package/src/Dropdown/Dropdown.tsx +117 -0
  101. package/src/Dropdown/types.ts +241 -11
  102. package/src/EmptyState/EmptyState.tsx +74 -4
  103. package/src/EmptyState/__tests__/EmptyState.Actions.test.tsx +7 -2
  104. package/src/EmptyState/__tests__/EmptyState.Description.test.tsx +3 -1
  105. package/src/EmptyState/__tests__/EmptyState.Root.test.tsx +10 -0
  106. package/src/EmptyState/__tests__/EmptyState.Title.test.tsx +3 -1
  107. package/src/EmptyState/types.ts +49 -6
  108. package/src/Field/Field.tsx +23 -0
  109. package/src/Field/__tests__/Field.basic-rendering.test.tsx +11 -0
  110. package/src/Field/__tests__/Field.error-handling.test.tsx +23 -0
  111. package/src/Field/__tests__/Field.state-cascade.test.tsx +21 -0
  112. package/src/Field/hooks/__tests__/useFieldProps.test.tsx +104 -9
  113. package/src/Field/types.ts +60 -12
  114. package/src/Fieldset/Fieldset.tsx +54 -18
  115. package/src/Fieldset/__tests__/Fieldset.basic-rendering.test.tsx +9 -0
  116. package/src/Fieldset/types.ts +20 -2
  117. package/src/Input/Input.tsx +14 -9
  118. package/src/Input/__tests__/Input.basic-rendering.test.tsx +5 -0
  119. package/src/Input/types.ts +19 -2
  120. package/src/InputGroup/InputGroup.tsx +11 -3
  121. package/src/InputGroup/__tests__/InputGroup.basic-rendering.test.tsx +14 -0
  122. package/src/InputGroup/types.ts +26 -5
  123. package/src/MillerColumns/MillerColumns.tsx +86 -19
  124. package/src/MillerColumns/types.ts +83 -27
  125. package/src/Modal/Modal.tsx +31 -4
  126. package/src/Modal/README.md +19 -10
  127. package/src/Modal/__tests__/Modal.focus-trap.test.tsx +162 -0
  128. package/src/Modal/hooks/useModalContent.ts +32 -0
  129. package/src/Modal/types.ts +110 -29
  130. package/src/NavigationMenu/NavigationMenu.tsx +890 -0
  131. package/src/NavigationMenu/NavigationMenuContext.ts +67 -0
  132. package/src/NavigationMenu/README.md +355 -0
  133. package/src/NavigationMenu/__tests__/NavigationMenu.anchor-positioning.test.tsx +132 -0
  134. package/src/NavigationMenu/__tests__/NavigationMenu.asChild.test.tsx +73 -0
  135. package/src/NavigationMenu/__tests__/NavigationMenu.basic-rendering.test.tsx +92 -0
  136. package/src/NavigationMenu/__tests__/NavigationMenu.contract.test.tsx +45 -0
  137. package/src/NavigationMenu/__tests__/NavigationMenu.controlled-state.test.tsx +134 -0
  138. package/src/NavigationMenu/__tests__/NavigationMenu.error-handling.test.tsx +62 -0
  139. package/src/NavigationMenu/__tests__/NavigationMenu.fixtures.tsx +79 -0
  140. package/src/NavigationMenu/__tests__/NavigationMenu.forceMount.test.tsx +52 -0
  141. package/src/NavigationMenu/__tests__/NavigationMenu.hover-interaction.test.tsx +254 -0
  142. package/src/NavigationMenu/__tests__/NavigationMenu.indicator.test.tsx +252 -0
  143. package/src/NavigationMenu/__tests__/NavigationMenu.keyboard-interaction.test.tsx +294 -0
  144. package/src/NavigationMenu/__tests__/NavigationMenu.keyboard-navigation.test.tsx +126 -0
  145. package/src/NavigationMenu/__tests__/NavigationMenu.link.test.tsx +139 -0
  146. package/src/NavigationMenu/__tests__/NavigationMenu.motion.test.tsx +568 -0
  147. package/src/NavigationMenu/__tests__/NavigationMenu.mouse-interaction.test.tsx +76 -0
  148. package/src/NavigationMenu/__tests__/NavigationMenu.uncontrolled-state.test.tsx +30 -0
  149. package/src/NavigationMenu/__tests__/NavigationMenu.viewport.test.tsx +113 -0
  150. package/src/NavigationMenu/constants.ts +5 -0
  151. package/src/NavigationMenu/hooks/index.ts +7 -0
  152. package/src/NavigationMenu/hooks/useNavigationMenuEntry.ts +33 -0
  153. package/src/NavigationMenu/hooks/useNavigationMenuIndicator.ts +70 -0
  154. package/src/NavigationMenu/hooks/useNavigationMenuLink.ts +72 -0
  155. package/src/NavigationMenu/hooks/useNavigationMenuRoot.ts +301 -0
  156. package/src/NavigationMenu/hooks/useNavigationMenuTopLevelEntry.ts +65 -0
  157. package/src/NavigationMenu/hooks/useNavigationMenuTrigger.ts +158 -0
  158. package/src/NavigationMenu/hooks/useNavigationMenuViewport.ts +101 -0
  159. package/src/NavigationMenu/index.ts +3 -0
  160. package/src/NavigationMenu/types.ts +259 -0
  161. package/src/NavigationMenu/utils.ts +89 -0
  162. package/src/Popover/Popover.tsx +427 -0
  163. package/src/Popover/PopoverContext.ts +13 -0
  164. package/src/Popover/README.md +106 -0
  165. package/src/Popover/__tests__/Popover.anchor.test.tsx +38 -0
  166. package/src/Popover/__tests__/Popover.asChild.test.tsx +160 -0
  167. package/src/Popover/__tests__/Popover.basic-rendering.test.tsx +106 -0
  168. package/src/Popover/__tests__/Popover.click-outside.test.tsx +149 -0
  169. package/src/Popover/__tests__/Popover.close.test.tsx +70 -0
  170. package/src/Popover/__tests__/Popover.content.test.tsx +58 -0
  171. package/src/Popover/__tests__/Popover.controlled-state.test.tsx +45 -0
  172. package/src/Popover/__tests__/Popover.error-handling.test.tsx +51 -0
  173. package/src/Popover/__tests__/Popover.focus.test.tsx +43 -0
  174. package/src/Popover/__tests__/Popover.keyboard-interaction.test.tsx +71 -0
  175. package/src/Popover/__tests__/Popover.mouse-interaction.test.tsx +69 -0
  176. package/src/Popover/__tests__/Popover.uncontrolled-state.test.tsx +44 -0
  177. package/src/Popover/hooks/index.ts +3 -0
  178. package/src/Popover/hooks/usePopoverContent.ts +98 -0
  179. package/src/Popover/hooks/usePopoverRoot.ts +84 -0
  180. package/src/Popover/hooks/usePopoverTrigger.ts +33 -0
  181. package/src/Popover/index.ts +2 -0
  182. package/src/Popover/types.ts +197 -0
  183. package/src/Portal/Portal.tsx +50 -10
  184. package/src/Portal/__tests__/Portal.basic-rendering.test.tsx +5 -0
  185. package/src/Portal/types.ts +5 -0
  186. package/src/Progress/Progress.tsx +33 -1
  187. package/src/Progress/__tests__/Progress.basic-rendering.test.tsx +10 -0
  188. package/src/Progress/__tests__/Progress.value.test.tsx +21 -0
  189. package/src/Progress/types.ts +20 -4
  190. package/src/Radio/Radio.tsx +9 -1
  191. package/src/Radio/__tests__/Radio.basic-rendering.test.tsx +14 -0
  192. package/src/Radio/hooks/useRadioRoot.ts +3 -0
  193. package/src/Radio/types.ts +20 -0
  194. package/src/RadioCard/RadioCard.tsx +11 -0
  195. package/src/RadioCard/__tests__/RadioCard.basic-rendering.test.tsx +8 -0
  196. package/src/RadioCard/__tests__/RadioCard.disabled-items.test.tsx +27 -0
  197. package/src/RadioCard/__tests__/RadioCard.keyboard-interaction.test.tsx +53 -0
  198. package/src/RadioCard/__tests__/RadioCard.ref-forwarding.test.tsx +54 -0
  199. package/src/RadioCard/__tests__/RadioCard.uncontrolled-state.test.tsx +21 -0
  200. package/src/RadioCard/hooks/useRadioCardRoot.ts +11 -0
  201. package/src/RadioCard/types.ts +95 -22
  202. package/src/RadioGroup/RadioGroup.tsx +11 -0
  203. package/src/RadioGroup/__tests__/RadioGroup.basic-rendering.test.tsx +8 -0
  204. package/src/RadioGroup/__tests__/RadioGroup.disabled.test.tsx +27 -0
  205. package/src/RadioGroup/__tests__/RadioGroup.ref-forwarding.test.tsx +29 -0
  206. package/src/RadioGroup/__tests__/RadioGroup.roving-tabindex.test.tsx +31 -0
  207. package/src/RadioGroup/hooks/useRadioGroupRoot.ts +11 -0
  208. package/src/RadioGroup/types.ts +73 -9
  209. package/src/SegmentedControl/README.md +154 -0
  210. package/src/SegmentedControl/SegmentedControl.tsx +309 -0
  211. package/src/SegmentedControl/SegmentedControlContext.ts +28 -0
  212. package/src/SegmentedControl/__tests__/SegmentedControl.asChild.test.tsx +50 -0
  213. package/src/SegmentedControl/__tests__/SegmentedControl.basic-rendering.test.tsx +100 -0
  214. package/src/SegmentedControl/__tests__/SegmentedControl.controlled-state.test.tsx +107 -0
  215. package/src/SegmentedControl/__tests__/SegmentedControl.disabled-keydown-guards.test.tsx +62 -0
  216. package/src/SegmentedControl/__tests__/SegmentedControl.disabled.test.tsx +151 -0
  217. package/src/SegmentedControl/__tests__/SegmentedControl.error-handling.test.tsx +17 -0
  218. package/src/SegmentedControl/__tests__/SegmentedControl.keyboard-interaction.test.tsx +117 -0
  219. package/src/SegmentedControl/__tests__/SegmentedControl.orientation.test.tsx +54 -0
  220. package/src/SegmentedControl/__tests__/SegmentedControl.reading-direction.test.tsx +56 -0
  221. package/src/SegmentedControl/__tests__/SegmentedControl.ref-forwarding.test.tsx +45 -0
  222. package/src/SegmentedControl/__tests__/SegmentedControl.roving-tabindex.test.tsx +104 -0
  223. package/src/SegmentedControl/__tests__/SegmentedControl.uncontrolled-state.test.tsx +94 -0
  224. package/src/SegmentedControl/hooks/index.ts +2 -0
  225. package/src/SegmentedControl/hooks/useSegmentedControlContext.ts +1 -0
  226. package/src/SegmentedControl/hooks/useSegmentedControlRoot.ts +86 -0
  227. package/src/SegmentedControl/index.ts +2 -0
  228. package/src/SegmentedControl/types.ts +138 -0
  229. package/src/Select/README.md +122 -157
  230. package/src/Select/Select.tsx +595 -68
  231. package/src/Select/SelectContext.ts +38 -0
  232. package/src/Select/SelectItemIndicatorContext.ts +29 -0
  233. package/src/Select/__tests__/Select.asChild.test.tsx +2 -2
  234. package/src/Select/__tests__/Select.basic-rendering.test.tsx +22 -3
  235. package/src/Select/__tests__/Select.controlled-state.test.tsx +6 -6
  236. package/src/Select/__tests__/Select.data-attributes.test.tsx +4 -4
  237. package/src/Select/__tests__/Select.field-integration.test.tsx +11 -11
  238. package/src/Select/__tests__/Select.form.test.tsx +38 -0
  239. package/src/Select/__tests__/Select.group.test.tsx +6 -6
  240. package/src/Select/__tests__/Select.keyboard-edge.test.tsx +95 -0
  241. package/src/Select/__tests__/Select.keyboard.test.tsx +124 -0
  242. package/src/Select/__tests__/Select.mutation-hardening.test.tsx +317 -0
  243. package/src/Select/__tests__/Select.native-item.test.tsx +30 -0
  244. package/src/Select/__tests__/Select.open-close.test.tsx +57 -0
  245. package/src/Select/__tests__/Select.placeholder.test.tsx +4 -4
  246. package/src/Select/__tests__/Select.rich-asChild.test.tsx +60 -0
  247. package/src/Select/__tests__/Select.rich-mode.test.tsx +16 -0
  248. package/src/Select/__tests__/Select.selection.test.tsx +104 -0
  249. package/src/Select/__tests__/Select.separator.test.tsx +71 -0
  250. package/src/Select/__tests__/Select.strict-context.test.tsx +36 -0
  251. package/src/Select/__tests__/Select.typeahead.test.tsx +156 -0
  252. package/src/Select/__tests__/Select.value-mirror.test.tsx +240 -0
  253. package/src/Select/constants.ts +8 -0
  254. package/src/Select/hooks/index.ts +2 -0
  255. package/src/Select/hooks/useSelectContent.ts +149 -0
  256. package/src/Select/hooks/useSelectRoot.ts +149 -0
  257. package/src/Select/types.ts +199 -31
  258. package/src/SkipNav/SkipNav.tsx +69 -29
  259. package/src/SkipNav/__tests__/SkipNav.basic-rendering.test.tsx +6 -0
  260. package/src/SkipNav/types.ts +17 -9
  261. package/src/Slider/Slider.tsx +33 -1
  262. package/src/Slider/SliderContext.ts +28 -1
  263. package/src/Slider/types.ts +157 -9
  264. package/src/Slot/Slot.tsx +94 -19
  265. package/src/Slot/__tests__/Slot.test.tsx +110 -0
  266. package/src/Slot/composeEventHandlers.ts +26 -2
  267. package/src/Slot/types.ts +16 -0
  268. package/src/Status/Status.tsx +36 -15
  269. package/src/Status/__tests__/Status.test.tsx +5 -0
  270. package/src/Status/types.ts +12 -1
  271. package/src/Switch/Switch.tsx +15 -2
  272. package/src/Switch/__tests__/Switch.basic-rendering.test.tsx +7 -0
  273. package/src/Switch/hooks/useSwitchRoot.ts +3 -0
  274. package/src/Switch/types.ts +49 -22
  275. package/src/Table/Table.tsx +44 -10
  276. package/src/Table/types.ts +66 -17
  277. package/src/Tabs/Tabs.tsx +8 -0
  278. package/src/Tabs/types.ts +29 -4
  279. package/src/Textarea/Textarea.tsx +9 -1
  280. package/src/Textarea/__tests__/Textarea.basic-rendering.test.tsx +5 -0
  281. package/src/Textarea/types.ts +20 -3
  282. package/src/Toggle/Toggle.tsx +51 -13
  283. package/src/Toggle/__tests__/Toggle.basic-rendering.test.tsx +5 -0
  284. package/src/Toggle/types.ts +54 -4
  285. package/src/ToggleGroup/ToggleGroup.tsx +14 -1
  286. package/src/ToggleGroup/__tests__/ToggleGroup.asChild.test.tsx +20 -0
  287. package/src/ToggleGroup/__tests__/ToggleGroup.basic-rendering.test.tsx +9 -0
  288. package/src/ToggleGroup/__tests__/ToggleGroup.dynamic-items.test.tsx +70 -0
  289. package/src/ToggleGroup/__tests__/ToggleGroup.error-handling.test.tsx +23 -0
  290. package/src/ToggleGroup/__tests__/ToggleGroup.keyboard-interaction.test.tsx +23 -1
  291. package/src/ToggleGroup/__tests__/ToggleGroup.ref-forwarding.test.tsx +58 -0
  292. package/src/ToggleGroup/hooks/useToggleGroupRoot.ts +21 -1
  293. package/src/ToggleGroup/types.ts +55 -2
  294. package/src/Tooltip/Tooltip.tsx +98 -20
  295. package/src/Tooltip/hooks/__tests__/useTooltipProvider.test.tsx +40 -0
  296. package/src/Tooltip/hooks/useTooltipProvider.ts +13 -1
  297. package/src/Tooltip/types.ts +89 -8
  298. package/src/Tree/Tree.tsx +187 -33
  299. package/src/Tree/types.ts +54 -12
  300. package/src/VisuallyHidden/VisuallyHidden.tsx +33 -8
  301. package/src/VisuallyHidden/__tests__/VisuallyHidden.test.tsx +15 -1
  302. package/src/VisuallyHidden/types.ts +11 -1
  303. package/src/index.ts +4 -0
  304. package/src/test/intersectionObserverPolyfill.ts +7 -0
  305. package/src/test/resizeObserverPolyfill.ts +80 -0
  306. package/src/utils/focusable.ts +15 -0
  307. package/src/utils/index.ts +1 -0
@@ -4,29 +4,50 @@ import { Slot } from "../Slot/index.ts";
4
4
  import { StatusProps } from "./types";
5
5
 
6
6
  /**
7
- * A polite live region for low-priority, non-urgent status messages.
7
+ * A polite live region for low-priority, non-urgent status messages,
8
+ * implementing the WAI-ARIA `status` role.
8
9
  *
9
- * Renders a `<div role="status">`. The `status` role carries an
10
- * implicit `aria-live="polite"` and `aria-atomic="true"`, so assistive
11
- * technology announces the message once the user is idle, without
12
- * interrupting them — use it for confirmations, counts, and background
13
- * progress. For errors the user must see immediately, reach for
14
- * `Alert` instead.
10
+ * Renders a `<div role="status">`. The `status` role carries an implicit
11
+ * `aria-live="polite"` and `aria-atomic="true"`, so assistive technology
12
+ * announces the message once the user is idle, without interrupting
13
+ * them — use it for confirmations, counts, and background progress. For
14
+ * errors the user must see immediately, reach for `Alert` instead.
15
15
  *
16
- * Render the `Status` conditionally, or update its text content while
17
- * it stays mounted: the live region announces content that changes
18
- * *after* it is already in the DOM.
16
+ * **Live region timing.** A live region only announces content that
17
+ * changes *after* the region is already in the DOM. Either render
18
+ * `Status` conditionally (mount when a message is ready), or keep it
19
+ * mounted and update its text:
19
20
  *
20
- * **`asChild` composition.** Renders the consumer's element instead of
21
- * a `<div>`, merging `role="status"` and all other props in via the
22
- * {@link Slot} utility.
21
+ * ```tsx
22
+ * // Conditional mount — announces on first appearance
23
+ * {saved && <Status>All changes saved.</Status>}
24
+ *
25
+ * // Persistent — announces on every content change
26
+ * <Status>{count} items in your cart</Status>
27
+ * ```
28
+ *
29
+ * **`asChild` composition.** Pass `asChild` to render the consumer's own
30
+ * element instead of a `<div>`, merging `role="status"` and all other
31
+ * props onto it via the {@link Slot} utility. Event handlers compose with
32
+ * the child's own handlers (child runs first).
33
+ *
34
+ * @extends HTMLDivElement
23
35
  *
24
36
  * @example Confirmation message
25
37
  * ```tsx
26
- * {saved && <Status>All changes saved.</Status>}
38
+ * import { Status } from "@primitiv-ui/react";
39
+ *
40
+ * function SaveIndicator({ saved }: { saved: boolean }) {
41
+ * return saved ? <Status>All changes saved.</Status> : null;
42
+ * }
43
+ * ```
44
+ *
45
+ * @example Cart count — persistent live region
46
+ * ```tsx
47
+ * <Status>{count} items in your cart</Status>
27
48
  * ```
28
49
  *
29
- * @example asChild — keep semantic markup
50
+ * @example asChild — apply the status role to a semantic element
30
51
  * ```tsx
31
52
  * <Status asChild>
32
53
  * <output>{count} items in your cart</output>
@@ -25,4 +25,9 @@ describe("Status component", () => {
25
25
  expect(status.tagName).toBe("SECTION");
26
26
  expect(status).toHaveTextContent("Saved");
27
27
  });
28
+
29
+ it('sets displayName to "Status" for React DevTools and stack traces', () => {
30
+ // Assert — an empty displayName would render it as an anonymous component.
31
+ expect(Status.displayName).toBe("Status");
32
+ });
28
33
  });
@@ -1,9 +1,20 @@
1
- import { ComponentProps } from "react";
1
+ import { ComponentProps, ReactNode } from "react";
2
2
 
3
3
  /**
4
4
  * Props for {@link Status} — all native `<div>` attributes plus the
5
5
  * `asChild` escape hatch.
6
6
  */
7
7
  export type StatusProps = ComponentProps<"div"> & {
8
+ /**
9
+ * Renders the child element instead of a native `<div>`, merging
10
+ * `role="status"` and all other props onto it via {@link Slot}.
11
+ * Event handlers compose with the child's own handlers (child runs
12
+ * first). Use this to apply the live-region role to a semantically
13
+ * appropriate element (e.g. `<output>`).
14
+ * @default false
15
+ */
8
16
  asChild?: boolean;
17
+ /** Content to announce. A live region announces changes that occur
18
+ * after the region is already present in the DOM. */
19
+ children?: ReactNode;
9
20
  };
@@ -42,6 +42,12 @@ function dataStateOf(checked: boolean) {
42
42
  * **Keyboard.** Toggles on `Space` (the native checkbox behaviour); `Enter`
43
43
  * does not toggle a checkbox-based control.
44
44
  *
45
+ * **`onChange` composition.** The consumer's raw `onChange` fires first; if it
46
+ * calls `event.preventDefault()`, the internal mirror update and
47
+ * `onCheckedChange` are skipped for that event. See {@link SwitchRootBaseProps}.
48
+ *
49
+ * @extends HTMLInputElement
50
+ *
45
51
  * @example Uncontrolled
46
52
  * ```tsx
47
53
  * <Switch.Root name="notify" value="on" defaultChecked aria-label="Enable notifications">
@@ -102,7 +108,11 @@ export function SwitchRoot({
102
108
  );
103
109
  }
104
110
 
105
- /** @internal */
111
+ // Runtime-dead: the compound alias below (same object via Object.assign)
112
+ // overwrites this to "Switch" at load, so the value is never observable. The
113
+ // assignment stays because it declares `displayName` on `typeof SwitchRoot`,
114
+ // which TSwitchCompound extends.
115
+ // Stryker disable next-line StringLiteral: overwritten by the compound alias — an equivalent mutant.
106
116
  SwitchRoot.displayName = "SwitchRoot";
107
117
 
108
118
  /**
@@ -114,7 +124,10 @@ SwitchRoot.displayName = "SwitchRoot";
114
124
  * **Styling hook.** Mirrors the root's `data-state="checked" | "unchecked"`.
115
125
  *
116
126
  * **`asChild` prop.** Pass `asChild` to render the consumer's own element as
117
- * the thumb, with `aria-hidden` and `data-state` merged in.
127
+ * the thumb, with `aria-hidden` and `data-state` merged in via the
128
+ * {@link Slot} pattern. See {@link SwitchThumbProps}.
129
+ *
130
+ * @extends HTMLSpanElement
118
131
  *
119
132
  * @example
120
133
  * ```tsx
@@ -92,4 +92,11 @@ describe("Switch basic rendering", () => {
92
92
  expect(thumb).toHaveAttribute("aria-hidden", "true");
93
93
  expect(thumb).toHaveAttribute("data-state", "unchecked");
94
94
  });
95
+
96
+ it("sets a displayName on the compound and the Thumb", () => {
97
+ // Assert — empty displayNames would render each as anonymous in DevTools.
98
+ // Root aliases the compound (Object.assign), so its name is "Switch".
99
+ expect(Switch.displayName).toBe("Switch");
100
+ expect(Switch.Thumb.displayName).toBe("SwitchThumb");
101
+ });
95
102
  });
@@ -34,6 +34,9 @@ export function useSwitchRoot({
34
34
  onChange?.(event);
35
35
  if (event.defaultPrevented) return;
36
36
  const next = event.target.checked;
37
+ // Stryker disable next-line ConditionalExpression: in controlled mode
38
+ // `checked` reads controlledChecked, never `mirror`, so setting mirror here
39
+ // (the mutant's always-run form) has no observable effect — equivalent.
37
40
  if (!isControlled) setMirror(next);
38
41
  onCheckedChange?.(next);
39
42
  };
@@ -1,50 +1,67 @@
1
1
  import { ChangeEventHandler, ComponentProps, ReactNode, Ref } from "react";
2
2
 
3
3
  /**
4
- * Props common to both controlled and uncontrolled `Switch.Root` modes — the
5
- * native `<input type="checkbox">` attributes (minus the ones the component
6
- * owns). `className` / `style` style the **track** (the visible control), not
7
- * the hidden input; everything else spreads onto the input, because
8
- * semantically the Root *is* the switch.
4
+ * Shared base for both {@link SwitchRootProps} variants — the native
5
+ * `<input type="checkbox">` attributes (minus the ones the component owns:
6
+ * `type`, `role`, `checked`, and `defaultChecked`), plus `children` and a
7
+ * typed `ref`.
8
+ *
9
+ * Prop routing: `className` / `style` style the **track** (the visible
10
+ * `<label>`, since the input is visually hidden); every other prop — `name`,
11
+ * `value`, `id`, `aria-*`, `required`, `disabled`, `ref`, … — spreads onto the
12
+ * hidden `<input>`, because semantically the Root *is* the switch.
9
13
  */
10
14
  export type SwitchRootBaseProps = Omit<
11
15
  ComponentProps<"input">,
12
16
  "type" | "role" | "checked" | "defaultChecked"
13
17
  > & {
14
- /** Optional content (typically `Switch.Thumb`). */
18
+ /** Content of the switch — typically a single
19
+ * {@link SwitchThumbProps | `Switch.Thumb`}. */
15
20
  children?: ReactNode;
16
- /** Ref to the underlying native `<input>` element. */
21
+ /** Forwarded to the underlying native `HTMLInputElement` (the real,
22
+ * visually-hidden checkbox), not the visible track. */
17
23
  ref?: Ref<HTMLInputElement>;
18
24
  };
19
25
 
20
26
  /**
21
- * Props for `Switch.Root` in uncontrolled mode — the **browser** owns the
22
- * checked state. Pass `defaultChecked` to set the initial value; `checked` is
23
- * forbidden.
27
+ * Uncontrolled variant of {@link SwitchRootProps}: the **browser** owns the
28
+ * checked state, so the switch participates in native form submission and
29
+ * reset. Pass `defaultChecked` (or omit it); `checked` is forbidden.
24
30
  */
25
31
  export type SwitchRootUncontrolledProps = SwitchRootBaseProps & {
26
- /** Initial checked state when uncontrolled. */
32
+ /** Checked state on first render. Defaults to `false` when omitted.
33
+ * @default false */
27
34
  defaultChecked?: boolean;
28
- /** Forbidden in uncontrolled mode. */
35
+ /** Forbidden in uncontrolled mode — use `defaultChecked` instead. */
29
36
  checked?: never;
30
- /** Called whenever the checked state changes. */
37
+ /** Called with the new boolean state whenever the switch toggles. Optional
38
+ * in uncontrolled mode. */
31
39
  onCheckedChange?: (checked: boolean) => void;
32
40
  };
33
41
 
34
42
  /**
35
- * Props for `Switch.Root` in controlled mode — the parent owns the checked
36
- * value. Pass `checked` and `onCheckedChange` together.
43
+ * Controlled variant of {@link SwitchRootProps}: the parent owns the checked
44
+ * value. Pass `checked` and `onCheckedChange` together; `defaultChecked` is
45
+ * forbidden.
37
46
  */
38
47
  export type SwitchRootControlledProps = SwitchRootBaseProps & {
39
- /** Forbidden in controlled mode. */
48
+ /** Forbidden in controlled mode — use `checked` instead. */
40
49
  defaultChecked?: never;
41
- /** The controlled checked state. */
50
+ /** The controlled checked state. Must be kept in sync by the parent via
51
+ * `onCheckedChange`. */
42
52
  checked: boolean;
43
- /** Called whenever the component requests a checked-state change. */
53
+ /** Called with the new boolean state whenever the user requests a toggle.
54
+ * Required in controlled mode. */
44
55
  onCheckedChange: (checked: boolean) => void;
45
56
  };
46
57
 
47
- /** Props for `Switch.Root` — discriminated controlled/uncontrolled union. */
58
+ /**
59
+ * Props for {@link SwitchRoot | `Switch.Root`}.
60
+ *
61
+ * Resolves to either {@link SwitchRootUncontrolledProps} or
62
+ * {@link SwitchRootControlledProps} — only one shape is accepted by TypeScript
63
+ * at a time.
64
+ */
48
65
  export type SwitchRootProps =
49
66
  | SwitchRootUncontrolledProps
50
67
  | SwitchRootControlledProps;
@@ -56,11 +73,21 @@ export type SwitchRootProps =
56
73
  */
57
74
  export type SwitchProps = SwitchRootProps;
58
75
 
59
- /** Props for `Switch.Thumb`, the sliding indicator inside the track. */
76
+ /**
77
+ * Props for {@link SwitchThumb | `Switch.Thumb`} — the decorative sliding
78
+ * indicator inside the track. All `HTMLSpanElement` attributes, plus the
79
+ * `asChild` escape hatch.
80
+ */
60
81
  export type SwitchThumbProps = ComponentProps<"span"> & {
61
- /** Optional thumb content. */
82
+ /** Optional thumb content (rarely needed — the thumb is usually styled
83
+ * purely with CSS). */
62
84
  children?: ReactNode;
63
- /** Render the child element instead of the default `<span>`. */
85
+ /**
86
+ * When `true`, render the consumer's own element as the thumb instead of the
87
+ * default `<span>`, merging `aria-hidden` and `data-state` onto it via the
88
+ * {@link Slot} pattern.
89
+ * @default false
90
+ */
64
91
  asChild?: boolean;
65
92
  };
66
93
 
@@ -16,13 +16,22 @@ import {
16
16
  * The root of a Table widget — renders a plain `<table>` element and passes
17
17
  * all `TableHTMLAttributes` through to the DOM.
18
18
  *
19
+ * Stateless: `Table` is a purely structural compound with no context, no
20
+ * internal state, and no `data-*` attributes of its own (verified by
21
+ * `Table.contract.test.tsx` against the registry contract) — every part
22
+ * renders exactly what its native HTML element provides.
23
+ *
19
24
  * The `<table>` element carries an implicit `role="table"` in the accessibility
20
25
  * tree. Assistive technology will announce it as a table and report the number
21
26
  * of rows and columns to the user.
22
27
  *
23
- * Always pair column headers (`Table.Header`) with the correct
24
- * {@link TableHeaderProps.scope | `scope`} attribute so screen readers can
25
- * associate data cells with their headers.
28
+ * Always pair column headers ({@link TableHeader | `Table.Header`}) with the
29
+ * correct {@link TableHeaderProps.scope | `scope`} attribute so screen
30
+ * readers can associate data cells with their headers. Wrap the whole table
31
+ * in {@link TableScrollArea | `Table.ScrollArea`} when it has many columns
32
+ * and needs to scroll horizontally on narrow viewports.
33
+ *
34
+ * @extends HTMLTableElement
26
35
  *
27
36
  * @example
28
37
  * ```tsx
@@ -54,7 +63,12 @@ TableRoot.displayName = "Table";
54
63
  *
55
64
  * Browsers and assistive technology treat rows inside `<thead>` as column
56
65
  * headers. When a table is printed across multiple pages, the browser may
57
- * repeat the `<thead>` content at the top of each page.
66
+ * repeat the `<thead>` content at the top of each page. Renders as a direct
67
+ * child of {@link TableRoot | `Table.Root`}'s `<table>`, typically
68
+ * containing a single {@link TableRow | `Table.Row`} of
69
+ * {@link TableHeader | `Table.Header`}s.
70
+ *
71
+ * @extends HTMLTableSectionElement
58
72
  *
59
73
  * @example
60
74
  * ```tsx
@@ -79,7 +93,9 @@ TableHead.displayName = "TableHead";
79
93
  * Using `<tbody>` explicitly improves accessibility and allows browsers to
80
94
  * scroll the body independently of a fixed header. Multiple `<tbody>` elements
81
95
  * are valid and useful for visually separating logical row groups within a
82
- * single table.
96
+ * single table — render more than one `Table.Body` as siblings for that case.
97
+ *
98
+ * @extends HTMLTableSectionElement
83
99
  *
84
100
  * @example
85
101
  * ```tsx
@@ -103,7 +119,11 @@ TableBody.displayName = "TableBody";
103
119
  *
104
120
  * Typically used for summary rows — totals, averages, counts. When a table is
105
121
  * printed across multiple pages some browsers repeat the `<tfoot>` content at
106
- * the bottom of each page.
122
+ * the bottom of each page. Renders as a sibling of
123
+ * {@link TableHead | `Table.Head`} and {@link TableBody | `Table.Body`}
124
+ * inside {@link TableRoot | `Table.Root`}.
125
+ *
126
+ * @extends HTMLTableSectionElement
107
127
  *
108
128
  * @example
109
129
  * ```tsx
@@ -128,9 +148,13 @@ TableFooter.displayName = "TableFooter";
128
148
  /**
129
149
  * An individual table row — renders a `<tr>` element.
130
150
  *
131
- * May contain `Table.Header` (`<th>`) or `Table.Cell` (`<td>`) children, or a
132
- * mix of both when the row contains both header and data cells (e.g. the first
133
- * column of each row is a row header).
151
+ * May contain {@link TableHeader | `Table.Header`} (`<th>`) or
152
+ * {@link TableCell | `Table.Cell`} (`<td>`) children, or a mix of both when
153
+ * the row contains both header and data cells (e.g. the first column of each
154
+ * row is a row header). Lives inside {@link TableHead | `Table.Head`},
155
+ * {@link TableBody | `Table.Body`}, or {@link TableFooter | `Table.Footer`}.
156
+ *
157
+ * @extends HTMLTableRowElement
134
158
  *
135
159
  * @example
136
160
  * ```tsx
@@ -166,6 +190,8 @@ TableRow.displayName = "TableRow";
166
190
  * All `ThHTMLAttributes` (including `colSpan`, `rowSpan`, `abbr`) pass
167
191
  * through to the DOM.
168
192
  *
193
+ * @extends HTMLTableCellElement
194
+ *
169
195
  * @example Column header
170
196
  * ```tsx
171
197
  * <Table.Header scope="col">Name</Table.Header>
@@ -190,7 +216,11 @@ TableHeader.displayName = "TableHeader";
190
216
  * A data cell — renders a `<td>` element.
191
217
  *
192
218
  * All `TdHTMLAttributes` pass through to the DOM, including `colSpan` and
193
- * `rowSpan` for spanning multiple columns or rows.
219
+ * `rowSpan` for spanning multiple columns or rows. Use
220
+ * {@link TableHeader | `Table.Header`} instead when a cell's content is a
221
+ * label for a row or column rather than data.
222
+ *
223
+ * @extends HTMLTableCellElement
194
224
  *
195
225
  * @example Basic cell
196
226
  * ```tsx
@@ -228,6 +258,8 @@ TableCell.displayName = "TableCell";
228
258
  * </Table.ScrollArea>
229
259
  * ```
230
260
  *
261
+ * @extends HTMLDivElement
262
+ *
231
263
  * @example
232
264
  * ```tsx
233
265
  * <Table.ScrollArea>
@@ -277,6 +309,8 @@ TableScrollArea.displayName = "TableScrollArea";
277
309
  * | `"bottom"` (default) | Below the table |
278
310
  * | `"top"` | Above the table |
279
311
  *
312
+ * @extends HTMLTableCaptionElement
313
+ *
280
314
  * @example Default (caption below table)
281
315
  * ```tsx
282
316
  * <Table.Root>
@@ -6,58 +6,107 @@ import type {
6
6
  TdHTMLAttributes,
7
7
  } from "react";
8
8
 
9
- /** Props for {@link Table.Root} — all `TableHTMLAttributes` on `<table>`. */
9
+ /**
10
+ * Props for {@link TableRoot | `Table.Root`} — all `TableHTMLAttributes` on
11
+ * the native `<table>`. No custom props are added.
12
+ *
13
+ * @extends HTMLTableElement
14
+ */
10
15
  export type TableRootProps = TableHTMLAttributes<HTMLTableElement>;
11
16
 
12
- /** Props for {@link Table.Head} — all `HTMLAttributes` on `<thead>`. */
17
+ /**
18
+ * Props for {@link TableHead | `Table.Head`} — all `HTMLAttributes` on the
19
+ * native `<thead>`. No custom props are added.
20
+ *
21
+ * @extends HTMLTableSectionElement
22
+ */
13
23
  export type TableHeadProps = HTMLAttributes<HTMLTableSectionElement>;
14
24
 
15
- /** Props for {@link Table.Body} — all `HTMLAttributes` on `<tbody>`. */
25
+ /**
26
+ * Props for {@link TableBody | `Table.Body`} — all `HTMLAttributes` on the
27
+ * native `<tbody>`. No custom props are added.
28
+ *
29
+ * @extends HTMLTableSectionElement
30
+ */
16
31
  export type TableBodyProps = HTMLAttributes<HTMLTableSectionElement>;
17
32
 
18
- /** Props for {@link Table.Footer} — all `HTMLAttributes` on `<tfoot>`. */
33
+ /**
34
+ * Props for {@link TableFooter | `Table.Footer`} — all `HTMLAttributes` on
35
+ * the native `<tfoot>`. No custom props are added.
36
+ *
37
+ * @extends HTMLTableSectionElement
38
+ */
19
39
  export type TableFooterProps = HTMLAttributes<HTMLTableSectionElement>;
20
40
 
21
- /** Props for {@link Table.Row} — all `HTMLAttributes` on `<tr>`. */
41
+ /**
42
+ * Props for {@link TableRow | `Table.Row`} — all `HTMLAttributes` on the
43
+ * native `<tr>`. No custom props are added.
44
+ *
45
+ * @extends HTMLTableRowElement
46
+ */
22
47
  export type TableRowProps = HTMLAttributes<HTMLTableRowElement>;
23
48
 
24
49
  /**
25
- * Props for {@link Table.Header} — all `ThHTMLAttributes` on `<th>`.
50
+ * Props for {@link TableHeader | `Table.Header`} — all `ThHTMLAttributes` on
51
+ * the native `<th>`, including `colSpan`, `rowSpan`, and `abbr`.
26
52
  *
27
53
  * The most important prop for accessibility is `scope`: set it to `"col"` for
28
54
  * column headers and `"row"` for row headers so assistive technology can
29
- * associate data cells with the correct header.
55
+ * associate data cells with the correct header. See the scope table on
56
+ * {@link TableHeader}.
57
+ *
58
+ * @extends HTMLTableCellElement
30
59
  */
31
60
  export type TableHeaderProps = ThHTMLAttributes<HTMLTableCellElement>;
32
61
 
33
62
  /**
34
- * Props for {@link Table.Cell} — all `TdHTMLAttributes` on `<td>`.
63
+ * Props for {@link TableCell | `Table.Cell`} — all `TdHTMLAttributes` on the
64
+ * native `<td>`.
35
65
  *
36
66
  * Includes `colSpan` and `rowSpan` for spanning multiple columns or rows.
67
+ *
68
+ * @extends HTMLTableCellElement
37
69
  */
38
70
  export type TableCellProps = TdHTMLAttributes<HTMLTableCellElement>;
39
71
 
40
72
  /**
41
- * Props for {@link Table.ScrollArea} — `children` plus all `HTMLAttributes`
42
- * on the wrapping `<div>`.
73
+ * Props for {@link TableScrollArea | `Table.ScrollArea`} — a required
74
+ * `children` plus all `HTMLAttributes` on the wrapping `<div>`.
43
75
  *
44
- * Any `style` properties you pass are merged with (and take priority over) the
45
- * base scroll styles (`display: block`, `overflow-x: auto`, `max-width: 100%`).
76
+ * @extends HTMLDivElement
46
77
  */
47
78
  export type TableScrollAreaProps = {
79
+ /** The table (typically a single {@link TableRoot | `Table.Root`}) to
80
+ * wrap in the horizontally-scrolling container. */
48
81
  children: ReactNode;
49
- } & HTMLAttributes<HTMLDivElement>;
82
+ /**
83
+ * Merged with (and taking priority over) the base scroll styles
84
+ * (`display: block`, `overflow-x: auto`, `max-width: 100%`), so
85
+ * additional styles can be layered on without repeating the scroll
86
+ * declarations. See {@link TableScrollArea}'s custom-styles example.
87
+ */
88
+ style?: HTMLAttributes<HTMLDivElement>["style"];
89
+ } & Omit<HTMLAttributes<HTMLDivElement>, "style">;
50
90
 
51
91
  /**
52
- * Props for {@link Table.Caption} — `children`, an optional
53
- * `captionSide`, plus all `HTMLAttributes` on `<caption>`.
92
+ * Props for {@link TableCaption | `Table.Caption`} — a required `children`,
93
+ * an optional `captionSide`, plus all `HTMLAttributes` on the native
94
+ * `<caption>`.
95
+ *
96
+ * @extends HTMLTableCaptionElement
54
97
  */
55
98
  export type TableCaptionProps = {
99
+ /** The visible, accessible label for the table. Preferred over
100
+ * `aria-label`/`aria-labelledby` on the table itself — the browser
101
+ * programmatically associates a `<caption>` with its `<table>`. */
56
102
  children: ReactNode;
57
103
  /**
58
- * Controls the CSS `caption-side` property.
59
- * - `"bottom"` (default) — caption appears below the table.
104
+ * Controls the CSS `caption-side` property, positioning the caption
105
+ * above or below the table. See {@link TableCaption}'s placement
106
+ * examples.
107
+ * - `"bottom"` — caption appears below the table.
60
108
  * - `"top"` — caption appears above the table.
109
+ * @default "bottom"
61
110
  */
62
111
  captionSide?: "bottom" | "top";
63
112
  } & HTMLAttributes<HTMLTableCaptionElement>;
package/src/Tabs/Tabs.tsx CHANGED
@@ -66,6 +66,8 @@ import type {
66
66
  * inherited from the nearest {@link DirectionProvider}, falling back to
67
67
  * `"ltr"` when there is no provider.
68
68
  *
69
+ * @extends HTMLDivElement
70
+ *
69
71
  * @example Uncontrolled
70
72
  * ```tsx
71
73
  * <Tabs.Root defaultValue="overview">
@@ -160,6 +162,8 @@ TabsRoot.displayName = "TabsRoot";
160
162
  *
161
163
  * **Styling hooks.** `data-orientation="horizontal" | "vertical"`.
162
164
  *
165
+ * @extends HTMLDivElement
166
+ *
163
167
  * @example
164
168
  * ```tsx
165
169
  * <Tabs.List label="Document sections">
@@ -241,6 +245,8 @@ TabsList.displayName = "TabsList";
241
245
  * - `data-disabled=""` when disabled (omitted otherwise), so CSS can target
242
246
  * `[data-disabled]` without the `:disabled` pseudo-class.
243
247
  *
248
+ * @extends HTMLButtonElement
249
+ *
244
250
  * @example Basic usage
245
251
  * ```tsx
246
252
  * <Tabs.Trigger value="account">Account</Tabs.Trigger>
@@ -345,6 +351,8 @@ TabsTrigger.displayName = "TabsTrigger";
345
351
  * - `data-state="active" | "inactive"`.
346
352
  * - `data-orientation="horizontal" | "vertical"`.
347
353
  *
354
+ * @extends HTMLDivElement
355
+ *
348
356
  * @example
349
357
  * ```tsx
350
358
  * <Tabs.Content value="account">
package/src/Tabs/types.ts CHANGED
@@ -60,9 +60,18 @@ export type ControlledTabsRootProps = {
60
60
  * the `HTMLDivElement` `ref` left in, a styled wrapper that spreads these props
61
61
  * straight back into `Tabs.Root` (`<Tabs.Root {...props} />`) would fail to
62
62
  * type-check on incompatible `ref` types (D58). */
63
- export type TabsRootProps = Omit<ComponentProps<"div">, "onChange" | "ref"> & {
63
+ export type TabsRootProps = Omit<
64
+ ComponentProps<"div">,
65
+ "onChange" | "ref" | "dir" | "defaultValue"
66
+ > & {
67
+ /** Layout axis; see {@link TabsOrientation}.
68
+ * @default "horizontal" */
64
69
  orientation?: TabsOrientation;
70
+ /** Reading direction; see {@link TabsReadingDirection}. Inherited from the
71
+ * nearest `DirectionProvider` when omitted, falling back to `"ltr"`. */
65
72
  dir?: TabsReadingDirection;
73
+ /** When a focused trigger becomes active; see {@link TabsActivationMode}.
74
+ * @default "automatic" */
66
75
  activationMode?: TabsActivationMode;
67
76
  /** When `true`, a panel's children are not rendered until that tab is first
68
77
  * activated. Once mounted they remain in the DOM across subsequent tab
@@ -105,8 +114,19 @@ export type TabsListProps = Omit<
105
114
  "label" | "aria-labelledby"
106
115
  > &
107
116
  (
108
- | { label: string; ariaLabelledBy?: never }
109
- | { label?: never; ariaLabelledBy: string }
117
+ | {
118
+ /** Accessible name for the tablist, announced as `aria-label`. Pick a
119
+ * short, human-readable description of the set (e.g. `"Account
120
+ * sections"`, not `"Tabs"`). Mutually exclusive with `ariaLabelledBy`. */
121
+ label: string;
122
+ ariaLabelledBy?: never;
123
+ }
124
+ | {
125
+ label?: never;
126
+ /** Id of an existing element to use as the tablist's accessible name,
127
+ * set as `aria-labelledby`. Mutually exclusive with `label`. */
128
+ ariaLabelledBy: string;
129
+ }
110
130
  );
111
131
  /** Props for `Tabs.Trigger` — an individual `role="tab"` button. Identified by
112
132
  * its required `value`, which links it to the `Tabs.Content` of the same value.
@@ -114,9 +134,14 @@ export type TabsListProps = Omit<
114
134
  * `asChild` and the `ref` type parameter. */
115
135
  export type TabsTriggerProps<T extends HTMLElement = HTMLButtonElement> = Omit<
116
136
  ComponentProps<"button">,
117
- "ref"
137
+ "ref" | "value"
118
138
  > & {
139
+ /** Removes the trigger from the roving tab order and marks it
140
+ * `aria-disabled`/`data-disabled`; arrow-key navigation skips it.
141
+ * @default false */
119
142
  disabled?: boolean;
143
+ /** Identifies this trigger, linking it to the `Tabs.Content` of the same
144
+ * value. Not the visible label — use `children` for that. */
120
145
  value: string;
121
146
  /** Render the child element instead of the default `<button>`. All tab
122
147
  * ARIA attributes and event handlers are merged onto the child. The child
@@ -39,10 +39,18 @@ import { TextareaProps } from "./types";
39
39
  * textarea[data-disabled] { opacity: 0.5; cursor: not-allowed; }
40
40
  * ```
41
41
  *
42
+ * **Styling hooks.**
43
+ * - `data-disabled=""` — present when `disabled` is `true`; omitted otherwise.
44
+ * Target with `[data-disabled]` rather than the `:disabled` pseudo-class so
45
+ * styles work identically in both native and `asChild` modes.
46
+ *
42
47
  * **`asChild` composition.** Renders the consumer's element instead of
43
48
  * `<textarea>`, merging all props (aria-*, data-*, event handlers, ref)
44
49
  * via the {@link Slot} utility. Use it to wrap an autosizing textarea
45
- * implementation while keeping this component's prop contract.
50
+ * implementation while keeping this component's prop contract. Event handlers
51
+ * compose with the child's own handlers (child runs first).
52
+ *
53
+ * @extends HTMLTextAreaElement
46
54
  *
47
55
  * @example Basic usage
48
56
  * ```tsx
@@ -104,4 +104,9 @@ describe("Textarea basic rendering", () => {
104
104
  // Assert
105
105
  expect(onChange).toHaveBeenCalledTimes(2);
106
106
  });
107
+
108
+ it('sets displayName to "Textarea" for React DevTools and stack traces', () => {
109
+ // Assert — an empty displayName would render it as an anonymous component.
110
+ expect(Textarea.displayName).toBe("Textarea");
111
+ });
107
112
  });