From 506cbe5cf9cce3c7e0bd328051ae9481557e7f80 Mon Sep 17 00:00:00 2001 From: Benji <64439681+benjitrosch@users.noreply.github.com> Date: Fri, 15 Apr 2022 12:31:59 -0400 Subject: [PATCH] chore(Carousel): customizable button renderprops and added stories (#90) BREAKING CHANGE: refactored fullWidth prop to width type --- src/Carousel/Carousel.stories.tsx | 120 +++++++++++++++++++++++++++++- src/Carousel/Carousel.tsx | 34 +++++++-- src/Carousel/CarouselItem.tsx | 51 ++++++++++--- 3 files changed, 185 insertions(+), 20 deletions(-) diff --git a/src/Carousel/Carousel.stories.tsx b/src/Carousel/Carousel.stories.tsx index 6d620e3e..c8e61ca2 100644 --- a/src/Carousel/Carousel.stories.tsx +++ b/src/Carousel/Carousel.stories.tsx @@ -2,6 +2,7 @@ import React from 'react' import { Story, Meta } from '@storybook/react' import Carousel, { CarouselProps } from '.' +import Button from '../Button' export default { title: 'Data Display/Carousel', @@ -10,7 +11,7 @@ export default { export const Default: Story = (args) => { return ( - + @@ -22,3 +23,120 @@ export const Default: Story = (args) => { ) } Default.args = {} + +export const Snap: Story = (args) => { + return ( + + + + + + + + + + ) +} +Snap.args = { + snap: 'end' +} + +export const FullWidth: Story = (args) => { + return ( + + + + + + + + + + ) +} +FullWidth.args = { + width: 'full', +} + +export const HalfWidth: Story = (args) => { + return ( + + + + + + + + + + ) +} +HalfWidth.args = { + width: 'half', +} + +export const Vertical: Story = (args) => { + return ( + + + + + + + + + + ) +} +Vertical.args = { + width: 'full', + vertical: true, +} + +export const Numbered: Story = (args) => { + return ( + + + + + + + ) +} +Numbered.args = { + display: 'numbered', +} + +export const Sequential: Story = (args) => { + return ( + + + + + + + ) +} +Sequential.args = { + display: 'sequential', +} + +export const CustomButton: Story = (args) => { + const buttonStyle = (value: string) => { + return + } + + args.buttonStyle = buttonStyle + + return ( + + + + + + + ) +} +CustomButton.args = { + display: 'sequential', +} diff --git a/src/Carousel/Carousel.tsx b/src/Carousel/Carousel.tsx index 0a1802b8..d3f70915 100644 --- a/src/Carousel/Carousel.tsx +++ b/src/Carousel/Carousel.tsx @@ -12,7 +12,7 @@ import { twMerge } from 'tailwind-merge' import { IComponentBaseProps } from '../types' -import CarouselItem, { CarouselItemProps } from './CarouselItem' +import CarouselItem, { CarouselItemProps, CarouselItemWidth } from './CarouselItem' import Button from '../Button' export type CarouselProps = React.HTMLAttributes & @@ -21,12 +21,22 @@ export type CarouselProps = React.HTMLAttributes & display?: 'slider' | 'numbered' | 'sequential' snap?: 'start' | 'center' | 'end' vertical?: boolean - fullWidth?: boolean + width?: CarouselItemWidth + buttonStyle?: (value: string) => React.ReactElement } const Carousel = forwardRef( ( - { children, display = 'slider', snap, vertical, fullWidth, dataTheme, className, ...props }, + { children, + display = 'slider', + snap, + vertical, + width, + buttonStyle, + dataTheme, + className, + ...props + }, ref ): JSX.Element => { const classes = twMerge( @@ -69,15 +79,15 @@ const Carousel = forwardRef( > {children.map((child, i) => { return cloneElement(child, { - className: display !== 'slider' || fullWidth ? 'w-full' : '', innerRef: itemRefs[i], index: i + 1, children: child.props.children, src: child.props.src, alt: child.props.alt, - buttons: display === 'sequential', - fullWidth: display !== 'slider' || fullWidth, - onPrev: () => scrollToIndex(i - 1 <= 0 ? children.length - 1 : i - 1), + width: display !== 'slider' ? 'full' : width, + hasButtons: display === 'sequential', + buttonStyle, + onPrev: () => scrollToIndex(i - 1 < 0 ? children.length - 1 : i - 1), onNext: () => scrollToIndex(i + 1 > children.length - 1 ? 0 : i + 1), ...child.props, }) @@ -86,8 +96,16 @@ const Carousel = forwardRef( {display === 'numbered' && (
{children.map((_, i) => { + if (buttonStyle != null) { + return ( + cloneElement(buttonStyle((i + 1).toString()), { + key: i, + onClick: () => scrollToIndex(i) + }) + ) + } + return ( - // TODO: pass in customizable numbered buttons diff --git a/src/Carousel/CarouselItem.tsx b/src/Carousel/CarouselItem.tsx index 64909312..a2378757 100644 --- a/src/Carousel/CarouselItem.tsx +++ b/src/Carousel/CarouselItem.tsx @@ -1,16 +1,19 @@ -import React, { LegacyRef } from 'react' +import React, { cloneElement, LegacyRef } from 'react' import clsx from 'clsx' import { twMerge } from 'tailwind-merge' import Button from '../Button' +export type CarouselItemWidth = 'full' | 'half' + export type CarouselItemProps = React.HTMLAttributes & { readonly innerRef?: LegacyRef src?: string alt?: string index?: number - buttons?: boolean - fullWidth?: boolean + width?: CarouselItemWidth + hasButtons?: boolean + buttonStyle?: (value: string) => React.ReactElement onPrev?: () => void onNext?: () => void } @@ -21,8 +24,9 @@ const CarouselItem = ({ src, alt, index = 0, - buttons, - fullWidth, + width, + hasButtons, + buttonStyle, onPrev, onNext, className, @@ -30,21 +34,46 @@ const CarouselItem = ({ }: CarouselItemProps): JSX.Element => { const classes = twMerge( "carousel-item relative", - className + className, + clsx({ + 'w-full': width === 'full', + 'w-1/2': width === 'half', + 'h-full': true, + }) ) const imageClasses = clsx({ - 'w-full': fullWidth + 'w-full': width === 'full', }) + const renderButtons = () => { + if (buttonStyle != null) { + return ( + <> + {cloneElement(buttonStyle('❮'), { + onClick: onPrev + })} + {cloneElement(buttonStyle('❯'), { + onClick: onNext + })} + + ) + } + + return ( + <> + + + + ) + } + return (
{src ? {alt} : children} - {buttons && ( + {hasButtons && (
- {/* TODO: pass in customizable prev/next buttons */} - - + {renderButtons()}
)}