diff --git a/packages/vkui/src/components/AppRoot/AppRoot.tsx b/packages/vkui/src/components/AppRoot/AppRoot.tsx index b961c987c4d..b189ee1fd6d 100644 --- a/packages/vkui/src/components/AppRoot/AppRoot.tsx +++ b/packages/vkui/src/components/AppRoot/AppRoot.tsx @@ -82,6 +82,7 @@ export const AppRoot = ({ ...props }: AppRootProps): React.ReactNode => { const appRootRef = React.useRef(null); + const popoutModalContainerRef = React.useRef(null); const portalRootRef = React.useRef( portalRootProp ? extractPortalRootByProp(portalRootProp) : null, ); @@ -121,6 +122,7 @@ export const AppRoot = ({ () => ({ appRoot: appRootRef, portalRoot: portalRootRef, + popoutModalRoot: popoutModalContainerRef, setPortalRoot: (element: HTMLElement) => (portalRootRef.current = element), safeAreaInsets, embedded: mode === 'embedded', diff --git a/packages/vkui/src/components/AppRoot/AppRootContext.ts b/packages/vkui/src/components/AppRoot/AppRootContext.ts index 0daa849439f..6ca44719139 100644 --- a/packages/vkui/src/components/AppRoot/AppRootContext.ts +++ b/packages/vkui/src/components/AppRoot/AppRootContext.ts @@ -5,6 +5,7 @@ import { type AppRootUserSelectMode, type SafeAreaInsets } from './types'; export interface AppRootContextInterface { appRoot: React.RefObject; portalRoot: React.MutableRefObject; + popoutModalRoot: React.MutableRefObject; setPortalRoot: (element: HTMLElement) => void; safeAreaInsets?: SafeAreaInsets; embedded: boolean; @@ -24,6 +25,7 @@ export const DEFAULT_APP_ROOT_CONTEXT_VALUE: AppRootContextInterface = { appRoot: React.createRef(), mode: 'full', portalRoot: React.createRef(), + popoutModalRoot: React.createRef(), setPortalRoot: noop, safeAreaInsets: undefined, embedded: false, diff --git a/packages/vkui/src/components/AppRoot/AppRootPortal.tsx b/packages/vkui/src/components/AppRoot/AppRootPortal.tsx index fd56bf410dc..d6d0675b7e0 100644 --- a/packages/vkui/src/components/AppRoot/AppRootPortal.tsx +++ b/packages/vkui/src/components/AppRoot/AppRootPortal.tsx @@ -16,16 +16,20 @@ export interface AppRootPortalProps extends HasChildren { * - При передаче `true` будет использовать `portalRoot` из контекста `AppRoot`. * - При передаче элемента будут игнорироваться `portalRoot` и `disablePortal` из контекста `AppRoot`. */ - usePortal?: boolean | HTMLElement | React.RefObject | null; + usePortal?: boolean | HTMLElement | React.RefObject | null | 'in-app-after-content'; + className?: string; } -export const AppRootPortal = ({ children, usePortal }: AppRootPortalProps): React.ReactNode => { - const { portalRoot, setPortalRoot, appRoot, mode, disablePortal } = - React.useContext(AppRootContext); +export const AppRootPortal = ({ + children, + usePortal, + className, +}: AppRootPortalProps): React.ReactNode => { + const { setPortalRoot, appRoot, mode, disablePortal } = React.useContext(AppRootContext); const appearance = useAppearance(); const canUsePortal = shouldUsePortal(usePortal, mode, Boolean(disablePortal)); - const portalContainer = resolvePortalContainer(usePortal, portalRoot.current); + const portalContainer = usePortalContainer(usePortal); useIsomorphicLayoutEffect( // Создаём контейнер для портала по запросу один раз @@ -50,7 +54,7 @@ export const AppRootPortal = ({ children, usePortal }: AppRootPortalProps): Reac if (canUsePortal && portalContainer) { return createPortal( - {children} + {children} , portalContainer, ); @@ -75,12 +79,14 @@ function shouldUsePortal( return disablePortal === false && usePortal === true; } -function resolvePortalContainer( - usePortal: AppRootPortalProps['usePortal'], - portalRootFromContext: PortalRootFromContext, -): HTMLElement | null { +function usePortalContainer(usePortal: AppRootPortalProps['usePortal']): HTMLElement | null { + const { portalRoot, popoutModalRoot } = React.useContext(AppRootContext); if (typeof usePortal === 'boolean' || usePortal === undefined) { - return portalRootFromContext ? portalRootFromContext : null; + return portalRoot.current; + } + + if (usePortal === 'in-app-after-content') { + return popoutModalRoot.current; } return isRefObject(usePortal) ? usePortal.current : usePortal; diff --git a/packages/vkui/src/components/ModalRoot/ModalRoot.module.css b/packages/vkui/src/components/ModalRoot/ModalRoot.module.css index d60c0dff1d3..85128644b2e 100644 --- a/packages/vkui/src/components/ModalRoot/ModalRoot.module.css +++ b/packages/vkui/src/components/ModalRoot/ModalRoot.module.css @@ -1,4 +1,13 @@ .host { + position: fixed; + inset-inline-start: 0; + inset-block-start: 0; + z-index: var(--vkui--z_index_modal); + inline-size: 100%; + block-size: 100%; +} + +.wrapper { inline-size: 100%; block-size: 100%; } diff --git a/packages/vkui/src/components/ModalRoot/ModalRoot.tsx b/packages/vkui/src/components/ModalRoot/ModalRoot.tsx index 8eae410c35c..46bfbfbb753 100644 --- a/packages/vkui/src/components/ModalRoot/ModalRoot.tsx +++ b/packages/vkui/src/components/ModalRoot/ModalRoot.tsx @@ -545,12 +545,12 @@ class ModalRootTouchComponent extends React.Component< } return ( - + { + const { popoutModalRoot } = React.useContext(AppRootContext); + return ( {children} -
+
{!!popout && {popout}} - {!!modal && {modal}} + {modal}
);