From 02122098c7ca13cc7d950ddb6c921335bb1deebc Mon Sep 17 00:00:00 2001 From: doouding Date: Wed, 5 Feb 2025 07:25:53 +0000 Subject: [PATCH] fix: drag block issue (#9902) ### Changed - Added support for changing the preview offset during dragging. - Fixed the preview rendering for embed block and surface-ref block - Resolved an issue where the host element might be reused in certain cases, which could cause unexpected behavior - Moved viewport-related constants and methods to a more appropriate location --- .../embed-synced-doc-block.ts | 14 ++++- .../src/surface-ref-block.ts | 28 ++++++++- .../affine/components/src/toolbar/tooltip.ts | 5 +- .../table/stats/column-stats-column.ts | 1 + .../src/watchers/drag-event-watcher.ts | 5 +- .../edgeless/edgeless-root-block.ts | 5 +- .../edgeless/edgeless-root-preview-block.ts | 10 --- .../edgeless/edgeless-root-service.ts | 48 ++------------ .../edgeless/gfx-tool/default-tool.ts | 7 +-- .../src/root-block/edgeless/utils/viewport.ts | 28 --------- .../src/root-block/edgeless/utils/zoom.ts | 5 -- .../edgeless-zoom-toolbar/zoom-toolbar.ts | 8 ++- .../block-std/src/extension/dnd/index.ts | 62 ++++++++++++++++++- .../framework/block-std/src/gfx/controller.ts | 27 +++++++- .../block-std/src/gfx/view/view-manager.ts | 7 ++- .../framework/block-std/src/gfx/view/view.ts | 1 - .../framework/block-std/src/gfx/viewport.ts | 4 ++ .../block-std/src/scope/block-std-scope.ts | 22 +++---- .../store/src/transformer/transformer.ts | 6 +- .../src/blocksuite/presets/ai/ai-panel.ts | 10 ++- .../src/blocksuite/presets/ai/slides/index.ts | 3 +- .../view/doc-preview/doc-peek-view.tsx | 9 +-- 22 files changed, 177 insertions(+), 138 deletions(-) delete mode 100644 blocksuite/blocks/src/root-block/edgeless/utils/viewport.ts delete mode 100644 blocksuite/blocks/src/root-block/edgeless/utils/zoom.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 f4faabc946..40455b81f2 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 @@ -30,7 +30,10 @@ import { BlockStdScope, type EditorHost, } from '@blocksuite/block-std'; -import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; +import { + GfxControllerIdentifier, + GfxExtension, +} from '@blocksuite/block-std/gfx'; import { assertExists, Bound, getCommonBound } from '@blocksuite/global/utils'; import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store'; import { computed, signal } from '@preact/signals-core'; @@ -145,8 +148,17 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent { diff --git a/blocksuite/affine/components/src/toolbar/tooltip.ts b/blocksuite/affine/components/src/toolbar/tooltip.ts index 29883b8bfb..2aebe78e54 100644 --- a/blocksuite/affine/components/src/toolbar/tooltip.ts +++ b/blocksuite/affine/components/src/toolbar/tooltip.ts @@ -1,3 +1,4 @@ +import { requestConnectedFrame } from '@blocksuite/affine-shared/utils'; import { assertExists } from '@blocksuite/global/utils'; import { arrow, @@ -188,9 +189,9 @@ export class Tooltip extends LitElement { assertExists(parent, 'Tooltip must have a parent element'); // Wait for render - setTimeout(() => { + requestConnectedFrame(() => { this._hoverController.setReference(parent); - }, 0); + }, this); }; private _getStyles() { diff --git a/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts b/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts index 04fb1d8d29..69dc56b13f 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts @@ -211,6 +211,7 @@ export class DatabaseColumnStatsCell extends SignalWatcher( this.subscriptionMap.forEach(unsub => { unsub(); }); + this.subscriptionMap.clear(); }); } 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 aeb95f703c..2770df1ac8 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 @@ -617,7 +617,7 @@ export class DragEventWatcher { onDrop: () => { this._cleanup(); }, - setDragPreview: ({ source, container }) => { + setDragPreview: ({ source, container, setOffset }) => { if (!source.data?.bsEntity?.modelIds.length) { return; } @@ -626,6 +626,9 @@ export class DragEventWatcher { source.data?.bsEntity?.modelIds, container ); + + const rect = container.getBoundingClientRect(); + setOffset({ x: rect.width / 2, y: rect.height / 2 }); }, setDragData: () => { const { snapshot } = this._getSnapshotFromHoveredBlocks(); diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts index aa244c95d2..789c2c6443 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts @@ -47,7 +47,6 @@ import { EdgelessPageKeyboardManager } from './edgeless-keyboard.js'; import type { EdgelessRootService } from './edgeless-root-service.js'; import { getBackgroundGrid, isCanvasElement } from './utils/query.js'; import { mountShapeTextEditor } from './utils/text.js'; -import { fitToScreen } from './utils/viewport.js'; export class EdgelessRootBlockComponent extends BlockComponent< RootBlockModel, @@ -341,9 +340,7 @@ export class EdgelessRootBlockComponent extends BlockComponent< const storedViewport = std.get(EditPropsStore).getStorage('viewport'); if (!storedViewport) { - fitToScreen(this.gfx.gfxElements, gfx.viewport, { - smooth: false, - }); + this.gfx.fitToScreen(); return; } 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 a8e03399f1..f8a43ad6fb 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 @@ -23,7 +23,6 @@ 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< @@ -178,14 +177,6 @@ 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); @@ -195,7 +186,6 @@ export class EdgelessRootPreviewBlockComponent override connectedCallback() { super.connectedCallback(); - this._initViewport(); this.handleEvent('selectionChange', () => { const surface = this.host.selection.value.find( (sel): sel is SurfaceSelection => sel.is(SurfaceSelection) diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts index 0e09f2a868..80e3dc2bdc 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts @@ -27,6 +27,9 @@ import { GfxControllerIdentifier, GfxExtensionIdentifier, isGfxGroupCompatibleModel, + ZOOM_MAX, + ZOOM_MIN, + ZOOM_STEP, } from '@blocksuite/block-std/gfx'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { Bound, getCommonBound } from '@blocksuite/global/utils'; @@ -41,15 +44,7 @@ import { createStickerMiddleware, replaceIdMiddleware, } from './services/template-middlewares.js'; -import { FIT_TO_SCREEN_PADDING } from './utils/consts.js'; import { getCursorMode } from './utils/query.js'; -import { - ZOOM_INITIAL, - ZOOM_MAX, - ZOOM_MIN, - ZOOM_STEP, - type ZoomAction, -} from './utils/zoom.js'; export class EdgelessRootService extends RootService implements SurfaceContext { static override readonly flavour = RootBlockSchema.model.flavour; @@ -288,34 +283,6 @@ export class EdgelessRootService extends RootService implements SurfaceContext { return this.surface.getConnectors(id) as ConnectorElementModel[]; } - getFitToScreenData( - padding: [number, number, number, number] = [0, 0, 0, 0], - inputBounds?: Bound[] - ) { - let bounds = []; - if (inputBounds && inputBounds.length) { - bounds = inputBounds; - } else { - this.blocks.forEach(block => { - bounds.push(Bound.deserialize(block.xywh)); - }); - - const surfaceElementsBound = getCommonBound(this.elements); - if (surfaceElementsBound) { - bounds.push(surfaceElementsBound); - } - } - - const bound = getCommonBound(bounds); - - return this.viewport.getFitToScreenData( - bound, - padding, - ZOOM_INITIAL, - FIT_TO_SCREEN_PADDING - ); - } - override mounted() { super.mounted(); this._initSlotEffects(); @@ -372,12 +339,12 @@ export class EdgelessRootService extends RootService implements SurfaceContext { } } - setZoomByAction(action: ZoomAction) { + setZoomByAction(action: 'fit' | 'out' | 'reset' | 'in') { if (this.locked) return; switch (action) { case 'fit': - this.zoomToFit(); + this.gfx.fitToScreen(); break; case 'reset': this.viewport.smoothZoom(1.0); @@ -439,9 +406,4 @@ export class EdgelessRootService extends RootService implements SurfaceContext { this.selectionManager.set([]); this.disposables.dispose(); } - - zoomToFit() { - const { centerX, centerY, zoom } = this.getFitToScreenData(); - this.viewport.setViewport(zoom, [centerX, centerY], true); - } } diff --git a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts index 5feff03136..969a0467bc 100644 --- a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts +++ b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts @@ -67,7 +67,6 @@ import { mountShapeTextEditor, mountTextElementEditor, } from '../utils/text.js'; -import { fitToScreen } from '../utils/viewport.js'; import { CanvasElementEventExt } from './default-tool-ext/event-ext.js'; import type { DefaultToolExt } from './default-tool-ext/ext.js'; import { DefaultModeDragType } from './default-tool-ext/ext.js'; @@ -766,11 +765,7 @@ export class DefaultTool extends BaseTool { if (this.doc.readonly) { const viewport = this.gfx.viewport; if (viewport.zoom === 1) { - // Fit to Screen - fitToScreen( - [...this.gfx.layer.blocks, ...this.gfx.layer.canvasElements], - this.gfx.viewport - ); + this.gfx.fitToScreen(); } else { // Zoom to 100% and Center const [x, y] = viewport.toModelCoord(e.x, e.y); diff --git a/blocksuite/blocks/src/root-block/edgeless/utils/viewport.ts b/blocksuite/blocks/src/root-block/edgeless/utils/viewport.ts deleted file mode 100644 index 324fa4d58f..0000000000 --- a/blocksuite/blocks/src/root-block/edgeless/utils/viewport.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { GfxModel, Viewport } from '@blocksuite/block-std/gfx'; -import { Bound, getCommonBound } from '@blocksuite/global/utils'; - -import { FIT_TO_SCREEN_PADDING } from './consts.js'; -import { ZOOM_INITIAL } from './zoom.js'; - -export function fitToScreen( - elements: GfxModel[], - viewport: Viewport, - options: { - padding?: [number, number, number, number]; - smooth?: boolean; - } = { - padding: [0, 0, 0, 0], - smooth: true, - } -) { - const elemBounds = elements.map(element => Bound.deserialize(element.xywh)); - const commonBound = getCommonBound(elemBounds); - const { zoom, centerX, centerY } = viewport.getFitToScreenData( - commonBound, - options.padding, - ZOOM_INITIAL, - FIT_TO_SCREEN_PADDING - ); - - viewport.setViewport(zoom, [centerX, centerY], options.smooth); -} diff --git a/blocksuite/blocks/src/root-block/edgeless/utils/zoom.ts b/blocksuite/blocks/src/root-block/edgeless/utils/zoom.ts deleted file mode 100644 index 03e0fdc88d..0000000000 --- a/blocksuite/blocks/src/root-block/edgeless/utils/zoom.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type ZoomAction = 'fit' | 'out' | 'reset' | 'in'; -export const ZOOM_MAX = 6.0; -export const ZOOM_MIN = 0.1; -export const ZOOM_STEP = 0.25; -export const ZOOM_INITIAL = 1.0; diff --git a/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/zoom-toolbar.ts b/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/zoom-toolbar.ts index ddf9fc8bfb..56016842dc 100644 --- a/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/zoom-toolbar.ts +++ b/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/zoom-toolbar.ts @@ -4,6 +4,7 @@ import { ViewBarIcon, } from '@blocksuite/affine-components/icons'; import { stopPropagation } from '@blocksuite/affine-shared/utils'; +import { ZOOM_STEP } from '@blocksuite/block-std/gfx'; import { WithDisposable } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import { baseTheme } from '@toeverything/theme'; @@ -11,7 +12,6 @@ import { css, html, LitElement, nothing, unsafeCSS } from 'lit'; import { property } from 'lit/decorators.js'; import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js'; -import { ZOOM_STEP } from '../../edgeless/utils/zoom.js'; export class EdgelessZoomToolbar extends WithDisposable(LitElement) { static override styles = css` @@ -87,6 +87,10 @@ export class EdgelessZoomToolbar extends WithDisposable(LitElement) { return this.edgeless.service; } + get gfx() { + return this.edgeless.gfx; + } + get edgelessTool() { return this.edgeless.gfx.tool.currentToolOption$.peek(); } @@ -162,7 +166,7 @@ export class EdgelessZoomToolbar extends WithDisposable(LitElement) { .tooltip=${'Fit to screen'} .tipPosition=${this._isVerticalBar() ? 'right' : 'top-end'} .arrow=${!this._isVerticalBar()} - @click=${() => this.edgelessService.zoomToFit()} + @click=${() => this.gfx.fitToScreen()} .iconContainerPadding=${4} .disabled=${locked} > diff --git a/blocksuite/framework/block-std/src/extension/dnd/index.ts b/blocksuite/framework/block-std/src/extension/dnd/index.ts index bdd8a3ef55..a674b35dc7 100644 --- a/blocksuite/framework/block-std/src/extension/dnd/index.ts +++ b/blocksuite/framework/block-std/src/extension/dnd/index.ts @@ -4,7 +4,10 @@ import { type ElementGetFeedbackArgs, monitorForElements, } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; +import { centerUnderPointer } from '@atlaskit/pragmatic-drag-and-drop/element/center-under-pointer'; import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview'; +import { pointerOutsideOfPreview } from '@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview'; +import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source'; import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview'; import type { DropTargetRecord } from '@atlaskit/pragmatic-drag-and-drop/types'; import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element'; @@ -89,7 +92,7 @@ export type DraggableOption< * If you want to completely disable the drag preview, just set `setDragPreview` to `false`. * * @example - * dnd.draggable{ + * dnd.draggable({ * // ... * setDragPreview: ({ container }) => { * const preview = document.createElement('div'); @@ -98,8 +101,12 @@ export type DraggableOption< * preview.style.backgroundColor = 'red'; * preview.innerText = 'Custom Drag Preview'; * container.appendChild(preview); + * + * return () => { + * // do some cleanup + * } * } - * } + * }) * * @param callback - callback to set custom drag preview * @returns @@ -116,8 +123,11 @@ export type DraggableOption< */ nativeSetDragImage: DataTransfer['setDragImage'] | null; container: HTMLElement; + setOffset: ( + offset: 'preserve' | 'center' | { x: number; y: number } + ) => void; } - ) => void); + ) => void | (() => void)); } & ElementDragEventMap, DropPayload>; export type DropTargetOption< @@ -228,9 +238,55 @@ export class DndController extends LifeCycleWatcher { dragHandle, onGenerateDragPreview: options => { if (setDragPreview) { + let state: typeof centerUnderPointer | { x: number; y: number }; + + const setOffset = ( + offset: 'preserve' | 'center' | { x: number; y: number } + ) => { + if (offset === 'center') { + state = centerUnderPointer; + } else if (offset === 'preserve') { + state = preserveOffsetOnSource({ + element: options.source.element, + input: options.location.current.input, + }); + } else if (typeof offset === 'object') { + if ( + offset.x < 0 || + offset.y < 0 || + typeof offset.x === 'string' || + typeof offset.y === 'string' + ) { + state = pointerOutsideOfPreview({ + x: + typeof offset.x === 'number' + ? `${Math.abs(offset.x)}px` + : offset.x, + y: + typeof offset.y === 'number' + ? `${Math.abs(offset.y)}px` + : offset.y, + }); + } + state = offset; + } + }; + setCustomNativeDragPreview({ + getOffset: (...args) => { + if (!state) { + setOffset('center'); + } + + if (typeof state === 'function') { + return state(...args); + } + + return state; + }, render: renderOption => { setDragPreview({ + setOffset, ...options, ...renderOption, }); diff --git a/blocksuite/framework/block-std/src/gfx/controller.ts b/blocksuite/framework/block-std/src/gfx/controller.ts index 17c15e2fbd..f2b8dcb6d7 100644 --- a/blocksuite/framework/block-std/src/gfx/controller.ts +++ b/blocksuite/framework/block-std/src/gfx/controller.ts @@ -2,6 +2,7 @@ import { assertType, Bound, DisposableGroup, + getCommonBound, getCommonBoundWithRotation, type IBound, last, @@ -30,7 +31,7 @@ import { GfxPrimitiveElementModel, } from './model/surface/element-model.js'; import type { SurfaceBlockModel } from './model/surface/surface-model.js'; -import { Viewport } from './viewport.js'; +import { FIT_TO_SCREEN_PADDING, Viewport, ZOOM_INITIAL } from './viewport.js'; export class GfxController extends LifeCycleWatcher { static override key = gfxControllerKey; @@ -300,4 +301,28 @@ export class GfxController extends LifeCycleWatcher { block && this.doc.updateBlock(block.model, props); } } + + fitToScreen( + options: { + bounds?: Bound[]; + smooth?: boolean; + padding?: [number, number, number, number]; + } = { + smooth: false, + padding: [0, 0, 0, 0], + } + ) { + const elemBounds = + options.bounds ?? + this.gfxElements.map(element => Bound.deserialize(element.xywh)); + const commonBound = getCommonBound(elemBounds); + const { zoom, centerX, centerY } = this.viewport.getFitToScreenData( + commonBound, + options.padding, + ZOOM_INITIAL, + FIT_TO_SCREEN_PADDING + ); + + this.viewport.setViewport(zoom, [centerX, centerY], options.smooth); + } } diff --git a/blocksuite/framework/block-std/src/gfx/view/view-manager.ts b/blocksuite/framework/block-std/src/gfx/view/view-manager.ts index 4542098374..2ce38dd956 100644 --- a/blocksuite/framework/block-std/src/gfx/view/view-manager.ts +++ b/blocksuite/framework/block-std/src/gfx/view/view-manager.ts @@ -60,9 +60,12 @@ export class ViewManager extends GfxExtension { this._disposable.add( surface.elementAdded.on(payload => { const model = surface.getElementById(payload.id)!; - const View = this._viewCtorMap.get(model.type) ?? GfxElementModelView; + const ViewCtor = + this._viewCtorMap.get(model.type) ?? GfxElementModelView; + const view = new ViewCtor(model, this.gfx); - this._viewMap.set(model.id, new View(model, this.gfx)); + this._viewMap.set(model.id, view); + view.onCreated(); }) ); diff --git a/blocksuite/framework/block-std/src/gfx/view/view.ts b/blocksuite/framework/block-std/src/gfx/view/view.ts index 832bc11c47..ec02a8c13b 100644 --- a/blocksuite/framework/block-std/src/gfx/view/view.ts +++ b/blocksuite/framework/block-std/src/gfx/view/view.ts @@ -72,7 +72,6 @@ export class GfxElementModelView< readonly gfx: GfxController ) { this.model = model; - this.onCreated(); } static setup(di: Container): void { diff --git a/blocksuite/framework/block-std/src/gfx/viewport.ts b/blocksuite/framework/block-std/src/gfx/viewport.ts index 485b32e799..a4affa8e32 100644 --- a/blocksuite/framework/block-std/src/gfx/viewport.ts +++ b/blocksuite/framework/block-std/src/gfx/viewport.ts @@ -15,6 +15,10 @@ function cutoff(value: number, ref: number, sign: number) { export const ZOOM_MAX = 6.0; export const ZOOM_MIN = 0.1; +export const ZOOM_STEP = 0.25; +export const ZOOM_INITIAL = 1.0; + +export const FIT_TO_SCREEN_PADDING = 100; export class Viewport { private _cachedBoundingClientRect: DOMRect | null = null; diff --git a/blocksuite/framework/block-std/src/scope/block-std-scope.ts b/blocksuite/framework/block-std/src/scope/block-std-scope.ts index 8bb4056a2a..11c451611a 100644 --- a/blocksuite/framework/block-std/src/scope/block-std-scope.ts +++ b/blocksuite/framework/block-std/src/scope/block-std-scope.ts @@ -51,8 +51,6 @@ const internalExtensions = [ export class BlockStdScope { static internalExtensions = internalExtensions; - private _getHost: () => EditorHost; - readonly container: Container; readonly store: Store; @@ -65,6 +63,8 @@ export class BlockStdScope { return this.provider.getAll(LifeCycleWatcherIdentifier); } + private _host!: EditorHost; + get dnd() { return this.get(DndController); } @@ -94,7 +94,14 @@ export class BlockStdScope { } get host() { - return this._getHost(); + if (!this._host) { + throw new BlockSuiteError( + ErrorCode.ValueNotExists, + 'Host is not ready to use, the `render` method should be called first' + ); + } + + return this._host; } get range() { @@ -110,12 +117,6 @@ export class BlockStdScope { } constructor(options: BlockStdOptions) { - this._getHost = () => { - throw new BlockSuiteError( - ErrorCode.ValueNotExists, - 'Host is not ready to use, the `render` method should be called first' - ); - }; this.store = options.store; this.userExtensions = options.extensions; this.container = new Container(); @@ -190,7 +191,7 @@ export class BlockStdScope { const element = new EditorHost(); element.std = this; element.doc = this.store; - this._getHost = () => element; + this._host = element; this._lifeCycleWatchers.forEach(watcher => { watcher.rendered.call(watcher); }); @@ -202,7 +203,6 @@ export class BlockStdScope { this._lifeCycleWatchers.forEach(watcher => { watcher.unmounted.call(watcher); }); - this._getHost = () => null as unknown as EditorHost; } } diff --git a/blocksuite/framework/store/src/transformer/transformer.ts b/blocksuite/framework/store/src/transformer/transformer.ts index c835b88b9d..12f1c95b03 100644 --- a/blocksuite/framework/store/src/transformer/transformer.ts +++ b/blocksuite/framework/store/src/transformer/transformer.ts @@ -255,13 +255,13 @@ export class Transformer { this._flattenSnapshot(tmpRootSnapshot, flatSnapshots, parent, index); const blockTree = await this._convertFlatSnapshots(flatSnapshots); - const first = content[0]; + // check if the slice is already in the doc if (first && doc.hasBlock(first.id)) { // if the slice is already in the doc, we need to move the blocks instead of adding them - const models = flatSnapshots - .map(flat => doc.getBlock(flat.snapshot.id)?.model) + const models = content + .map(block => doc.getBlock(block.id)?.model) .filter(Boolean) as BlockModel[]; const parentModel = parent ? doc.getBlock(parent)?.model : undefined; if (!parentModel) { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts index 0b577289ef..a0d979ade2 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts @@ -117,13 +117,11 @@ function createNewNote(host: EditorHost): AIItemConfig { const newNote = doc.getBlock(noteBlockId)?.model; if (!newNote || !matchFlavours(newNote, ['affine:note'])) return; const newNoteBound = Bound.deserialize(newNote.xywh); - const bounds = [bound, newNoteBound]; - const { zoom, centerX, centerY } = service.getFitToScreenData( - [20, 20, 20, 20], - bounds - ); - service.viewport.setViewport(zoom, [centerX, centerY]); + service.gfx.fitToScreen({ + bounds, + padding: [20, 20, 20, 20], + }); }) .catch(err => { console.error(err); diff --git a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts index 759f657bc6..57a2c937be 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts @@ -62,8 +62,7 @@ export const PPTBuilder = (host: EditorHost) => { const block = snapshot.snapshot.content[0]; for (const child of block.children) { await addDoc(child); - const { centerX, centerY, zoom } = service.getFitToScreenData(); - service.viewport.setViewport(zoom, [centerX, centerY]); + service.gfx.fitToScreen(); } } catch (e) { console.error(e); diff --git a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx index c15fe4ebf9..d0ab8e23ee 100644 --- a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx @@ -64,12 +64,9 @@ function fitViewport( false ); } else { - const data = rootService.getFitToScreenData(); - rootService.viewport.setViewport( - data.zoom, - [data.centerX, data.centerY], - false - ); + rootService.gfx.fitToScreen({ + smooth: false, + }); } } catch (e) { logger.warn('failed to fitViewPort', e);