Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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();
Expand Down Expand Up @@ -202,6 +204,23 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
[isOpen, renderOpener, setIsOpen]
);

const subButton = useMemo(
() =>
subButtonOptions ? (
<Box alignSelf="center" mt={12}>
<GhostButton
size="md"
onClick={() => subButtonOptions.onClick?.({ close: closeModal })}
disabled={subButtonOptions.disabled}
IconComponent={subButtonOptions.IconComponent}
>
{subButtonOptions.text}
</GhostButton>
</Box>
) : null,
[closeModal, subButtonOptions]
);

return (
<>
{opener}
Expand Down Expand Up @@ -286,27 +305,49 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
</ScrollBox>
)}

{isDefined(primaryButtonOptions) &&
!isDefined(secondaryButtonOptions) &&
!isDefined(subButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}
>
{primaryButtonOptions.text}
</ContainedButton>
</VStack>
)}
{isDefined(primaryButtonOptions) &&
isDefined(secondaryButtonOptions) &&
!isDefined(subButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0} width="100%" spacing={8}>
{isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}
>
{primaryButtonOptions.text}
</ContainedButton>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
{!isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0}>
<ContainedButton
kind={secondaryButtonOptions.kind ?? 'tertiary'}
size="xl"
onClick={() => secondaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={secondaryButtonOptions.disabled}
loading={secondaryButtonOptions.loading}
IconComponent={secondaryButtonOptions.IconComponent}
>
{secondaryButtonOptions.text}
</ContainedButton>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
{isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && (
<VStack>
<Stack
px={[20, 32]}
mt={[20, 24]}
flexShrink={0}
width="100%"
spacing={8}
direction={buttonDirection}
reverse={buttonDirection === 'horizontal' ? true : false}
>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
Expand All @@ -329,35 +370,10 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
>
{secondaryButtonOptions.text}
</ContainedButton>
</VStack>
)}
{isDefined(primaryButtonOptions) &&
!isDefined(secondaryButtonOptions) &&
isDefined(subButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0} width="100%" spacing={16}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}
>
{primaryButtonOptions.text}
</ContainedButton>
<Box alignSelf="center">
<GhostButton
size="md"
onClick={() => subButtonOptions.onClick?.({ close: closeModal })}
disabled={subButtonOptions.disabled}
IconComponent={subButtonOptions.IconComponent}
>
{subButtonOptions.text}
</GhostButton>
</Box>
</VStack>
)}
</Stack>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
</Box>
</ScrollBox>
</Animated.View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export const MultipleModal: ComponentStory<typeof ModalBottomSheet> = () => {
);
};

export const withButtonOptions: ComponentStory<typeof ModalBottomSheet> = () => (
export const withButtonOptions: ComponentStory<typeof ModalBottomSheet> = props => (
<HStack mt={200} width="100%" spacing={20}>
<ModalBottomSheet
title=""
Expand All @@ -167,6 +167,7 @@ export const withButtonOptions: ComponentStory<typeof ModalBottomSheet> = () =>
)}
primaryButtonOptions={{ text: 'primary', disabled: false }}
secondaryButtonOptions={{ text: 'secondary', disabled: false }}
buttonDirection={props.buttonDirection}
/>
<ModalBottomSheet
title=""
Expand All @@ -179,6 +180,19 @@ export const withButtonOptions: ComponentStory<typeof ModalBottomSheet> = () =>
primaryButtonOptions={{ text: 'primary', disabled: false }}
subButtonOptions={{ text: 'sub', disabled: false }}
/>
<ModalBottomSheet
title=""
defaultOpen={false}
renderOpener={({ open }) => (
<ContainedButton kind="primary" size="md" onClick={open}>
Primary + Secondary + Sub
</ContainedButton>
)}
primaryButtonOptions={{ text: 'primary', disabled: false }}
secondaryButtonOptions={{ text: 'secondary', disabled: false }}
subButtonOptions={{ text: 'sub', disabled: false }}
buttonDirection={props.buttonDirection}
/>
</HStack>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -37,6 +38,7 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
primaryButtonOptions,
secondaryButtonOptions,
subButtonOptions,
buttonDirection = 'vertical',
onClose,
showCloseButton = true,
dimClosable = true,
Expand Down Expand Up @@ -132,6 +134,23 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
return () => window.removeEventListener('keydown', onKeydown);
}, [closeModal, isOpen, dimClosable, showCloseButton]);

