Skip to content

Commit

Permalink
fix(mobile): disable navigation gesture for swipe-dialog (#8993)
Browse files Browse the repository at this point in the history
  • Loading branch information
CatsJuice committed Dec 12, 2024
1 parent 01b6e43 commit 84df2a1
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 51 deletions.
25 changes: 11 additions & 14 deletions packages/frontend/apps/ios/src/modal-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,19 @@ import { type PropsWithChildren, useCallback } from 'react';
export const ModalConfigProvider = ({ children }: PropsWithChildren) => {
const navigationGesture = useService(NavigationGestureService);

const onOpenChange = useCallback(
(open: boolean) => {
const prev = navigationGesture.enabled$.value;
if (open && !prev) {
navigationGesture.setEnabled(false);
return () => {
navigationGesture.setEnabled(prev);
};
}
return;
},
[navigationGesture]
);
const onOpen = useCallback(() => {
const prev = navigationGesture.enabled$.value;
if (prev) {
navigationGesture.setEnabled(false);
return () => {
navigationGesture.setEnabled(prev);
};
}
return;
}, [navigationGesture]);

return (
<ModalConfigContext.Provider value={{ onOpenChange }}>
<ModalConfigContext.Provider value={{ onOpen }}>
{children}
</ModalConfigContext.Provider>
);
Expand Down
6 changes: 4 additions & 2 deletions packages/frontend/component/src/ui/modal/context.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { createContext } from 'react';

type OnClose = (() => void) | undefined;
export interface ModalConfig {
/**
* add global callback for modal open/close
* add global callback for modal open,
* return a function to handle close/unmount callback
*/
onOpenChange?: (open: boolean) => void;
onOpen?: () => OnClose;
}
export const ModalConfigContext = createContext<ModalConfig>({});

Expand Down
7 changes: 4 additions & 3 deletions packages/frontend/component/src/ui/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function createContainer() {

export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
(props, ref) => {
const modalConfig = useContext(ModalConfigContext);
const { onOpen: modalConfigOnOpen } = useContext(ModalConfigContext);
const {
modal,
portalOptions,
Expand Down Expand Up @@ -173,8 +173,9 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
);

useEffect(() => {
modalConfig.onOpenChange?.(open ?? false);
}, [modalConfig, open]);
if (open) return modalConfigOnOpen?.();
return;
}, [modalConfigOnOpen, open]);

useEffect(() => {
if (open) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface NavigationBackButtonProps extends IconButtonProps {
* A button to control the back behavior of the mobile app, as well as manage navigation gesture
*/
export const NavigationBackButton = ({
icon,
backAction,
style: propsStyle,
...otherProps
Expand Down Expand Up @@ -46,7 +47,7 @@ export const NavigationBackButton = ({
size={24}
style={style}
onClick={handleRouteBack}
icon={isInsideModal ? <CloseIcon /> : <ArrowLeftSmallIcon />}
icon={icon ?? (isInsideModal ? <CloseIcon /> : <ArrowLeftSmallIcon />)}
data-testid="page-header-back"
{...otherProps}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SafeArea } from '@affine/component';
import clsx from 'clsx';
import { forwardRef, type HtmlHTMLAttributes, type ReactNode } from 'react';
import type { HtmlHTMLAttributes, ReactElement, ReactNode } from 'react';
import { forwardRef } from 'react';

import { NavigationBackButton } from '../navigation-back';
import * as styles from './styles.css';
Expand All @@ -11,6 +12,7 @@ export interface PageHeaderProps
* whether to show back button
*/
back?: boolean;
backIcon?: ReactElement;
/**
* Override back button action
*/
Expand Down Expand Up @@ -51,6 +53,7 @@ export const PageHeader = forwardRef<HTMLDivElement, PageHeaderProps>(
function PageHeader(
{
back,
backIcon,
backAction,
prefix,
suffix,
Expand Down Expand Up @@ -82,7 +85,9 @@ export const PageHeader = forwardRef<HTMLDivElement, PageHeaderProps>(
className={clsx(styles.prefix, prefixClassName)}
style={prefixStyle}
>
{back ? <NavigationBackButton backAction={backAction} /> : null}
{back ? (
<NavigationBackButton icon={backIcon} backAction={backAction} />
) : null}
{prefix}
</section>

Expand Down
73 changes: 44 additions & 29 deletions packages/frontend/core/src/mobile/dialogs/setting/swipe-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Scrollable } from '@affine/component';
import {
InsideModalContext,
ModalConfigContext,
Scrollable,
} from '@affine/component';
import { PageHeader } from '@affine/core/mobile/components';
import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import anime from 'animejs';
import {
Expand Down Expand Up @@ -146,6 +151,8 @@ export const SwipeDialog = ({
triggerSize = 10,
onOpenChange,
}: SwipeDialogProps) => {
const insideModal = useContext(InsideModalContext);
const { onOpen: globalOnOpen } = useContext(ModalConfigContext);
const swiperTriggerRef = useRef<HTMLDivElement>(null);
const overlayRef = useRef<HTMLDivElement>(null);
const dialogRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -202,39 +209,47 @@ export const SwipeDialog = ({
}
}, [open, prev]);

useEffect(() => {
if (open) return globalOnOpen?.();
return;
}, [globalOnOpen, open]);

if (!open) return null;

return (
<SwipeDialogContext.Provider value={{ stack: [...stack, dialogRef] }}>
{createPortal(
<div className={styles.root}>
<div className={styles.overlay} ref={overlayRef} />
<div role="dialog" className={styles.dialog} ref={dialogRef}>
<div className={styles.content}>
<PageHeader
back
backAction={animateClose}
className={styles.header}
>
<span className={styles.dialogTitle}>{title}</span>
</PageHeader>

<Scrollable.Root className={styles.scrollArea}>
<Scrollable.Viewport>{children}</Scrollable.Viewport>
<Scrollable.Scrollbar orientation="vertical" />
</Scrollable.Root>
<InsideModalContext.Provider value={insideModal + 1}>
{createPortal(
<div className={styles.root}>
<div className={styles.overlay} ref={overlayRef} />
<div role="dialog" className={styles.dialog} ref={dialogRef}>
<div className={styles.content}>
<PageHeader
back
backIcon={<ArrowLeftSmallIcon />}
backAction={animateClose}
className={styles.header}
>
<span className={styles.dialogTitle}>{title}</span>
</PageHeader>

<Scrollable.Root className={styles.scrollArea}>
<Scrollable.Viewport>{children}</Scrollable.Viewport>
<Scrollable.Scrollbar orientation="vertical" />
</Scrollable.Root>
</div>
<div
ref={swiperTriggerRef}
className={styles.swipeBackTrigger}
style={assignInlineVars({
[styles.triggerSizeVar]: `${triggerSize}px`,
})}
/>
</div>
<div
ref={swiperTriggerRef}
className={styles.swipeBackTrigger}
style={assignInlineVars({
[styles.triggerSizeVar]: `${triggerSize}px`,
})}
/>
</div>
</div>,
document.body
)}
</div>,
document.body
)}
</InsideModalContext.Provider>
</SwipeDialogContext.Provider>
);
};

0 comments on commit 84df2a1

Please sign in to comment.