@primitiv-ui/react 0.1.27 → 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/Carousel/types.ts
CHANGED
|
@@ -7,8 +7,20 @@ import { ComponentProps, ReactNode, RefObject } from "react";
|
|
|
7
7
|
* rejects shapes that supply both or neither.
|
|
8
8
|
*/
|
|
9
9
|
export type CarouselRootLabelProps =
|
|
10
|
-
| {
|
|
11
|
-
|
|
10
|
+
| {
|
|
11
|
+
/** Accessible name for the carousel region, announced as
|
|
12
|
+
* `aria-label`. Prefer a short, human-readable description (e.g.
|
|
13
|
+
* `"Featured products"`). Mutually exclusive with `ariaLabelledBy`. */
|
|
14
|
+
ariaLabel: string;
|
|
15
|
+
ariaLabelledBy?: never;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
ariaLabel?: never;
|
|
19
|
+
/** Id of an existing element to name the carousel region, set as
|
|
20
|
+
* `aria-labelledby`. Use when a visible heading already labels the
|
|
21
|
+
* carousel. Mutually exclusive with `ariaLabel`. */
|
|
22
|
+
ariaLabelledBy: string;
|
|
23
|
+
};
|
|
12
24
|
|
|
13
25
|
/**
|
|
14
26
|
* Uncontrolled page state — the Root owns the active page internally,
|
|
@@ -87,18 +99,46 @@ export type CarouselRootPlayingStateProps =
|
|
|
87
99
|
export type CarouselAutoplay = boolean | { delay: number };
|
|
88
100
|
|
|
89
101
|
/**
|
|
90
|
-
* Visual transition mode for the viewport.
|
|
102
|
+
* Visual transition mode for the viewport. The resolved value is
|
|
103
|
+
* published on the Root as `data-transition` so consumer CSS can switch
|
|
104
|
+
* the visual off a single hook.
|
|
91
105
|
*
|
|
92
106
|
* - `"slide"` (default) — relies on native CSS scroll-snap; the
|
|
93
107
|
* Viewport scrolls programmatically when the page changes and
|
|
94
108
|
* listens for `scrollsnapchange` to update React state when the
|
|
95
109
|
* user swipes.
|
|
96
|
-
* - `"
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
110
|
+
* - `"fade"` — installs no scroll wiring (like `"none"`), but names the
|
|
111
|
+
* intent so a styled surface can ship a crossfade by default: stack
|
|
112
|
+
* the slides and cross-fade opacity off the per-slide `data-state`
|
|
113
|
+
* hook. Native swipe/drag and peek don't apply (there's no scroll);
|
|
114
|
+
* controls, indicators, and keyboard paging still work.
|
|
115
|
+
* - `"none"` — the Viewport installs no scroll wiring at all, and the
|
|
116
|
+
* styled surface ships no default visual: consumer CSS owns the
|
|
117
|
+
* transition entirely via the `data-state` hook on each slide, which
|
|
118
|
+
* still flips with the active page.
|
|
100
119
|
*/
|
|
101
|
-
export type CarouselTransition = "slide" | "none";
|
|
120
|
+
export type CarouselTransition = "slide" | "fade" | "none";
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Resolved wrap-around navigation mode — the value published as the
|
|
124
|
+
* `data-loop` styling hook on the Root. The consumer-facing `loop` prop
|
|
125
|
+
* accepts `boolean | "wrap" | "infinite"` and resolves to this:
|
|
126
|
+
*
|
|
127
|
+
* - `"none"` — navigation clamps at the ends (`loop` omitted / `false`).
|
|
128
|
+
* - `"wrap"` — *semantic* wrapping (`loop` / `loop={true}` / `loop="wrap"`):
|
|
129
|
+
* Next/Previous and autoplay wrap past the ends, the triggers never
|
|
130
|
+
* disable, but wrapping last→first smooth-scrolls the whole track back
|
|
131
|
+
* (a visible rewind, the same path `Home`/`End` take).
|
|
132
|
+
* - `"infinite"` — continuous infinite (`loop="infinite"`): the same wrap
|
|
133
|
+
* page model, plus a cloned edge buffer and a native-scroll recentre so
|
|
134
|
+
* the wrap is a continuous glide with no visible rewind.
|
|
135
|
+
*
|
|
136
|
+
* Both `"wrap"` and `"infinite"` share the page model (the wrap
|
|
137
|
+
* arithmetic in `next`/`previous` and the never-disable boundaries);
|
|
138
|
+
* `"infinite"` layers the clone/scroll behaviour on top, keyed off the
|
|
139
|
+
* `data-loop="infinite"` hook.
|
|
140
|
+
*/
|
|
141
|
+
export type CarouselLoopMode = "none" | "wrap" | "infinite";
|
|
102
142
|
|
|
103
143
|
/**
|
|
104
144
|
* Scroll-snap alignment that the Viewport should target when
|
|
@@ -112,8 +152,135 @@ export type CarouselTransition = "slide" | "none";
|
|
|
112
152
|
* `(viewportWidth − slideWidth) / 2`. Use this with
|
|
113
153
|
* `scroll-snap-align: center` in consumer CSS (e.g. Cover Flow
|
|
114
154
|
* layouts where slides are narrower than the Viewport).
|
|
155
|
+
* - `"end"` — scrolls so the first slide of the target page's
|
|
156
|
+
* **trailing** edge aligns with the Viewport's trailing edge. The
|
|
157
|
+
* target is offset inward by the full `viewportWidth − slideWidth`.
|
|
158
|
+
* Use with `scroll-snap-align: end`.
|
|
159
|
+
*
|
|
160
|
+
* Settable on `Carousel.Root` (the default for every slide) and
|
|
161
|
+
* overridden per-slide via {@link CarouselSlideProps.snapAlign} — e.g. a
|
|
162
|
+
* variable-width layout where only some slides should centre. Matches
|
|
163
|
+
* Ark UI's per-`Item` `snapAlign`.
|
|
164
|
+
*/
|
|
165
|
+
export type CarouselSnapAlign = "start" | "center" | "end";
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* `scroll-snap-type` strictness the Viewport scrolls with.
|
|
169
|
+
*
|
|
170
|
+
* - `"mandatory"` (default) — the browser always rests on a snap point;
|
|
171
|
+
* scrolling can't stop mid-way between slides.
|
|
172
|
+
* - `"proximity"` — the browser only nudges toward a snap point when the
|
|
173
|
+
* scroll ends *near* one, otherwise leaving the scroll wherever it
|
|
174
|
+
* stopped — for a looser, free-scrolling feel (e.g. a gallery where
|
|
175
|
+
* forcing a rest on every slide feels too rigid).
|
|
176
|
+
*
|
|
177
|
+
* The resolved value is published on the Viewport as `data-snap-type` so
|
|
178
|
+
* consumer CSS can switch `scroll-snap-type`'s strictness off a single hook.
|
|
179
|
+
* Matches Ark UI's `snapType`.
|
|
180
|
+
*/
|
|
181
|
+
export type CarouselSnapType = "mandatory" | "proximity";
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Payload passed to `Carousel.Root`'s `onDragStatusChange` on every
|
|
185
|
+
* mouse-drag status transition (only reachable when `allowMouseDrag` is
|
|
186
|
+
* `true`):
|
|
187
|
+
*
|
|
188
|
+
* - `"dragging.start"` — the pointer just crossed the click-vs-drag
|
|
189
|
+
* movement threshold; a drag has begun.
|
|
190
|
+
* - `"dragging"` — a subsequent pointer move while already dragging.
|
|
191
|
+
* - `"dragging.end"` — the drag ended (`pointerup` or `pointercancel`).
|
|
192
|
+
*
|
|
193
|
+
* `page` is the live active page at the moment of the event; `isDragging`
|
|
194
|
+
* mirrors the imperative `isDragging()` snapshot at that moment (`true`
|
|
195
|
+
* for `"dragging.start"`/`"dragging"`, `false` for `"dragging.end"`).
|
|
196
|
+
* Matches Ark UI's `onDragStatusChange` shape.
|
|
197
|
+
*/
|
|
198
|
+
export type CarouselDragStatus = {
|
|
199
|
+
type: "dragging.start" | "dragging" | "dragging.end";
|
|
200
|
+
page: number;
|
|
201
|
+
isDragging: boolean;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Payload passed to `Carousel.Root`'s `onOverscrollStatusChange` whenever
|
|
206
|
+
* the user pushes against a boundary that has nowhere further to go —
|
|
207
|
+
* detected off the same `canGoNext` / `canGoPrevious` page-boundary truth
|
|
208
|
+
* the rest of the primitive already uses, from three input sources the
|
|
209
|
+
* carousel directly owns the physics for:
|
|
210
|
+
*
|
|
211
|
+
* - `"keyboard"` — the forward/backward arrow key pressed while already
|
|
212
|
+
* at that boundary (`Home`/`End` are absolute jumps, not directional
|
|
213
|
+
* pushes, so they never fire this).
|
|
214
|
+
* - `"wheel"` — the existing horizontal-desktop wheel-to-scroll
|
|
215
|
+
* translation, blocked at a boundary.
|
|
216
|
+
* - `"drag"` — a mouse drag (`allowMouseDrag`) pushing past a boundary.
|
|
217
|
+
*
|
|
218
|
+
* `"keyboard"` and `"wheel"` are instantaneous taps with no meaningful
|
|
219
|
+
* distance — they always fire a single bare `"overscroll"` with
|
|
220
|
+
* `amount: 0`. `"drag"` is the one continuous, physically real case —
|
|
221
|
+
* it fires `"overscroll.start"` the moment the drag starts pushing past
|
|
222
|
+
* the boundary, `"overscroll"` on every subsequent move while still
|
|
223
|
+
* pushing (with the live `amount`, the drag delta past the boundary),
|
|
224
|
+
* and `"overscroll.end"` when the drag stops pushing past it (a reversal
|
|
225
|
+
* back within bounds, or the drag ending) — mirroring
|
|
226
|
+
* `CarouselDragStatus`'s shape. `page` is the active page at the moment
|
|
227
|
+
* of the event.
|
|
228
|
+
*
|
|
229
|
+
* Native touch/swipe overscroll (OS-level rubber-banding) is
|
|
230
|
+
* deliberately out of scope — that's browser-owned scroll physics with
|
|
231
|
+
* no JS hook to observe it from, consistent with the primitive's
|
|
232
|
+
* "native scroll is the source of truth" approach elsewhere.
|
|
115
233
|
*/
|
|
116
|
-
export type
|
|
234
|
+
export type CarouselOverscrollStatus = {
|
|
235
|
+
type: "overscroll.start" | "overscroll" | "overscroll.end";
|
|
236
|
+
edge: "start" | "end";
|
|
237
|
+
source: "keyboard" | "wheel" | "drag";
|
|
238
|
+
amount: number;
|
|
239
|
+
page: number;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Payload passed to `Carousel.Root`'s `onAutoplayStatusChange` on every
|
|
244
|
+
* autoplay status transition (only reachable when `autoplay` is enabled):
|
|
245
|
+
*
|
|
246
|
+
* - `"autoplay.start"` — the timer just became active: autoplay is
|
|
247
|
+
* enabled, `playing` is `true`, another page remains, and the timer
|
|
248
|
+
* isn't suspended by hover/focus/touch.
|
|
249
|
+
* - `"autoplay"` — a scheduled tick fired and is about to advance the
|
|
250
|
+
* page, while the timer stays active.
|
|
251
|
+
* - `"autoplay.stop"` — the timer stopped running, whether because
|
|
252
|
+
* `playing` flipped `false`, the last page was reached, or
|
|
253
|
+
* hover/focus/touch suspended it.
|
|
254
|
+
*
|
|
255
|
+
* Fires on every tick, not just play/pause toggles. `page` is the active
|
|
256
|
+
* page at the moment of the event; `isPlaying` mirrors whether the timer
|
|
257
|
+
* is running right after the event (`true` for `"autoplay.start"`/
|
|
258
|
+
* `"autoplay"`, `false` for `"autoplay.stop"`). Matches Ark UI's
|
|
259
|
+
* `onAutoplayStatusChange` shape.
|
|
260
|
+
*/
|
|
261
|
+
export type CarouselAutoplayStatus = {
|
|
262
|
+
type: "autoplay.start" | "autoplay" | "autoplay.stop";
|
|
263
|
+
page: number;
|
|
264
|
+
isPlaying: boolean;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Axis the carousel scrolls and paginates along.
|
|
269
|
+
*
|
|
270
|
+
* - `"horizontal"` (default) — slides lay out inline; the viewport
|
|
271
|
+
* scroll-snaps on the inline (x) axis. `Carousel.NextTrigger` /
|
|
272
|
+
* `Carousel.PreviousTrigger` and the viewport `ArrowRight` /
|
|
273
|
+
* `ArrowLeft` keys advance / retreat.
|
|
274
|
+
* - `"vertical"` — slides lay out in the block direction; the viewport
|
|
275
|
+
* scroll-snaps on the block (y) axis. The viewport `ArrowDown` /
|
|
276
|
+
* `ArrowUp` keys advance / retreat instead (the horizontal arrows are
|
|
277
|
+
* inert), and programmatic paging scrolls on the block axis.
|
|
278
|
+
*
|
|
279
|
+
* The resolved value is published on the Root as `data-orientation` so
|
|
280
|
+
* consumer CSS can switch layout (e.g. a column viewport with a
|
|
281
|
+
* `scroll-snap-type: y mandatory`) off a single hook.
|
|
282
|
+
*/
|
|
283
|
+
export type CarouselOrientation = "horizontal" | "vertical";
|
|
117
284
|
|
|
118
285
|
/**
|
|
119
286
|
* Pin DOM `id`s on the rendered sub-components for SSR / hydration
|
|
@@ -151,6 +318,10 @@ export type CarouselTranslations = {
|
|
|
151
318
|
/** Accessible name for `Carousel.PlayPauseTrigger` while playing.
|
|
152
319
|
* Default: `"Stop automatic slide show"`. */
|
|
153
320
|
stopSlideshow?: string;
|
|
321
|
+
/** Format used for `Carousel.ProgressText`'s default rendered content.
|
|
322
|
+
* Receives the 0-indexed active `page` and the live `totalPages`.
|
|
323
|
+
* Default: `({ page, totalPages }) => "${page + 1} of ${totalPages}"`. */
|
|
324
|
+
progressText?: (params: { page: number; totalPages: number }) => string;
|
|
154
325
|
};
|
|
155
326
|
|
|
156
327
|
/** Props for `Carousel.Root` — the labelled `<section>` wrapping the whole widget; combines label, page-state, and playing-state shapes with autoplay, transition, and layout options. */
|
|
@@ -170,13 +341,27 @@ export type CarouselRootProps = Omit<
|
|
|
170
341
|
* greater than `1`, slides are grouped into pages of that size for
|
|
171
342
|
* navigation purposes: indicators auto-render per page, boundary
|
|
172
343
|
* clamp moves to the last page, and `Carousel.NextTrigger` /
|
|
173
|
-
* `Carousel.PreviousTrigger` advance one page at a time.
|
|
344
|
+
* `Carousel.PreviousTrigger` advance one page at a time. The **last
|
|
345
|
+
* page always end-aligns** (its window is full, flush with the track
|
|
346
|
+
* end) rather than leaving a partial page — a partial page's leading
|
|
347
|
+
* slide can't align to the viewport start, which desyncs the active
|
|
348
|
+
* page against the scroll. So 7 slides at `slidesPerPage={3}` are 3
|
|
349
|
+
* pages — `[0,1,2] [3,4,5] [4,5,6]` — the last shifted back by one to
|
|
350
|
+
* stay full. Coerced to an integer ≥ 1 — `0`, negative, fractional,
|
|
351
|
+
* and non-finite values are clamped (e.g. `2.5 → 2`, `0 → 1`) so the
|
|
352
|
+
* page maths never divides by zero. */
|
|
174
353
|
slidesPerPage?: number;
|
|
175
354
|
/** Number of slides advanced by `Carousel.NextTrigger` /
|
|
176
|
-
* `Carousel.PreviousTrigger`. `"auto"` (default) advances one
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
355
|
+
* `Carousel.PreviousTrigger`. `"auto"` (default) advances one full page
|
|
356
|
+
* at a time (= `slidesPerPage`); a number advances exactly that many
|
|
357
|
+
* slides per click and pages are windowed so the visible window always
|
|
358
|
+
* stays full. A numeric move is coerced to an integer in
|
|
359
|
+
* `[1, slidesPerPage]` — it can neither drop below one nor skip past a
|
|
360
|
+
* page (which would orphan the slides in the gap) — and the **last page
|
|
361
|
+
* is end-aligned to the track end**, so every slide stays reachable even
|
|
362
|
+
* when the move doesn't divide the slide count evenly (e.g. 6 slides,
|
|
363
|
+
* `slidesPerPage={3}`, `slidesPerMove={2}` yields pages
|
|
364
|
+
* `[0,1,2] [2,3,4] [3,4,5]`). */
|
|
180
365
|
slidesPerMove?: number | "auto";
|
|
181
366
|
/** Override the default user-visible strings the component owns —
|
|
182
367
|
* see {@link CarouselTranslations}. Useful for i18n. */
|
|
@@ -191,6 +376,60 @@ export type CarouselRootProps = Omit<
|
|
|
191
376
|
* `scroll-snap-align: center` on slides (e.g. Cover Flow layouts
|
|
192
377
|
* where slides are narrower than the Viewport). */
|
|
193
378
|
snapAlign?: CarouselSnapAlign;
|
|
379
|
+
/** Axis the carousel scrolls and paginates along — see
|
|
380
|
+
* {@link CarouselOrientation}. Defaults to `"horizontal"`. Switches
|
|
381
|
+
* the viewport scroll axis, the arrow-key bindings, and the
|
|
382
|
+
* `data-orientation` styling hook on the Root. */
|
|
383
|
+
orientation?: CarouselOrientation;
|
|
384
|
+
/** Wrap-around navigation mode — see {@link CarouselLoopMode}.
|
|
385
|
+
* Defaults to `false` (`"none"`). Accepts a boolean for ergonomics or a
|
|
386
|
+
* named mode:
|
|
387
|
+
*
|
|
388
|
+
* - `false` / omitted → `"none"` (clamp at the ends).
|
|
389
|
+
* - `true` / `"wrap"` → `"wrap"` (semantic wrap: Next/Previous and
|
|
390
|
+
* autoplay wrap past the ends and the triggers never disable, but the
|
|
391
|
+
* wrap last→first smooth-scrolls the track back — a visible rewind).
|
|
392
|
+
* - `"infinite"` → continuous infinite: the same wrap page model plus a
|
|
393
|
+
* cloned edge buffer and native-scroll recentre so the wrap is a
|
|
394
|
+
* continuous glide with no rewind.
|
|
395
|
+
*
|
|
396
|
+
* All wrapping requires more than one page — a single-page carousel has
|
|
397
|
+
* no wrap target, so the triggers stay disabled regardless. The resolved
|
|
398
|
+
* mode is published as `data-loop="none" | "wrap" | "infinite"` on the
|
|
399
|
+
* Root. */
|
|
400
|
+
loop?: boolean | "wrap" | "infinite";
|
|
401
|
+
/** Whether the Viewport supports mouse click-and-drag scrolling —
|
|
402
|
+
* the pointer tracks 1:1 into `scrollLeft`/`scrollTop` (no momentum)
|
|
403
|
+
* once past a small movement threshold, release lets the existing
|
|
404
|
+
* `scroll-snap-type` settle. Defaults to `false`: an unconditionally-on
|
|
405
|
+
* drag can conflict with a consumer's own drag-sensitive slide content
|
|
406
|
+
* (a nested carousel, a draggable card, a canvas), so it's opt-in.
|
|
407
|
+
* Touch/pen scrolling is unaffected either way — that's native,
|
|
408
|
+
* independent of this prop. */
|
|
409
|
+
allowMouseDrag?: boolean;
|
|
410
|
+
/** Fires on every mouse-drag status transition — see
|
|
411
|
+
* {@link CarouselDragStatus}. Matches Ark UI's `onDragStatusChange`.
|
|
412
|
+
* No-op unless `allowMouseDrag` is `true` (a drag can't start
|
|
413
|
+
* otherwise). */
|
|
414
|
+
onDragStatusChange?: (status: CarouselDragStatus) => void;
|
|
415
|
+
/** Fires whenever the user pushes against a boundary with nowhere
|
|
416
|
+
* further to go, from the keyboard, wheel, or a mouse drag — see
|
|
417
|
+
* {@link CarouselOverscrollStatus}. */
|
|
418
|
+
onOverscrollStatusChange?: (status: CarouselOverscrollStatus) => void;
|
|
419
|
+
/** Fires on every autoplay status transition — see
|
|
420
|
+
* {@link CarouselAutoplayStatus}. Matches Ark UI's
|
|
421
|
+
* `onAutoplayStatusChange`. Fires on every tick, not just play/pause
|
|
422
|
+
* toggles — useful for analytics. No-op unless `autoplay` is enabled. */
|
|
423
|
+
onAutoplayStatusChange?: (status: CarouselAutoplayStatus) => void;
|
|
424
|
+
/** Visibility threshold(s) the `isInView` fallback's
|
|
425
|
+
* `IntersectionObserver` uses — both as the observer's own `threshold`
|
|
426
|
+
* option and (for an array, the highest value) the cutoff a slide's
|
|
427
|
+
* `intersectionRatio` must clear to count as "in view". Matches Ark
|
|
428
|
+
* UI's `inViewThreshold` shape. Defaults to `0.6`. */
|
|
429
|
+
inViewThreshold?: number | number[];
|
|
430
|
+
/** `scroll-snap-type` strictness — see {@link CarouselSnapType}.
|
|
431
|
+
* Defaults to `"mandatory"`. */
|
|
432
|
+
snapType?: CarouselSnapType;
|
|
194
433
|
};
|
|
195
434
|
|
|
196
435
|
/**
|
|
@@ -209,12 +448,33 @@ export type CarouselContextValue = {
|
|
|
209
448
|
/** Ordered list of currently-mounted slide keys. The slide's index is
|
|
210
449
|
* its position in this array; the array's length is the total. */
|
|
211
450
|
slideKeys: string[];
|
|
212
|
-
/** Number of slides visible per page
|
|
451
|
+
/** Number of slides visible per page — the consumer's `slidesPerPage`
|
|
452
|
+
* coerced to an integer ≥ 1 (0 / negative / non-finite → 1). */
|
|
213
453
|
slidesPerPage: number;
|
|
214
454
|
/** Resolved slides advanced per Prev/Next click — equal to
|
|
215
|
-
* `slidesPerPage` when the consumer left `slidesPerMove="auto"`,
|
|
216
|
-
*
|
|
455
|
+
* `slidesPerPage` when the consumer left `slidesPerMove="auto"`, else
|
|
456
|
+
* the numeric value coerced to an integer in `[1, slidesPerPage]` (a
|
|
457
|
+
* move can neither drop below one nor skip past a page). */
|
|
217
458
|
effectiveSlidesPerMove: number;
|
|
459
|
+
/** Start slide index of the *last* page's window — `max(0, total -
|
|
460
|
+
* slidesPerPage)`. Every page's own offset is `min(page *
|
|
461
|
+
* effectiveSlidesPerMove, maxOffset)`; used to derive any page's window
|
|
462
|
+
* (not just the current one), e.g. the multi-slide `scroll-margin`
|
|
463
|
+
* extension that keeps native scroll-snap alignment consistent with the
|
|
464
|
+
* programmatic scroll for `slidesPerPage > 1`. */
|
|
465
|
+
maxOffset: number;
|
|
466
|
+
/** Start slide index of the currently-active window. In `"auto"`
|
|
467
|
+
* (paged) mode this is `currentPage * slidesPerPage` (the last page may
|
|
468
|
+
* be partial); in numeric (windowed) mode the last page is end-aligned
|
|
469
|
+
* — clamped to `total − slidesPerPage` — so every slide stays reachable
|
|
470
|
+
* even when the move doesn't divide the track evenly. Drives the slide
|
|
471
|
+
* `data-state` window and the viewport scroll target. */
|
|
472
|
+
currentPageOffset: number;
|
|
473
|
+
/** Map a leading slide index (e.g. a user swipe's snap target) back to
|
|
474
|
+
* its page index, clamped into `[0, totalPages − 1]`. Paged mode groups
|
|
475
|
+
* by `slidesPerPage`; windowed mode inverts the move offset to the
|
|
476
|
+
* nearest window start. */
|
|
477
|
+
pageForSlideIndex: (slideIndex: number) => number;
|
|
218
478
|
/** Live total page count — `ceil(total / slidesPerPage)` in `"auto"`
|
|
219
479
|
* mode (partial last page allowed), else
|
|
220
480
|
* `floor((total - slidesPerPage) / effectiveSlidesPerMove) + 1`
|
|
@@ -231,13 +491,17 @@ export type CarouselContextValue = {
|
|
|
231
491
|
/** `true` when there is a backward navigation target. Drives the
|
|
232
492
|
* `disabled` attribute on `Carousel.PreviousTrigger`. */
|
|
233
493
|
canGoPrevious: boolean;
|
|
234
|
-
/** Advance the active page by one step. No-op when `!canGoNext`.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
494
|
+
/** Advance the active page by one step. No-op when `!canGoNext`. Pass
|
|
495
|
+
* `instant` to bypass the resolved smooth/reduced-motion scroll for
|
|
496
|
+
* just this one call — see {@link CarouselImperativeApi.next}. */
|
|
497
|
+
next: (instant?: boolean) => void;
|
|
498
|
+
/** Retreat the active page by one step. No-op when `!canGoPrevious`.
|
|
499
|
+
* See {@link CarouselContextValue.next} for the `instant` override. */
|
|
500
|
+
previous: (instant?: boolean) => void;
|
|
238
501
|
/** Jump directly to `target` (zero-based page index). Used by
|
|
239
|
-
* `Carousel.Indicator` to dispatch click-to-jump.
|
|
240
|
-
|
|
502
|
+
* `Carousel.Indicator` to dispatch click-to-jump. See
|
|
503
|
+
* {@link CarouselContextValue.next} for the `instant` override. */
|
|
504
|
+
goTo: (target: number, instant?: boolean) => void;
|
|
241
505
|
/** Whether autoplay is currently in the "playing" state. */
|
|
242
506
|
playing: boolean;
|
|
243
507
|
/** Toggles `playing`. Used by `Carousel.PlayPauseTrigger`. */
|
|
@@ -260,8 +524,27 @@ export type CarouselContextValue = {
|
|
|
260
524
|
ids: CarouselIds;
|
|
261
525
|
/** Resolved visual transition mode (defaults to `"slide"`). */
|
|
262
526
|
transition: CarouselTransition;
|
|
263
|
-
/** Resolved scroll-snap alignment (defaults to `"
|
|
527
|
+
/** Resolved scroll-snap alignment (defaults to `"center"`). */
|
|
264
528
|
snapAlign: CarouselSnapAlign;
|
|
529
|
+
/** Resolved scroll/pagination axis (defaults to `"horizontal"`).
|
|
530
|
+
* Drives the viewport scroll axis, the arrow-key bindings, and the
|
|
531
|
+
* `data-orientation` hook on the Root. */
|
|
532
|
+
orientation: CarouselOrientation;
|
|
533
|
+
/** Resolved wrap-around navigation mode (defaults to `"none"`) — see
|
|
534
|
+
* {@link CarouselLoopMode}. `"wrap"` and `"infinite"` both drive the
|
|
535
|
+
* boundary flags (`canGoNext`/`canGoPrevious` stay true past the ends
|
|
536
|
+
* when there is more than one page) and the wrap arithmetic in
|
|
537
|
+
* `next`/`previous`; `"infinite"` additionally signals the clone/scroll
|
|
538
|
+
* layer via the `data-loop` hook on the Root. */
|
|
539
|
+
loop: CarouselLoopMode;
|
|
540
|
+
/** Resolved mouse click-and-drag scrolling opt-in (defaults to
|
|
541
|
+
* `false`). */
|
|
542
|
+
allowMouseDrag: boolean;
|
|
543
|
+
/** Resolved `isInView` IntersectionObserver threshold(s) (defaults to
|
|
544
|
+
* `0.6`). */
|
|
545
|
+
inViewThreshold: number | number[];
|
|
546
|
+
/** Resolved `scroll-snap-type` strictness (defaults to `"mandatory"`). */
|
|
547
|
+
snapType: CarouselSnapType;
|
|
265
548
|
/** Bumped by `refresh()` to force the viewport's scroll-align
|
|
266
549
|
* effect to re-run without a page change. */
|
|
267
550
|
refreshTick: number;
|
|
@@ -271,12 +554,55 @@ export type CarouselContextValue = {
|
|
|
271
554
|
visibleSlideIndicesRef: RefObject<Set<number>>;
|
|
272
555
|
/** Used by the Viewport hook to record visibility transitions. */
|
|
273
556
|
setSlideInView: (slideIndex: number, inView: boolean) => void;
|
|
557
|
+
/** Used by the Viewport hook to report the live continuous scroll
|
|
558
|
+
* position, read on demand by the imperative `getScrollProgress()`. */
|
|
559
|
+
setScrollProgress: (value: number) => void;
|
|
560
|
+
/** Used by the Viewport hook to report a slide's live continuous
|
|
561
|
+
* center-distance, read on demand by the imperative
|
|
562
|
+
* `getSlideProgress()`. */
|
|
563
|
+
setSlideProgress: (slideIndex: number, value: number) => void;
|
|
274
564
|
/** Set to `true` by `next()` and `previous()` the moment programmatic
|
|
275
565
|
* navigation begins, and cleared by the Viewport hook once the scroll
|
|
276
566
|
* animation settles (`scrollend` or a timeout fallback). The
|
|
277
567
|
* IntersectionObserver callback checks this flag before calling `goTo`
|
|
278
568
|
* so that IO entries firing mid-animation cannot undo the navigation. */
|
|
279
569
|
isProgrammaticScrollRef: RefObject<boolean>;
|
|
570
|
+
/** One-shot override of the resolved smooth/reduced-motion
|
|
571
|
+
* `scrollBehavior`, set by `next()` / `previous()` / `goTo()` on every
|
|
572
|
+
* call (`true` when their optional `instant` argument was passed,
|
|
573
|
+
* `false` otherwise) and consumed — then reset to `false` — by the
|
|
574
|
+
* Viewport hook's scroll effect on its very next run, so an instant
|
|
575
|
+
* jump never outlives the single call that requested it. */
|
|
576
|
+
instantScrollRef: RefObject<boolean>;
|
|
577
|
+
/** One-shot hint for the infinite-loop engine, set to `true` by `goTo()` /
|
|
578
|
+
* `scrollToIndex()` (an absolute jump to a specific page — most visibly an
|
|
579
|
+
* indicator/thumbnail click) and to `false` by `next()` / `previous()` (a
|
|
580
|
+
* relative step, which should always take the loop's wrap shortcut).
|
|
581
|
+
* Consumed and reset by the engine's positioning effect on its very next
|
|
582
|
+
* run, so it never outlives the single navigation that requested it. */
|
|
583
|
+
directJumpRef: RefObject<boolean>;
|
|
584
|
+
/** Live mouse-drag state (only ever `true` when `allowMouseDrag` is
|
|
585
|
+
* `true`). Mutated by the Viewport hook and read by the imperative
|
|
586
|
+
* `isDragging()`. */
|
|
587
|
+
isDraggingRef: RefObject<boolean>;
|
|
588
|
+
/** Used by the Viewport hook to record drag start/end transitions. */
|
|
589
|
+
setDragging: (value: boolean) => void;
|
|
590
|
+
/** The consumer's `onDragStatusChange`, if provided — called by the
|
|
591
|
+
* Viewport hook on every drag status transition. */
|
|
592
|
+
onDragStatusChange?: (status: CarouselDragStatus) => void;
|
|
593
|
+
/** Live mouse-drag overscroll state (only ever `true` mid-drag, when
|
|
594
|
+
* `allowMouseDrag` is `true` and the drag is currently pushing past a
|
|
595
|
+
* boundary). Mutated by the Viewport hook and read by the imperative
|
|
596
|
+
* `isOverscrolling()`. Keyboard/wheel overscroll taps never set this —
|
|
597
|
+
* they're instantaneous, not a sustained state. */
|
|
598
|
+
isOverscrollingRef: RefObject<boolean>;
|
|
599
|
+
/** Used by the Viewport hook to record drag-overscroll start/end
|
|
600
|
+
* transitions. */
|
|
601
|
+
setOverscrolling: (value: boolean) => void;
|
|
602
|
+
/** The consumer's `onOverscrollStatusChange`, if provided — called by
|
|
603
|
+
* the Viewport hook whenever the keyboard, wheel, or a mouse drag
|
|
604
|
+
* pushes against a boundary with nowhere further to go. */
|
|
605
|
+
onOverscrollStatusChange?: (status: CarouselOverscrollStatus) => void;
|
|
280
606
|
};
|
|
281
607
|
|
|
282
608
|
/** Props for `Carousel.Viewport` — the scroll-snap slide container; accepts all native `<div>` props. */
|
|
@@ -289,6 +615,13 @@ export type CarouselSlideProps = Omit<ComponentProps<"div">, "aria-label"> & {
|
|
|
289
615
|
* (e.g. `"Hand-picked for you"`). When omitted, slides are labelled
|
|
290
616
|
* with their live index and total in registration order. */
|
|
291
617
|
ariaLabel?: string;
|
|
618
|
+
/** Override the root's {@link CarouselRootProps.snapAlign | `snapAlign`}
|
|
619
|
+
* for this slide only — e.g. a variable-width layout where only some
|
|
620
|
+
* slides should centre or end-align. Only takes effect on a slide
|
|
621
|
+
* that's a valid scroll-snap resting position (a page's leading
|
|
622
|
+
* slide); an interior slide of a multi-slide page never snaps,
|
|
623
|
+
* regardless of this prop. Matches Ark UI's per-`Item` `snapAlign`. */
|
|
624
|
+
snapAlign?: CarouselSnapAlign;
|
|
292
625
|
};
|
|
293
626
|
|
|
294
627
|
/** Props for `Carousel.NextTrigger` — the button that advances one page; native `<button>` props plus `asChild`. */
|
|
@@ -316,14 +649,31 @@ export type CarouselIndicatorGroupProps = Omit<
|
|
|
316
649
|
"label" | "aria-labelledby"
|
|
317
650
|
> &
|
|
318
651
|
(
|
|
319
|
-
| {
|
|
320
|
-
|
|
652
|
+
| {
|
|
653
|
+
/** Accessible name for the indicator group, announced as
|
|
654
|
+
* `aria-label` (e.g. `"Choose slide"`). Mutually exclusive with
|
|
655
|
+
* `ariaLabelledBy`. */
|
|
656
|
+
label: string;
|
|
657
|
+
ariaLabelledBy?: never;
|
|
658
|
+
}
|
|
659
|
+
| {
|
|
660
|
+
label?: never;
|
|
661
|
+
/** Id of an existing element to name the indicator group, set as
|
|
662
|
+
* `aria-labelledby`. Mutually exclusive with `label`. */
|
|
663
|
+
ariaLabelledBy: string;
|
|
664
|
+
}
|
|
321
665
|
);
|
|
322
666
|
|
|
323
667
|
/** Props for `Carousel.Indicator` — a button that jumps to its target page; native `<button>` props plus the target `index` and `asChild`. */
|
|
324
668
|
export type CarouselIndicatorProps = ComponentProps<"button"> & {
|
|
325
669
|
/** Zero-based page this indicator targets. Clicking jumps to it. */
|
|
326
670
|
index: number;
|
|
671
|
+
/** Renders a presentational-only `<span>` instead of a `<button>`:
|
|
672
|
+
* `aria-hidden="true"`, and clicking no longer calls `goTo`. Use for a
|
|
673
|
+
* progress display when navigation happens some other way (e.g. a
|
|
674
|
+
* carousel driven solely by `allowMouseDrag`). The consumer's own
|
|
675
|
+
* `onClick`, if passed, still fires. Default `false`. */
|
|
676
|
+
readOnly?: boolean;
|
|
327
677
|
/** Render the child element instead of the default `<button>`.
|
|
328
678
|
* Trigger props (onClick, aria-label, aria-disabled, data-state)
|
|
329
679
|
* are merged onto the child via `Slot`. The child must accept a
|
|
@@ -338,12 +688,27 @@ export type CarouselIndicatorProps = ComponentProps<"button"> & {
|
|
|
338
688
|
* fire as if the user had clicked.
|
|
339
689
|
*/
|
|
340
690
|
export type CarouselImperativeApi = {
|
|
341
|
-
/** Advance the active page by one. No-op on the last page.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
691
|
+
/** Advance the active page by one. No-op on the last page. Pass
|
|
692
|
+
* `instant` (default `false`) to bypass the resolved smooth/
|
|
693
|
+
* reduced-motion scroll for just this one call — e.g. an instant
|
|
694
|
+
* jump on initial deep-link vs. smooth for user-initiated
|
|
695
|
+
* navigation. Matches Ark UI's `scrollNext(instant?)`. */
|
|
696
|
+
next: (instant?: boolean) => void;
|
|
697
|
+
/** Retreat the active page by one. No-op on the first page. See
|
|
698
|
+
* `next`'s `instant` parameter. Matches Ark UI's
|
|
699
|
+
* `scrollPrev(instant?)`. */
|
|
700
|
+
previous: (instant?: boolean) => void;
|
|
701
|
+
/** Jump directly to `target` (zero-based page index). See `next`'s
|
|
702
|
+
* `instant` parameter. Matches Ark UI's `scrollTo(page, instant?)`. */
|
|
703
|
+
goTo: (target: number, instant?: boolean) => void;
|
|
704
|
+
/** Jump to the page containing the given zero-based **slide** index —
|
|
705
|
+
* slide granularity, distinct from `goTo`'s page granularity. In a
|
|
706
|
+
* multi-slide (`slidesPerPage > 1`) layout an interior slide isn't its
|
|
707
|
+
* own scroll-snap position, so this lands on that slide's *containing*
|
|
708
|
+
* page (the same mapping `Carousel.Indicator` uses internally). See
|
|
709
|
+
* `next`'s `instant` parameter. Matches Ark UI's
|
|
710
|
+
* `scrollToIndex(index, instant?)`. */
|
|
711
|
+
scrollToIndex: (slideIndex: number, instant?: boolean) => void;
|
|
347
712
|
/** Set `playing` to `true`. Dismisses the hover/focus pause for the
|
|
348
713
|
* lifetime of the resulting playing session. */
|
|
349
714
|
play: () => void;
|
|
@@ -361,6 +726,42 @@ export type CarouselImperativeApi = {
|
|
|
361
726
|
* visible in the viewport (per IntersectionObserver, ≥ 60%
|
|
362
727
|
* intersection). Useful for lazy-loading slide content. */
|
|
363
728
|
isInView: (slideIndex: number) => boolean;
|
|
729
|
+
/** The leading slide index each page snaps to, one entry per page
|
|
730
|
+
* (length `totalPages`). The last entry is the end-aligned offset
|
|
731
|
+
* (see the multi-slide page model), not necessarily a clean multiple
|
|
732
|
+
* of `slidesPerMove`. Useful for a custom progress bar or indicator
|
|
733
|
+
* that needs the raw offsets rather than just the page count. */
|
|
734
|
+
getPageSnapPoints: () => number[];
|
|
735
|
+
/** Live snapshot of whether a mouse drag is currently in progress
|
|
736
|
+
* (`allowMouseDrag`-gated — always `false` when it's off). Mirrors
|
|
737
|
+
* Ark UI's `api.isDragging`; see also `onDragStatusChange`. */
|
|
738
|
+
isDragging: () => boolean;
|
|
739
|
+
/** Live snapshot of whether a mouse drag is currently pushing past a
|
|
740
|
+
* boundary (`allowMouseDrag`-gated — always `false` when it's off, and
|
|
741
|
+
* never `true` for a keyboard/wheel overscroll tap, which is
|
|
742
|
+
* instantaneous rather than a sustained state). See
|
|
743
|
+
* `onOverscrollStatusChange`. */
|
|
744
|
+
isOverscrolling: () => boolean;
|
|
745
|
+
/** Continuous `[0, 1]` scroll position along the main axis — `0` at
|
|
746
|
+
* the start, `1` at the end, `0` when there's no overflow to scroll.
|
|
747
|
+
* Unlike `getProgress()`'s page-granular step function, this changes
|
|
748
|
+
* on every scroll tick (mirrored live onto the Viewport's
|
|
749
|
+
* `--carousel-progress` CSS custom property, rAF-batched, so a
|
|
750
|
+
* consumer can drive a progress bar from CSS alone without reading
|
|
751
|
+
* this at all). Robust under RTL without any `dir` check — RTL's
|
|
752
|
+
* standardized negative-`scrollLeft` convention is handled via
|
|
753
|
+
* `Math.abs`. */
|
|
754
|
+
getScrollProgress: () => number;
|
|
755
|
+
/** Continuous `[-1, 1]` signal for how far the slide at the zero-based
|
|
756
|
+
* index sits from the viewport's center along the main axis — `0` =
|
|
757
|
+
* centered, `±1` = the slide's center has reached the viewport edge
|
|
758
|
+
* (clamped beyond that). `0` for a never-registered/out-of-range
|
|
759
|
+
* index. Normalised by the *viewport's* half-extent, not the slide's
|
|
760
|
+
* own, so at `slidesPerPage > 1` a fully on-screen outer page member
|
|
761
|
+
* can already read a large magnitude — this is not equivalent to
|
|
762
|
+
* `isInView` flipping to `false`. Mirrored live onto that slide's
|
|
763
|
+
* `--slide-progress` CSS custom property, rAF-batched. */
|
|
764
|
+
getSlideProgress: (slideIndex: number) => number;
|
|
364
765
|
};
|
|
365
766
|
|
|
366
767
|
/** Live progress snapshot reported by the carousel: the active page, the total page count, and a normalised `value` in `[0, 1]`. */
|
|
@@ -382,9 +783,24 @@ export type CarouselIndicatorsProps = Omit<
|
|
|
382
783
|
"label" | "aria-labelledby" | "children"
|
|
383
784
|
> &
|
|
384
785
|
(
|
|
385
|
-
| {
|
|
386
|
-
|
|
387
|
-
|
|
786
|
+
| {
|
|
787
|
+
/** Accessible name for the indicator group, announced as
|
|
788
|
+
* `aria-label` (e.g. `"Choose slide"`). Mutually exclusive with
|
|
789
|
+
* `ariaLabelledBy`. */
|
|
790
|
+
label: string;
|
|
791
|
+
ariaLabelledBy?: never;
|
|
792
|
+
}
|
|
793
|
+
| {
|
|
794
|
+
label?: never;
|
|
795
|
+
/** Id of an existing element to name the indicator group, set as
|
|
796
|
+
* `aria-labelledby`. Mutually exclusive with `label`. */
|
|
797
|
+
ariaLabelledBy: string;
|
|
798
|
+
}
|
|
799
|
+
) & {
|
|
800
|
+
/** Forwarded to every generated `Carousel.Indicator`. See
|
|
801
|
+
* `CarouselIndicatorProps.readOnly`. Default `false`. */
|
|
802
|
+
readOnly?: boolean;
|
|
803
|
+
};
|
|
388
804
|
|
|
389
805
|
/**
|
|
390
806
|
* Render-prop or static children supported by
|
|
@@ -406,3 +822,9 @@ export type CarouselPlayPauseTriggerProps = Omit<
|
|
|
406
822
|
* is not supported under `asChild`; pass a single element instead. */
|
|
407
823
|
asChild?: boolean;
|
|
408
824
|
};
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Props for `Carousel.ProgressText` — renders the live active-page
|
|
828
|
+
* progress as text; native `<span>` props. `children`, if provided,
|
|
829
|
+
* overrides the default `translations.progressText` content. */
|
|
830
|
+
export type CarouselProgressTextProps = ComponentProps<"span">;
|
|
@@ -50,6 +50,8 @@ function dataStateOf(checked: CheckedState) {
|
|
|
50
50
|
* mirror the input, but shipped CSS keys the mark off the input's native
|
|
51
51
|
* `:checked` / `:indeterminate` instead; `data-state` is a convenience mirror.
|
|
52
52
|
*
|
|
53
|
+
* @extends HTMLInputElement
|
|
54
|
+
*
|
|
53
55
|
* @example Uncontrolled
|
|
54
56
|
* ```tsx
|
|
55
57
|
* <Checkbox.Root name="terms" value="accepted" defaultChecked aria-label="Accept terms">
|
|
@@ -120,7 +122,11 @@ export function CheckboxRoot(props: CheckboxRootProps): ReactElement {
|
|
|
120
122
|
);
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
// Runtime-dead: the compound alias below (same object via Object.assign)
|
|
126
|
+
// overwrites this to "Checkbox" at load, so the value is never observable. The
|
|
127
|
+
// assignment stays because it declares `displayName` on `typeof CheckboxRoot`,
|
|
128
|
+
// which TCheckboxCompound extends.
|
|
129
|
+
// Stryker disable next-line StringLiteral: overwritten by the compound alias — an equivalent mutant.
|
|
124
130
|
CheckboxRoot.displayName = "CheckboxRoot";
|
|
125
131
|
|
|
126
132
|
/**
|
|
@@ -138,6 +144,8 @@ CheckboxRoot.displayName = "CheckboxRoot";
|
|
|
138
144
|
* (typically an `<svg>` tick) as the indicator itself, with `data-state`
|
|
139
145
|
* merged onto that element rather than a wrapper.
|
|
140
146
|
*
|
|
147
|
+
* @extends HTMLSpanElement
|
|
148
|
+
*
|
|
141
149
|
* @example Icon as the indicator via `asChild`
|
|
142
150
|
* ```tsx
|
|
143
151
|
* <Checkbox.Indicator asChild>
|