feat(mobile): auto show text keyboard subtoolbar when selecting text (#9256)

Close [BS-1924](https://linear.app/affine-design/issue/BS-1924/文本选中后-切换toolbar)

https://github.com/user-attachments/assets/2361dfb9-82ae-4be3-808c-6ea33a70c84d
This commit is contained in:
L-Sun
2024-12-24 04:11:00 +00:00
parent 98f88d2615
commit 4c11537bef
2 changed files with 56 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import {
createDefaultDoc,
openFileOrFiles,
type Signal,
} from '@blocksuite/affine-shared/utils';
import type { BlockStdScope } from '@blocksuite/block-std';
import { viewPresets } from '@blocksuite/data-view/view-presets';
@@ -54,6 +55,7 @@ import {
YesterdayIcon,
YoutubeDuotoneIcon,
} from '@blocksuite/icons/lit';
import { computed } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import type { TemplateResult } from 'lit';
@@ -113,6 +115,10 @@ export type KeyboardToolbarActionItem = {
export type KeyboardSubToolbarConfig = {
icon: KeyboardIconType;
items: KeyboardToolbarItem[];
/**
* It will enter this sub-toolbar when the condition is met.
*/
autoShow?: (ctx: KeyboardToolbarContext) => Signal<boolean>;
};
export type KeyboardToolbarContext = {
@@ -868,6 +874,13 @@ const textSubToolbarConfig: KeyboardSubToolbarConfig = {
},
highlightToolPanel,
],
autoShow: ({ std }) => {
return computed(() => {
const selection =
std.command.exec('getTextSelection').currentTextSelection;
return selection ? !selection.isCollapsed() : false;
});
},
};
export const defaultKeyboardToolbarConfig: KeyboardToolbarConfig = {

View File

@@ -9,7 +9,7 @@ import {
} from '@blocksuite/block-std';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
import { ArrowLeftBigIcon, KeyboardIcon } from '@blocksuite/icons/lit';
import { effect, signal } from '@preact/signals-core';
import { effect, type Signal, signal } from '@preact/signals-core';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
@@ -283,6 +283,48 @@ export class AffineKeyboardToolbar extends SignalWatcher(
});
})
);
this._watchAutoShow();
}
private _watchAutoShow() {
const autoShowSubToolbars: { path: number[]; signal: Signal<boolean> }[] =
[];
const traverse = (item: KeyboardToolbarItem, path: number[]) => {
if (isKeyboardSubToolBarConfig(item) && item.autoShow) {
autoShowSubToolbars.push({
path,
signal: item.autoShow(this._context),
});
item.items.forEach((subItem, index) => {
traverse(subItem, [...path, index]);
});
}
};
this.config.items.forEach((item, index) => {
traverse(item, [index]);
});
const samePath = (a: number[], b: number[]) =>
a.length === b.length && a.every((v, i) => v === b[i]);
let prevPath = this._path$.peek();
this.disposables.add(
effect(() => {
autoShowSubToolbars.forEach(({ path, signal }) => {
if (signal.value) {
if (samePath(this._path$.peek(), path)) return;
prevPath = this._path$.peek();
this._path$.value = path;
} else {
this._path$.value = prevPath;
}
});
})
);
}
override disconnectedCallback() {