mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 14:27:02 +08:00
fix(ios): can not open keyboard in editor (#11401)
Close [BS-2917](https://linear.app/affine-design/issue/BS-2917/【移动端】ios-唤起键盘的edge-case) This PR fixes an issue where the keyboard cannot be re-triggered on iOS devices after the keyboard toolbar is hidden or executing some actions in keyboard toolbar. Key changes: - Preserve and restore the initial input mode when keyboard toolbar shows/hides - Improve virtual keyboard service interface to better handle keyboard state - Add proper cleanup of input mode state in component lifecycle
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
import { getDocTitleByEditorHost } from '@blocksuite/affine-fragment-doc-title';
|
||||
import type { RootBlockModel } from '@blocksuite/affine-model';
|
||||
import { FeatureFlagService } from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
VirtualKeyboardProvider,
|
||||
type VirtualKeyboardProviderWithAction,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
||||
import { WidgetComponent } from '@blocksuite/std';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import { effect, signal } from '@preact/signals-core';
|
||||
import { html, nothing } from 'lit';
|
||||
|
||||
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||
@@ -22,6 +26,7 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<
|
||||
if (blur) {
|
||||
if (document.activeElement === this._docTitle?.inlineEditorContainer) {
|
||||
this._docTitle?.inlineEditor?.setInlineRange(null);
|
||||
this._docTitle?.inlineEditor?.eventSource?.blur();
|
||||
} else if (document.activeElement === this.block?.rootComponent) {
|
||||
this.std.selection.clear();
|
||||
}
|
||||
@@ -31,6 +36,27 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<
|
||||
|
||||
private readonly _show$ = signal(false);
|
||||
|
||||
private _initialInputMode: string = '';
|
||||
|
||||
get keyboard(): VirtualKeyboardProviderWithAction {
|
||||
return {
|
||||
// fallback keyboard actions
|
||||
show: () => {
|
||||
const rootComponent = this.block?.rootComponent;
|
||||
if (rootComponent && rootComponent === document.activeElement) {
|
||||
rootComponent.inputMode = this._initialInputMode;
|
||||
}
|
||||
},
|
||||
hide: () => {
|
||||
const rootComponent = this.block?.rootComponent;
|
||||
if (rootComponent && rootComponent === document.activeElement) {
|
||||
rootComponent.inputMode = 'none';
|
||||
}
|
||||
},
|
||||
...this.std.get(VirtualKeyboardProvider),
|
||||
};
|
||||
}
|
||||
|
||||
private get _docTitle() {
|
||||
return getDocTitleByEditorHost(this.std.host);
|
||||
}
|
||||
@@ -48,12 +74,25 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<
|
||||
|
||||
const rootComponent = this.block?.rootComponent;
|
||||
if (rootComponent) {
|
||||
this._initialInputMode = rootComponent.inputMode;
|
||||
this.disposables.add(() => {
|
||||
rootComponent.inputMode = this._initialInputMode;
|
||||
});
|
||||
this.disposables.addFromEvent(rootComponent, 'focus', () => {
|
||||
this._show$.value = true;
|
||||
});
|
||||
this.disposables.addFromEvent(rootComponent, 'blur', () => {
|
||||
this._show$.value = false;
|
||||
});
|
||||
|
||||
this.disposables.add(
|
||||
effect(() => {
|
||||
// recover input mode when keyboard toolbar is hidden
|
||||
if (!this._show$.value) {
|
||||
rootComponent.inputMode = this._initialInputMode;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (this._docTitle) {
|
||||
@@ -84,10 +123,11 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<
|
||||
return html`<blocksuite-portal
|
||||
.shadowDom=${false}
|
||||
.template=${html`<affine-keyboard-toolbar
|
||||
.keyboard=${this.keyboard}
|
||||
.config=${this.config}
|
||||
.rootComponent=${this.block.rootComponent}
|
||||
.close=${this._close}
|
||||
></affine-keyboard-toolbar> `}
|
||||
></affine-keyboard-toolbar>`}
|
||||
></blocksuite-portal>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
|
||||
import { VirtualKeyboardProvider } from '@blocksuite/affine-shared/services';
|
||||
import { type VirtualKeyboardProviderWithAction } from '@blocksuite/affine-shared/services';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||
import { ArrowLeftBigIcon, KeyboardIcon } from '@blocksuite/icons/lit';
|
||||
import {
|
||||
@@ -50,10 +50,6 @@ export class AffineKeyboardToolbar extends SignalWatcher(
|
||||
return this.rootComponent.std;
|
||||
}
|
||||
|
||||
get keyboard() {
|
||||
return this._context.std.get(VirtualKeyboardProvider);
|
||||
}
|
||||
|
||||
get panelOpened() {
|
||||
return this._currentPanelIndex$.value !== -1;
|
||||
}
|
||||
@@ -324,6 +320,9 @@ export class AffineKeyboardToolbar extends SignalWatcher(
|
||||
`;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor keyboard!: VirtualKeyboardProviderWithAction;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor close: (blur: boolean) => void = () => {};
|
||||
|
||||
|
||||
@@ -230,9 +230,6 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
||||
}
|
||||
|
||||
override firstUpdated() {
|
||||
if (!this.keyboard.visible$.value) {
|
||||
this.keyboard.show();
|
||||
}
|
||||
this._scrollInputToTop();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,16 @@ import { createIdentifier } from '@blocksuite/global/di';
|
||||
import type { ReadonlySignal } from '@preact/signals-core';
|
||||
|
||||
export interface VirtualKeyboardProvider {
|
||||
show: () => void;
|
||||
hide: () => void;
|
||||
readonly visible$: ReadonlySignal<boolean>;
|
||||
readonly height$: ReadonlySignal<number>;
|
||||
}
|
||||
|
||||
export const VirtualKeyboardProvider =
|
||||
createIdentifier<VirtualKeyboardProvider>('VirtualKeyboardProvider');
|
||||
export interface VirtualKeyboardProviderWithAction
|
||||
extends VirtualKeyboardProvider {
|
||||
show: () => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
export const VirtualKeyboardProvider = createIdentifier<
|
||||
VirtualKeyboardProvider | VirtualKeyboardProviderWithAction
|
||||
>('VirtualKeyboardProvider');
|
||||
|
||||
Reference in New Issue
Block a user