From 076c5ba044a01d36265119bf0ef395b34f6fc8e5 Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sun, 13 Apr 2025 06:46:37 +0000 Subject: [PATCH] fix(editor): repeat trigger keys of at-menu was added (#11631) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close [BS-2716](https://linear.app/affine-design/issue/BS-2716/移动端通过toolpanel唤起的at-menu,出现两个) --- .../configs/slash-menu.ts | 22 +---------- .../src/widgets/keyboard-toolbar/config.ts | 39 +++---------------- .../affine/widgets/linked-doc/src/config.ts | 1 + .../linked-doc/src/linked-doc-popover.ts | 14 +++---- .../affine/widgets/linked-doc/src/widget.ts | 38 ++++++++++++------ tests/blocksuite/e2e/slash-menu.spec.ts | 18 +++++++++ 6 files changed, 61 insertions(+), 71 deletions(-) diff --git a/blocksuite/affine/blocks/embed/src/embed-linked-doc-block/configs/slash-menu.ts b/blocksuite/affine/blocks/embed/src/embed-linked-doc-block/configs/slash-menu.ts index ffb1ad0ff4..b2428f5326 100644 --- a/blocksuite/affine/blocks/embed/src/embed-linked-doc-block/configs/slash-menu.ts +++ b/blocksuite/affine/blocks/embed/src/embed-linked-doc-block/configs/slash-menu.ts @@ -1,8 +1,5 @@ import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model'; -import { - getInlineEditorByModel, - insertContent, -} from '@blocksuite/affine-rich-text'; +import { insertContent } from '@blocksuite/affine-rich-text'; import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts'; import { createDefaultDoc } from '@blocksuite/affine-shared/utils'; import { @@ -68,22 +65,7 @@ const linkedDocSlashMenuConfig: SlashMenuConfig = { if (!linkedDocWidget) return; // TODO(@L-Sun): make linked-doc-widget as extension // @ts-expect-error same as above - const triggerKey = linkedDocWidget.config.triggerKeys[0]; - - insertContent(std, model, triggerKey); - - const inlineEditor = getInlineEditorByModel(std, model); - if (inlineEditor) { - // Wait for range to be updated - const subscription = inlineEditor.slots.inlineRangeSync.subscribe( - () => { - // TODO(@L-Sun): make linked-doc-widget as extension - subscription.unsubscribe(); - // @ts-expect-error same as above - linkedDocWidget.show({ addTriggerKey: true }); - } - ); - } + linkedDocWidget.show({ addTriggerKey: true }); }, }, ], diff --git a/blocksuite/affine/blocks/root/src/widgets/keyboard-toolbar/config.ts b/blocksuite/affine/blocks/root/src/widgets/keyboard-toolbar/config.ts index 47c656cfec..7f845408d6 100644 --- a/blocksuite/affine/blocks/root/src/widgets/keyboard-toolbar/config.ts +++ b/blocksuite/affine/blocks/root/src/widgets/keyboard-toolbar/config.ts @@ -34,10 +34,7 @@ import { toggleUnderline, } from '@blocksuite/affine-inline-preset'; import type { FrameBlockModel } from '@blocksuite/affine-model'; -import { - getInlineEditorByModel, - insertContent, -} from '@blocksuite/affine-rich-text'; +import { insertContent } from '@blocksuite/affine-rich-text'; import { copySelectedModelsCommand, deleteSelectedModelsCommand, @@ -348,35 +345,11 @@ const pageToolGroup: KeyboardToolPanelGroup = { ); if (!linkedDocWidget) return; assertType(linkedDocWidget); - - const triggerKey = linkedDocWidget.config.triggerKeys[0]; - - std.command - .chain() - .pipe(getSelectedModelsCommand) - .pipe(ctx => { - const { selectedModels } = ctx; - if (!selectedModels?.length) return; - - const currentModel = selectedModels[0]; - insertContent(std, currentModel, triggerKey); - - const inlineEditor = getInlineEditorByModel(std, currentModel); - // Wait for range to be updated - if (inlineEditor) { - const subscription = inlineEditor.slots.inlineRangeSync.subscribe( - () => { - subscription.unsubscribe(); - linkedDocWidget.show({ - mode: 'mobile', - addTriggerKey: true, - }); - closeToolPanel(); - } - ); - } - }) - .run(); + linkedDocWidget.show({ + mode: 'mobile', + addTriggerKey: true, + }); + closeToolPanel(); }, }, ], diff --git a/blocksuite/affine/widgets/linked-doc/src/config.ts b/blocksuite/affine/widgets/linked-doc/src/config.ts index 44d841989f..54ebc44220 100644 --- a/blocksuite/affine/widgets/linked-doc/src/config.ts +++ b/blocksuite/affine/widgets/linked-doc/src/config.ts @@ -112,6 +112,7 @@ export type LinkedDocContext = { std: BlockStdScope; inlineEditor: AffineInlineEditor; startRange: InlineRange; + startNativeRange: Range; triggerKey: string; config: LinkedWidgetConfig; close: () => void; diff --git a/blocksuite/affine/widgets/linked-doc/src/linked-doc-popover.ts b/blocksuite/affine/widgets/linked-doc/src/linked-doc-popover.ts index 5ef3388293..f122244f3e 100644 --- a/blocksuite/affine/widgets/linked-doc/src/linked-doc-popover.ts +++ b/blocksuite/affine/widgets/linked-doc/src/linked-doc-popover.ts @@ -7,7 +7,6 @@ import { import { unsafeCSSVar } from '@blocksuite/affine-shared/theme'; import { createKeydownObserver, - getCurrentNativeRange, getPopperPosition, getViewportElement, } from '@blocksuite/affine-shared/utils'; @@ -160,11 +159,15 @@ export class LinkedDocPopover extends SignalWatcher( // init this._updateLinkedDocGroup().catch(console.error); - this._disposables.addFromEvent(this, 'mousedown', e => { + this._disposables.addFromEvent(this, 'pointerdown', e => { // Prevent input from losing focus e.preventDefault(); }); - this._disposables.addFromEvent(window, 'mousedown', e => { + this._disposables.addFromEvent(this, 'mousedown', e => { + // Prevent input from losing focus in electron + e.preventDefault(); + }); + this._disposables.addFromEvent(window, 'pointerdown', e => { if (e.target === this) return; // We don't clear the query when clicking outside the popover this.context.close(); @@ -338,11 +341,8 @@ export class LinkedDocPopover extends SignalWatcher( override willUpdate() { if (!this.hasUpdated) { - const curRange = getCurrentNativeRange(); - if (!curRange) return; - const updatePosition = throttle(() => { - this._position = getPopperPosition(this, curRange); + this._position = getPopperPosition(this, this.context.startNativeRange); }, 10); this.disposables.addFromEvent(window, 'resize', updatePosition); diff --git a/blocksuite/affine/widgets/linked-doc/src/widget.ts b/blocksuite/affine/widgets/linked-doc/src/widget.ts index d1878799fb..53d0e9d5ec 100644 --- a/blocksuite/affine/widgets/linked-doc/src/widget.ts +++ b/blocksuite/affine/widgets/linked-doc/src/widget.ts @@ -43,6 +43,19 @@ export class AffineLinkedDocWidget extends WidgetComponent { private readonly _mode$ = signal<'desktop' | 'mobile' | 'none'>('none'); + private _addTriggerKey(inlineEditor: InlineEditor, triggerKey: string) { + const inlineRange = inlineEditor.getInlineRange(); + if (!inlineRange) return; + inlineEditor.insertText( + { index: inlineRange.index, length: 0 }, + triggerKey + ); + inlineEditor.setInlineRange({ + index: inlineRange.index + triggerKey.length, + length: 0, + }); + } + private _updateInputRects() { if (!this._context) return; const { inlineEditor, startRange, triggerKey } = this._context; @@ -258,27 +271,30 @@ export class AffineLinkedDocWidget extends WidgetComponent { inlineEditor = props.inlineEditor; } - const inlineRange = inlineEditor.getInlineRange(); - if (!inlineRange) return; - if (addTriggerKey) { - inlineEditor.insertText( - { index: inlineRange.index, length: 0 }, - primaryTriggerKey - ); - inlineEditor.setInlineRange({ - index: inlineRange.index + primaryTriggerKey.length, - length: 0, + this._addTriggerKey(inlineEditor, primaryTriggerKey); + // we need to wait the range sync to get the correct startNativeRange + const subscription = inlineEditor.slots.inlineRangeSync.subscribe(() => { + this.show({ ...props, addTriggerKey: false }); + subscription.unsubscribe(); }); + return; } + const startRange = inlineEditor.getInlineRange(); + if (!startRange) return; + + const startNativeRange = inlineEditor.getNativeRange(); + if (!startNativeRange) return; + const disposable = inlineEditor.slots.renderComplete.subscribe(() => { this._updateInputRects(); }); this._context = { std: this.std, inlineEditor, - startRange: inlineRange, + startRange, + startNativeRange, triggerKey: primaryTriggerKey, config: this.config, close: () => { diff --git a/tests/blocksuite/e2e/slash-menu.spec.ts b/tests/blocksuite/e2e/slash-menu.spec.ts index 9a33e3c189..2e6e69f6ba 100644 --- a/tests/blocksuite/e2e/slash-menu.spec.ts +++ b/tests/blocksuite/e2e/slash-menu.spec.ts @@ -841,3 +841,21 @@ test('delete block by slash menu should remove children', async ({ await redoByKeyboard(page); await assertRichTexts(page, ['123']); }); + +test('should slash menu can trigger linked doc popover', async ({ page }) => { + await enterPlaygroundRoom(page); + await initEmptyParagraphState(page); + await focusRichText(page); + + await type(page, '/linked'); + await pressEnter(page); + await expect(page.locator('.linked-doc-popover')).toBeVisible(); + await assertRichTexts(page, ['@']); + + await type(page, 'doc'); + await pressEnter(page); + await expect(page.locator('affine-reference')).toBeVisible(); + await expect( + page.locator('affine-reference .affine-reference-title') + ).toHaveText('doc'); +});