-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add first initial version of working carousel
- Loading branch information
Showing
12 changed files
with
8,099 additions
and
30,808 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
91 changes: 91 additions & 0 deletions
91
packages/ui/src/components/Organisms/Carousel/Carousel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import React, { | ||
ReactComponentElement, | ||
ReactElement, | ||
ReactNode, | ||
useEffect, | ||
} from 'react'; | ||
import { DotButton, useDotButton } from './CarouselDotButton'; | ||
import { | ||
PrevButton, | ||
NextButton, | ||
usePrevNextButtons, | ||
} from './CarouselArrowButtons'; | ||
import useEmblaCarousel from 'embla-carousel-react'; | ||
import { EmblaOptionsType } from 'embla-carousel'; | ||
import clsx from 'clsx'; | ||
|
||
export function Carousel({ | ||
children, | ||
options, | ||
visibleSlides = 2, | ||
}: { | ||
children: ReactNode; | ||
options: EmblaOptionsType; | ||
visibleSlides?: number; | ||
}) { | ||
const [emblaRef, emblaApi] = useEmblaCarousel(options); | ||
|
||
const { selectedIndex, scrollSnaps, onDotButtonClick } = | ||
useDotButton(emblaApi); | ||
|
||
const { | ||
prevBtnDisabled, | ||
nextBtnDisabled, | ||
onPrevButtonClick, | ||
onNextButtonClick, | ||
} = usePrevNextButtons(emblaApi); | ||
|
||
useEffect(() => { | ||
if (emblaApi) { | ||
// Do we want to use emblaApi for anything? | ||
// console.log(emblaApi.slideNodes()); | ||
} | ||
}, [emblaApi]); | ||
|
||
return ( | ||
<div className="embla m-auto max-w-full"> | ||
<div className="embla__viewport overflow-hidden" ref={emblaRef}> | ||
<div | ||
className={clsx( | ||
'embla__container grid grid-flow-col gap-4 touch-pan-y touch-pinch-zoom', | ||
{ | ||
'auto-cols-[100%]': visibleSlides === 1, | ||
'auto-cols-[50%]': visibleSlides === 2, | ||
'auto-cols-[33%]': visibleSlides === 3, | ||
'auto-cols-[25%]': visibleSlides === 4, | ||
}, | ||
)} | ||
> | ||
{React.Children.map(children, (child, index) => ( | ||
<div key={index} className="embla__slide min-w-0 p-2"> | ||
{child} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
|
||
<div className="embla__controls grid grid-cols-[auto_1fr] justify-between gap-4 mt-4"> | ||
<div className="embla__buttons grid grid-cols-[repeat(2,1fr)] gap-2"> | ||
<PrevButton onClick={onPrevButtonClick} disabled={prevBtnDisabled} /> | ||
<NextButton onClick={onNextButtonClick} disabled={nextBtnDisabled} /> | ||
</div> | ||
|
||
<div className="embla__dots flex flex-wrap gap-2 justify-end align-center"> | ||
{scrollSnaps.map((_: unknown, index: number) => ( | ||
<DotButton | ||
key={index} | ||
onClick={() => onDotButtonClick(index)} | ||
className={clsx( | ||
'embla__dot touch-manipulation cursor-pointer w-6 h-6 inline-flex items-center justify-center rounded-[50%] text-gray-400', | ||
{ | ||
'embla__dot--selected bg-gray-800': index === selectedIndex, | ||
'bg-gray-200': index !== selectedIndex, | ||
}, | ||
)} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
92 changes: 92 additions & 0 deletions
92
packages/ui/src/components/Organisms/Carousel/CarouselArrowButtons.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import React, { | ||
ComponentPropsWithRef, | ||
useCallback, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
import { EmblaCarouselType } from 'embla-carousel'; | ||
|
||
type UsePrevNextButtonsType = { | ||
prevBtnDisabled: boolean; | ||
nextBtnDisabled: boolean; | ||
onPrevButtonClick: () => void; | ||
onNextButtonClick: () => void; | ||
}; | ||
|
||
export const usePrevNextButtons = ( | ||
emblaApi: EmblaCarouselType | undefined, | ||
): UsePrevNextButtonsType => { | ||
const [prevBtnDisabled, setPrevBtnDisabled] = useState(true); | ||
const [nextBtnDisabled, setNextBtnDisabled] = useState(true); | ||
|
||
const onPrevButtonClick = useCallback(() => { | ||
if (!emblaApi) return; | ||
emblaApi.scrollPrev(); | ||
}, [emblaApi]); | ||
|
||
const onNextButtonClick = useCallback(() => { | ||
if (!emblaApi) return; | ||
emblaApi.scrollNext(); | ||
}, [emblaApi]); | ||
|
||
const onSelect = useCallback((emblaApi: EmblaCarouselType) => { | ||
setPrevBtnDisabled(!emblaApi.canScrollPrev()); | ||
setNextBtnDisabled(!emblaApi.canScrollNext()); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (!emblaApi) return; | ||
|
||
onSelect(emblaApi); | ||
emblaApi.on('reInit', onSelect).on('select', onSelect); | ||
}, [emblaApi, onSelect]); | ||
|
||
return { | ||
prevBtnDisabled, | ||
nextBtnDisabled, | ||
onPrevButtonClick, | ||
onNextButtonClick, | ||
}; | ||
}; | ||
|
||
type PropType = ComponentPropsWithRef<'button'>; | ||
|
||
export const PrevButton: React.FC<PropType> = (props) => { | ||
const { children, ...restProps } = props; | ||
|
||
return ( | ||
<button | ||
className="embla__button embla__button--prev touch-manipulation inline-flex cursor-pointer items-center justify-center w-8 h-8 text-gray-400" | ||
type="button" | ||
{...restProps} | ||
> | ||
<svg className="embla__button__svg w-[35%] h-[35%]" viewBox="0 0 532 532"> | ||
<path | ||
fill="currentColor" | ||
d="M355.66 11.354c13.793-13.805 36.208-13.805 50.001 0 13.785 13.804 13.785 36.238 0 50.034L201.22 266l204.442 204.61c13.785 13.805 13.785 36.239 0 50.044-13.793 13.796-36.208 13.796-50.002 0a5994246.277 5994246.277 0 0 0-229.332-229.454 35.065 35.065 0 0 1-10.326-25.126c0-9.2 3.393-18.26 10.326-25.2C172.192 194.973 332.731 34.31 355.66 11.354Z" | ||
/> | ||
</svg> | ||
{children} | ||
</button> | ||
); | ||
}; | ||
|
||
export const NextButton: React.FC<PropType> = (props) => { | ||
const { children, ...restProps } = props; | ||
|
||
return ( | ||
<button | ||
className="embla__button embla__button--next touch-manipulation inline-flex cursor-pointer items-center justify-center w-8 h-8 text-gray-400" | ||
type="button" | ||
{...restProps} | ||
> | ||
<svg className="embla__button__svg w-[35%] h-[35%]" viewBox="0 0 532 532"> | ||
<path | ||
fill="currentColor" | ||
d="M176.34 520.646c-13.793 13.805-36.208 13.805-50.001 0-13.785-13.804-13.785-36.238 0-50.034L330.78 266 126.34 61.391c-13.785-13.805-13.785-36.239 0-50.044 13.793-13.796 36.208-13.796 50.002 0 22.928 22.947 206.395 206.507 229.332 229.454a35.065 35.065 0 0 1 10.326 25.126c0 9.2-3.393 18.26-10.326 25.2-45.865 45.901-206.404 206.564-229.332 229.52Z" | ||
/> | ||
</svg> | ||
{children} | ||
</button> | ||
); | ||
}; |
62 changes: 62 additions & 0 deletions
62
packages/ui/src/components/Organisms/Carousel/CarouselDotButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React, { | ||
ComponentPropsWithRef, | ||
useCallback, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
import { EmblaCarouselType } from 'embla-carousel'; | ||
|
||
type UseDotButtonType = { | ||
selectedIndex: number; | ||
scrollSnaps: number[]; | ||
onDotButtonClick: (index: number) => void; | ||
}; | ||
|
||
export const useDotButton = ( | ||
emblaApi: EmblaCarouselType | undefined, | ||
): UseDotButtonType => { | ||
const [selectedIndex, setSelectedIndex] = useState(0); | ||
const [scrollSnaps, setScrollSnaps] = useState<number[]>([]); | ||
|
||
const onDotButtonClick = useCallback( | ||
(index: number) => { | ||
if (!emblaApi) return; | ||
emblaApi.scrollTo(index); | ||
}, | ||
[emblaApi], | ||
); | ||
|
||
const onInit = useCallback((emblaApi: EmblaCarouselType) => { | ||
setScrollSnaps(emblaApi.scrollSnapList()); | ||
}, []); | ||
|
||
const onSelect = useCallback((emblaApi: EmblaCarouselType) => { | ||
setSelectedIndex(emblaApi.selectedScrollSnap()); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (!emblaApi) return; | ||
|
||
onInit(emblaApi); | ||
onSelect(emblaApi); | ||
emblaApi.on('reInit', onInit).on('reInit', onSelect).on('select', onSelect); | ||
}, [emblaApi, onInit, onSelect]); | ||
|
||
return { | ||
selectedIndex, | ||
scrollSnaps, | ||
onDotButtonClick, | ||
}; | ||
}; | ||
|
||
type PropType = ComponentPropsWithRef<'button'>; | ||
|
||
export const DotButton: React.FC<PropType> = (props) => { | ||
const { children, ...restProps } = props; | ||
|
||
return ( | ||
<button type="button" {...restProps}> | ||
{children} | ||
</button> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.