@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
|
@@ -10,6 +10,7 @@ import { Slot } from "../Slot/index.ts";
|
|
|
10
10
|
import { CarouselProvider } from "./CarouselContext";
|
|
11
11
|
import {
|
|
12
12
|
useCarouselContext,
|
|
13
|
+
useCarouselLoop,
|
|
13
14
|
useCarouselRoot,
|
|
14
15
|
useCarouselSlide,
|
|
15
16
|
useCarouselViewport,
|
|
@@ -25,6 +26,7 @@ import type {
|
|
|
25
26
|
CarouselIndicatorProps,
|
|
26
27
|
CarouselIndicatorsProps,
|
|
27
28
|
CarouselPlayPauseTriggerProps,
|
|
29
|
+
CarouselProgressTextProps,
|
|
28
30
|
} from "./types";
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -42,6 +44,13 @@ import type {
|
|
|
42
44
|
* The discriminated union on the props type rejects both-or-neither at
|
|
43
45
|
* compile time.
|
|
44
46
|
*
|
|
47
|
+
* **Orientation.** Pass `orientation="vertical"` to page along the block
|
|
48
|
+
* axis instead of the inline axis: the viewport scroll-snaps vertically,
|
|
49
|
+
* the viewport `ArrowDown` / `ArrowUp` keys advance / retreat (the
|
|
50
|
+
* horizontal arrows go inert), and the resolved value is published as
|
|
51
|
+
* `data-orientation` on the rendered `<section>` so consumer CSS can
|
|
52
|
+
* switch layout off a single hook. Defaults to `"horizontal"`.
|
|
53
|
+
*
|
|
45
54
|
* Supports two **page-state modes**, statically discriminated at the type
|
|
46
55
|
* level so only one of the two shapes is accepted by TypeScript:
|
|
47
56
|
*
|
|
@@ -51,6 +60,12 @@ import type {
|
|
|
51
60
|
* parent owns the active page; the component defers every state
|
|
52
61
|
* change back through the callback.
|
|
53
62
|
*
|
|
63
|
+
* The `ref` is an imperative handle ({@link CarouselImperativeApi}), not
|
|
64
|
+
* the DOM node — the `<section>`'s native attributes are still spread
|
|
65
|
+
* through from the remaining props.
|
|
66
|
+
*
|
|
67
|
+
* @extends HTMLElement
|
|
68
|
+
*
|
|
54
69
|
* @example Labelled inline, uncontrolled
|
|
55
70
|
* ```tsx
|
|
56
71
|
* <Carousel.Root ariaLabel="Featured products" defaultPage={0}>…</Carousel.Root>
|
|
@@ -89,12 +104,20 @@ export const CarouselRoot: ForwardRefExoticComponent<
|
|
|
89
104
|
playing,
|
|
90
105
|
onPlayingChange,
|
|
91
106
|
autoplay,
|
|
107
|
+
onAutoplayStatusChange,
|
|
92
108
|
slidesPerPage,
|
|
93
109
|
slidesPerMove,
|
|
94
110
|
translations,
|
|
95
111
|
ids,
|
|
96
112
|
transition,
|
|
97
113
|
snapAlign,
|
|
114
|
+
orientation,
|
|
115
|
+
loop,
|
|
116
|
+
allowMouseDrag,
|
|
117
|
+
onDragStatusChange,
|
|
118
|
+
onOverscrollStatusChange,
|
|
119
|
+
inViewThreshold,
|
|
120
|
+
snapType,
|
|
98
121
|
children,
|
|
99
122
|
...rest
|
|
100
123
|
},
|
|
@@ -109,12 +132,20 @@ export const CarouselRoot: ForwardRefExoticComponent<
|
|
|
109
132
|
playing,
|
|
110
133
|
onPlayingChange,
|
|
111
134
|
autoplay,
|
|
135
|
+
onAutoplayStatusChange,
|
|
112
136
|
slidesPerPage,
|
|
113
137
|
slidesPerMove,
|
|
114
138
|
translations,
|
|
115
139
|
ids,
|
|
116
140
|
transition,
|
|
117
141
|
snapAlign,
|
|
142
|
+
orientation,
|
|
143
|
+
loop,
|
|
144
|
+
allowMouseDrag,
|
|
145
|
+
onDragStatusChange,
|
|
146
|
+
onOverscrollStatusChange,
|
|
147
|
+
inViewThreshold,
|
|
148
|
+
snapType,
|
|
118
149
|
},
|
|
119
150
|
imperativeRef,
|
|
120
151
|
);
|
|
@@ -123,6 +154,9 @@ export const CarouselRoot: ForwardRefExoticComponent<
|
|
|
123
154
|
<CarouselProvider value={contextValue}>
|
|
124
155
|
<section
|
|
125
156
|
aria-roledescription="carousel"
|
|
157
|
+
data-orientation={contextValue.orientation}
|
|
158
|
+
data-transition={contextValue.transition}
|
|
159
|
+
data-loop={contextValue.loop}
|
|
126
160
|
className={className}
|
|
127
161
|
{...(ariaLabel !== undefined && { "aria-label": ariaLabel })}
|
|
128
162
|
{...(ariaLabelledBy !== undefined && {
|
|
@@ -160,7 +194,14 @@ CarouselRoot.displayName = "CarouselRoot";
|
|
|
160
194
|
*
|
|
161
195
|
* **Styling hooks.** `data-carousel-viewport` is set on the rendered
|
|
162
196
|
* element. The component ships no styles — apply your own scroll-snap
|
|
163
|
-
* recipe via this attribute.
|
|
197
|
+
* recipe via this attribute. `data-snap-type="mandatory" | "proximity"`
|
|
198
|
+
* mirrors the resolved root {@link CarouselRootProps.snapType | `snapType`}
|
|
199
|
+
* — scope `scroll-snap-type`'s strictness to it. `data-mouse-drag` is
|
|
200
|
+
* present whenever `allowMouseDrag` is `true` (a persistent hook — the
|
|
201
|
+
* natural place for a `cursor: grab` affordance, since showing that cursor
|
|
202
|
+
* when dragging isn't actually enabled would be misleading); `data-dragging`
|
|
203
|
+
* is additionally present only for the duration of an active drag (see
|
|
204
|
+
* below) — pair it with `cursor: grabbing`.
|
|
164
205
|
*
|
|
165
206
|
* **Keyboard navigation.** The Viewport is in the tab order
|
|
166
207
|
* (`tabIndex={0}`) so keyboard users can reach the rotation control
|
|
@@ -177,6 +218,44 @@ CarouselRoot.displayName = "CarouselRoot";
|
|
|
177
218
|
* target — focus inside a slide (e.g. on a link or form control) keeps
|
|
178
219
|
* its native arrow-key semantics.
|
|
179
220
|
*
|
|
221
|
+
* **Mouse click-and-drag** — opt-in via {@link CarouselRootProps.allowMouseDrag |
|
|
222
|
+
* `allowMouseDrag`} on `Carousel.Root` (default `false`; an
|
|
223
|
+
* unconditionally-on drag could conflict with a consumer's own
|
|
224
|
+
* drag-sensitive slide content). When enabled: click and hold, then drag,
|
|
225
|
+
* and the viewport scrolls like a swipe: `scrollLeft`/`scrollTop` track
|
|
226
|
+
* the pointer, amplified by a sensitivity multiplier (no momentum — the
|
|
227
|
+
* multiplier only scales the tracked delta, motion still stops dead on
|
|
228
|
+
* release), once the drag clears a small movement threshold — below it,
|
|
229
|
+
* nothing happens, so a plain click on a link/button inside a slide
|
|
230
|
+
* still reaches it. Release lets `scroll-snap-type` settle to the
|
|
231
|
+
* nearest slide (the same `scrollsnapchange` sync a touch swipe already
|
|
232
|
+
* drives). A `data-dragging` attribute is set for the duration of an
|
|
233
|
+
* active drag. Only `pointerType === "mouse"` is handled — touch/pen
|
|
234
|
+
* already scroll natively regardless of this prop.
|
|
235
|
+
*
|
|
236
|
+
* **Mouse-wheel scroll.** A physical wheel's vertical notches already
|
|
237
|
+
* scroll a `orientation="vertical"` carousel natively. On the default
|
|
238
|
+
* horizontal orientation, a plain vertical wheel notch (`deltaY`)
|
|
239
|
+
* translates into horizontal scroll — browsers only do this
|
|
240
|
+
* automatically when `Shift` is held. Stands down whenever `deltaX` is
|
|
241
|
+
* non-negligible, so a trackpad/Magic Mouse horizontal swipe (which
|
|
242
|
+
* already scrolls a horizontal viewport natively via `deltaX`) is never
|
|
243
|
+
* fought.
|
|
244
|
+
*
|
|
245
|
+
* **Overscroll.** Pushing against a boundary with nowhere further to go —
|
|
246
|
+
* via the keyboard, the wheel, or a mouse drag — fires the root's
|
|
247
|
+
* {@link CarouselRootProps.onOverscrollStatusChange | `onOverscrollStatusChange`}.
|
|
248
|
+
* A mouse drag past a boundary additionally sets a persistent
|
|
249
|
+
* `data-overscroll="start" | "end"` attribute on the Viewport for the
|
|
250
|
+
* duration (removed once the drag stops pushing past it, whether by
|
|
251
|
+
* reversing back within bounds or releasing) — the natural hook for a
|
|
252
|
+
* rubber-band resistance visual. Keyboard/wheel overscroll is a single
|
|
253
|
+
* instantaneous tap with no equivalent sustained DOM state. Native
|
|
254
|
+
* touch/swipe overscroll (OS-level rubber-banding) isn't covered — that's
|
|
255
|
+
* browser-owned scroll physics with no JS hook to observe it from.
|
|
256
|
+
*
|
|
257
|
+
* @extends HTMLDivElement
|
|
258
|
+
*
|
|
180
259
|
* @example
|
|
181
260
|
* ```tsx
|
|
182
261
|
* <Carousel.Root ariaLabel="Featured products">
|
|
@@ -191,21 +270,79 @@ export function CarouselViewport({
|
|
|
191
270
|
children,
|
|
192
271
|
...rest
|
|
193
272
|
}: CarouselViewportProps): ReactElement {
|
|
194
|
-
const { isAutoRotating, ids } =
|
|
195
|
-
|
|
273
|
+
const { isAutoRotating, ids, allowMouseDrag, snapType, slidesPerPage } =
|
|
274
|
+
useCarouselContext();
|
|
275
|
+
const {
|
|
276
|
+
viewportRef,
|
|
277
|
+
onKeyDown,
|
|
278
|
+
onDragStart,
|
|
279
|
+
onPointerDown,
|
|
280
|
+
onPointerMove,
|
|
281
|
+
onPointerUp,
|
|
282
|
+
onPointerCancel,
|
|
283
|
+
onClickCapture,
|
|
284
|
+
} = useCarouselViewport();
|
|
285
|
+
// Infinite loop swaps the native scroll-snap viewport for a JS transform track
|
|
286
|
+
// (RFC 0018, clone-strip revision): the engine translates one contiguous track
|
|
287
|
+
// whose real slides are flanked by a full period of aria-hidden clones, so every
|
|
288
|
+
// seam is already-painted DOM and a settle-time re-base is invisible (no per-slide
|
|
289
|
+
// shifts, no native snap to fight — the two things that flashed on iOS). Every
|
|
290
|
+
// other mode renders the slides straight into the scroll viewport as before.
|
|
291
|
+
const { trackRef, headCloneRef, tailCloneRef, isInfinite, dragHandlers } =
|
|
292
|
+
useCarouselLoop();
|
|
293
|
+
// Infinite is transform-driven, so its own pointer engine (drag → fling) owns
|
|
294
|
+
// the pointer events; the scroll-snap modes keep useCarouselViewport's
|
|
295
|
+
// mouse-drag handlers.
|
|
296
|
+
const pointerHandlers = dragHandlers ?? {
|
|
297
|
+
onPointerDown,
|
|
298
|
+
onPointerMove,
|
|
299
|
+
onPointerUp,
|
|
300
|
+
onPointerCancel,
|
|
301
|
+
};
|
|
196
302
|
|
|
197
303
|
return (
|
|
198
304
|
<div
|
|
199
305
|
ref={viewportRef}
|
|
200
306
|
data-carousel-viewport=""
|
|
307
|
+
data-snap-type={snapType}
|
|
201
308
|
tabIndex={0}
|
|
202
309
|
className={className}
|
|
203
310
|
aria-live={isAutoRotating ? "off" : "polite"}
|
|
204
311
|
onKeyDown={onKeyDown}
|
|
312
|
+
onDragStart={onDragStart}
|
|
313
|
+
{...pointerHandlers}
|
|
314
|
+
onClickCapture={onClickCapture}
|
|
315
|
+
{...(allowMouseDrag && { "data-mouse-drag": "" })}
|
|
205
316
|
{...(ids.viewport !== undefined && { id: ids.viewport })}
|
|
206
317
|
{...rest}
|
|
207
318
|
>
|
|
208
|
-
{
|
|
319
|
+
{isInfinite ? (
|
|
320
|
+
<div
|
|
321
|
+
className="primitiv-carousel__track"
|
|
322
|
+
data-carousel-track=""
|
|
323
|
+
data-slides-per-page={slidesPerPage}
|
|
324
|
+
ref={trackRef}
|
|
325
|
+
>
|
|
326
|
+
{/* Clone buffers (a full period each side) — the engine fills these
|
|
327
|
+
display:contents holders with aria-hidden copies so the strip is
|
|
328
|
+
periodic and every seam is contiguous painted DOM. */}
|
|
329
|
+
<div
|
|
330
|
+
data-carousel-clones="head"
|
|
331
|
+
aria-hidden="true"
|
|
332
|
+
style={{ display: "contents" }}
|
|
333
|
+
ref={headCloneRef}
|
|
334
|
+
/>
|
|
335
|
+
{children}
|
|
336
|
+
<div
|
|
337
|
+
data-carousel-clones="tail"
|
|
338
|
+
aria-hidden="true"
|
|
339
|
+
style={{ display: "contents" }}
|
|
340
|
+
ref={tailCloneRef}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
) : (
|
|
344
|
+
children
|
|
345
|
+
)}
|
|
209
346
|
</div>
|
|
210
347
|
);
|
|
211
348
|
}
|
|
@@ -238,10 +375,20 @@ CarouselViewport.displayName = "CarouselViewport";
|
|
|
238
375
|
* recipe targets `[data-carousel-slide]`).
|
|
239
376
|
* - `data-index="N"` — the slide's zero-based position in registration order.
|
|
240
377
|
* - `data-total="N"` — the live total slide count.
|
|
378
|
+
* - `data-snap-align="start" | "center" | "end"` — present only on a page's
|
|
379
|
+
* leading slide (every slide when `slidesPerPage` is 1), valued from this
|
|
380
|
+
* slide's own {@link CarouselSlideProps.snapAlign | `snapAlign`} prop if
|
|
381
|
+
* set, else the root's resolved `snapAlign`. The registry stylesheet
|
|
382
|
+
* scopes `scroll-snap-align` to this hook, both so an interior slide of a
|
|
383
|
+
* multi-slide page is never a valid scroll-snap resting position, and so
|
|
384
|
+
* the native resting position agrees with `snapAlign` rather than always
|
|
385
|
+
* being `"start"`.
|
|
241
386
|
*
|
|
242
387
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
243
388
|
* elsewhere throws a descriptive error.
|
|
244
389
|
*
|
|
390
|
+
* @extends HTMLDivElement
|
|
391
|
+
*
|
|
245
392
|
* @example Auto-labelled
|
|
246
393
|
* ```tsx
|
|
247
394
|
* <Carousel.Viewport>
|
|
@@ -254,15 +401,23 @@ CarouselViewport.displayName = "CarouselViewport";
|
|
|
254
401
|
* ```tsx
|
|
255
402
|
* <Carousel.Slide ariaLabel="Hand-picked for you">…</Carousel.Slide>
|
|
256
403
|
* ```
|
|
404
|
+
*
|
|
405
|
+
* @example Per-slide snap alignment (overrides the root default)
|
|
406
|
+
* ```tsx
|
|
407
|
+
* <Carousel.Slide snapAlign="end">…</Carousel.Slide>
|
|
408
|
+
* ```
|
|
257
409
|
*/
|
|
258
410
|
export function CarouselSlide({
|
|
259
411
|
className = "",
|
|
260
412
|
ariaLabel,
|
|
413
|
+
snapAlign: snapAlignOverride,
|
|
261
414
|
children,
|
|
262
415
|
...rest
|
|
263
416
|
}: CarouselSlideProps): ReactElement {
|
|
264
|
-
const { slideRef, index, total, state } =
|
|
417
|
+
const { slideRef, index, total, state, snapAlign } =
|
|
418
|
+
useCarouselSlide(snapAlignOverride);
|
|
265
419
|
const { translations } = useCarouselContext();
|
|
420
|
+
|
|
266
421
|
const autoLabel =
|
|
267
422
|
index >= 0 && total > 0
|
|
268
423
|
? translations.slideLabel({ index: index + 1, total })
|
|
@@ -280,6 +435,7 @@ export function CarouselSlide({
|
|
|
280
435
|
data-state={state}
|
|
281
436
|
className={className}
|
|
282
437
|
{...(label !== undefined && { "aria-label": label })}
|
|
438
|
+
{...(snapAlign !== undefined && { "data-snap-align": snapAlign })}
|
|
283
439
|
{...rest}
|
|
284
440
|
>
|
|
285
441
|
{children}
|
|
@@ -306,6 +462,8 @@ CarouselSlide.displayName = "CarouselSlide";
|
|
|
306
462
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
307
463
|
* elsewhere throws a descriptive error.
|
|
308
464
|
*
|
|
465
|
+
* @extends HTMLButtonElement
|
|
466
|
+
*
|
|
309
467
|
* @example
|
|
310
468
|
* ```tsx
|
|
311
469
|
* <Carousel.NextTrigger>Next</Carousel.NextTrigger>
|
|
@@ -373,6 +531,8 @@ CarouselNextTrigger.displayName = "CarouselNextTrigger";
|
|
|
373
531
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
374
532
|
* elsewhere throws a descriptive error.
|
|
375
533
|
*
|
|
534
|
+
* @extends HTMLButtonElement
|
|
535
|
+
*
|
|
376
536
|
* @example
|
|
377
537
|
* ```tsx
|
|
378
538
|
* <Carousel.PreviousTrigger>Previous</Carousel.PreviousTrigger>
|
|
@@ -439,6 +599,8 @@ CarouselPreviousTrigger.displayName = "CarouselPreviousTrigger";
|
|
|
439
599
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
440
600
|
* elsewhere throws a descriptive error.
|
|
441
601
|
*
|
|
602
|
+
* @extends HTMLDivElement
|
|
603
|
+
*
|
|
442
604
|
* @example
|
|
443
605
|
* ```tsx
|
|
444
606
|
* <Carousel.IndicatorGroup label="Choose slide">
|
|
@@ -488,6 +650,15 @@ CarouselIndicatorGroup.displayName = "CarouselIndicatorGroup";
|
|
|
488
650
|
* `aria-disabled="false"`. Both states also flip `data-state` between
|
|
489
651
|
* `"active"` and `"inactive"` so consumer CSS can paint the active dot.
|
|
490
652
|
*
|
|
653
|
+
* **`readOnly`.** When `true`, the indicator becomes a presentational-only
|
|
654
|
+
* progress dot instead of a navigation control: it renders a `<span>` (no
|
|
655
|
+
* button semantics), carries `aria-hidden="true"` (it's decorative, not
|
|
656
|
+
* announced), and clicking it no longer calls `goTo` — for a carousel whose
|
|
657
|
+
* only navigation is e.g. `allowMouseDrag`, where clickable dots would be a
|
|
658
|
+
* redundant/misleading control. It still tracks `data-state`, so CSS-driven
|
|
659
|
+
* progress display keeps working, and the consumer's own `onClick` (if
|
|
660
|
+
* passed) still fires — only the internal navigation is suppressed.
|
|
661
|
+
*
|
|
491
662
|
* **Styling hooks.**
|
|
492
663
|
* - `data-carousel-indicator` — CSS-targeting attribute.
|
|
493
664
|
* - `data-state="active" | "inactive"` — tracks the current page.
|
|
@@ -495,15 +666,19 @@ CarouselIndicatorGroup.displayName = "CarouselIndicatorGroup";
|
|
|
495
666
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
496
667
|
* elsewhere throws a descriptive error.
|
|
497
668
|
*
|
|
669
|
+
* @extends HTMLButtonElement
|
|
670
|
+
*
|
|
498
671
|
* @example
|
|
499
672
|
* ```tsx
|
|
500
673
|
* <Carousel.Indicator index={0} />
|
|
674
|
+
* <Carousel.Indicator index={0} readOnly />
|
|
501
675
|
* ```
|
|
502
676
|
*/
|
|
503
677
|
export function CarouselIndicator({
|
|
504
678
|
className = "",
|
|
505
679
|
index,
|
|
506
680
|
onClick,
|
|
681
|
+
readOnly = false,
|
|
507
682
|
asChild = false,
|
|
508
683
|
children,
|
|
509
684
|
...rest
|
|
@@ -514,18 +689,22 @@ export function CarouselIndicator({
|
|
|
514
689
|
const handleClick = useCallback(
|
|
515
690
|
(event: MouseEvent<HTMLButtonElement>) => {
|
|
516
691
|
onClick?.(event);
|
|
517
|
-
goTo(index);
|
|
692
|
+
if (!readOnly) goTo(index);
|
|
518
693
|
},
|
|
519
|
-
[goTo, index, onClick],
|
|
694
|
+
[goTo, index, onClick, readOnly],
|
|
520
695
|
);
|
|
521
696
|
|
|
522
697
|
const indicatorProps = {
|
|
523
698
|
className,
|
|
524
|
-
"aria-label": translations.indicatorLabel({ index: index + 1 }),
|
|
525
|
-
"aria-disabled": isActive,
|
|
526
699
|
"data-carousel-indicator": "",
|
|
527
700
|
"data-state": isActive ? "active" : "inactive",
|
|
528
701
|
onClick: handleClick,
|
|
702
|
+
...(readOnly
|
|
703
|
+
? { "aria-hidden": true }
|
|
704
|
+
: {
|
|
705
|
+
"aria-label": translations.indicatorLabel({ index: index + 1 }),
|
|
706
|
+
"aria-disabled": isActive,
|
|
707
|
+
}),
|
|
529
708
|
...rest,
|
|
530
709
|
};
|
|
531
710
|
|
|
@@ -533,6 +712,10 @@ export function CarouselIndicator({
|
|
|
533
712
|
return <Slot {...indicatorProps}>{children}</Slot>;
|
|
534
713
|
}
|
|
535
714
|
|
|
715
|
+
if (readOnly) {
|
|
716
|
+
return <span {...indicatorProps}>{children}</span>;
|
|
717
|
+
}
|
|
718
|
+
|
|
536
719
|
return (
|
|
537
720
|
<button type="button" {...indicatorProps}>
|
|
538
721
|
{children}
|
|
@@ -555,23 +738,30 @@ CarouselIndicator.displayName = "CarouselIndicator";
|
|
|
555
738
|
* thumbnail previews on hover), drop down to
|
|
556
739
|
* `Carousel.IndicatorGroup` + `Carousel.Indicator` instead.
|
|
557
740
|
*
|
|
741
|
+
* `readOnly` forwards to every generated indicator — see
|
|
742
|
+
* `Carousel.Indicator`'s own `readOnly` doc.
|
|
743
|
+
*
|
|
558
744
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
559
745
|
* elsewhere throws a descriptive error.
|
|
560
746
|
*
|
|
747
|
+
* @extends HTMLDivElement
|
|
748
|
+
*
|
|
561
749
|
* @example
|
|
562
750
|
* ```tsx
|
|
563
751
|
* <Carousel.Indicators label="Choose slide" />
|
|
752
|
+
* <Carousel.Indicators label="Progress" readOnly />
|
|
564
753
|
* ```
|
|
565
754
|
*/
|
|
566
|
-
export function CarouselIndicators(
|
|
567
|
-
|
|
568
|
-
|
|
755
|
+
export function CarouselIndicators({
|
|
756
|
+
readOnly,
|
|
757
|
+
...props
|
|
758
|
+
}: CarouselIndicatorsProps): ReactElement {
|
|
569
759
|
const { totalPages } = useCarouselContext();
|
|
570
760
|
|
|
571
761
|
return (
|
|
572
762
|
<CarouselIndicatorGroup {...props}>
|
|
573
763
|
{Array.from({ length: totalPages }, (_, index) => (
|
|
574
|
-
<CarouselIndicator key={index} index={index} />
|
|
764
|
+
<CarouselIndicator key={index} index={index} readOnly={readOnly} />
|
|
575
765
|
))}
|
|
576
766
|
</CarouselIndicatorGroup>
|
|
577
767
|
);
|
|
@@ -598,9 +788,23 @@ CarouselIndicators.displayName = "CarouselIndicators";
|
|
|
598
788
|
* Static children also work — useful when you want a single icon and
|
|
599
789
|
* style it via `[data-state]` selectors.
|
|
600
790
|
*
|
|
791
|
+
* Requires autoplay to be enabled on `Carousel.Root` — a control that
|
|
792
|
+
* toggled a non-existent slideshow would be misleading, so rendering
|
|
793
|
+
* this trigger without an `autoplay` prop on the Root throws a
|
|
794
|
+
* descriptive error. Toggling `playing` to `true` starts the timer that
|
|
795
|
+
* advances the page on each tick (see {@link CarouselAutoplay}).
|
|
796
|
+
*
|
|
601
797
|
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
602
|
-
* elsewhere throws a descriptive error.
|
|
603
|
-
*
|
|
798
|
+
* elsewhere throws a descriptive error.
|
|
799
|
+
*
|
|
800
|
+
* @extends HTMLButtonElement
|
|
801
|
+
*
|
|
802
|
+
* @example State-aware render prop
|
|
803
|
+
* ```tsx
|
|
804
|
+
* <Carousel.PlayPauseTrigger>
|
|
805
|
+
* {({ playing }) => (playing ? "Pause" : "Play")}
|
|
806
|
+
* </Carousel.PlayPauseTrigger>
|
|
807
|
+
* ```
|
|
604
808
|
*/
|
|
605
809
|
export function CarouselPlayPauseTrigger({
|
|
606
810
|
className = "",
|
|
@@ -654,6 +858,48 @@ export function CarouselPlayPauseTrigger({
|
|
|
654
858
|
/** @internal */
|
|
655
859
|
CarouselPlayPauseTrigger.displayName = "CarouselPlayPauseTrigger";
|
|
656
860
|
|
|
861
|
+
/**
|
|
862
|
+
* A `<span>` rendering the live active-page progress as text — `"1 of
|
|
863
|
+
* 3"` by default, via `translations.progressText`. Closes the gap
|
|
864
|
+
* between the imperative `getProgress()` data and an actual DOM node a
|
|
865
|
+
* consumer can drop in without wiring the announcement themselves.
|
|
866
|
+
*
|
|
867
|
+
* ```tsx
|
|
868
|
+
* <Carousel.ProgressText />
|
|
869
|
+
* ```
|
|
870
|
+
*
|
|
871
|
+
* Pass `children` to render custom content instead of the default
|
|
872
|
+
* translated text (e.g. an icon alongside the count) — the computed
|
|
873
|
+
* text is only used as a fallback.
|
|
874
|
+
*
|
|
875
|
+
* Must be rendered as a descendant of `Carousel.Root`; rendering it
|
|
876
|
+
* elsewhere throws a descriptive error (via the shared Carousel
|
|
877
|
+
* context guard).
|
|
878
|
+
*
|
|
879
|
+
* @extends HTMLSpanElement
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* ```tsx
|
|
883
|
+
* <Carousel.ProgressText />
|
|
884
|
+
* ```
|
|
885
|
+
*/
|
|
886
|
+
export function CarouselProgressText({
|
|
887
|
+
children,
|
|
888
|
+
...rest
|
|
889
|
+
}: CarouselProgressTextProps): ReactElement {
|
|
890
|
+
const { currentPage, totalPages, translations } = useCarouselContext();
|
|
891
|
+
|
|
892
|
+
return (
|
|
893
|
+
<span {...rest}>
|
|
894
|
+
{children ??
|
|
895
|
+
translations.progressText({ page: currentPage, totalPages })}
|
|
896
|
+
</span>
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/** @internal */
|
|
901
|
+
CarouselProgressText.displayName = "CarouselProgressText";
|
|
902
|
+
|
|
657
903
|
/** Static-property shape of the compound {@link Carousel} export: the callable {@link CarouselRoot} plus its namespaced sub-components. */
|
|
658
904
|
type CarouselCompound = typeof CarouselRoot & {
|
|
659
905
|
Root: typeof CarouselRoot;
|
|
@@ -665,6 +911,7 @@ type CarouselCompound = typeof CarouselRoot & {
|
|
|
665
911
|
Indicator: typeof CarouselIndicator;
|
|
666
912
|
Indicators: typeof CarouselIndicators;
|
|
667
913
|
PlayPauseTrigger: typeof CarouselPlayPauseTrigger;
|
|
914
|
+
ProgressText: typeof CarouselProgressText;
|
|
668
915
|
};
|
|
669
916
|
|
|
670
917
|
/**
|
|
@@ -717,6 +964,7 @@ const CarouselCompound: CarouselCompound = Object.assign(CarouselRoot, {
|
|
|
717
964
|
Indicator: CarouselIndicator,
|
|
718
965
|
Indicators: CarouselIndicators,
|
|
719
966
|
PlayPauseTrigger: CarouselPlayPauseTrigger,
|
|
967
|
+
ProgressText: CarouselProgressText,
|
|
720
968
|
});
|
|
721
969
|
|
|
722
970
|
CarouselCompound.displayName = "Carousel";
|