Skip to content

Commit

Permalink
feat: added stack behavior to bottom sheet modal (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhom authored Jan 2, 2021
1 parent 36c2993 commit 84e06df
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 44 deletions.
5 changes: 3 additions & 2 deletions src/components/bottomSheetModal/BottomSheetModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const BottomSheetModalComponent = forwardRef<
const {
// modal props
name,
stackBehavior = 'replace',
dismissOnPanDown = DEFAULT_DISMISS_ON_PAN_DOWN,
onDismiss: _providedOnDismiss,

Expand Down Expand Up @@ -121,9 +122,9 @@ const BottomSheetModalComponent = forwardRef<
const handlePresent = useCallback(() => {
requestAnimationFrame(() => {
setMount(true);
mountSheet(key, ref);
mountSheet(key, ref, stackBehavior);
});
}, [key, mountSheet, ref]);
}, [key, stackBehavior, mountSheet, ref]);
const handleDismiss = useCallback(
(force: boolean = false) => {
if (force) {
Expand Down
1 change: 1 addition & 0 deletions src/components/bottomSheetModal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export { default } from './BottomSheetModal';
export type {
BottomSheetModalProps,
BottomSheetModalPrivateMethods,
BottomSheetModalStackBehavior,
} from './types';
12 changes: 12 additions & 0 deletions src/components/bottomSheetModal/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface BottomSheetModalPrivateMethods {
restore: () => void;
}

export type BottomSheetModalStackBehavior = 'push' | 'replace';

export interface BottomSheetModalProps
extends Exclude<BottomSheetProps, 'animateOnMount' | 'containerHeight'> {
/**
Expand All @@ -14,6 +16,16 @@ export interface BottomSheetModalProps
* @default nanoid generated unique key.
*/
name?: string;

/**
* Defines the stack behavior when modal mount.
* - `push` it will mount the modal on top of current modal.
* - `replace` it will minimize the current modal then mount the modal.
* @type `push` | `replace`
* @default replace
*/
stackBehavior?: BottomSheetModalStackBehavior;

/**
* Dismiss modal when panning down.
* @type boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '../../contexts';
import BottomSheetContainer from '../bottomSheetContainer';
import { WINDOW_HEIGHT } from '../../constants';
import type { BottomSheetModalStackBehavior } from '../bottomSheetModal';
import type {
BottomSheetModalProviderProps,
BottomSheetModalRef,
Expand All @@ -32,52 +33,60 @@ const BottomSheetModalProviderWrapper = (
//#endregion

//#region private methods
const handleMountSheet = useCallback((key: string, ref) => {
/**
* Here we try to minimize the current sheet if exists,
* also we make sure that it is not incoming mounted sheet.
*/
const mountedSheet =
sheetsQueueRef.current[sheetsQueueRef.current.length - 1];
if (mountedSheet && mountedSheet.key !== key && !mountedSheet.willUnmount) {
sheetsQueueRef.current[
sheetsQueueRef.current.length - 1
].ref.current.minimize();
}

/**
* We check if the incoming sheet is already mounted.
*/
const isIncomingSheetMounted =
sheetsQueueRef.current.find(item => item.key === key) !== undefined;

if (isIncomingSheetMounted) {
const handleMountSheet = useCallback(
(key: string, ref, stackBehavior: BottomSheetModalStackBehavior) => {
/**
* We move the mounted incoming sheet to the
* end of the queue.
* Here we try to minimize the current sheet if exists,
* also we make sure that it is not incoming mounted sheet.
*/
const newSheetsQueue = sheetsQueueRef.current.filter(
item => item.key !== key
);
newSheetsQueue.push({
key,
ref,
willUnmount: false,
});
sheetsQueueRef.current = newSheetsQueue;
const mountedSheet =
sheetsQueueRef.current[sheetsQueueRef.current.length - 1];
if (
stackBehavior === 'replace' &&
mountedSheet &&
mountedSheet.key !== key &&
!mountedSheet.willUnmount
) {
sheetsQueueRef.current[
sheetsQueueRef.current.length - 1
].ref.current.minimize();
}

ref.current.restore();
} else {
/**
* We add the incoming sheet to the end of the queue.
* We check if the incoming sheet is already mounted.
*/
sheetsQueueRef.current.push({
key,
ref,
willUnmount: false,
});
}
}, []);
const isIncomingSheetMounted =
sheetsQueueRef.current.find(item => item.key === key) !== undefined;

if (isIncomingSheetMounted) {
/**
* We move the mounted incoming sheet to the
* end of the queue.
*/
const newSheetsQueue = sheetsQueueRef.current.filter(
item => item.key !== key
);
newSheetsQueue.push({
key,
ref,
willUnmount: false,
});
sheetsQueueRef.current = newSheetsQueue;

ref.current.restore();
} else {
/**
* We add the incoming sheet to the end of the queue.
*/
sheetsQueueRef.current.push({
key,
ref,
willUnmount: false,
});
}
},
[]
);
const handleUnmountSheet = useCallback((key: string) => {
/**
* Here we remove the unmounted sheet and update
Expand Down
7 changes: 6 additions & 1 deletion src/contexts/modal/internal.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { createContext, Ref } from 'react';
import type BottomSheet from '../../components/bottomSheet';
import type { BottomSheetModalStackBehavior } from '../../components/bottomSheetModal';

export interface BottomSheetModalInternalContextType {
containerHeight: number;
mountSheet: (key: string, ref: Ref<BottomSheet>) => void;
mountSheet: (
key: string,
ref: Ref<BottomSheet>,
stackBehavior: BottomSheetModalStackBehavior
) => void;
unmountSheet: (key: string) => void;
willUnmountSheet: (key: string) => void;
}
Expand Down

0 comments on commit 84e06df

Please sign in to comment.