From b6fc0a2192cab6e4f9f8c2ba2d0f538c575e6b52 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:02:38 +0800 Subject: [PATCH] fix(mobile): mobile keyboard padding (#15365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### PR Dependency Tree * **PR #15365** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) ## Summary by CodeRabbit - **Bug Fixes** - Improved mobile keyboard and toolbar layout handling when the keyboard overlays or resizes app content. - Prevented incorrect extra spacing when Android applies keyboard insets directly. - Updated toolbar sizing and visibility states for smoother transitions. - **Style** - Adjusted mobile bottom spacing to account for keyboard height, safe areas, and toolbar height. --- .../keyboard-toolbar/src/keyboard-toolbar.ts | 37 ++++++++----------- packages/frontend/apps/android/src/app.tsx | 3 ++ .../mobile/keyboard-toolbar-extension.ts | 22 ++++++----- .../providers/virtual-keyboard.ts | 1 + .../services/virtual-keyboard.ts | 4 +- .../core/src/mobile/styles/mobile.css.ts | 6 +++ 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/blocksuite/affine/widgets/keyboard-toolbar/src/keyboard-toolbar.ts b/blocksuite/affine/widgets/keyboard-toolbar/src/keyboard-toolbar.ts index ca8d5f18dd..16f619b877 100644 --- a/blocksuite/affine/widgets/keyboard-toolbar/src/keyboard-toolbar.ts +++ b/blocksuite/affine/widgets/keyboard-toolbar/src/keyboard-toolbar.ts @@ -41,8 +41,6 @@ export class AffineKeyboardToolbar extends SignalWatcher( ) { static override styles = keyboardToolbarStyles; - private readonly _expanded$ = signal(false); - get std() { return this.rootComponent.std; } @@ -52,13 +50,17 @@ export class AffineKeyboardToolbar extends SignalWatcher( } private get panelHeight() { - return this._expanded$.value - ? `${ - this.keyboard.staticHeight$.value !== 0 - ? this.keyboard.staticHeight$.value - : 330 - }px` - : this.keyboard.appTabSafeArea$.value; + if (this.keyboard.visible$.value) { + return `${this.keyboard.height$.value}px`; + } + if (this.panelOpened) { + return `${ + this.keyboard.staticHeight$.value !== 0 + ? this.keyboard.staticHeight$.value + : 330 + }px`; + } + return this.keyboard.appTabSafeArea$.value; } /** @@ -266,20 +268,13 @@ export class AffineKeyboardToolbar extends SignalWatcher( super.connectedCallback(); this.setAttribute(RANGE_SYNC_EXCLUDE_ATTR, 'true'); - // There are two cases that `_expanded$` will be true: - // 1. when virtual keyboard is opened, the panel need to be expanded and overlapped by the keyboard, - // so that the toolbar will be on the top of the keyboard. - // 2. the panel is opened, whether the keyboard is closed or not exists (e.g. a physical keyboard connected) - // - // There is one case that `_expanded$` will be false: - // 1. the panel is closed, and the keyboard is closed, the toolbar will be rendered at the bottom of the viewport this._disposables.add( effect(() => { - if (this.keyboard.visible$.value || this.panelOpened) { - this._expanded$.value = true; - } else { - this._expanded$.value = false; - } + this.toggleAttribute( + 'data-keyboard-visible', + this.keyboard.visible$.value + ); + this.toggleAttribute('data-panel-open', this.panelOpened); }) ); diff --git a/packages/frontend/apps/android/src/app.tsx b/packages/frontend/apps/android/src/app.tsx index 5ebd8c2fae..f327cd864b 100644 --- a/packages/frontend/apps/android/src/app.tsx +++ b/packages/frontend/apps/android/src/app.tsx @@ -149,6 +149,9 @@ framework.impl(VirtualKeyboardProvider, { // even though the `keyboardWillShow` event is still triggered. visible: info.keyboardHeight !== 0, height: info.keyboardHeight - navBarHeight, + // SystemBars applies the IME inset to the WebView parent, so the + // keyboard no longer overlaps the web content on Android. + overlaysContent: false, }); })().catch(console.error); }), diff --git a/packages/frontend/core/src/blocksuite/view-extensions/mobile/keyboard-toolbar-extension.ts b/packages/frontend/core/src/blocksuite/view-extensions/mobile/keyboard-toolbar-extension.ts index df3271757a..1324859a13 100644 --- a/packages/frontend/core/src/blocksuite/view-extensions/mobile/keyboard-toolbar-extension.ts +++ b/packages/frontend/core/src/blocksuite/view-extensions/mobile/keyboard-toolbar-extension.ts @@ -45,15 +45,19 @@ export function KeyboardToolbarExtension( override mounted() { this._disposables.add( - affineVirtualKeyboardProvider.onChange(({ visible, height }) => { - batch(() => { - if (visible && this.staticHeight$.peek() !== height) { - this.staticHeight$.value = height; - } - this.visible$.value = visible; - this.height$.value = height; - }); - }) + affineVirtualKeyboardProvider.onChange( + ({ visible, height, overlaysContent }) => { + const layoutHeight = overlaysContent === false ? 0 : height; + + batch(() => { + if (visible && this.staticHeight$.peek() !== height) { + this.staticHeight$.value = height; + } + this.visible$.value = visible; + this.height$.value = layoutHeight; + }); + } + ) ); } diff --git a/packages/frontend/core/src/mobile/modules/virtual-keyboard/providers/virtual-keyboard.ts b/packages/frontend/core/src/mobile/modules/virtual-keyboard/providers/virtual-keyboard.ts index 1637159f54..d2d16c9a13 100644 --- a/packages/frontend/core/src/mobile/modules/virtual-keyboard/providers/virtual-keyboard.ts +++ b/packages/frontend/core/src/mobile/modules/virtual-keyboard/providers/virtual-keyboard.ts @@ -3,6 +3,7 @@ import { createIdentifier } from '@toeverything/infra'; interface VirtualKeyboardInfo { visible: boolean; height: number; + overlaysContent?: boolean; } type VirtualKeyboardAction = { diff --git a/packages/frontend/core/src/mobile/modules/virtual-keyboard/services/virtual-keyboard.ts b/packages/frontend/core/src/mobile/modules/virtual-keyboard/services/virtual-keyboard.ts index 53caf4c021..030cbb7dfd 100644 --- a/packages/frontend/core/src/mobile/modules/virtual-keyboard/services/virtual-keyboard.ts +++ b/packages/frontend/core/src/mobile/modules/virtual-keyboard/services/virtual-keyboard.ts @@ -20,8 +20,10 @@ export class VirtualKeyboardService extends Service { private _observe() { this.disposables.push( this.virtualKeyboardProvider.onChange(info => { + const layoutHeight = info.overlaysContent === false ? 0 : info.height; + this.visible$.next(info.visible); - this.height$.next(info.height); + this.height$.next(layoutHeight); setElementVars(document.body, { [globalVars.appKeyboardHeight]: `${this.height$.value}px`, diff --git a/packages/frontend/core/src/mobile/styles/mobile.css.ts b/packages/frontend/core/src/mobile/styles/mobile.css.ts index e0f281a7af..a071c3364f 100644 --- a/packages/frontend/core/src/mobile/styles/mobile.css.ts +++ b/packages/frontend/core/src/mobile/styles/mobile.css.ts @@ -22,6 +22,12 @@ globalStyle('body:has(>#app-tabs):not(:has(affine-keyboard-toolbar))', { paddingBottom: globalVars.appTabSafeArea, }); globalStyle('body:has(affine-keyboard-toolbar)', { + paddingBottom: `calc(${globalVars.appTabSafeArea} + 46px)`, +}); +globalStyle('body:has(affine-keyboard-toolbar[data-keyboard-visible])', { + paddingBottom: `calc(${globalVars.appKeyboardHeight} + 46px)`, +}); +globalStyle('body:has(affine-keyboard-toolbar[data-panel-open])', { paddingBottom: `calc(${globalVars.appKeyboardStaticHeight} + 46px)`, }); globalStyle('body:has(>#app-tabs) edgeless-toolbar-widget', {