fix(ios): mobile modal occlusion issues (#11427)

Close [BS-2925](https://linear.app/affine-design/issue/BS-2925/移动端-dialog-遮挡相关)
This commit is contained in:
L-Sun
2025-04-03 01:51:57 +00:00
parent 80a663efe7
commit b53b2acfe3
7 changed files with 49 additions and 6 deletions

View File

@@ -490,6 +490,7 @@ export type MenuHandler = {
const popMobileMenu = (options: MenuOptions): MenuHandler => {
const model = createModal(document.body);
model.style.position = 'fixed';
const menu = new Menu({
...options,
onClose: () => {

View File

@@ -1,6 +1,9 @@
import { EmbedOptionProvider } from '@blocksuite/affine-shared/services';
import {
EmbedOptionProvider,
VirtualKeyboardProvider,
} from '@blocksuite/affine-shared/services';
import { isValidUrl, stopPropagation } from '@blocksuite/affine-shared/utils';
import { WithDisposable } from '@blocksuite/global/lit';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import type { EditorHost } from '@blocksuite/std';
import { ShadowlessElement } from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
@@ -8,11 +11,14 @@ import type { BlockModel } from '@blocksuite/store';
import { html } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styleMap } from 'lit-html/directives/style-map.js';
import { toast } from '../toast';
import { embedCardModalStyles } from './styles.js';
export class EmbedCardCreateModal extends WithDisposable(ShadowlessElement) {
export class EmbedCardCreateModal extends SignalWatcher(
WithDisposable(ShadowlessElement)
) {
static override styles = embedCardModalStyles;
private readonly _onCancel = () => {
@@ -98,7 +104,14 @@ export class EmbedCardCreateModal extends WithDisposable(ShadowlessElement) {
}
override render() {
return html`<div class="embed-card-modal">
const keyboard = this.host.std.getOptional(VirtualKeyboardProvider);
const style = styleMap({
height: keyboard?.visible$.value
? `calc(100% - ${keyboard.height$.value}px)`
: undefined,
});
return html`<div class="embed-card-modal" style=${style}>
<div class="embed-card-modal-mask" @click=${this._onCancel}></div>
<div class="embed-card-modal-wrapper">
<div class="embed-card-modal-row">

View File

@@ -2,6 +2,17 @@ import { fontXSStyle, panelBaseStyle } from '@blocksuite/affine-shared/styles';
import { css } from 'lit';
export const embedCardModalStyles = css`
.embed-card-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
height: 100%;
transition: height 0.3s ease-in-out;
}
.embed-card-modal-mask {
position: absolute;
left: 0;

View File

@@ -6,7 +6,7 @@ import type {
DropdownMenuSubContentProps,
DropdownMenuSubProps,
} from '@radix-ui/react-dropdown-menu';
import type { ReactNode } from 'react';
import type { CSSProperties, ReactNode } from 'react';
export interface MenuProps {
children: ReactNode;
@@ -15,6 +15,7 @@ export interface MenuProps {
portalOptions?: Omit<DropdownMenuPortalProps, 'children'>;
rootOptions?: Omit<DropdownMenuProps, 'children'>;
contentOptions?: Omit<DropdownMenuContentProps, 'children'>;
contentWrapperStyle?: CSSProperties;
noPortal?: boolean;
}

View File

@@ -32,6 +32,7 @@ export const MobileMenu = ({
...otherContentOptions
} = {},
contentWrapperStyle,
rootOptions,
}: MenuProps) => {
const [subMenus, setSubMenus] = useState<SubMenuContent[]>([]);
@@ -131,6 +132,7 @@ export const MobileMenu = ({
className: clsx(className, styles.mobileMenuModal),
...otherContentOptions,
}}
contentWrapperStyle={contentWrapperStyle}
disableAutoFocus={true}
>
<div

View File

@@ -1,9 +1,11 @@
import { style } from '@vanilla-extract/css';
import { globalVars } from '../../styles/variables.css';
export const root = style({
padding: '40px',
justifyContent: 'flex-end',
minHeight: '100dvh',
minHeight: `calc(100dvh - ${globalVars.appKeyboardHeight})`,
display: 'flex',
flexDirection: 'column',
position: 'relative',

View File

@@ -2,8 +2,11 @@ import { DatePicker, Menu } from '@affine/component';
import type { DialogComponentProps } from '@affine/core/modules/dialogs';
import type { WORKSPACE_DIALOG_SCHEMA } from '@affine/core/modules/dialogs/constant';
import { useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra';
import { useCallback, useState } from 'react';
import { VirtualKeyboardService } from '../../modules/virtual-keyboard';
/**
* A global date selector popover for mobile, mainly used in blocksuite editor
*/
@@ -12,6 +15,9 @@ export const DateSelectorDialog = ({
onSelect,
}: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['date-selector']>) => {
const [selectedDate, setSelectedDate] = useState<string>();
const keyboardService = useService(VirtualKeyboardService);
const keyboardHeight = useLiveData(keyboardService.height$);
const keyboardVisible = useLiveData(keyboardService.visible$);
const t = useI18n();
@@ -44,6 +50,13 @@ export const DateSelectorDialog = ({
padding: '15px 20px',
},
}}
contentWrapperStyle={
keyboardVisible
? {
paddingBottom: `calc(${keyboardHeight}px + 12px)`,
}
: undefined
}
items={
<DatePicker
weekDays={t['com.affine.calendar-date-picker.week-days']()}