|
@@ -1,8 +1,6 @@
|
|
|
-import React, { useRef } from 'react'
|
|
|
+import React, { ComponentPropsWithoutRef, ReactNode, RefObject, forwardRef, useImperativeHandle, useRef } from 'react'
|
|
|
|
|
|
-import { SvgGlyphChevronLeft, SvgGlyphChevronRight } from '@/shared/icons'
|
|
|
-
|
|
|
-import { Arrow, BackgroundGradient, Container, GliderContainer, Track } from './Carousel.style'
|
|
|
+import { Container, Dots, GliderContainer, Track } from './Carousel.style'
|
|
|
|
|
|
import { GliderProps, useGlider } from '../Glider'
|
|
|
|
|
@@ -11,41 +9,59 @@ export type CarouselProps = {
|
|
|
paddingTop?: number
|
|
|
className?: string
|
|
|
arrowPosition?: number
|
|
|
+ dotsVisible?: boolean
|
|
|
} & GliderProps
|
|
|
+export const Carousel = forwardRef<
|
|
|
+ ReactNode,
|
|
|
+ CarouselProps &
|
|
|
+ ComponentPropsWithoutRef<'div'> & {
|
|
|
+ prevArrowRef: RefObject<HTMLButtonElement>
|
|
|
+ nextArrowRef: RefObject<HTMLButtonElement>
|
|
|
+ }
|
|
|
+>(
|
|
|
+ (
|
|
|
+ {
|
|
|
+ children,
|
|
|
+ paddingLeft = 0,
|
|
|
+ paddingTop = 0,
|
|
|
+ className = '',
|
|
|
+ arrowPosition,
|
|
|
+ slidesToShow = 'auto',
|
|
|
+ dotsVisible,
|
|
|
+ prevArrowRef,
|
|
|
+ nextArrowRef,
|
|
|
+ ...gliderOptions
|
|
|
+ },
|
|
|
+ ref
|
|
|
+ ) => {
|
|
|
+ const dotsRef = useRef<HTMLDivElement>(null)
|
|
|
+ const {
|
|
|
+ ref: gliderRef,
|
|
|
+ getContainerProps,
|
|
|
+ getGliderProps,
|
|
|
+ getTrackProps,
|
|
|
+ getPrevArrowProps,
|
|
|
+ getNextArrowProps,
|
|
|
+ getDotsProps,
|
|
|
+ } = useGlider<HTMLDivElement>({
|
|
|
+ slidesToShow,
|
|
|
+ arrows: { prev: prevArrowRef.current, next: nextArrowRef.current },
|
|
|
+ dots: dotsRef.current,
|
|
|
+ ...gliderOptions,
|
|
|
+ })
|
|
|
|
|
|
-export const Carousel: React.FC<CarouselProps> = ({
|
|
|
- children,
|
|
|
- paddingLeft = 0,
|
|
|
- paddingTop = 0,
|
|
|
- className = '',
|
|
|
- arrowPosition,
|
|
|
- slidesToShow = 'auto',
|
|
|
- ...gliderOptions
|
|
|
-}) => {
|
|
|
- // TODO: this is the only place in the app that requires refs to buttons. Once we refactor this component, we can remove forwardRef from buttons
|
|
|
- const nextArrowRef = useRef<HTMLButtonElement>(null)
|
|
|
- const prevArrowRef = useRef<HTMLButtonElement>(null)
|
|
|
- const { ref, getContainerProps, getGliderProps, getTrackProps, getPrevArrowProps, getNextArrowProps } = useGlider<
|
|
|
- HTMLDivElement
|
|
|
- >({
|
|
|
- slidesToShow,
|
|
|
- arrows: { prev: prevArrowRef.current, next: nextArrowRef.current },
|
|
|
- ...gliderOptions,
|
|
|
- })
|
|
|
+ useImperativeHandle(ref, () => ({
|
|
|
+ getPrevArrowProps,
|
|
|
+ getNextArrowProps,
|
|
|
+ }))
|
|
|
|
|
|
- return (
|
|
|
- <Container {...getContainerProps({ className })}>
|
|
|
- <Arrow {...getPrevArrowProps()} ref={prevArrowRef} arrowPosition={arrowPosition} size="large">
|
|
|
- <SvgGlyphChevronLeft />
|
|
|
- </Arrow>
|
|
|
- <BackgroundGradient direction="prev" paddingLeft={paddingLeft} paddingTop={paddingTop} />
|
|
|
- <GliderContainer {...getGliderProps()} paddingLeft={paddingLeft} paddingTop={paddingTop} ref={ref}>
|
|
|
- <Track {...getTrackProps()}>{children}</Track>
|
|
|
- </GliderContainer>
|
|
|
- <Arrow {...getNextArrowProps()} ref={nextArrowRef} arrowPosition={arrowPosition} size="large">
|
|
|
- <SvgGlyphChevronRight />
|
|
|
- </Arrow>
|
|
|
- <BackgroundGradient direction="next" paddingLeft={paddingLeft} paddingTop={paddingTop} />
|
|
|
- </Container>
|
|
|
- )
|
|
|
-}
|
|
|
+ return (
|
|
|
+ <Container {...getContainerProps({ className })}>
|
|
|
+ <GliderContainer {...getGliderProps()} paddingLeft={paddingLeft} paddingTop={paddingTop} ref={gliderRef}>
|
|
|
+ <Track {...getTrackProps()}>{children}</Track>
|
|
|
+ </GliderContainer>
|
|
|
+ {dotsVisible && <Dots {...getDotsProps()} ref={dotsRef} />}
|
|
|
+ </Container>
|
|
|
+ )
|
|
|
+ }
|
|
|
+)
|