From 116dec269b1bd5ab5448f89b14424d541af5f98a Mon Sep 17 00:00:00 2001 From: xiaoxin Date: Mon, 13 Jan 2025 17:44:23 +0800 Subject: [PATCH] feat: add scrollable --- blocksuite/affine/shared/src/utils/event.ts | 2 +- .../src/watchers/drag-event-watcher.ts | 75 +++++++------------ blocksuite/framework/block-std/package.json | 1 + .../framework/block-std/src/extension/dnd.ts | 25 +++++++ .../block-std/src/extension/dnd/types.ts | 5 ++ yarn.lock | 11 +++ 6 files changed, 69 insertions(+), 50 deletions(-) diff --git a/blocksuite/affine/shared/src/utils/event.ts b/blocksuite/affine/shared/src/utils/event.ts index daa5a6e3958d8..39f04a621c8f2 100644 --- a/blocksuite/affine/shared/src/utils/event.ts +++ b/blocksuite/affine/shared/src/utils/event.ts @@ -170,7 +170,7 @@ export function requestConnectedFrame( * A wrapper around `requestConnectedFrame` that only calls at most once in one frame */ export function requestThrottledConnectedFrame< - T extends (...args: unknown[]) => void, + T extends (...args: any[]) => void, >(func: T, element?: HTMLElement): T { let raqId: number | undefined = undefined; let latestArgs: unknown[] = []; 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 acf4aa170b34a..3380dd3171edf 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 @@ -14,13 +14,13 @@ import { TelemetryProvider, } from '@blocksuite/affine-shared/services'; import { - autoScroll, captureEventTarget, type DropResult, getBlockComponentsExcludeSubtrees, getRectByBlockComponent, getScrollContainer, matchFlavours, + requestThrottledConnectedFrame, SpecProvider, } from '@blocksuite/affine-shared/utils'; import { @@ -61,10 +61,6 @@ export type DragBlockPayload = DragPayload; export class DragEventWatcher { dropIndicator: null | DropIndicator = null; - lastDragPoint: Point | null = null; - - rafID: number = 0; - get host() { return this.widget.host; } @@ -122,23 +118,22 @@ export class DragEventWatcher { private readonly _cleanup = () => { this._clearDropIndicator(); - this.clearRaf(); this.widget.hide(true); this.std.selection.setGroup('gfx', []); }; - private readonly _onDragMove = ( - point: Point, - payload: DragBlockPayload, - dropPayload: DropPayload, - block: BlockComponent - ) => { - this._createDropIndicator(); - this.clearRaf(); - this.rafID = requestAnimationFrame(() => { - this._updateDropIndicator(point, payload, dropPayload, block, true); - }); - }; + private readonly _onDragMove = requestThrottledConnectedFrame( + ( + point: Point, + payload: DragBlockPayload, + dropPayload: DropPayload, + block: BlockComponent + ) => { + this._createDropIndicator(); + this._updateDropIndicator(point, payload, dropPayload, block); + }, + this.widget + ); /** * When dragging, should update indicator position and target drop block id @@ -220,8 +215,7 @@ export class DragEventWatcher { point: Point, dragPayload: DragBlockPayload, dropPayload: DropPayload, - dropBlock: BlockComponent, - shouldAutoScroll: boolean = false + dropBlock: BlockComponent ) => { const closestNoteBlock = dropBlock && getParentNoteBlock(dropBlock); @@ -245,37 +239,8 @@ export class DragEventWatcher { } this.lastDragPoint = point; - - if (this.mode === 'page') { - if (!shouldAutoScroll) return; - - const scrollContainer = getScrollContainer(this.widget.rootComponent); - const result = autoScroll(scrollContainer, point.y); - if (!result) { - this.clearRaf(); - return; - } - this.rafID = requestAnimationFrame(() => - this._updateDropIndicator( - point, - dragPayload, - dropPayload, - dropBlock, - true - ) - ); - } else { - this.clearRaf(); - } }; - clearRaf() { - if (this.rafID) { - cancelAnimationFrame(this.rafID); - this.rafID = 0; - } - } - private readonly _resetDropResult = () => { if (this.dropIndicator) this.dropIndicator.rect = null; }; @@ -670,6 +635,7 @@ export class DragEventWatcher { const widget = this.widget; const std = this.std; const disposables = widget.disposables; + const scrollable = getScrollContainer(this.host); disposables.add( std.dnd.draggable({ @@ -718,6 +684,17 @@ export class DragEventWatcher { }) ); + if (scrollable) { + disposables.add( + std.dnd.autoScroll({ + element: scrollable, + canScroll: ({ source }) => { + return source.data.draggable?.entity?.type === 'blocks'; + }, + }) + ); + } + // used to handle drag move and drop disposables.add( std.dnd.monitor({ diff --git a/blocksuite/framework/block-std/package.json b/blocksuite/framework/block-std/package.json index c53b8ceb69f38..abdc68e336225 100644 --- a/blocksuite/framework/block-std/package.json +++ b/blocksuite/framework/block-std/package.json @@ -15,6 +15,7 @@ "license": "MIT", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.4.0", + "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", "@blocksuite/global": "workspace:*", "@blocksuite/inline": "workspace:*", diff --git a/blocksuite/framework/block-std/src/extension/dnd.ts b/blocksuite/framework/block-std/src/extension/dnd.ts index 4a0a2ef1e179f..2787492dbed07 100644 --- a/blocksuite/framework/block-std/src/extension/dnd.ts +++ b/blocksuite/framework/block-std/src/extension/dnd.ts @@ -7,6 +7,7 @@ import { import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview'; 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'; import { attachClosestEdge, type Edge, @@ -22,6 +23,7 @@ import type { ElementDropEventMap, ElementDropTargetFeedbackArgs, ElementMonitorFeedbackArgs, + OriginalAutoScrollOption, OriginalDraggableOption, OriginalDropTargetOption, OriginalMonitorOption, @@ -173,6 +175,22 @@ export type MonitorOption< ) => boolean; } & ElementDragEventMap, DropPayload>; +export type AutoScroll< + PayloadEntity extends DragEntity, + PayloadFrom extends DragFrom, +> = { + element: HTMLElement; + canScroll?: ( + args: ElementDragEventBaseArgs> + ) => void; + getAllowedAxis?: ( + args: ElementDragEventBaseArgs> + ) => ReturnType['getAllowedAxis']>; + getConfiguration?: ( + args: ElementDragEventBaseArgs> + ) => ReturnType['getConfiguration']>; +}; + export const DndExtensionIdentifier = LifeCycleWatcherIdentifier( 'DndController' ) as ServiceIdentifier; @@ -289,4 +307,11 @@ export class DndController extends LifeCycleWatcher { >(args: MonitorOption>) { return monitorForElements(args as OriginalMonitorOption); } + + autoScroll< + PayloadEntity extends DragEntity = DragEntity, + PayloadFrom extends DragFrom = DragFromBlockSuite, + >(options: AutoScroll) { + return autoScrollForElements(options as OriginalAutoScrollOption); + } } diff --git a/blocksuite/framework/block-std/src/extension/dnd/types.ts b/blocksuite/framework/block-std/src/extension/dnd/types.ts index ce6fa08a3bdf2..04f2794fd4040 100644 --- a/blocksuite/framework/block-std/src/extension/dnd/types.ts +++ b/blocksuite/framework/block-std/src/extension/dnd/types.ts @@ -12,6 +12,7 @@ import type { DropTargetRecord, ElementDragType, } from '@atlaskit/pragmatic-drag-and-drop/types'; +import type { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element'; export type ElementDragEventBaseArgs = { /** @@ -111,3 +112,7 @@ export type OriginalDropTargetOption = Parameters< >[0]; export type OriginalMonitorOption = Parameters[0]; + +export type OriginalAutoScrollOption = Parameters< + typeof autoScrollForElements +>[0]; diff --git a/yarn.lock b/yarn.lock index 00423d47a884b..681371f03b917 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1210,6 +1210,16 @@ __metadata: languageName: node linkType: hard +"@atlaskit/pragmatic-drag-and-drop-auto-scroll@npm:^2.1.0": + version: 2.1.0 + resolution: "@atlaskit/pragmatic-drag-and-drop-auto-scroll@npm:2.1.0" + dependencies: + "@atlaskit/pragmatic-drag-and-drop": "npm:^1.4.0" + "@babel/runtime": "npm:^7.0.0" + checksum: 10/a137947d240b01414c8235d9b3a5c949456ef3877488abdbfa92c491631ade10dd7fd6b3dc5ca31077617067c44dd1e90b1f6d1049b71d05d7064db92bc7810b + languageName: node + linkType: hard + "@atlaskit/pragmatic-drag-and-drop-hitbox@npm:^1.0.3": version: 1.0.3 resolution: "@atlaskit/pragmatic-drag-and-drop-hitbox@npm:1.0.3" @@ -3813,6 +3823,7 @@ __metadata: resolution: "@blocksuite/block-std@workspace:blocksuite/framework/block-std" dependencies: "@atlaskit/pragmatic-drag-and-drop": "npm:^1.4.0" + "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "npm:^2.1.0" "@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3" "@blocksuite/global": "workspace:*" "@blocksuite/inline": "workspace:*"