-
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.
Merge branch 'SLB-455-card-subgrid' into dev
- Loading branch information
Showing
11 changed files
with
421 additions
and
76 deletions.
There are no files selected for viewing
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
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
87 changes: 87 additions & 0 deletions
87
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,87 @@ | ||
import clsx from 'clsx'; | ||
import { EmblaOptionsType } from 'embla-carousel'; | ||
import useEmblaCarousel from 'embla-carousel-react'; | ||
import React, { ReactNode, useEffect } from 'react'; | ||
|
||
import { | ||
NextButton, | ||
PrevButton, | ||
usePrevNextButtons, | ||
} from './CarouselArrowButtons'; | ||
import { DotButton, useDotButton } from './CarouselDotButton'; | ||
|
||
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 touch-pan-y touch-pinch-zoom grid-flow-col gap-4', | ||
{ | ||
'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 mt-4 grid grid-cols-[auto_1fr] justify-between gap-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 align-center flex flex-wrap justify-end gap-2"> | ||
{scrollSnaps.map((_: unknown, index: number) => ( | ||
<DotButton | ||
key={index} | ||
onClick={() => onDotButtonClick(index)} | ||
className={clsx( | ||
'embla__dot inline-flex h-6 w-6 cursor-pointer touch-manipulation 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 { EmblaCarouselType } from 'embla-carousel'; | ||
import React, { | ||
ComponentPropsWithRef, | ||
useCallback, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
|
||
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 inline-flex h-8 w-8 cursor-pointer touch-manipulation items-center justify-center text-gray-400" | ||
type="button" | ||
{...restProps} | ||
> | ||
<svg className="embla__button__svg h-[35%] w-[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 inline-flex h-8 w-8 cursor-pointer touch-manipulation items-center justify-center text-gray-400" | ||
type="button" | ||
{...restProps} | ||
> | ||
<svg className="embla__button__svg h-[35%] w-[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 { EmblaCarouselType } from 'embla-carousel'; | ||
import React, { | ||
ComponentPropsWithRef, | ||
useCallback, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
|
||
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.