diff --git a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.native.tsx b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.native.tsx index d698e555c..ea910b4ea 100644 --- a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.native.tsx +++ b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.native.tsx @@ -21,6 +21,7 @@ import { ContainedButton } from '../ContainedButton'; import { GhostButton } from '../GhostButton'; import { HStack } from '../HStack'; import { IconButton } from '../IconButton'; +import { Stack } from '../Stack'; import { Title } from '../Title'; import { VStack } from '../VStack'; import { withModalBottomSheetVariation } from './ModalBottomSheetProps'; @@ -45,6 +46,7 @@ export const ModalBottomSheet = withModalBottomSheetVariation( transitionDuration = 300, native_swipeToCloseThreshold = 0.4, native_swipeToCloseVelocity = 200, + buttonDirection = 'vertical', }) => { const { getResponsiveValue } = useResponsiveValue(); const { generateStyle } = useSafeArea(); @@ -202,6 +204,23 @@ export const ModalBottomSheet = withModalBottomSheetVariation( [isOpen, renderOpener, setIsOpen] ); + const subButton = useMemo( + () => + subButtonOptions ? ( + + subButtonOptions.onClick?.({ close: closeModal })} + disabled={subButtonOptions.disabled} + IconComponent={subButtonOptions.IconComponent} + > + {subButtonOptions.text} + + + ) : null, + [closeModal, subButtonOptions] + ); + return ( <> {opener} @@ -286,27 +305,49 @@ export const ModalBottomSheet = withModalBottomSheetVariation( )} - {isDefined(primaryButtonOptions) && - !isDefined(secondaryButtonOptions) && - !isDefined(subButtonOptions) && ( - - primaryButtonOptions.onClick?.({ close: closeModal })} - full={true} - disabled={primaryButtonOptions.disabled} - loading={primaryButtonOptions.loading} - IconComponent={primaryButtonOptions.IconComponent} - > - {primaryButtonOptions.text} - - - )} - {isDefined(primaryButtonOptions) && - isDefined(secondaryButtonOptions) && - !isDefined(subButtonOptions) && ( - + {isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && ( + + primaryButtonOptions.onClick?.({ close: closeModal })} + full={true} + disabled={primaryButtonOptions.disabled} + loading={primaryButtonOptions.loading} + IconComponent={primaryButtonOptions.IconComponent} + > + {primaryButtonOptions.text} + + {isDefined(subButtonOptions) && subButton} + + )} + {!isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && ( + + secondaryButtonOptions.onClick?.({ close: closeModal })} + full={true} + disabled={secondaryButtonOptions.disabled} + loading={secondaryButtonOptions.loading} + IconComponent={secondaryButtonOptions.IconComponent} + > + {secondaryButtonOptions.text} + + {isDefined(subButtonOptions) && subButton} + + )} + {isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && ( + + {secondaryButtonOptions.text} - - )} - {isDefined(primaryButtonOptions) && - !isDefined(secondaryButtonOptions) && - isDefined(subButtonOptions) && ( - - primaryButtonOptions.onClick?.({ close: closeModal })} - full={true} - disabled={primaryButtonOptions.disabled} - loading={primaryButtonOptions.loading} - IconComponent={primaryButtonOptions.IconComponent} - > - {primaryButtonOptions.text} - - - subButtonOptions.onClick?.({ close: closeModal })} - disabled={subButtonOptions.disabled} - IconComponent={subButtonOptions.IconComponent} - > - {subButtonOptions.text} - - - - )} + + {isDefined(subButtonOptions) && subButton} + + )} diff --git a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.stories.tsx b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.stories.tsx index 5e14291a9..d481c2cb2 100644 --- a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.stories.tsx +++ b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.stories.tsx @@ -145,7 +145,7 @@ export const MultipleModal: ComponentStory = () => { ); }; -export const withButtonOptions: ComponentStory = () => ( +export const withButtonOptions: ComponentStory = props => ( = () => )} primaryButtonOptions={{ text: 'primary', disabled: false }} secondaryButtonOptions={{ text: 'secondary', disabled: false }} + buttonDirection={props.buttonDirection} /> = () => primaryButtonOptions={{ text: 'primary', disabled: false }} subButtonOptions={{ text: 'sub', disabled: false }} /> + ( + + Primary + Secondary + Sub + + )} + primaryButtonOptions={{ text: 'primary', disabled: false }} + secondaryButtonOptions={{ text: 'secondary', disabled: false }} + subButtonOptions={{ text: 'sub', disabled: false }} + buttonDirection={props.buttonDirection} + /> ); diff --git a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.tsx b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.tsx index e5fb8c852..aebc97921 100644 --- a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.tsx +++ b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheet.tsx @@ -21,6 +21,7 @@ import { ContainedButton } from '../ContainedButton'; import { GhostButton } from '../GhostButton'; import { HStack } from '../HStack'; import { IconButton } from '../IconButton'; +import { Stack } from '../Stack'; import { Title } from '../Title'; import { VStack } from '../VStack'; import { withModalBottomSheetVariation } from './ModalBottomSheetProps'; @@ -37,6 +38,7 @@ export const ModalBottomSheet = withModalBottomSheetVariation( primaryButtonOptions, secondaryButtonOptions, subButtonOptions, + buttonDirection = 'vertical', onClose, showCloseButton = true, dimClosable = true, @@ -132,6 +134,23 @@ export const ModalBottomSheet = withModalBottomSheetVariation( return () => window.removeEventListener('keydown', onKeydown); }, [closeModal, isOpen, dimClosable, showCloseButton]); + const subButton = useMemo( + () => + subButtonOptions ? ( + + subButtonOptions.onClick?.({ close: closeModal })} + disabled={subButtonOptions.disabled} + IconComponent={subButtonOptions.IconComponent} + > + {subButtonOptions.text} + + + ) : null, + [closeModal, subButtonOptions] + ); + return ( <> {opener} @@ -196,7 +215,15 @@ export const ModalBottomSheet = withModalBottomSheetVariation( )} {subtitle ? ( - + {subtitle} ) : null} @@ -207,7 +234,7 @@ export const ModalBottomSheet = withModalBottomSheetVariation( )} - {isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && !isDefined(subButtonOptions) && ( + {isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && ( {primaryButtonOptions.text} + {isDefined(subButtonOptions) && subButton} )} - {isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && !isDefined(subButtonOptions) && ( - - primaryButtonOptions.onClick?.({ close: closeModal })} - full={true} - disabled={primaryButtonOptions.disabled} - loading={primaryButtonOptions.loading} - IconComponent={primaryButtonOptions.IconComponent} - > - {primaryButtonOptions.text} - + + {!isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && ( + {secondaryButtonOptions.text} + {isDefined(subButtonOptions) && subButton} )} - {isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && isDefined(subButtonOptions) && ( - - primaryButtonOptions.onClick?.({ close: closeModal })} - full={true} - disabled={primaryButtonOptions.disabled} - loading={primaryButtonOptions.loading} - IconComponent={primaryButtonOptions.IconComponent} + + {isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && ( + + - {primaryButtonOptions.text} - - - subButtonOptions.onClick?.({ close: closeModal })} - disabled={subButtonOptions.disabled} - IconComponent={subButtonOptions.IconComponent} + primaryButtonOptions.onClick?.({ close: closeModal })} + full={true} + disabled={primaryButtonOptions.disabled} + loading={primaryButtonOptions.loading} + IconComponent={primaryButtonOptions.IconComponent} + > + {primaryButtonOptions.text} + + secondaryButtonOptions.onClick?.({ close: closeModal })} + full={true} + disabled={secondaryButtonOptions.disabled} + loading={secondaryButtonOptions.loading} + IconComponent={secondaryButtonOptions.IconComponent} > - {subButtonOptions.text} - - + {secondaryButtonOptions.text} + + + {isDefined(subButtonOptions) && subButton} )} diff --git a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheetProps.ts b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheetProps.ts index 4b8f39f83..f3ad31d70 100644 --- a/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheetProps.ts +++ b/packages/vibrant-components/src/lib/ModalBottomSheet/ModalBottomSheetProps.ts @@ -35,23 +35,35 @@ export type ModalBottomSheetProps = Either< * @default 200 */ native_swipeToCloseVelocity?: number; -} & ( - | { - primaryButtonOptions: ButtonOptions; - secondaryButtonOptions?: ButtonOptions; - subButtonOptions?: never; - } - | { - primaryButtonOptions: ButtonOptions; - secondaryButtonOptions?: never; - subButtonOptions?: Omit; - } - | { - primaryButtonOptions?: never; - secondaryButtonOptions?: never; - subButtonOptions?: never; - } - ); +} & (NoButtons | PrimaryButtonOnly | PrimarySecondaryButtons | SecondaryButtonOnly); + +type PrimaryButtonOnly = { + primaryButtonOptions: ButtonOptions; + secondaryButtonOptions?: never; + subButtonOptions?: Omit; + buttonDirection?: never; +}; + +type SecondaryButtonOnly = { + primaryButtonOptions?: never; + secondaryButtonOptions: ButtonOptions; + subButtonOptions?: Omit; + buttonDirection?: never; +}; + +type PrimarySecondaryButtons = { + primaryButtonOptions: ButtonOptions; + secondaryButtonOptions: ButtonOptions; + subButtonOptions?: Omit; + buttonDirection?: 'horizontal' | 'vertical'; +}; + +type NoButtons = { + primaryButtonOptions?: never; + secondaryButtonOptions?: never; + subButtonOptions?: never; + buttonDirection?: never; +}; export type ButtonOptions = { kind?: 'primary' | 'secondary' | 'tertiary';