UNPKG

koval-ui

Version:

React components collection with minimalistic design. Supports theming, layout, and input validation.

1 lines 9.28 kB
{"version":3,"file":"Carousel.cjs","sources":["../../../../src/lib/Carousel/Carousel.tsx"],"sourcesContent":["import type {ReactNode} from 'react';\nimport {Children, forwardRef, useMemo, useState, useCallback, useRef} from 'react';\nimport classNames from 'classnames';\nimport {useLocalTheme} from 'css-vars-hook';\n\nimport type {DataAttributes, LibraryProps} from '@/internal/LibraryAPI';\nimport {IconArrowLeft, IconArrowRight} from '@/internal/Icons';\nimport {useLinkRefs} from '@/internal/hooks/useLinkRefs.ts';\nimport {useResizeObserver} from '@/internal/hooks/useResizeObserver.ts';\n\nimport {Cell} from './Cell.tsx';\nimport {Dots} from './Dots.tsx';\nimport {useAutoRotate} from './useAutoRotate.ts';\nimport classes from './Carousel.module.css';\n\nexport type Props = DataAttributes &\n LibraryProps & {\n width: number;\n height: number;\n children?: ReactNode;\n defaultVisible?: number;\n showDots?: boolean;\n showArrows?: boolean;\n /** Provide time interval in seconds to auto rotate Carousel */\n autoRotate?: number;\n /** Callback when user clicks navigation arrows */\n onRotate?: (index: number) => void;\n };\n\nconst getVisibleIndex = (index: number, length: number) => {\n return index % length >= 0 ? index % length : length + (index % length);\n};\n\n// CSS formulas\n// const getTranslateZ = (width: number, amount: number) => width / (2 * Math.tan(Math.PI / amount));\n// const getRotateY = (amount: number, index: number) => Math.round(index * (360 / amount));\n// see https://3dtransforms.desandro.com/carousel\n\nexport const Carousel = forwardRef<HTMLDivElement, Props>(\n (\n {\n children,\n className,\n width,\n height,\n defaultVisible = 0,\n showDots = true,\n showArrows = true,\n autoRotate,\n onRotate = () => {},\n ...nativeProps\n },\n ref\n ) => {\n const initialState = defaultVisible !== 0 ? defaultVisible - 1 : defaultVisible;\n\n const [visible, setVisible] = useState(initialState);\n\n const cellsAmount = Children.toArray(children).length;\n\n const {LocalRoot, ref: innerRef} = useLocalTheme<HTMLDivElement>();\n\n useLinkRefs(ref, innerRef);\n\n const viewPortRef = useRef<HTMLDivElement>(null);\n\n const [elementWidth, setElementWidth] = useState(width);\n const [elementHeight, setElementHeight] = useState(height);\n\n const handleResize = useCallback(\n (parent?: HTMLDivElement | null) => {\n const parentWidth = parent?.offsetWidth;\n if (parentWidth && parentWidth < elementWidth) {\n const nextHeight = height * (parentWidth / width);\n setElementWidth(parentWidth);\n setElementHeight(nextHeight);\n } else if (parentWidth && parentWidth > elementWidth) {\n setElementWidth(width);\n setElementHeight(height);\n }\n },\n [elementWidth, height, width]\n );\n\n useResizeObserver(innerRef.current?.parentElement as HTMLDivElement, handleResize);\n\n const theme = useMemo(\n () => ({\n width: elementWidth,\n height: elementHeight,\n 'cells-amount': cellsAmount,\n rotations: visible,\n }),\n [elementWidth, elementHeight, cellsAmount, visible]\n );\n\n const visibleIndex = getVisibleIndex(visible, cellsAmount);\n\n const handleIncrement = useCallback(() => {\n const nextVisible = visible + 1;\n setVisible(nextVisible);\n onRotate(getVisibleIndex(nextVisible, cellsAmount));\n }, [visible, onRotate, cellsAmount]);\n\n const handleDecrement = useCallback(() => {\n const nextVisible = visible - 1;\n setVisible(nextVisible);\n onRotate(getVisibleIndex(nextVisible, cellsAmount));\n }, [visible, onRotate, cellsAmount]);\n\n const handleRotate = useCallback(() => {\n setVisible(visible + 1);\n }, [visible, setVisible]);\n\n useAutoRotate({\n rotateFn: handleRotate,\n interval: autoRotate && autoRotate * 1000,\n ref: innerRef,\n });\n\n const cells = useMemo(\n () =>\n Children.toArray(children).map((element, index) => {\n return (\n <Cell index={index} key={index}>\n {element}\n </Cell>\n );\n }),\n [children]\n );\n\n return (\n <LocalRoot\n {...nativeProps}\n theme={theme}\n className={classNames(classes.carousel, className)}>\n <div className={classes.scene}>\n {showArrows && (\n <button\n className={classNames(classes.navigation, classes.left)}\n onClick={handleDecrement}>\n <IconArrowLeft className={classes.icon} />\n </button>\n )}\n <div className={classes.viewport} ref={viewPortRef}>\n {cells}\n </div>\n {showArrows && (\n <button\n className={classNames(classes.navigation, classes.right)}\n onClick={handleIncrement}>\n <IconArrowRight className={classes.icon} />\n </button>\n )}\n </div>\n {showDots && (\n <Dots amount={Children.toArray(children).length} active={visibleIndex} />\n )}\n </LocalRoot>\n );\n }\n);\n\nCarousel.displayName = 'Carousel';\n"],"names":["getVisibleIndex","index","length","Carousel","forwardRef","children","className","width","height","defaultVisible","showDots","showArrows","autoRotate","onRotate","nativeProps","ref","initialState","visible","setVisible","useState","cellsAmount","Children","LocalRoot","innerRef","useLocalTheme","useLinkRefs","viewPortRef","useRef","elementWidth","setElementWidth","elementHeight","setElementHeight","handleResize","useCallback","parent","parentWidth","nextHeight","useResizeObserver","_a","theme","useMemo","visibleIndex","handleIncrement","nextVisible","handleDecrement","handleRotate","useAutoRotate","cells","element","jsx","Cell","jsxs","classNames","classes","IconArrowLeft","IconArrowRight","Dots"],"mappings":"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"}