@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.
- package/README.md +4 -0
- package/package.json +6 -1
- package/src/AccessibleIcon/AccessibleIcon.tsx +32 -9
- package/src/AccessibleIcon/__tests__/AccessibleIcon.test.tsx +5 -0
- package/src/AccessibleIcon/types.ts +15 -2
- package/src/Accordion/Accordion.tsx +25 -4
- package/src/Accordion/__tests__/Accordion.asChild.test.tsx +46 -0
- package/src/Accordion/__tests__/Accordion.basic-rendering.test.tsx +15 -0
- package/src/Accordion/__tests__/Accordion.disabled-items.test.tsx +42 -0
- package/src/Accordion/__tests__/Accordion.error-handling.test.tsx +33 -0
- package/src/Accordion/hooks/useAccordionRoot.ts +44 -7
- package/src/Accordion/hooks/useAccordionTrigger.ts +9 -1
- package/src/Accordion/types.ts +72 -21
- package/src/Alert/Alert.tsx +36 -7
- package/src/Alert/__tests__/Alert.test.tsx +5 -0
- package/src/Alert/types.ts +18 -2
- package/src/Avatar/Avatar.tsx +99 -15
- package/src/Avatar/__tests__/Avatar.basic-rendering.test.tsx +10 -0
- package/src/Avatar/__tests__/Avatar.fallback.test.tsx +30 -0
- package/src/Avatar/__tests__/Avatar.image-loading.test.tsx +35 -0
- package/src/Avatar/hooks/useAvatarImage.ts +16 -0
- package/src/Avatar/types.ts +15 -3
- package/src/Breadcrumb/Breadcrumb.tsx +136 -18
- package/src/Breadcrumb/README.md +47 -0
- package/src/Breadcrumb/__tests__/Breadcrumb.basic-rendering.test.tsx +11 -0
- package/src/Breadcrumb/__tests__/Breadcrumb.ellipsis.test.tsx +110 -0
- package/src/Breadcrumb/types.ts +73 -7
- package/src/Button/Button.tsx +2 -0
- package/src/Button/__tests__/Button.basic-rendering.test.tsx +6 -0
- package/src/Button/types.ts +21 -0
- package/src/Carousel/Carousel.tsx +263 -15
- package/src/Carousel/README.md +749 -72
- package/src/Carousel/__tests__/Carousel.autoplay-status.test.tsx +239 -0
- package/src/Carousel/__tests__/Carousel.drag-status.test.tsx +292 -0
- package/src/Carousel/__tests__/Carousel.dynamic-slides.test.tsx +38 -0
- package/src/Carousel/__tests__/Carousel.indicators.test.tsx +101 -0
- package/src/Carousel/__tests__/Carousel.infinite.test.tsx +1453 -0
- package/src/Carousel/__tests__/Carousel.instant-scroll.test.tsx +124 -0
- package/src/Carousel/__tests__/Carousel.intersection-observer.test.tsx +88 -0
- package/src/Carousel/__tests__/Carousel.loop.test.tsx +163 -0
- package/src/Carousel/__tests__/Carousel.loopEngine.test.ts +77 -0
- package/src/Carousel/__tests__/Carousel.mouse-drag.test.tsx +504 -0
- package/src/Carousel/__tests__/Carousel.multi-slide-bounds.test.tsx +91 -0
- package/src/Carousel/__tests__/Carousel.orientation.test.tsx +207 -0
- package/src/Carousel/__tests__/Carousel.overscroll.test.tsx +532 -0
- package/src/Carousel/__tests__/Carousel.page-snap-points.test.tsx +50 -0
- package/src/Carousel/__tests__/Carousel.progress-text.test.tsx +76 -0
- package/src/Carousel/__tests__/Carousel.reduced-motion.test.tsx +3 -6
- package/src/Carousel/__tests__/Carousel.refresh-progress.test.tsx +2 -5
- package/src/Carousel/__tests__/Carousel.scroll-margin.test.tsx +167 -0
- package/src/Carousel/__tests__/Carousel.scroll-progress.test.tsx +518 -0
- package/src/Carousel/__tests__/Carousel.scroll-snap-change.test.tsx +32 -11
- package/src/Carousel/__tests__/Carousel.scroll-sync.test.tsx +237 -24
- package/src/Carousel/__tests__/Carousel.scroll-to-index.test.tsx +115 -0
- package/src/Carousel/__tests__/Carousel.slide-snap.test.tsx +172 -0
- package/src/Carousel/__tests__/Carousel.slides-per-move.test.tsx +179 -1
- package/src/Carousel/__tests__/Carousel.slides-per-page.test.tsx +91 -7
- package/src/Carousel/__tests__/Carousel.snap-type.test.tsx +35 -0
- package/src/Carousel/__tests__/Carousel.transition-modes.test.tsx +30 -5
- package/src/Carousel/__tests__/Carousel.translations.test.tsx +23 -0
- package/src/Carousel/__tests__/Carousel.wheel.test.tsx +160 -0
- package/src/Carousel/hooks/index.ts +1 -0
- package/src/Carousel/hooks/useCarouselLoop.ts +869 -0
- package/src/Carousel/hooks/useCarouselRoot.ts +338 -42
- package/src/Carousel/hooks/useCarouselSlide.ts +44 -9
- package/src/Carousel/hooks/useCarouselViewport.ts +649 -46
- package/src/Carousel/loopEngine.ts +54 -0
- package/src/Carousel/types.ts +457 -35
- package/src/Checkbox/Checkbox.tsx +9 -1
- package/src/Checkbox/__tests__/Checkbox.basic-rendering.test.tsx +14 -0
- package/src/Checkbox/hooks/useCheckboxInput.ts +4 -0
- package/src/Checkbox/types.ts +19 -0
- package/src/CheckboxCard/CheckboxCard.tsx +13 -4
- package/src/CheckboxCard/__tests__/CheckboxCard.basic-rendering.test.tsx +7 -0
- package/src/CheckboxCard/types.ts +65 -17
- package/src/Collapsible/Collapsible.tsx +49 -3
- package/src/Collapsible/README.md +40 -0
- package/src/Collapsible/__tests__/Collapsible.asChild.test.tsx +89 -0
- package/src/Collapsible/__tests__/Collapsible.basic-rendering.test.tsx +27 -0
- package/src/Collapsible/__tests__/Collapsible.collapsedHeight.test.tsx +140 -0
- package/src/Collapsible/hooks/useCollapsibleTrigger.ts +3 -1
- package/src/Collapsible/types.ts +89 -22
- package/src/ContextMenu/ContextMenu.tsx +270 -4
- package/src/ContextMenu/types.ts +148 -6
- package/src/DirectionProvider/DirectionProvider.tsx +41 -9
- package/src/DirectionProvider/__tests__/DirectionProvider.test.tsx +5 -0
- package/src/DirectionProvider/types.ts +28 -3
- package/src/Divider/Divider.tsx +24 -10
- package/src/Divider/__tests__/Divider.test.tsx +5 -0
- package/src/Divider/types.ts +10 -3
- package/src/Drawer/Drawer.tsx +315 -0
- package/src/Drawer/README.md +124 -0
- package/src/Drawer/__tests__/Drawer.behavior.test.tsx +100 -0
- package/src/Drawer/__tests__/Drawer.focus-trap.test.tsx +55 -0
- package/src/Drawer/__tests__/Drawer.rendering.test.tsx +111 -0
- package/src/Drawer/__tests__/Drawer.side.test.tsx +69 -0
- package/src/Drawer/__tests__/dialog-polyfill.ts +39 -0
- package/src/Drawer/index.ts +2 -0
- package/src/Drawer/types.ts +66 -0
- package/src/Dropdown/Dropdown.tsx +117 -0
- package/src/Dropdown/types.ts +241 -11
- package/src/EmptyState/EmptyState.tsx +74 -4
- package/src/EmptyState/__tests__/EmptyState.Actions.test.tsx +7 -2
- package/src/EmptyState/__tests__/EmptyState.Description.test.tsx +3 -1
- package/src/EmptyState/__tests__/EmptyState.Root.test.tsx +10 -0
- package/src/EmptyState/__tests__/EmptyState.Title.test.tsx +3 -1
- package/src/EmptyState/types.ts +49 -6
- package/src/Field/Field.tsx +23 -0
- package/src/Field/__tests__/Field.basic-rendering.test.tsx +11 -0
- package/src/Field/__tests__/Field.error-handling.test.tsx +23 -0
- package/src/Field/__tests__/Field.state-cascade.test.tsx +21 -0
- package/src/Field/hooks/__tests__/useFieldProps.test.tsx +104 -9
- package/src/Field/types.ts +60 -12
- package/src/Fieldset/Fieldset.tsx +54 -18
- package/src/Fieldset/__tests__/Fieldset.basic-rendering.test.tsx +9 -0
- package/src/Fieldset/types.ts +20 -2
- package/src/Input/Input.tsx +14 -9
- package/src/Input/__tests__/Input.basic-rendering.test.tsx +5 -0
- package/src/Input/types.ts +19 -2
- package/src/InputGroup/InputGroup.tsx +11 -3
- package/src/InputGroup/__tests__/InputGroup.basic-rendering.test.tsx +14 -0
- package/src/InputGroup/types.ts +26 -5
- package/src/MillerColumns/MillerColumns.tsx +86 -19
- package/src/MillerColumns/types.ts +83 -27
- package/src/Modal/Modal.tsx +31 -4
- package/src/Modal/README.md +19 -10
- package/src/Modal/__tests__/Modal.focus-trap.test.tsx +162 -0
- package/src/Modal/hooks/useModalContent.ts +32 -0
- package/src/Modal/types.ts +110 -29
- package/src/NavigationMenu/NavigationMenu.tsx +890 -0
- package/src/NavigationMenu/NavigationMenuContext.ts +67 -0
- package/src/NavigationMenu/README.md +355 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.anchor-positioning.test.tsx +132 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.asChild.test.tsx +73 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.basic-rendering.test.tsx +92 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.contract.test.tsx +45 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.controlled-state.test.tsx +134 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.error-handling.test.tsx +62 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.fixtures.tsx +79 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.forceMount.test.tsx +52 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.hover-interaction.test.tsx +254 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.indicator.test.tsx +252 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.keyboard-interaction.test.tsx +294 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.keyboard-navigation.test.tsx +126 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.link.test.tsx +139 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.motion.test.tsx +568 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.mouse-interaction.test.tsx +76 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.uncontrolled-state.test.tsx +30 -0
- package/src/NavigationMenu/__tests__/NavigationMenu.viewport.test.tsx +113 -0
- package/src/NavigationMenu/constants.ts +5 -0
- package/src/NavigationMenu/hooks/index.ts +7 -0
- package/src/NavigationMenu/hooks/useNavigationMenuEntry.ts +33 -0
- package/src/NavigationMenu/hooks/useNavigationMenuIndicator.ts +70 -0
- package/src/NavigationMenu/hooks/useNavigationMenuLink.ts +72 -0
- package/src/NavigationMenu/hooks/useNavigationMenuRoot.ts +301 -0
- package/src/NavigationMenu/hooks/useNavigationMenuTopLevelEntry.ts +65 -0
- package/src/NavigationMenu/hooks/useNavigationMenuTrigger.ts +158 -0
- package/src/NavigationMenu/hooks/useNavigationMenuViewport.ts +101 -0
- package/src/NavigationMenu/index.ts +3 -0
- package/src/NavigationMenu/types.ts +259 -0
- package/src/NavigationMenu/utils.ts +89 -0
- package/src/Popover/Popover.tsx +427 -0
- package/src/Popover/PopoverContext.ts +13 -0
- package/src/Popover/README.md +106 -0
- package/src/Popover/__tests__/Popover.anchor.test.tsx +38 -0
- package/src/Popover/__tests__/Popover.asChild.test.tsx +160 -0
- package/src/Popover/__tests__/Popover.basic-rendering.test.tsx +106 -0
- package/src/Popover/__tests__/Popover.click-outside.test.tsx +149 -0
- package/src/Popover/__tests__/Popover.close.test.tsx +70 -0
- package/src/Popover/__tests__/Popover.content.test.tsx +58 -0
- package/src/Popover/__tests__/Popover.controlled-state.test.tsx +45 -0
- package/src/Popover/__tests__/Popover.error-handling.test.tsx +51 -0
- package/src/Popover/__tests__/Popover.focus.test.tsx +43 -0
- package/src/Popover/__tests__/Popover.keyboard-interaction.test.tsx +71 -0
- package/src/Popover/__tests__/Popover.mouse-interaction.test.tsx +69 -0
- package/src/Popover/__tests__/Popover.uncontrolled-state.test.tsx +44 -0
- package/src/Popover/hooks/index.ts +3 -0
- package/src/Popover/hooks/usePopoverContent.ts +98 -0
- package/src/Popover/hooks/usePopoverRoot.ts +84 -0
- package/src/Popover/hooks/usePopoverTrigger.ts +33 -0
- package/src/Popover/index.ts +2 -0
- package/src/Popover/types.ts +197 -0
- package/src/Portal/Portal.tsx +50 -10
- package/src/Portal/__tests__/Portal.basic-rendering.test.tsx +5 -0
- package/src/Portal/types.ts +5 -0
- package/src/Progress/Progress.tsx +33 -1
- package/src/Progress/__tests__/Progress.basic-rendering.test.tsx +10 -0
- package/src/Progress/__tests__/Progress.value.test.tsx +21 -0
- package/src/Progress/types.ts +20 -4
- package/src/Radio/Radio.tsx +9 -1
- package/src/Radio/__tests__/Radio.basic-rendering.test.tsx +14 -0
- package/src/Radio/hooks/useRadioRoot.ts +3 -0
- package/src/Radio/types.ts +20 -0
- package/src/RadioCard/RadioCard.tsx +11 -0
- package/src/RadioCard/__tests__/RadioCard.basic-rendering.test.tsx +8 -0
- package/src/RadioCard/__tests__/RadioCard.disabled-items.test.tsx +27 -0
- package/src/RadioCard/__tests__/RadioCard.keyboard-interaction.test.tsx +53 -0
- package/src/RadioCard/__tests__/RadioCard.ref-forwarding.test.tsx +54 -0
- package/src/RadioCard/__tests__/RadioCard.uncontrolled-state.test.tsx +21 -0
- package/src/RadioCard/hooks/useRadioCardRoot.ts +11 -0
- package/src/RadioCard/types.ts +95 -22
- package/src/RadioGroup/RadioGroup.tsx +11 -0
- package/src/RadioGroup/__tests__/RadioGroup.basic-rendering.test.tsx +8 -0
- package/src/RadioGroup/__tests__/RadioGroup.disabled.test.tsx +27 -0
- package/src/RadioGroup/__tests__/RadioGroup.ref-forwarding.test.tsx +29 -0
- package/src/RadioGroup/__tests__/RadioGroup.roving-tabindex.test.tsx +31 -0
- package/src/RadioGroup/hooks/useRadioGroupRoot.ts +11 -0
- package/src/RadioGroup/types.ts +73 -9
- package/src/SegmentedControl/README.md +154 -0
- package/src/SegmentedControl/SegmentedControl.tsx +309 -0
- package/src/SegmentedControl/SegmentedControlContext.ts +28 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.asChild.test.tsx +50 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.basic-rendering.test.tsx +100 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.controlled-state.test.tsx +107 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.disabled-keydown-guards.test.tsx +62 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.disabled.test.tsx +151 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.error-handling.test.tsx +17 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.keyboard-interaction.test.tsx +117 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.orientation.test.tsx +54 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.reading-direction.test.tsx +56 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.ref-forwarding.test.tsx +45 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.roving-tabindex.test.tsx +104 -0
- package/src/SegmentedControl/__tests__/SegmentedControl.uncontrolled-state.test.tsx +94 -0
- package/src/SegmentedControl/hooks/index.ts +2 -0
- package/src/SegmentedControl/hooks/useSegmentedControlContext.ts +1 -0
- package/src/SegmentedControl/hooks/useSegmentedControlRoot.ts +86 -0
- package/src/SegmentedControl/index.ts +2 -0
- package/src/SegmentedControl/types.ts +138 -0
- package/src/Select/README.md +122 -157
- package/src/Select/Select.tsx +595 -68
- package/src/Select/SelectContext.ts +38 -0
- package/src/Select/SelectItemIndicatorContext.ts +29 -0
- package/src/Select/__tests__/Select.asChild.test.tsx +2 -2
- package/src/Select/__tests__/Select.basic-rendering.test.tsx +22 -3
- package/src/Select/__tests__/Select.controlled-state.test.tsx +6 -6
- package/src/Select/__tests__/Select.data-attributes.test.tsx +4 -4
- package/src/Select/__tests__/Select.field-integration.test.tsx +11 -11
- package/src/Select/__tests__/Select.form.test.tsx +38 -0
- package/src/Select/__tests__/Select.group.test.tsx +6 -6
- package/src/Select/__tests__/Select.keyboard-edge.test.tsx +95 -0
- package/src/Select/__tests__/Select.keyboard.test.tsx +124 -0
- package/src/Select/__tests__/Select.mutation-hardening.test.tsx +317 -0
- package/src/Select/__tests__/Select.native-item.test.tsx +30 -0
- package/src/Select/__tests__/Select.open-close.test.tsx +57 -0
- package/src/Select/__tests__/Select.placeholder.test.tsx +4 -4
- package/src/Select/__tests__/Select.rich-asChild.test.tsx +60 -0
- package/src/Select/__tests__/Select.rich-mode.test.tsx +16 -0
- package/src/Select/__tests__/Select.selection.test.tsx +104 -0
- package/src/Select/__tests__/Select.separator.test.tsx +71 -0
- package/src/Select/__tests__/Select.strict-context.test.tsx +36 -0
- package/src/Select/__tests__/Select.typeahead.test.tsx +156 -0
- package/src/Select/__tests__/Select.value-mirror.test.tsx +240 -0
- package/src/Select/constants.ts +8 -0
- package/src/Select/hooks/index.ts +2 -0
- package/src/Select/hooks/useSelectContent.ts +149 -0
- package/src/Select/hooks/useSelectRoot.ts +149 -0
- package/src/Select/types.ts +199 -31
- package/src/SkipNav/SkipNav.tsx +69 -29
- package/src/SkipNav/__tests__/SkipNav.basic-rendering.test.tsx +6 -0
- package/src/SkipNav/types.ts +17 -9
- package/src/Slider/Slider.tsx +33 -1
- package/src/Slider/SliderContext.ts +28 -1
- package/src/Slider/types.ts +157 -9
- package/src/Slot/Slot.tsx +94 -19
- package/src/Slot/__tests__/Slot.test.tsx +110 -0
- package/src/Slot/composeEventHandlers.ts +26 -2
- package/src/Slot/types.ts +16 -0
- package/src/Status/Status.tsx +36 -15
- package/src/Status/__tests__/Status.test.tsx +5 -0
- package/src/Status/types.ts +12 -1
- package/src/Switch/Switch.tsx +15 -2
- package/src/Switch/__tests__/Switch.basic-rendering.test.tsx +7 -0
- package/src/Switch/hooks/useSwitchRoot.ts +3 -0
- package/src/Switch/types.ts +49 -22
- package/src/Table/Table.tsx +44 -10
- package/src/Table/types.ts +66 -17
- package/src/Tabs/Tabs.tsx +8 -0
- package/src/Tabs/types.ts +29 -4
- package/src/Textarea/Textarea.tsx +9 -1
- package/src/Textarea/__tests__/Textarea.basic-rendering.test.tsx +5 -0
- package/src/Textarea/types.ts +20 -3
- package/src/Toggle/Toggle.tsx +51 -13
- package/src/Toggle/__tests__/Toggle.basic-rendering.test.tsx +5 -0
- package/src/Toggle/types.ts +54 -4
- package/src/ToggleGroup/ToggleGroup.tsx +14 -1
- package/src/ToggleGroup/__tests__/ToggleGroup.asChild.test.tsx +20 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.basic-rendering.test.tsx +9 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.dynamic-items.test.tsx +70 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.error-handling.test.tsx +23 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.keyboard-interaction.test.tsx +23 -1
- package/src/ToggleGroup/__tests__/ToggleGroup.ref-forwarding.test.tsx +58 -0
- package/src/ToggleGroup/hooks/useToggleGroupRoot.ts +21 -1
- package/src/ToggleGroup/types.ts +55 -2
- package/src/Tooltip/Tooltip.tsx +98 -20
- package/src/Tooltip/hooks/__tests__/useTooltipProvider.test.tsx +40 -0
- package/src/Tooltip/hooks/useTooltipProvider.ts +13 -1
- package/src/Tooltip/types.ts +89 -8
- package/src/Tree/Tree.tsx +187 -33
- package/src/Tree/types.ts +54 -12
- package/src/VisuallyHidden/VisuallyHidden.tsx +33 -8
- package/src/VisuallyHidden/__tests__/VisuallyHidden.test.tsx +15 -1
- package/src/VisuallyHidden/types.ts +11 -1
- package/src/index.ts +4 -0
- package/src/test/intersectionObserverPolyfill.ts +7 -0
- package/src/test/resizeObserverPolyfill.ts +80 -0
- package/src/utils/focusable.ts +15 -0
- package/src/utils/index.ts +1 -0
package/src/Status/Status.tsx
CHANGED
|
@@ -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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* {
|
|
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
|
-
* {
|
|
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 —
|
|
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
|
});
|
package/src/Status/types.ts
CHANGED
|
@@ -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
|
};
|
package/src/Switch/Switch.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
};
|
package/src/Switch/types.ts
CHANGED
|
@@ -1,50 +1,67 @@
|
|
|
1
1
|
import { ChangeEventHandler, ComponentProps, ReactNode, Ref } from "react";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
/**
|
|
18
|
+
/** Content of the switch — typically a single
|
|
19
|
+
* {@link SwitchThumbProps | `Switch.Thumb`}. */
|
|
15
20
|
children?: ReactNode;
|
|
16
|
-
/**
|
|
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
|
-
*
|
|
22
|
-
* checked state
|
|
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
|
-
/**
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
package/src/Table/Table.tsx
CHANGED
|
@@ -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
|
|
24
|
-
* {@link TableHeaderProps.scope | `scope`} attribute so screen
|
|
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
|
|
132
|
-
*
|
|
133
|
-
*
|
|
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>
|
package/src/Table/types.ts
CHANGED
|
@@ -6,58 +6,107 @@ import type {
|
|
|
6
6
|
TdHTMLAttributes,
|
|
7
7
|
} from "react";
|
|
8
8
|
|
|
9
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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} —
|
|
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
|
-
*
|
|
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
|
-
|
|
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`,
|
|
53
|
-
* `captionSide`, plus all `HTMLAttributes` on
|
|
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
|
-
*
|
|
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<
|
|
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
|
-
| {
|
|
109
|
-
|
|
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
|
});
|