diff --git a/packages/frontend/apps/ios/src/modal-config.tsx b/packages/frontend/apps/ios/src/modal-config.tsx index 57acb06653..9f2902282e 100644 --- a/packages/frontend/apps/ios/src/modal-config.tsx +++ b/packages/frontend/apps/ios/src/modal-config.tsx @@ -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 ( - + {children} ); diff --git a/packages/frontend/component/src/ui/modal/context.ts b/packages/frontend/component/src/ui/modal/context.ts index f40370d4ed..a28cda62e0 100644 --- a/packages/frontend/component/src/ui/modal/context.ts +++ b/packages/frontend/component/src/ui/modal/context.ts @@ -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({}); diff --git a/packages/frontend/component/src/ui/modal/modal.tsx b/packages/frontend/component/src/ui/modal/modal.tsx index 108796be25..fe33eedfca 100644 --- a/packages/frontend/component/src/ui/modal/modal.tsx +++ b/packages/frontend/component/src/ui/modal/modal.tsx @@ -130,7 +130,7 @@ function createContainer() { export const ModalInner = forwardRef( (props, ref) => { - const modalConfig = useContext(ModalConfigContext); + const { onOpen: modalConfigOnOpen } = useContext(ModalConfigContext); const { modal, portalOptions, @@ -173,8 +173,9 @@ export const ModalInner = forwardRef( ); useEffect(() => { - modalConfig.onOpenChange?.(open ?? false); - }, [modalConfig, open]); + if (open) return modalConfigOnOpen?.(); + return; + }, [modalConfigOnOpen, open]); useEffect(() => { if (open) { diff --git a/packages/frontend/core/src/mobile/components/navigation-back/index.tsx b/packages/frontend/core/src/mobile/components/navigation-back/index.tsx index b29efe9f90..4fa7f53638 100644 --- a/packages/frontend/core/src/mobile/components/navigation-back/index.tsx +++ b/packages/frontend/core/src/mobile/components/navigation-back/index.tsx @@ -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 @@ -46,7 +47,7 @@ export const NavigationBackButton = ({ size={24} style={style} onClick={handleRouteBack} - icon={isInsideModal ? : } + icon={icon ?? (isInsideModal ? : )} data-testid="page-header-back" {...otherProps} /> diff --git a/packages/frontend/core/src/mobile/components/page-header/index.tsx b/packages/frontend/core/src/mobile/components/page-header/index.tsx index b9254303e1..dd52be4fdb 100644 --- a/packages/frontend/core/src/mobile/components/page-header/index.tsx +++ b/packages/frontend/core/src/mobile/components/page-header/index.tsx @@ -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'; @@ -11,6 +12,7 @@ export interface PageHeaderProps * whether to show back button */ back?: boolean; + backIcon?: ReactElement; /** * Override back button action */ @@ -51,6 +53,7 @@ export const PageHeader = forwardRef( function PageHeader( { back, + backIcon, backAction, prefix, suffix, @@ -82,7 +85,9 @@ export const PageHeader = forwardRef( className={clsx(styles.prefix, prefixClassName)} style={prefixStyle} > - {back ? : null} + {back ? ( + + ) : null} {prefix} diff --git a/packages/frontend/core/src/mobile/dialogs/setting/swipe-dialog.tsx b/packages/frontend/core/src/mobile/dialogs/setting/swipe-dialog.tsx index 07f04d15e1..6c30ad4dc6 100644 --- a/packages/frontend/core/src/mobile/dialogs/setting/swipe-dialog.tsx +++ b/packages/frontend/core/src/mobile/dialogs/setting/swipe-dialog.tsx @@ -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 { @@ -146,6 +151,8 @@ export const SwipeDialog = ({ triggerSize = 10, onOpenChange, }: SwipeDialogProps) => { + const insideModal = useContext(InsideModalContext); + const { onOpen: globalOnOpen } = useContext(ModalConfigContext); const swiperTriggerRef = useRef(null); const overlayRef = useRef(null); const dialogRef = useRef(null); @@ -202,39 +209,47 @@ export const SwipeDialog = ({ } }, [open, prev]); + useEffect(() => { + if (open) return globalOnOpen?.(); + return; + }, [globalOnOpen, open]); + if (!open) return null; return ( - {createPortal( -
-
-
-
- - {title} - + + {createPortal( +
+
+
+
+ } + backAction={animateClose} + className={styles.header} + > + {title} + - - {children} - - + + {children} + + +
+
-
-
-
, - document.body - )} +
, + document.body + )} + ); };