From 6921c3073c0ee85d01df41e74a78eaad48c8ab10 Mon Sep 17 00:00:00 2001 From: fundon Date: Thu, 19 Sep 2024 02:58:11 +0000 Subject: [PATCH] refactor(core): improve scroll anchoring logic (#8269) Upstreams: https://github.com/toeverything/blocksuite/pull/8378 --- .../src/modules/editor/entities/editor.ts | 12 +- .../modules/editor/utils/scroll-anchoring.ts | 134 ++++-------------- packages/frontend/i18n/src/resources/en.json | 1 + tests/affine-local/e2e/quick-search.spec.ts | 2 +- 4 files changed, 39 insertions(+), 110 deletions(-) diff --git a/packages/frontend/core/src/modules/editor/entities/editor.ts b/packages/frontend/core/src/modules/editor/entities/editor.ts index eaeb96391f..5d6be817c7 100644 --- a/packages/frontend/core/src/modules/editor/entities/editor.ts +++ b/packages/frontend/core/src/modules/editor/entities/editor.ts @@ -180,12 +180,12 @@ export class Editor extends Entity { (a, b) => a?.id === b?.id && a?.refreshKey === b?.refreshKey ) .subscribe(params => { - if (params?.id) { - const std = editorContainer.host?.std; - if (std) { - scrollAnchoring(std, this.mode$.value, params.id); - } - } + if (!params?.id) return; + + const std = editorContainer.host?.std; + if (!std) return; + + scrollAnchoring(std, this.mode$.value, params.id); }); unsubs.push(subscription.unsubscribe.bind(subscription)); diff --git a/packages/frontend/core/src/modules/editor/utils/scroll-anchoring.ts b/packages/frontend/core/src/modules/editor/utils/scroll-anchoring.ts index 3471fa3a5b..32a87cb795 100644 --- a/packages/frontend/core/src/modules/editor/utils/scroll-anchoring.ts +++ b/packages/frontend/core/src/modules/editor/utils/scroll-anchoring.ts @@ -1,115 +1,43 @@ import { notify } from '@affine/component'; import { I18n } from '@affine/i18n'; -import type { BlockStdScope, SelectionManager } from '@blocksuite/block-std'; -import type { - DocMode, - EdgelessRootService, - PageRootService, -} from '@blocksuite/blocks'; -import { Bound, deserializeXYWH } from '@blocksuite/global/utils'; - -function scrollAnchoringInEdgelessMode( - service: EdgelessRootService, - id: string -) { - requestAnimationFrame(() => { - let bounds: Bound | null = null; - let pageSelection: SelectionManager | null = null; - - const blockComponent = service.std.view.getBlock(id); - const parentComponent = blockComponent?.parentComponent; - if (parentComponent && parentComponent.flavour === 'affine:note') { - pageSelection = parentComponent.std.selection; - if (!pageSelection) return; - - const { left: x, width: w } = parentComponent.getBoundingClientRect(); - const { top: y, height: h } = blockComponent.getBoundingClientRect(); - const coord = service.viewport.toModelCoordFromClientCoord([x, y]); - bounds = new Bound( - coord[0], - coord[1], - w / service.viewport.zoom, - h / service.viewport.zoom - ); - } else { - if (!service.getElementById) return; - const model = service.getElementById(id); - if (!model) return; - - bounds = Bound.fromXYWH(deserializeXYWH(model.xywh)); - } - - if (!bounds) { - notify.error({ title: I18n['Block not found']() }); - return; - } - - const { zoom, centerX, centerY } = service.getFitToScreenData( - [20, 20, 100, 20], - [bounds] - ); - - service.viewport.setCenter(centerX, centerY); - service.viewport.setZoom(zoom); - - if (pageSelection) { - pageSelection.setGroup('note', [ - pageSelection.create('block', { - blockId: id, - }), - ]); - } else { - service.selection.set({ - elements: [id], - editing: false, - }); - } - - // const surfaceComponent = service.std.view.getBlock(service.surface.id); - // if (!surfaceComponent) return; - // (surfaceComponent as SurfaceBlockComponent).refresh(); - - // TODO(@fundon): toolbar should be hidden - }); -} - -function scrollAnchoringInPageMode(service: PageRootService, id: string) { - const blockComponent = service.std.view.getBlock(id); - if (!blockComponent) { - notify.error({ title: I18n['Block not found']() }); - return; - } - - blockComponent.scrollIntoView({ - behavior: 'instant', - block: 'center', - }); - - const selection = service.std.selection; - if (!selection) return; - - selection.setGroup('note', [ - selection.create('block', { - blockId: id, - }), - ]); - - // TODO(@fundon): toolbar should be hidden -} +import type { BlockStdScope } from '@blocksuite/block-std'; +import { + GfxControllerIdentifier, + type GfxModel, +} from '@blocksuite/block-std/gfx'; +import type { DocMode } from '@blocksuite/blocks'; // TODO(@fundon): it should be a command export function scrollAnchoring(std: BlockStdScope, mode: DocMode, id: string) { - if (mode === 'edgeless') { - const service = std.getService('affine:page'); - if (!service) return; + let key = 'blockIds'; + let exists = false; - scrollAnchoringInEdgelessMode(service, id); + if (mode === 'page') { + exists = std.doc.hasBlock(id); + } else { + const controller = std.getOptional(GfxControllerIdentifier); + if (!controller) return; + exists = !!controller.getElementById(id)?.xywh; + if (controller.surface?.hasElementById(id)) { + key = 'elementIds'; + } + } + + if (!exists) { + notify.error({ + title: I18n['Block not found'](), + message: I18n['Block not found description'](), + }); return; } - const service = std.getService('affine:page'); - if (!service) return; + const selection = std.selection; - scrollAnchoringInPageMode(service, id); + selection.setGroup('scene', [ + selection.create('highlight', { + mode, + [key]: [id], + }), + ]); } diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 0e081ad1d2..95a16b7ffa 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -27,6 +27,7 @@ "Back to Quick Search": "Back to quick search", "Back to all": "Back to all", "Block not found": "Block not found", + "Block not found description": "The block you are trying to access does not exist or has been removed.", "Body text": "Body text", "Bold": "Bold", "Cancel": "Cancel", diff --git a/tests/affine-local/e2e/quick-search.spec.ts b/tests/affine-local/e2e/quick-search.spec.ts index acc45822de..2b9e144848 100644 --- a/tests/affine-local/e2e/quick-search.spec.ts +++ b/tests/affine-local/e2e/quick-search.spec.ts @@ -404,7 +404,7 @@ test('can use cmdk to search page content and scroll to it, then the block will ); expect(isVisitable).toBe(true); const selectionElement = page.locator( - 'affine-block-selection[style*="display: block;"]' + 'affine-scroll-anchoring-widget div.highlight' ); await expect(selectionElement).toBeVisible(); });