mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 09:59:55 +08:00
916887e9dc
Close [AF-2764](https://linear.app/affine-design/issue/AF-2764/移动端没法删除图片和其他非文本block) #### PR Dependency Tree * **PR #13386** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved virtual keyboard handling on mobile devices to prevent unexpected keyboard closure during certain editing actions. * Added new signals for keyboard height and safe area, enhancing UI responsiveness and adaptability to keyboard state. * **Refactor** * Streamlined keyboard toolbar logic for more reliable panel height calculation and smoother panel open/close transitions. * Simplified and modernized the approach to toolbar visibility and input mode restoration. * **Style** * Updated keyboard toolbar and panel styling for better positioning and layout consistency across devices. * **Bug Fixes** * Fixed an issue where the virtual keyboard could be incorrectly reported as visible when a physical keyboard is connected. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
133 lines
3.8 KiB
TypeScript
133 lines
3.8 KiB
TypeScript
import { getDocTitleByEditorHost } from '@blocksuite/affine-fragment-doc-title';
|
|
import type { RootBlockModel } from '@blocksuite/affine-model';
|
|
import {
|
|
FeatureFlagService,
|
|
isVirtualKeyboardProviderWithAction,
|
|
VirtualKeyboardProvider,
|
|
type VirtualKeyboardProviderWithAction,
|
|
} from '@blocksuite/affine-shared/services';
|
|
import { IS_MOBILE } from '@blocksuite/global/env';
|
|
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/std';
|
|
import { effect, signal } from '@preact/signals-core';
|
|
import { html, nothing } from 'lit';
|
|
import { literal, unsafeStatic } from 'lit/static-html.js';
|
|
|
|
import {
|
|
defaultKeyboardToolbarConfig,
|
|
KeyboardToolbarConfigExtension,
|
|
} from './config.js';
|
|
|
|
export const AFFINE_KEYBOARD_TOOLBAR_WIDGET = 'affine-keyboard-toolbar-widget';
|
|
|
|
export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel> {
|
|
private readonly _show$ = signal(false);
|
|
|
|
private _initialInputMode: string = '';
|
|
|
|
get keyboard(): VirtualKeyboardProviderWithAction & { fallback?: boolean } {
|
|
const provider = this.std.get(VirtualKeyboardProvider);
|
|
if (isVirtualKeyboardProviderWithAction(provider)) return provider;
|
|
|
|
return {
|
|
// fallback keyboard actions
|
|
fallback: true,
|
|
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';
|
|
}
|
|
},
|
|
...provider,
|
|
};
|
|
}
|
|
|
|
private get _docTitle() {
|
|
return getDocTitleByEditorHost(this.std.host);
|
|
}
|
|
|
|
get config() {
|
|
return {
|
|
...defaultKeyboardToolbarConfig,
|
|
...this.std.getOptional(KeyboardToolbarConfigExtension.identifier),
|
|
};
|
|
}
|
|
|
|
override connectedCallback(): void {
|
|
super.connectedCallback();
|
|
|
|
this.disposables.add(
|
|
effect(() => {
|
|
this._show$.value = this.std.event.active$.value;
|
|
})
|
|
);
|
|
|
|
const rootComponent = this.block?.rootComponent;
|
|
if (rootComponent && this.keyboard.fallback) {
|
|
this._initialInputMode = rootComponent.inputMode;
|
|
this.disposables.add(() => {
|
|
rootComponent.inputMode = this._initialInputMode;
|
|
});
|
|
this.disposables.add(
|
|
effect(() => {
|
|
// recover input mode when keyboard toolbar is hidden
|
|
if (!this._show$.value) {
|
|
rootComponent.inputMode = this._initialInputMode;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
if (this._docTitle) {
|
|
const { inlineEditorContainer } = this._docTitle;
|
|
this.disposables.addFromEvent(inlineEditorContainer, 'focus', () => {
|
|
this._show$.value = true;
|
|
});
|
|
this.disposables.addFromEvent(inlineEditorContainer, 'blur', () => {
|
|
this._show$.value = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
override render() {
|
|
if (
|
|
this.store.readonly ||
|
|
!IS_MOBILE ||
|
|
!this.store
|
|
.get(FeatureFlagService)
|
|
.getFlag('enable_mobile_keyboard_toolbar')
|
|
)
|
|
return nothing;
|
|
|
|
if (!this._show$.value) return nothing;
|
|
|
|
if (!this.block?.rootComponent) return nothing;
|
|
|
|
return html`<blocksuite-portal
|
|
.shadowDom=${false}
|
|
.template=${html`<affine-keyboard-toolbar
|
|
.keyboard=${this.keyboard}
|
|
.config=${this.config}
|
|
.rootComponent=${this.block.rootComponent}
|
|
></affine-keyboard-toolbar>`}
|
|
></blocksuite-portal>`;
|
|
}
|
|
}
|
|
|
|
export const keyboardToolbarWidget = WidgetViewExtension(
|
|
'affine:page',
|
|
AFFINE_KEYBOARD_TOOLBAR_WIDGET,
|
|
literal`${unsafeStatic(AFFINE_KEYBOARD_TOOLBAR_WIDGET)}`
|
|
);
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
[AFFINE_KEYBOARD_TOOLBAR_WIDGET]: AffineKeyboardToolbarWidget;
|
|
}
|
|
}
|