@chassis-ui/react 0.0.0-20260831090525
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/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/index.d.ts +5909 -0
- package/dist/index.js +2 -0
- package/dist/style.css +1 -0
- package/package.json +114 -0
- package/src/components/accordion/Accordion.tsx +190 -0
- package/src/components/accordion/AccordionBody.tsx +46 -0
- package/src/components/accordion/AccordionHeader.tsx +21 -0
- package/src/components/accordion/AccordionItem.tsx +59 -0
- package/src/components/accordion/context.ts +8 -0
- package/src/components/accordion/index.ts +8 -0
- package/src/components/autocomplete/Autocomplete.tsx +464 -0
- package/src/components/autocomplete/AutocompleteGroup.tsx +20 -0
- package/src/components/autocomplete/AutocompleteItem.tsx +18 -0
- package/src/components/autocomplete/index.ts +6 -0
- package/src/components/avatar/Avatar.tsx +134 -0
- package/src/components/avatar/AvatarImage.tsx +19 -0
- package/src/components/avatar/AvatarStack.tsx +98 -0
- package/src/components/avatar/index.ts +6 -0
- package/src/components/badge/Badge.tsx +94 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/breadcrumb/Breadcrumb.tsx +59 -0
- package/src/components/breadcrumb/BreadcrumbItem.tsx +38 -0
- package/src/components/breadcrumb/index.ts +4 -0
- package/src/components/button/Button.tsx +229 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/button-group/ButtonGroup.tsx +55 -0
- package/src/components/button-group/ButtonToolbar.tsx +47 -0
- package/src/components/button-group/index.ts +4 -0
- package/src/components/calendar/Calendar.scss +57 -0
- package/src/components/calendar/Calendar.tsx +324 -0
- package/src/components/calendar/CalendarMonthBlock.tsx +57 -0
- package/src/components/calendar/CalendarMonthGrid.tsx +92 -0
- package/src/components/calendar/CalendarMonthYearPicker.tsx +162 -0
- package/src/components/calendar/CalendarNavButton.tsx +24 -0
- package/src/components/calendar/CalendarWeekGrid.tsx +58 -0
- package/src/components/calendar/CalendarYearGrid.tsx +126 -0
- package/src/components/calendar/RangeCalendar.scss +95 -0
- package/src/components/calendar/RangeCalendar.tsx +361 -0
- package/src/components/calendar/index.ts +5 -0
- package/src/components/card/Card.tsx +173 -0
- package/src/components/card/CardBody.tsx +75 -0
- package/src/components/card/CardFooter.tsx +47 -0
- package/src/components/card/CardGroup.tsx +51 -0
- package/src/components/card/CardHeader.tsx +47 -0
- package/src/components/card/CardImage.tsx +70 -0
- package/src/components/card/CardImageOverlay.tsx +47 -0
- package/src/components/card/CardLink.tsx +40 -0
- package/src/components/card/CardSubtitle.tsx +47 -0
- package/src/components/card/CardText.tsx +47 -0
- package/src/components/card/CardTitle.tsx +47 -0
- package/src/components/card/index.ts +22 -0
- package/src/components/carousel/Carousel.tsx +742 -0
- package/src/components/carousel/CarouselControlButton.tsx +74 -0
- package/src/components/carousel/CarouselControlNext.tsx +22 -0
- package/src/components/carousel/CarouselControlPrev.tsx +22 -0
- package/src/components/carousel/CarouselIndicators.tsx +44 -0
- package/src/components/carousel/CarouselInner.tsx +56 -0
- package/src/components/carousel/CarouselItem.tsx +51 -0
- package/src/components/carousel/CarouselOverlay.tsx +51 -0
- package/src/components/carousel/CarouselPlayPause.tsx +61 -0
- package/src/components/carousel/carouselEngine.ts +170 -0
- package/src/components/carousel/context.ts +29 -0
- package/src/components/carousel/index.ts +21 -0
- package/src/components/checkbox/Checkbox.tsx +236 -0
- package/src/components/checkbox/CheckboxGroup.tsx +145 -0
- package/src/components/checkbox/context.ts +14 -0
- package/src/components/checkbox/index.ts +4 -0
- package/src/components/chip/Chip.tsx +183 -0
- package/src/components/chip/index.ts +2 -0
- package/src/components/chip-input/ChipInput.tsx +363 -0
- package/src/components/chip-input/ChipList.tsx +95 -0
- package/src/components/chip-input/index.ts +2 -0
- package/src/components/close-button/CloseButton.tsx +205 -0
- package/src/components/close-button/index.ts +2 -0
- package/src/components/collapse/Collapse.tsx +128 -0
- package/src/components/collapse/index.ts +2 -0
- package/src/components/color-input/ColorInput.tsx +106 -0
- package/src/components/color-input/index.ts +2 -0
- package/src/components/combobox/Combobox.tsx +320 -0
- package/src/components/combobox/ComboboxGroup.tsx +27 -0
- package/src/components/combobox/ComboboxItem.tsx +44 -0
- package/src/components/combobox/ComboboxListBox.tsx +98 -0
- package/src/components/combobox/index.ts +6 -0
- package/src/components/datepicker/CalendarToggleButton.tsx +58 -0
- package/src/components/datepicker/ClearButton.tsx +35 -0
- package/src/components/datepicker/DateField.tsx +54 -0
- package/src/components/datepicker/DatePicker.scss +51 -0
- package/src/components/datepicker/DatePicker.tsx +574 -0
- package/src/components/datepicker/DateRangePicker.scss +11 -0
- package/src/components/datepicker/DateRangePicker.tsx +343 -0
- package/src/components/datepicker/index.ts +4 -0
- package/src/components/datepicker/renderDatePickerShell.tsx +104 -0
- package/src/components/drawer/Drawer.tsx +211 -0
- package/src/components/drawer/DrawerBody.tsx +47 -0
- package/src/components/drawer/DrawerFooter.tsx +51 -0
- package/src/components/drawer/DrawerHeader.tsx +60 -0
- package/src/components/drawer/DrawerTitle.tsx +49 -0
- package/src/components/drawer/index.ts +10 -0
- package/src/components/file-input/FileInput.tsx +100 -0
- package/src/components/file-input/index.ts +2 -0
- package/src/components/flex/Flex.tsx +134 -0
- package/src/components/flex/index.ts +2 -0
- package/src/components/floating-input/FloatingInput.tsx +94 -0
- package/src/components/floating-input/index.ts +2 -0
- package/src/components/form/Form.tsx +26 -0
- package/src/components/form/FormFeedback.tsx +64 -0
- package/src/components/form/FormHelp.tsx +46 -0
- package/src/components/form/FormLabel.tsx +26 -0
- package/src/components/form/index.ts +8 -0
- package/src/components/form/renderFormCheck.tsx +86 -0
- package/src/components/form-field/FormField.tsx +84 -0
- package/src/components/form-field/index.ts +2 -0
- package/src/components/form-field/renderFormField.tsx +74 -0
- package/src/components/grid/Col.tsx +69 -0
- package/src/components/grid/Container.tsx +59 -0
- package/src/components/grid/Grid.tsx +86 -0
- package/src/components/grid/GridItem.tsx +123 -0
- package/src/components/grid/Row.tsx +71 -0
- package/src/components/grid/gap.ts +8 -0
- package/src/components/grid/index.ts +10 -0
- package/src/components/icon/Icon.tsx +74 -0
- package/src/components/icon/index.ts +2 -0
- package/src/components/input-adorn/InputAdorn.tsx +55 -0
- package/src/components/input-adorn/index.ts +2 -0
- package/src/components/input-group/InputGroup.tsx +50 -0
- package/src/components/input-group/InputGroupAddon.tsx +50 -0
- package/src/components/input-group/index.ts +4 -0
- package/src/components/link/Link.tsx +148 -0
- package/src/components/link/index.ts +2 -0
- package/src/components/list/List.tsx +193 -0
- package/src/components/list/ListItem.tsx +91 -0
- package/src/components/list/index.ts +4 -0
- package/src/components/menu/Menu.tsx +398 -0
- package/src/components/menu/MenuDivider.tsx +19 -0
- package/src/components/menu/MenuHeader.tsx +55 -0
- package/src/components/menu/MenuItem.tsx +85 -0
- package/src/components/menu/MenuItemDef.ts +83 -0
- package/src/components/menu/MenuList.tsx +142 -0
- package/src/components/menu/MenuSubmenu.tsx +284 -0
- package/src/components/menu/MenuSubmenuBack.tsx +39 -0
- package/src/components/menu/MenuText.tsx +47 -0
- package/src/components/menu/MenuToggle.tsx +148 -0
- package/src/components/menu/index.ts +19 -0
- package/src/components/menu/menuNavigation.ts +106 -0
- package/src/components/menu/submenuGroup.ts +43 -0
- package/src/components/modal/Modal.tsx +162 -0
- package/src/components/modal/ModalBody.tsx +47 -0
- package/src/components/modal/ModalFooter.tsx +51 -0
- package/src/components/modal/ModalHeader.tsx +60 -0
- package/src/components/modal/ModalTitle.tsx +49 -0
- package/src/components/modal/index.ts +10 -0
- package/src/components/nav/Nav.tsx +97 -0
- package/src/components/nav/NavItem.tsx +42 -0
- package/src/components/nav/NavLink.tsx +48 -0
- package/src/components/nav/NavTitle.tsx +22 -0
- package/src/components/nav/index.ts +7 -0
- package/src/components/navbar/Navbar.tsx +112 -0
- package/src/components/navbar/NavbarBrand.tsx +55 -0
- package/src/components/navbar/NavbarNav.tsx +47 -0
- package/src/components/navbar/NavbarText.tsx +47 -0
- package/src/components/navbar/NavbarToggler.tsx +34 -0
- package/src/components/navbar/index.ts +10 -0
- package/src/components/notification/Notification.scss +15 -0
- package/src/components/notification/Notification.tsx +187 -0
- package/src/components/notification/NotificationIcon.tsx +21 -0
- package/src/components/notification/NotificationStack.tsx +66 -0
- package/src/components/notification/NotificationText.tsx +47 -0
- package/src/components/notification/NotificationTitle.tsx +47 -0
- package/src/components/notification/context.ts +14 -0
- package/src/components/notification/index.ts +17 -0
- package/src/components/notification/notificationQueue.ts +48 -0
- package/src/components/otp-input/OtpBox.tsx +68 -0
- package/src/components/otp-input/OtpInput.tsx +341 -0
- package/src/components/otp-input/index.ts +2 -0
- package/src/components/pagination/Pagination.tsx +199 -0
- package/src/components/pagination/PaginationItem.tsx +133 -0
- package/src/components/pagination/index.ts +4 -0
- package/src/components/password-strength/PasswordStrength.tsx +155 -0
- package/src/components/password-strength/index.ts +2 -0
- package/src/components/password-strength/strengthScore.ts +79 -0
- package/src/components/placeholder/Placeholder.tsx +178 -0
- package/src/components/placeholder/index.ts +2 -0
- package/src/components/popover/Popover.tsx +243 -0
- package/src/components/popover/index.ts +2 -0
- package/src/components/progress/Progress.tsx +154 -0
- package/src/components/progress/ProgressBar.tsx +88 -0
- package/src/components/progress/index.ts +4 -0
- package/src/components/radio/Radio.tsx +88 -0
- package/src/components/radio/RadioGroup.tsx +142 -0
- package/src/components/radio/context.ts +14 -0
- package/src/components/radio/index.ts +4 -0
- package/src/components/range-input/RangeInput.tsx +109 -0
- package/src/components/range-input/index.ts +2 -0
- package/src/components/select/Select.tsx +277 -0
- package/src/components/select/index.ts +2 -0
- package/src/components/skeleton/Skeleton.tsx +89 -0
- package/src/components/skeleton/SkeletonLoader.tsx +91 -0
- package/src/components/skeleton/index.ts +4 -0
- package/src/components/spinner/Spinner.tsx +77 -0
- package/src/components/spinner/index.ts +2 -0
- package/src/components/stack/Stack.tsx +81 -0
- package/src/components/stack/index.ts +2 -0
- package/src/components/stepper/Stepper.tsx +172 -0
- package/src/components/stepper/StepperItem.tsx +66 -0
- package/src/components/stepper/index.ts +4 -0
- package/src/components/switch/Switch.tsx +246 -0
- package/src/components/switch/index.ts +2 -0
- package/src/components/table/Table.css +39 -0
- package/src/components/table/Table.tsx +390 -0
- package/src/components/table/TableBody.tsx +25 -0
- package/src/components/table/TableCell.tsx +27 -0
- package/src/components/table/TableColumn.tsx +31 -0
- package/src/components/table/TableHeader.tsx +26 -0
- package/src/components/table/TableRow.tsx +24 -0
- package/src/components/table/index.ts +12 -0
- package/src/components/tabs/Tab.tsx +36 -0
- package/src/components/tabs/TabList.tsx +76 -0
- package/src/components/tabs/TabPanel.tsx +68 -0
- package/src/components/tabs/Tabs.tsx +136 -0
- package/src/components/tabs/context.ts +24 -0
- package/src/components/tabs/index.ts +8 -0
- package/src/components/text-input/TextInput.tsx +188 -0
- package/src/components/text-input/index.ts +2 -0
- package/src/components/textarea/Textarea.tsx +145 -0
- package/src/components/textarea/index.ts +2 -0
- package/src/components/toast/Toast.tsx +219 -0
- package/src/components/toast/ToastBody.tsx +64 -0
- package/src/components/toast/ToastFooter.tsx +47 -0
- package/src/components/toast/ToastHeader.tsx +104 -0
- package/src/components/toast/ToastIcon.tsx +21 -0
- package/src/components/toast/Toaster.tsx +87 -0
- package/src/components/toast/context.ts +14 -0
- package/src/components/toast/index.ts +18 -0
- package/src/components/toast/toastQueue.ts +56 -0
- package/src/components/tooltip/Tooltip.tsx +155 -0
- package/src/components/tooltip/index.ts +2 -0
- package/src/global.d.ts +2 -0
- package/src/hooks/index.ts +57 -0
- package/src/hooks/useAutoDismiss.ts +88 -0
- package/src/hooks/useButtonSemantics.ts +33 -0
- package/src/hooks/useControllableState.ts +24 -0
- package/src/hooks/useDialogElement.ts +216 -0
- package/src/hooks/useDisabledAnchorGuard.ts +22 -0
- package/src/hooks/useDismissibleTransition.ts +126 -0
- package/src/hooks/useDrawer.ts +9 -0
- package/src/hooks/useFloatingOverlay.ts +115 -0
- package/src/hooks/useForkedRef.ts +50 -0
- package/src/hooks/useFormField.ts +89 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +9 -0
- package/src/hooks/useModal.ts +9 -0
- package/src/hooks/useNotification.ts +10 -0
- package/src/hooks/useOverlayPlacement.ts +93 -0
- package/src/hooks/usePagination.ts +85 -0
- package/src/hooks/useToast.ts +9 -0
- package/src/hooks/useToastRegionQueue.ts +27 -0
- package/src/index.ts +276 -0
- package/src/types.ts +133 -0
- package/src/utils/breakpoints.ts +43 -0
- package/src/utils/comboboxCollection.tsx +152 -0
- package/src/utils/dateRangePresets.ts +6 -0
- package/src/utils/dialogTransition.ts +39 -0
- package/src/utils/focusRedirect.ts +29 -0
- package/src/utils/isWholeUnitDisabled.ts +17 -0
- package/src/utils/mergeIsDateUnavailable.ts +15 -0
- package/src/utils/overlayPlacement.ts +93 -0
- package/src/utils/pointerInteraction.ts +21 -0
- package/src/utils/polymorphic.ts +36 -0
- package/src/utils/renderMenuItemContent.tsx +62 -0
- package/src/utils/setVisibleRangeStart.ts +64 -0
- package/src/utils/spacingClassName.ts +14 -0
- package/src/utils/suppressFocusRingGlobally.ts +69 -0
- package/src/utils/validationClassName.ts +8 -0
- package/src/utils/virtualFocusStyle.ts +16 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes, forwardRef, useEffect, useRef } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import { useForkedRef } from '../../hooks'
|
|
5
|
+
import { markPointerClick } from '../../utils/pointerInteraction'
|
|
6
|
+
import { Icon } from '../icon'
|
|
7
|
+
import { useCarouselContext } from './context'
|
|
8
|
+
|
|
9
|
+
interface CarouselControlButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
10
|
+
/**
|
|
11
|
+
* A string of all className you want applied to the component.
|
|
12
|
+
*/
|
|
13
|
+
className?: string
|
|
14
|
+
/**
|
|
15
|
+
* Which direction this control navigates, and which end-of-track state disables it.
|
|
16
|
+
*/
|
|
17
|
+
direction: 'prev' | 'next'
|
|
18
|
+
/**
|
|
19
|
+
* The accessible label announced by assistive technology.
|
|
20
|
+
*/
|
|
21
|
+
label?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Shared prev/next control, used by both CarouselControlPrev and CarouselControlNext — mirrors
|
|
25
|
+
// how CalendarNavButton.tsx factors the same shape for Calendar/RangeCalendar.
|
|
26
|
+
export const CarouselControlButton = forwardRef<HTMLButtonElement, CarouselControlButtonProps>(
|
|
27
|
+
({ children, className, direction, disabled, label, onClick, ...rest }, ref) => {
|
|
28
|
+
const { atEnd, atStart, ends, next, prev, registerControl } = useCarouselContext()
|
|
29
|
+
const buttonRef = useRef<HTMLButtonElement>(null)
|
|
30
|
+
const forkedRef = useForkedRef(ref, buttonRef)
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const element = buttonRef.current
|
|
34
|
+
if (!element) return undefined
|
|
35
|
+
return registerControl(direction, element)
|
|
36
|
+
}, [registerControl, direction])
|
|
37
|
+
|
|
38
|
+
const atBoundary = direction === 'next' ? atEnd : atStart
|
|
39
|
+
const navigate = direction === 'next' ? next : prev
|
|
40
|
+
|
|
41
|
+
// Compose rather than let a caller's `onClick`/`disabled` silently replace navigation: the
|
|
42
|
+
// carousel's own end-of-track state can only ever add a disable, and the click handler always
|
|
43
|
+
// still navigates the carousel alongside whatever the caller's handler does.
|
|
44
|
+
const isDisabled = disabled || (ends === 'stop' && atBoundary)
|
|
45
|
+
const handleClick: typeof onClick = (event) => {
|
|
46
|
+
onClick?.(event)
|
|
47
|
+
if (event.detail !== 0) markPointerClick(event.currentTarget)
|
|
48
|
+
navigate()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
className={classNames('button small icon-only', className)}
|
|
55
|
+
disabled={isDisabled}
|
|
56
|
+
onClick={handleClick}
|
|
57
|
+
{...rest}
|
|
58
|
+
ref={forkedRef}
|
|
59
|
+
>
|
|
60
|
+
{children ?? (
|
|
61
|
+
<>
|
|
62
|
+
<Icon
|
|
63
|
+
name={direction === 'next' ? 'chevron-right-outline' : 'chevron-left-outline'}
|
|
64
|
+
className="directional-icon"
|
|
65
|
+
/>
|
|
66
|
+
<span className="visually-hidden">{label}</span>
|
|
67
|
+
</>
|
|
68
|
+
)}
|
|
69
|
+
</button>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
CarouselControlButton.displayName = 'CarouselControlButton'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes, forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { CarouselControlButton } from './CarouselControlButton'
|
|
4
|
+
|
|
5
|
+
export interface CarouselControlNextProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
/**
|
|
7
|
+
* A string of all className you want applied to the component.
|
|
8
|
+
*/
|
|
9
|
+
className?: string
|
|
10
|
+
/**
|
|
11
|
+
* The accessible label announced by assistive technology.
|
|
12
|
+
*/
|
|
13
|
+
label?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const CarouselControlNext = forwardRef<HTMLButtonElement, CarouselControlNextProps>(
|
|
17
|
+
({ label = 'Next slide', ...rest }, ref) => (
|
|
18
|
+
<CarouselControlButton {...rest} direction="next" label={label} ref={ref} />
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
CarouselControlNext.displayName = 'CarouselControlNext'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes, forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { CarouselControlButton } from './CarouselControlButton'
|
|
4
|
+
|
|
5
|
+
export interface CarouselControlPrevProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
/**
|
|
7
|
+
* A string of all className you want applied to the component.
|
|
8
|
+
*/
|
|
9
|
+
className?: string
|
|
10
|
+
/**
|
|
11
|
+
* The accessible label announced by assistive technology.
|
|
12
|
+
*/
|
|
13
|
+
label?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const CarouselControlPrev = forwardRef<HTMLButtonElement, CarouselControlPrevProps>(
|
|
17
|
+
({ label = 'Previous slide', ...rest }, ref) => (
|
|
18
|
+
<CarouselControlButton {...rest} direction="prev" label={label} ref={ref} />
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
CarouselControlPrev.displayName = 'CarouselControlPrev'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLAttributes } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import { useCarouselContext } from './context'
|
|
5
|
+
|
|
6
|
+
export interface CarouselIndicatorsProps extends HTMLAttributes<HTMLOListElement> {
|
|
7
|
+
/**
|
|
8
|
+
* A string of all className you want applied to the component.
|
|
9
|
+
*/
|
|
10
|
+
className?: string
|
|
11
|
+
/**
|
|
12
|
+
* Accessible label for each indicator button. Receives the slide's 1-based position.
|
|
13
|
+
*/
|
|
14
|
+
label?: (position: number) => string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const CarouselIndicators = forwardRef<HTMLOListElement, CarouselIndicatorsProps>(
|
|
18
|
+
({ className, label = (position) => `Slide ${position}`, ...rest }, ref) => {
|
|
19
|
+
const { activeIndex, itemCount, itemsVisible, to } = useCarouselContext()
|
|
20
|
+
const _className = classNames('carousel-indicators', className)
|
|
21
|
+
// One indicator per reachable position, not per item — mirrors `navigate()`'s own clamping so
|
|
22
|
+
// an indicator never targets an index the carousel can't actually land on (e.g. with
|
|
23
|
+
// `items > 1`, the last few slides only ever appear alongside an earlier one).
|
|
24
|
+
const indicatorCount = itemCount === 0 ? 0 : Math.max(1, itemCount - itemsVisible + 1)
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ol className={_className} {...rest} ref={ref}>
|
|
28
|
+
{Array.from({ length: indicatorCount }, (_, index) => index).map((index) => (
|
|
29
|
+
<li key={index}>
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
32
|
+
className={index === activeIndex ? 'active' : undefined}
|
|
33
|
+
aria-current={index === activeIndex ? 'true' : undefined}
|
|
34
|
+
aria-label={label(index + 1)}
|
|
35
|
+
onClick={() => to(index)}
|
|
36
|
+
/>
|
|
37
|
+
</li>
|
|
38
|
+
))}
|
|
39
|
+
</ol>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
CarouselIndicators.displayName = 'CarouselIndicators'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import { useForkedRef } from '../../hooks'
|
|
5
|
+
import {
|
|
6
|
+
createPolymorphicComponent,
|
|
7
|
+
PolymorphicComponentProps,
|
|
8
|
+
PolymorphicRef
|
|
9
|
+
} from '../../utils/polymorphic'
|
|
10
|
+
import { useCarouselContext } from './context'
|
|
11
|
+
|
|
12
|
+
type CarouselInnerOwnProps<C extends ElementType> = {
|
|
13
|
+
/**
|
|
14
|
+
* A string of all className you want applied to the component.
|
|
15
|
+
*/
|
|
16
|
+
className?: string
|
|
17
|
+
/**
|
|
18
|
+
* Component used for the root node. Either a string to use a HTML element or a component.
|
|
19
|
+
*/
|
|
20
|
+
component?: C
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type CarouselInnerProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
|
|
24
|
+
C,
|
|
25
|
+
CarouselInnerOwnProps<C>
|
|
26
|
+
>
|
|
27
|
+
|
|
28
|
+
type CarouselInnerComponent = (<C extends ElementType = 'div'>(
|
|
29
|
+
props: CarouselInnerProps<C> & { ref?: PolymorphicRef<C> }
|
|
30
|
+
) => ReactElement | null) & { displayName?: string }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The scroll viewport — a real horizontally-scrolling container using CSS scroll-snap. Wrap
|
|
34
|
+
* CarouselItem children in this rather than passing them directly to Carousel, so controls and
|
|
35
|
+
* indicators can sit alongside it (above, below, or overlaid) instead of inside the scroll track.
|
|
36
|
+
*/
|
|
37
|
+
function CarouselInnerRender<C extends ElementType = 'div'>(
|
|
38
|
+
{ children, className, component, ...rest }: CarouselInnerProps<C>,
|
|
39
|
+
ref: PolymorphicRef<C>
|
|
40
|
+
) {
|
|
41
|
+
const { registerViewport } = useCarouselContext()
|
|
42
|
+
const Component = component ?? 'div'
|
|
43
|
+
const forkedRef = useForkedRef(ref, registerViewport)
|
|
44
|
+
const _className = classNames('carousel-inner', className)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Component className={_className} {...rest} ref={forkedRef}>
|
|
48
|
+
{children}
|
|
49
|
+
</Component>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const CarouselInner = createPolymorphicComponent<CarouselInnerComponent>(
|
|
54
|
+
CarouselInnerRender as ForwardRefRenderFunction<Element, CarouselInnerProps<ElementType>>,
|
|
55
|
+
'CarouselInner'
|
|
56
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createPolymorphicComponent,
|
|
6
|
+
PolymorphicComponentProps,
|
|
7
|
+
PolymorphicRef
|
|
8
|
+
} from '../../utils/polymorphic'
|
|
9
|
+
|
|
10
|
+
type CarouselItemOwnProps<C extends ElementType> = {
|
|
11
|
+
/**
|
|
12
|
+
* A string of all className you want applied to the component.
|
|
13
|
+
*/
|
|
14
|
+
className?: string
|
|
15
|
+
/**
|
|
16
|
+
* Component used for the root node. Either a string to use a HTML element or a component.
|
|
17
|
+
*/
|
|
18
|
+
component?: C
|
|
19
|
+
/**
|
|
20
|
+
* Milliseconds to wait before autoplay advances past this slide, overriding the carousel's own `interval`.
|
|
21
|
+
*/
|
|
22
|
+
interval?: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type CarouselItemProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
|
|
26
|
+
C,
|
|
27
|
+
CarouselItemOwnProps<C>
|
|
28
|
+
>
|
|
29
|
+
|
|
30
|
+
type CarouselItemComponent = (<C extends ElementType = 'div'>(
|
|
31
|
+
props: CarouselItemProps<C> & { ref?: PolymorphicRef<C> }
|
|
32
|
+
) => ReactElement | null) & { displayName?: string }
|
|
33
|
+
|
|
34
|
+
function CarouselItemRender<C extends ElementType = 'div'>(
|
|
35
|
+
{ children, className, component, interval, ...rest }: CarouselItemProps<C>,
|
|
36
|
+
ref: PolymorphicRef<C>
|
|
37
|
+
) {
|
|
38
|
+
const Component = component ?? 'div'
|
|
39
|
+
const _className = classNames('carousel-item', className)
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Component className={_className} data-interval={interval} {...rest} ref={ref}>
|
|
43
|
+
{children}
|
|
44
|
+
</Component>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const CarouselItem = createPolymorphicComponent<CarouselItemComponent>(
|
|
49
|
+
CarouselItemRender as ForwardRefRenderFunction<Element, CarouselItemProps<ElementType>>,
|
|
50
|
+
'CarouselItem'
|
|
51
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createPolymorphicComponent,
|
|
6
|
+
PolymorphicComponentProps,
|
|
7
|
+
PolymorphicRef
|
|
8
|
+
} from '../../utils/polymorphic'
|
|
9
|
+
|
|
10
|
+
type CarouselOverlayOwnProps<C extends ElementType> = {
|
|
11
|
+
/**
|
|
12
|
+
* A string of all className you want applied to the component.
|
|
13
|
+
*/
|
|
14
|
+
className?: string
|
|
15
|
+
/**
|
|
16
|
+
* Component used for the root node. Either a string to use a HTML element or a component.
|
|
17
|
+
*/
|
|
18
|
+
component?: C
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type CarouselOverlayProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
|
|
22
|
+
C,
|
|
23
|
+
CarouselOverlayOwnProps<C>
|
|
24
|
+
>
|
|
25
|
+
|
|
26
|
+
type CarouselOverlayComponent = (<C extends ElementType = 'div'>(
|
|
27
|
+
props: CarouselOverlayProps<C> & { ref?: PolymorphicRef<C> }
|
|
28
|
+
) => ReactElement | null) & { displayName?: string }
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Overlays its children (typically controls and indicators) on top of the slides instead of
|
|
32
|
+
* stacking them in the flow.
|
|
33
|
+
*/
|
|
34
|
+
function CarouselOverlayRender<C extends ElementType = 'div'>(
|
|
35
|
+
{ children, className, component, ...rest }: CarouselOverlayProps<C>,
|
|
36
|
+
ref: PolymorphicRef<C>
|
|
37
|
+
) {
|
|
38
|
+
const Component = component ?? 'div'
|
|
39
|
+
const _className = classNames('carousel-overlay', className)
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Component className={_className} {...rest} ref={ref}>
|
|
43
|
+
{children}
|
|
44
|
+
</Component>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const CarouselOverlay = createPolymorphicComponent<CarouselOverlayComponent>(
|
|
49
|
+
CarouselOverlayRender as ForwardRefRenderFunction<Element, CarouselOverlayProps<ElementType>>,
|
|
50
|
+
'CarouselOverlay'
|
|
51
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes, forwardRef } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import { Icon } from '../icon'
|
|
5
|
+
import { useCarouselContext } from './context'
|
|
6
|
+
|
|
7
|
+
export interface CarouselPlayPauseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
|
+
/**
|
|
9
|
+
* A string of all className you want applied to the component.
|
|
10
|
+
*/
|
|
11
|
+
className?: string
|
|
12
|
+
/**
|
|
13
|
+
* The accessible label announced while autoplay is running.
|
|
14
|
+
*/
|
|
15
|
+
pauseLabel?: string
|
|
16
|
+
/**
|
|
17
|
+
* The accessible label announced while autoplay is stopped.
|
|
18
|
+
*/
|
|
19
|
+
playLabel?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A discoverable toggle so a viewer can stop an autoplaying carousel, as required by WCAG 2.2
|
|
24
|
+
* Success Criterion 2.2.2 (Pause, Stop, Hide). Reflects the current state automatically — a pause
|
|
25
|
+
* icon while playing, a play icon once stopped.
|
|
26
|
+
*/
|
|
27
|
+
export const CarouselPlayPause = forwardRef<HTMLButtonElement, CarouselPlayPauseProps>(
|
|
28
|
+
({ children, className, onClick, pauseLabel = 'Pause', playLabel = 'Play', ...rest }, ref) => {
|
|
29
|
+
const { playing, togglePlayPause } = useCarouselContext()
|
|
30
|
+
const _className = classNames(
|
|
31
|
+
'carousel-control-play-pause button small icon-only',
|
|
32
|
+
{ paused: !playing },
|
|
33
|
+
className
|
|
34
|
+
)
|
|
35
|
+
// Compose rather than let a caller's `onClick` silently replace the toggle.
|
|
36
|
+
const handleClick: typeof onClick = (event) => {
|
|
37
|
+
onClick?.(event)
|
|
38
|
+
togglePlayPause()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
className={_className}
|
|
45
|
+
aria-label={playing ? pauseLabel : playLabel}
|
|
46
|
+
onClick={handleClick}
|
|
47
|
+
{...rest}
|
|
48
|
+
ref={ref}
|
|
49
|
+
>
|
|
50
|
+
{children ?? (
|
|
51
|
+
<>
|
|
52
|
+
<Icon name="pause-solid" className="carousel-icon-pause" aria-hidden="true" />
|
|
53
|
+
<Icon name="play-solid" className="carousel-icon-play" aria-hidden="true" />
|
|
54
|
+
</>
|
|
55
|
+
)}
|
|
56
|
+
</button>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
CarouselPlayPause.displayName = 'CarouselPlayPause'
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Internal helpers shared by the carousel family. Not exported from the component's public
|
|
2
|
+
// barrel (see CONVENTIONS.md's helper-module carve-out).
|
|
3
|
+
|
|
4
|
+
export const ITEM_SELECTOR = '.carousel-item:not(.carousel-item-clone)'
|
|
5
|
+
|
|
6
|
+
export function getCarouselItems(viewport: HTMLElement): HTMLElement[] {
|
|
7
|
+
return Array.from(viewport.querySelectorAll<HTMLElement>(`:scope > ${ITEM_SELECTOR}`))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isRTL(element: Element): boolean {
|
|
11
|
+
return getComputedStyle(element).direction === 'rtl'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function prefersReducedMotion(): boolean {
|
|
15
|
+
return (
|
|
16
|
+
typeof window !== 'undefined' &&
|
|
17
|
+
typeof window.matchMedia === 'function' &&
|
|
18
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isElementVisible(element: Element | null): boolean {
|
|
23
|
+
if (!element) return false
|
|
24
|
+
const rect = element.getBoundingClientRect()
|
|
25
|
+
return (
|
|
26
|
+
rect.top < (window.innerHeight || document.documentElement.clientHeight) &&
|
|
27
|
+
rect.bottom > 0 &&
|
|
28
|
+
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
|
|
29
|
+
rect.right > 0
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Horizontal distance to scroll `viewport` so `target` rests where the active slide belongs —
|
|
34
|
+
// centered when `center` is set, otherwise flush with the scroll-padding (peek) offset, which is
|
|
35
|
+
// exactly where scroll-snap settles. Scrolling the viewport itself (rather than
|
|
36
|
+
// `target.scrollIntoView()`) keeps an off-screen carousel from yanking the whole page to itself.
|
|
37
|
+
export function scrollDeltaFor(
|
|
38
|
+
viewport: HTMLElement,
|
|
39
|
+
target: HTMLElement,
|
|
40
|
+
center: boolean
|
|
41
|
+
): number {
|
|
42
|
+
const viewportRect = viewport.getBoundingClientRect()
|
|
43
|
+
const rect = target.getBoundingClientRect()
|
|
44
|
+
|
|
45
|
+
if (center) {
|
|
46
|
+
return rect.left + rect.width / 2 - (viewportRect.left + viewportRect.width / 2)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const padStart = Number.parseFloat(getComputedStyle(viewport).scrollPaddingInlineStart) || 0
|
|
50
|
+
|
|
51
|
+
return isRTL(viewport)
|
|
52
|
+
? rect.right - (viewportRect.right - padStart)
|
|
53
|
+
: rect.left - (viewportRect.left + padStart)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isViewportScrollable(viewport: HTMLElement): boolean {
|
|
57
|
+
return viewport.scrollWidth - viewport.clientWidth > 0
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const SCROLL_DURATION_MS = 300
|
|
61
|
+
// Safety net above the animation's own duration, in case `requestAnimationFrame` stalls (a
|
|
62
|
+
// backgrounded tab, a frozen/suspended webview) and never drives the animation to completion.
|
|
63
|
+
// `setTimeout` still fires in that situation — throttled, but not indefinitely suspended the way
|
|
64
|
+
// rAF can be — so this guarantees the scroll lands on target and callers relying on completion to
|
|
65
|
+
// release a lock (e.g. re-enabling the IntersectionObserver) can never get stuck forever.
|
|
66
|
+
const SCROLL_SAFETY_MS = SCROLL_DURATION_MS + 200
|
|
67
|
+
|
|
68
|
+
const easeInOutCubic = (progress: number) =>
|
|
69
|
+
progress < 0.5 ? 4 * progress * progress * progress : 1 - (-2 * progress + 2) ** 3 / 2
|
|
70
|
+
|
|
71
|
+
// Animates `viewport.scrollLeft` to `targetLeft` by stepping the position by hand each frame,
|
|
72
|
+
// resolving deterministically once the animation completes — not by waiting on the `scrollend`
|
|
73
|
+
// event or a fixed timeout as the *primary* signal. Both of those only approximate when a native
|
|
74
|
+
// `scrollTo({behavior:'smooth'})` actually finishes, and firing early restores CSS scroll-snap
|
|
75
|
+
// mid-flight, which snaps the track back to the nearest point instead of the intended one rather
|
|
76
|
+
// than letting it arrive. Using `behavior: 'instant'` for every step keeps this animation from
|
|
77
|
+
// fighting the viewport's own CSS `scroll-behavior: smooth`. Returns a canceller so a caller that
|
|
78
|
+
// starts a newer scroll before this one finishes can stop it instead of both fighting over the
|
|
79
|
+
// position.
|
|
80
|
+
export function animateScrollTo(
|
|
81
|
+
viewport: HTMLElement,
|
|
82
|
+
targetLeft: number,
|
|
83
|
+
onSettled: () => void
|
|
84
|
+
): () => void {
|
|
85
|
+
if (prefersReducedMotion() || typeof requestAnimationFrame === 'undefined') {
|
|
86
|
+
viewport.scrollTo({ left: targetLeft, behavior: 'instant' })
|
|
87
|
+
onSettled()
|
|
88
|
+
return () => {}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const startLeft = viewport.scrollLeft
|
|
92
|
+
const distance = targetLeft - startLeft
|
|
93
|
+
let startTime: number | null = null
|
|
94
|
+
let frame: number | null = null
|
|
95
|
+
let done = false
|
|
96
|
+
|
|
97
|
+
const finish = () => {
|
|
98
|
+
if (done) return
|
|
99
|
+
done = true
|
|
100
|
+
if (frame !== null) cancelAnimationFrame(frame)
|
|
101
|
+
clearTimeout(safetyTimer)
|
|
102
|
+
viewport.scrollTo({ left: targetLeft, behavior: 'instant' })
|
|
103
|
+
onSettled()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const step = (now: number) => {
|
|
107
|
+
if (done) return
|
|
108
|
+
if (startTime === null) startTime = now
|
|
109
|
+
|
|
110
|
+
const progress = Math.min((now - startTime) / SCROLL_DURATION_MS, 1)
|
|
111
|
+
viewport.scrollTo({
|
|
112
|
+
left: startLeft + distance * easeInOutCubic(progress),
|
|
113
|
+
behavior: 'instant'
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (progress < 1) {
|
|
117
|
+
frame = requestAnimationFrame(step)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
finish()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const safetyTimer = setTimeout(finish, SCROLL_SAFETY_MS)
|
|
125
|
+
frame = requestAnimationFrame(step)
|
|
126
|
+
|
|
127
|
+
return () => {
|
|
128
|
+
if (done) return
|
|
129
|
+
done = true
|
|
130
|
+
if (frame !== null) cancelAnimationFrame(frame)
|
|
131
|
+
clearTimeout(safetyTimer)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function normalizeIndex(index: number, length: number, wraps: boolean): number | null {
|
|
136
|
+
if (Number.isNaN(index) || length === 0) return null
|
|
137
|
+
if (index < 0) return wraps ? length - 1 : null
|
|
138
|
+
if (index > length - 1) return wraps ? 0 : null
|
|
139
|
+
return index
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type CarouselDirection = 'left' | 'right'
|
|
143
|
+
|
|
144
|
+
export function directionBetween(from: number, to: number, rtl: boolean): CarouselDirection {
|
|
145
|
+
const isNext = to > from
|
|
146
|
+
if (rtl) return isNext ? 'right' : 'left'
|
|
147
|
+
return isNext ? 'left' : 'right'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function loopDirection(isNext: boolean, rtl: boolean): CarouselDirection {
|
|
151
|
+
if (rtl) return isNext ? 'right' : 'left'
|
|
152
|
+
return isNext ? 'left' : 'right'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Seamless looping only reads right for the plain single-slide scroll layout — multi-item, peek,
|
|
156
|
+
// centered, and variable-width layouts fall back to a `wrap` jump instead (see `canLoop`).
|
|
157
|
+
export function canLoop(
|
|
158
|
+
carouselElement: HTMLElement,
|
|
159
|
+
itemCount: number,
|
|
160
|
+
isFade: boolean,
|
|
161
|
+
center: boolean,
|
|
162
|
+
auto: boolean
|
|
163
|
+
): boolean {
|
|
164
|
+
if (isFade || itemCount < 2 || center || auto) return false
|
|
165
|
+
|
|
166
|
+
const styles = getComputedStyle(carouselElement)
|
|
167
|
+
const num = (name: string) => Number.parseFloat(styles.getPropertyValue(name)) || 0
|
|
168
|
+
|
|
169
|
+
return (num('--cx-carousel-items') || 1) === 1 && num('--cx-carousel-items-peek') === 0
|
|
170
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
export type CarouselEnds = 'loop' | 'wrap' | 'stop'
|
|
4
|
+
|
|
5
|
+
export interface CarouselContextProps {
|
|
6
|
+
activeIndex: number
|
|
7
|
+
atEnd: boolean
|
|
8
|
+
atStart: boolean
|
|
9
|
+
ends: CarouselEnds
|
|
10
|
+
itemCount: number
|
|
11
|
+
itemsVisible: number
|
|
12
|
+
next: () => void
|
|
13
|
+
playing: boolean
|
|
14
|
+
prev: () => void
|
|
15
|
+
registerControl: (kind: 'prev' | 'next', element: HTMLButtonElement) => () => void
|
|
16
|
+
registerViewport: (node: HTMLDivElement | null) => void
|
|
17
|
+
to: (index: number) => void
|
|
18
|
+
togglePlayPause: () => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const CarouselContext = createContext<CarouselContextProps | null>(null)
|
|
22
|
+
|
|
23
|
+
export const useCarouselContext = (): CarouselContextProps => {
|
|
24
|
+
const context = useContext(CarouselContext)
|
|
25
|
+
if (!context) {
|
|
26
|
+
throw new Error('Carousel sub-components must be rendered inside a Carousel')
|
|
27
|
+
}
|
|
28
|
+
return context
|
|
29
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { Carousel } from './Carousel'
|
|
2
|
+
export type {
|
|
3
|
+
CarouselEnds,
|
|
4
|
+
CarouselProps,
|
|
5
|
+
CarouselSlideDetail,
|
|
6
|
+
CarouselTransition
|
|
7
|
+
} from './Carousel'
|
|
8
|
+
export { CarouselControlNext } from './CarouselControlNext'
|
|
9
|
+
export type { CarouselControlNextProps } from './CarouselControlNext'
|
|
10
|
+
export { CarouselControlPrev } from './CarouselControlPrev'
|
|
11
|
+
export type { CarouselControlPrevProps } from './CarouselControlPrev'
|
|
12
|
+
export { CarouselIndicators } from './CarouselIndicators'
|
|
13
|
+
export type { CarouselIndicatorsProps } from './CarouselIndicators'
|
|
14
|
+
export { CarouselInner } from './CarouselInner'
|
|
15
|
+
export type { CarouselInnerProps } from './CarouselInner'
|
|
16
|
+
export { CarouselItem } from './CarouselItem'
|
|
17
|
+
export type { CarouselItemProps } from './CarouselItem'
|
|
18
|
+
export { CarouselOverlay } from './CarouselOverlay'
|
|
19
|
+
export type { CarouselOverlayProps } from './CarouselOverlay'
|
|
20
|
+
export { CarouselPlayPause } from './CarouselPlayPause'
|
|
21
|
+
export type { CarouselPlayPauseProps } from './CarouselPlayPause'
|