const subButton = useMemo(
() =>
subButtonOptions ? (
<Box alignSelf="center" mt={12}>
<GhostButton
size="md"
onClick={() => subButtonOptions.onClick?.({ close: closeModal })}
disabled={subButtonOptions.disabled}
IconComponent={subButtonOptions.IconComponent}
>
{subButtonOptions.text}
</GhostButton>
</Box>
) : null,
[closeModal, subButtonOptions]
);

return (
<>
{opener}
Expand Down Expand Up @@ -196,7 +215,15 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
)}
</HStack>
{subtitle ? (
<Body as="p" level={1} mt={[14, 20]} px={[20, 32]} flexShrink={0} whiteSpace="pre-wrap">
<Body
as="p"
level={1}
mt={[14, 20]}
px={[20, 32]}
flexShrink={0}
whiteSpace="pre-wrap"
color="onView2"
>
{subtitle}
</Body>
) : null}
Expand All @@ -207,7 +234,7 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
</ScrollBox>
)}

{isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && !isDefined(subButtonOptions) && (
{isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
Expand All @@ -220,21 +247,12 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
>
{primaryButtonOptions.text}
</ContainedButton>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
{isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && !isDefined(subButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0} width="100%" spacing={8}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}
>
{primaryButtonOptions.text}
</ContainedButton>

{!isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0}>
<ContainedButton
kind={secondaryButtonOptions.kind ?? 'tertiary'}
size="xl"
Expand All @@ -246,31 +264,45 @@ export const ModalBottomSheet = withModalBottomSheetVariation(
>
{secondaryButtonOptions.text}
</ContainedButton>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
{isDefined(primaryButtonOptions) && !isDefined(secondaryButtonOptions) && isDefined(subButtonOptions) && (
<VStack px={[20, 32]} mt={[20, 24]} flexShrink={0} width="100%" spacing={16}>
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}

{isDefined(primaryButtonOptions) && isDefined(secondaryButtonOptions) && (
<VStack>
<Stack
px={[20, 32]}
mt={[20, 24]}
flexShrink={0}
width="100%"
spacing={8}
direction={buttonDirection}
reverse={buttonDirection === 'horizontal' ? true : false}
>
{primaryButtonOptions.text}
</ContainedButton>
<Box alignSelf="center">
<GhostButton
size="md"
onClick={() => subButtonOptions.onClick?.({ close: closeModal })}
disabled={subButtonOptions.disabled}
IconComponent={subButtonOptions.IconComponent}
<ContainedButton
kind={primaryButtonOptions.kind ?? 'primary'}
size="xl"
onClick={() => primaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={primaryButtonOptions.disabled}
loading={primaryButtonOptions.loading}
IconComponent={primaryButtonOptions.IconComponent}
>
{primaryButtonOptions.text}
</ContainedButton>
<ContainedButton
kind={secondaryButtonOptions.kind ?? 'tertiary'}
size="xl"
onClick={() => secondaryButtonOptions.onClick?.({ close: closeModal })}
full={true}
disabled={secondaryButtonOptions.disabled}
loading={secondaryButtonOptions.loading}
IconComponent={secondaryButtonOptions.IconComponent}
>
{subButtonOptions.text}
</GhostButton>
</Box>
{secondaryButtonOptions.text}
</ContainedButton>
</Stack>
{isDefined(subButtonOptions) && subButton}
</VStack>
)}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ButtonOptions, 'kind' | 'loading'>;
}
| {
primaryButtonOptions?: never;
secondaryButtonOptions?: never;
subButtonOptions?: never;
}
);
} & (NoButtons | PrimaryButtonOnly | PrimarySecondaryButtons | SecondaryButtonOnly);

type PrimaryButtonOnly = {
primaryButtonOptions: ButtonOptions;
secondaryButtonOptions?: never;
subButtonOptions?: Omit<ButtonOptions, 'kind' | 'loading'>;
buttonDirection?: never;
};

type SecondaryButtonOnly = {
primaryButtonOptions?: never;
secondaryButtonOptions: ButtonOptions;
subButtonOptions?: Omit<ButtonOptions, 'kind' | 'loading'>;
buttonDirection?: never;
};

type PrimarySecondaryButtons = {
primaryButtonOptions: ButtonOptions;
secondaryButtonOptions: ButtonOptions;
subButtonOptions?: Omit<ButtonOptions, 'kind' | 'loading'>;
buttonDirection?: 'horizontal' | 'vertical';
};

type NoButtons = {
primaryButtonOptions?: never;
secondaryButtonOptions?: never;
subButtonOptions?: never;
buttonDirection?: never;
};

export type ButtonOptions = {
kind?: 'primary' | 'secondary' | 'tertiary';
Expand Down
Loading