From 1560880abde8c4c2c765e3dc51cb19e5568848f7 Mon Sep 17 00:00:00 2001 From: doouding Date: Mon, 20 Jan 2025 09:25:05 +0000 Subject: [PATCH] fix: drag embed block preview (#9791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes [BS-1518](https://linear.app/affine-design/issue/BS-1518/拖拽一个-embed-view-的-linked-doc,其-indicator-是错误的) --- .../embed-synced-doc-block.ts | 13 ++- .../affine/block-surface/src/surface-block.ts | 1 + .../src/services/editor-setting-service.ts | 1 + .../src/components/drag-preview.ts | 63 ------------- .../widget-drag-handle/src/drag-handle.ts | 3 - .../affine/widget-drag-handle/src/effects.ts | 2 - .../src/helpers/preview-helper.ts | 92 +++++++------------ .../src/watchers/drag-event-watcher.ts | 39 ++------ .../edgeless/edgeless-root-preview-block.ts | 18 ++++ .../block-std/src/gfx/viewport-element.ts | 11 ++- 10 files changed, 83 insertions(+), 160 deletions(-) delete mode 100644 blocksuite/affine/widget-drag-handle/src/components/drag-preview.ts diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts index 7ab4bf9db8..6731b264a2 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts @@ -14,6 +14,9 @@ import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts'; import { DocDisplayMetaProvider, DocModeProvider, + EditorSettingExtension, + EditorSettingProvider, + GeneralSettingSchema, ThemeExtensionIdentifier, ThemeProvider, } from '@blocksuite/affine-shared/services'; @@ -30,7 +33,7 @@ import { import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { assertExists, Bound, getCommonBound } from '@blocksuite/global/utils'; import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store'; -import { computed } from '@preact/signals-core'; +import { computed, signal } from '@preact/signals-core'; import { html, nothing, type PropertyValues } from 'lit'; import { query, state } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; @@ -114,6 +117,9 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent - affine-drag-preview { - box-sizing: border-box; - position: absolute; - display: block; - height: auto; - font-family: ${baseTheme.fontSansFamily}; - font-size: var(--affine-font-base); - line-height: var(--affine-line-height); - color: var(--affine-text-primary-color); - font-weight: 400; - top: 0; - left: 0; - transform-origin: 0 0; - opacity: 0.5; - user-select: none; - pointer-events: none; - caret-color: transparent; - z-index: 3; - } - - .affine-drag-preview-grabbing * { - cursor: grabbing !important; - }${this.template}`; - } - - @property({ attribute: false }) - accessor onRemove: (() => void) | null = null; - - @property({ attribute: false }) - accessor template: TemplateResult | EditorHost | null = null; -} - -declare global { - interface HTMLElementTagNameMap { - 'affine-drag-preview': DragPreview; - } -} diff --git a/blocksuite/affine/widget-drag-handle/src/drag-handle.ts b/blocksuite/affine/widget-drag-handle/src/drag-handle.ts index ddfa8c5253..b6c3fb6d9f 100644 --- a/blocksuite/affine/widget-drag-handle/src/drag-handle.ts +++ b/blocksuite/affine/widget-drag-handle/src/drag-handle.ts @@ -20,7 +20,6 @@ import { query, state } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; import type { AFFINE_DRAG_HANDLE_WIDGET } from './consts.js'; -import { PreviewHelper } from './helpers/preview-helper.js'; import { RectHelper } from './helpers/rect-helper.js'; import { SelectionHelper } from './helpers/selection-helper.js'; import { styles } from './styles.js'; @@ -143,8 +142,6 @@ export class AffineDragHandleWidget extends WidgetComponent { pointerEventWatcher = new PointerEventWatcher(this); - previewHelper = new PreviewHelper(this); - scale = signal(1); scaleInNote = computed(() => this.scale.value * this.noteScale.value); diff --git a/blocksuite/affine/widget-drag-handle/src/effects.ts b/blocksuite/affine/widget-drag-handle/src/effects.ts index 7e7545aebd..06339d68a0 100644 --- a/blocksuite/affine/widget-drag-handle/src/effects.ts +++ b/blocksuite/affine/widget-drag-handle/src/effects.ts @@ -1,10 +1,8 @@ -import { DragPreview } from './components/drag-preview'; import { DropIndicator } from './components/drop-indicator'; import { AFFINE_DRAG_HANDLE_WIDGET } from './consts'; import { AffineDragHandleWidget } from './drag-handle'; export function effects() { - customElements.define('affine-drag-preview', DragPreview); customElements.define('affine-drop-indicator', DropIndicator); customElements.define(AFFINE_DRAG_HANDLE_WIDGET, AffineDragHandleWidget); } diff --git a/blocksuite/affine/widget-drag-handle/src/helpers/preview-helper.ts b/blocksuite/affine/widget-drag-handle/src/helpers/preview-helper.ts index 02101c2663..50c30b33b8 100644 --- a/blocksuite/affine/widget-drag-handle/src/helpers/preview-helper.ts +++ b/blocksuite/affine/widget-drag-handle/src/helpers/preview-helper.ts @@ -1,25 +1,17 @@ -import { SpecProvider } from '@blocksuite/affine-shared/utils'; import { - type BlockComponent, - BlockStdScope, - type DndEventState, -} from '@blocksuite/block-std'; -import { Point } from '@blocksuite/global/utils'; + DocModeExtension, + DocModeProvider, + EditorSettingExtension, + EditorSettingProvider, +} from '@blocksuite/affine-shared/services'; +import { SpecProvider } from '@blocksuite/affine-shared/utils'; +import { BlockStdScope } from '@blocksuite/block-std'; import { type BlockViewType, type Query } from '@blocksuite/store'; +import { signal } from '@preact/signals-core'; -import { DragPreview } from '../components/drag-preview.js'; import type { AffineDragHandleWidget } from '../drag-handle.js'; export class PreviewHelper { - private readonly _calculatePreviewOffset = ( - blocks: BlockComponent[], - state: DndEventState - ) => { - const { top, left } = blocks[0].getBoundingClientRect(); - const previewOffset = new Point(state.raw.x - left, state.raw.y - top); - return previewOffset; - }; - private readonly _calculateQuery = (selectedIds: string[]): Query => { const ids: Array<{ id: string; viewType: BlockViewType }> = selectedIds.map( id => ({ @@ -55,52 +47,34 @@ export class PreviewHelper { }; }; - createDragPreview = ( - blocks: BlockComponent[], - state: DndEventState, - dragPreviewEl?: HTMLElement, - dragPreviewOffset?: Point - ): DragPreview => { - let dragPreview: DragPreview; - if (dragPreviewEl) { - dragPreview = new DragPreview(dragPreviewOffset); - dragPreview.append(dragPreviewEl); - } else { - let width = 0; - blocks.forEach(element => { - width = Math.max(width, element.getBoundingClientRect().width); - }); + renderDragPreview = (blockIds: string[], container: HTMLElement): void => { + const widget = this.widget; + const std = widget.std; + const docModeService = std.get(DocModeProvider); + const editorSetting = std.get(EditorSettingProvider).peek(); + const query = this._calculateQuery(blockIds as string[]); + const store = widget.doc.doc.getStore({ query }); + const previewSpec = SpecProvider.getInstance().getSpec('page:preview'); + const settingSignal = signal({ ...editorSetting }); + previewSpec.extend([ + DocModeExtension(docModeService), + EditorSettingExtension(settingSignal), + ]); - const selectedIds = blocks.map(block => block.model.id); + settingSignal.value = { + ...settingSignal.value, + edgelessDisableScheduleUpdate: true, + }; - const query = this._calculateQuery(selectedIds); + const previewStd = new BlockStdScope({ + store, + extensions: previewSpec.value, + }); + const previewTemplate = previewStd.render(); + const noteBlock = this.widget.host.querySelector('affine-note'); - const store = this.widget.doc.doc.getStore({ query }); - - const previewSpec = SpecProvider.getInstance().getSpec('page:preview'); - const previewStd = new BlockStdScope({ - store, - extensions: previewSpec.value, - }); - const previewTemplate = previewStd.render(); - - const offset = this._calculatePreviewOffset(blocks, state); - const posX = state.raw.x - offset.x; - const posY = state.raw.y - offset.y; - const altKey = state.raw.altKey; - - dragPreview = new DragPreview(offset); - dragPreview.template = previewTemplate; - dragPreview.onRemove = () => { - this.widget.doc.doc.clearQuery(query); - }; - dragPreview.style.width = `${width / this.widget.scaleInNote.peek()}px`; - dragPreview.style.transform = `translate(${posX}px, ${posY}px) scale(${this.widget.scaleInNote.peek()})`; - - dragPreview.style.opacity = altKey ? '1' : '0.5'; - } - this.widget.rootComponent.append(dragPreview); - return dragPreview; + container.style.width = `${noteBlock?.offsetWidth ?? noteBlock?.clientWidth ?? 500}px`; + container.append(previewTemplate); }; constructor(readonly widget: AffineDragHandleWidget) {} diff --git a/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts b/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts index b74902f341..5cc15bf5b7 100644 --- a/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts +++ b/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts @@ -20,12 +20,11 @@ import { getRectByBlockComponent, getScrollContainer, matchFlavours, - SpecProvider, } from '@blocksuite/affine-shared/utils'; import { type BlockComponent, BlockSelection, - BlockStdScope, + type BlockStdScope, type DragFromBlockSuite, type DragPayload, type DropPayload, @@ -37,6 +36,7 @@ import { Slice, type SliceSnapshot } from '@blocksuite/store'; import { DropIndicator } from '../components/drop-indicator.js'; import type { AffineDragHandleWidget } from '../drag-handle.js'; +import { PreviewHelper } from '../helpers/preview-helper.js'; import { newIdCrossDoc } from '../middleware/new-id-cross-doc.js'; import { reorderList } from '../middleware/reorder-list'; import { surfaceRefToEmbed } from '../middleware/surface-ref-to-embed.js'; @@ -64,6 +64,8 @@ declare module '@blocksuite/block-std' { export class DragEventWatcher { dropIndicator: null | DropIndicator = null; + previewHelper = new PreviewHelper(this.widget); + get host() { return this.widget.host; } @@ -668,21 +670,10 @@ export class DragEventWatcher { return; } - const query = widget.previewHelper['_calculateQuery']( - source.data?.bsEntity?.modelIds as string[] + this.previewHelper.renderDragPreview( + source.data?.bsEntity?.modelIds, + container ); - const store = widget.doc.doc.getStore({ query }); - const previewSpec = - SpecProvider.getInstance().getSpec('page:preview'); - const previewStd = new BlockStdScope({ - store, - extensions: previewSpec.value, - }); - const previewTemplate = previewStd.render(); - const noteBlock = this.widget.host.querySelector('affine-note'); - - container.style.width = `${noteBlock?.offsetWidth ?? noteBlock?.clientWidth ?? 500}px`; - container.append(previewTemplate); }, setDragData: () => { const { snapshot } = this._getSnapshotFromHoveredBlocks(); @@ -833,20 +824,10 @@ export class DragEventWatcher { return; } - const query = widget.previewHelper['_calculateQuery']( - source.data?.bsEntity?.modelIds as string[] + this.previewHelper.renderDragPreview( + source.data?.bsEntity?.modelIds, + container ); - const store = widget.doc.doc.getStore({ query }); - const previewSpec = - SpecProvider.getInstance().getSpec('page:preview'); - const previewStd = new BlockStdScope({ - store, - extensions: previewSpec.value, - }); - const previewTemplate = previewStd.render(); - - container.style.width = `${std.host.clientWidth || std.host.offsetWidth || 500}px`; - container.append(previewTemplate); }, setDragData: () => { const { snapshot } = this._getDraggedBlock(view); diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts index 55ad584dfd..a8e03399f1 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts @@ -5,6 +5,7 @@ import type { import type { EdgelessPreviewer } from '@blocksuite/affine-block-surface-ref'; import type { RootBlockModel } from '@blocksuite/affine-model'; import { + EditorSettingProvider, FontLoaderService, ThemeProvider, } from '@blocksuite/affine-shared/services'; @@ -22,6 +23,7 @@ import { query, state } from 'lit/decorators.js'; import type { EdgelessRootBlockWidgetName } from '../types.js'; import type { EdgelessRootService } from './edgeless-root-service.js'; import { getBackgroundGrid, isCanvasElement } from './utils/query.js'; +import { fitToScreen } from './utils/viewport.js'; export class EdgelessRootPreviewBlockComponent extends BlockComponent< @@ -176,9 +178,24 @@ export class EdgelessRootPreviewBlockComponent ); } + private _initViewport() { + const gfx = this.service.gfx; + + fitToScreen(gfx.gfxElements, gfx.viewport, { + smooth: false, + }); + } + + private get _disableScheduleUpdate() { + const editorSetting = this.std.getOptional(EditorSettingProvider); + + return editorSetting?.peek().edgelessDisableScheduleUpdate ?? false; + } + override connectedCallback() { super.connectedCallback(); + this._initViewport(); this.handleEvent('selectionChange', () => { const surface = this.host.selection.value.find( (sel): sel is SurfaceSelection => sel.is(SurfaceSelection) @@ -223,6 +240,7 @@ export class EdgelessRootPreviewBlockComponent return html`
{ const blocks = this.service.gfx.grid.search( diff --git a/blocksuite/framework/block-std/src/gfx/viewport-element.ts b/blocksuite/framework/block-std/src/gfx/viewport-element.ts index ec36a49969..07d7d7a67a 100644 --- a/blocksuite/framework/block-std/src/gfx/viewport-element.ts +++ b/blocksuite/framework/block-std/src/gfx/viewport-element.ts @@ -98,6 +98,10 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) { this._hideOutsideBlock(); }; + if (!this.enableChildrenSchedule) { + delete this.scheduleUpdateChildren; + } + viewportUpdateCallback(); this.disposables.add( this.viewport.viewportUpdated.on(() => viewportUpdateCallback()) @@ -111,7 +115,7 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) { return html``; } - scheduleUpdateChildren(id: string) { + scheduleUpdateChildren? = (id: string) => { const { promise, resolve } = Promise.withResolvers(); this._pendingChildrenUpdates.push({ id, resolve }); @@ -143,7 +147,7 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) { } return promise; - } + }; @property({ attribute: false }) accessor getModelsInViewport: undefined | (() => Set); @@ -154,6 +158,9 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) { @property({ type: Number }) accessor maxConcurrentRenders: number = 2; + @property({ attribute: false }) + accessor enableChildrenSchedule: boolean = true; + @property({ attribute: false }) accessor viewport!: Viewport; }