Skip to content

Commit

Permalink
refactor(editor): extract drag handle widget (#9415)
Browse files Browse the repository at this point in the history
  • Loading branch information
Saul-Mirone committed Dec 29, 2024
1 parent b96a03b commit cec4a4b
Show file tree
Hide file tree
Showing 47 changed files with 277 additions and 92 deletions.
2 changes: 2 additions & 0 deletions blocksuite/affine/block-surface/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export const ZOOM_WHEEL_STEP = 0.1;
export const GRID_SIZE = 3000;
export const GRID_GAP_MIN = 10;
export const GRID_GAP_MAX = 50;
export const DEFAULT_NOTE_OFFSET_X = 30;
export const DEFAULT_NOTE_OFFSET_Y = 40;

// TODO: need to check the default central area ratio
export const DEFAULT_CENTRAL_AREA_RATIO = 0.3;
Expand Down
7 changes: 6 additions & 1 deletion blocksuite/affine/block-surface/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,12 @@ import {
tryMoveNode,
} from './utils/mindmap/utils';
export * from './extensions';
export { getLastPropsKey, getSurfaceBlock } from './utils';
export {
addNote,
addNoteAtPoint,
getLastPropsKey,
getSurfaceBlock,
} from './utils';
export type { Options } from './utils/rough/core';
export { sortIndex } from './utils/sort';
export { updateXYWH } from './utils/update-xywh.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
import { focusTextModel } from '@blocksuite/affine-components/rich-text';
import {
DEFAULT_NOTE_HEIGHT,
Expand All @@ -18,7 +17,8 @@ import {
serializeXYWH,
} from '@blocksuite/global/utils';

import { DEFAULT_NOTE_OFFSET_X, DEFAULT_NOTE_OFFSET_Y } from './consts.js';
import { DEFAULT_NOTE_OFFSET_X, DEFAULT_NOTE_OFFSET_Y } from '../consts';
import { EdgelessCRUDIdentifier } from '../extensions/crud-extension';

export function addNoteAtPoint(
std: BlockStdScope,
Expand Down Expand Up @@ -96,7 +96,7 @@ export function addNote(
const doc = std.doc;

const blockId = doc.addBlock(
options.childFlavour,
options.childFlavour as BlockSuite.Flavour,
{ type: options.childType },
noteId
);
Expand All @@ -107,7 +107,10 @@ export function addNote(
note.edgeless.collapsedHeight = height;
});
}
gfx.tool.setTool('default');
gfx.tool.setTool(
// @ts-expect-error FIXME: resolve after gfx tool refactor
'default'
);

// Wait for edgelessTool updated
requestAnimationFrame(() => {
Expand Down
1 change: 1 addition & 0 deletions blocksuite/affine/block-surface/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ export function normalizeWheelDeltaY(delta: number, zoom = 1) {
return newZoom;
}

export { addNote, addNoteAtPoint } from './add-note';
export { getLastPropsKey } from './get-last-props-key';
export { getSurfaceBlock } from './get-surface-block';
27 changes: 14 additions & 13 deletions blocksuite/affine/shared/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
export * from './doc-display-meta-service.js';
export * from './doc-mode-service.js';
export * from './drag-handle-config.js';
export * from './edit-props-store.js';
export * from './editor-setting-service.js';
export * from './embed-option-service.js';
export * from './font-loader/index.js';
export * from './generate-url-service.js';
export * from './notification-service.js';
export * from './parse-url-service.js';
export * from './quick-search-service.js';
export * from './telemetry-service/index.js';
export * from './theme-service.js';
export * from './doc-display-meta-service';
export * from './doc-mode-service';
export * from './drag-handle-config';
export * from './edit-props-store';
export * from './editor-setting-service';
export * from './embed-option-service';
export * from './font-loader';
export * from './generate-url-service';
export * from './notification-service';
export * from './page-viewport-service';
export * from './parse-url-service';
export * from './quick-search-service';
export * from './telemetry-service';
export * from './theme-service';
15 changes: 15 additions & 0 deletions blocksuite/affine/shared/src/services/page-viewport-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { ExtensionType } from '@blocksuite/block-std';
import { createIdentifier } from '@blocksuite/global/di';
import { Slot } from '@blocksuite/store';

import type { Viewport } from '../types';

export const PageViewportService = createIdentifier<Slot<Viewport>>(
'PageViewportService'
);

export const PageViewportServiceExtension: ExtensionType = {
setup: di => {
di.addImpl(PageViewportService, () => new Slot<Viewport>());
},
};
41 changes: 21 additions & 20 deletions blocksuite/affine/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
export * from './button-popper.js';
export * from './collapsed/index.js';
export * from './dnd/index.js';
export * from './dom/index.js';
export * from './edgeless.js';
export * from './event.js';
export * from './file/index.js';
export * from './insert.js';
export * from './is-abort-error.js';
export * from './math.js';
export * from './model/index.js';
export * from './print-to-pdf.js';
export * from './reference.js';
export * from './reordering.js';
export * from './signal.js';
export * from './spec/index.js';
export * from './string.js';
export * from './title.js';
export * from './url.js';
export * from './zod-schema.js';
export * from './auto-scroll';
export * from './button-popper';
export * from './collapsed';
export * from './dnd';
export * from './dom';
export * from './edgeless';
export * from './event';
export * from './file';
export * from './insert';
export * from './is-abort-error';
export * from './math';
export * from './model';
export * from './print-to-pdf';
export * from './reference';
export * from './reordering';
export * from './signal';
export * from './spec';
export * from './string';
export * from './title';
export * from './url';
export * from './zod-schema';
47 changes: 47 additions & 0 deletions blocksuite/affine/widget-drag-handle/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@blocksuite/affine-widget-drag-handle",
"description": "Drag handle for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc",
"test:unit": "nx vite:test --run --passWithNoTests",
"test:unit:coverage": "nx vite:test --run --coverage",
"test:e2e": "playwright test"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-list": "workspace:*",
"@blocksuite/affine-block-note": "workspace:*",
"@blocksuite/affine-block-paragraph": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.1.75",
"@blocksuite/inline": "workspace:*",
"@blocksuite/store": "workspace:*",
"@floating-ui/dom": "^1.6.10",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.1",
"lit": "^3.2.0",
"minimatch": "^10.0.1",
"zod": "^3.23.8"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.19.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
import type { RootBlockModel } from '@blocksuite/affine-model';
import { DocModeProvider } from '@blocksuite/affine-shared/services';
import {
autoScroll,
calcDropTarget,
type DroppingType,
type DropResult,
Expand All @@ -24,7 +25,6 @@ import { html } from 'lit';
import { query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';

import { autoScroll } from '../../../root-block/text-selection/utils.js';
import type { DragPreview } from './components/drag-preview.js';
import type { DropIndicator } from './components/drop-indicator.js';
import type { AFFINE_DRAG_HANDLE_WIDGET } from './consts.js';
Expand Down Expand Up @@ -75,7 +75,9 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
const blockId = closestBlock.model.id;
const model = closestBlock.model;

const isDatabase = matchFlavours(model, ['affine:database']);
const isDatabase = matchFlavours(model, [
'affine:database' as BlockSuite.Flavour,
]);
if (isDatabase) return null;

// note block can only be dropped into another note block
Expand Down
10 changes: 10 additions & 0 deletions blocksuite/affine/widget-drag-handle/src/effects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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);
}
7 changes: 7 additions & 0 deletions blocksuite/affine/widget-drag-handle/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type * as SurfaceEffects from '@blocksuite/affine-block-surface/effects';

declare type _GLOBAL_ = typeof SurfaceEffects;

export * from './consts';
export * from './drag-handle';
export * from './utils';
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ export const getDropResult = (

const model = closestBlock.model;

const isDatabase = matchFlavours(model, ['affine:database']);
const isDatabase = matchFlavours(model, [
'affine:database' as BlockSuite.Flavour,
]);
if (isDatabase) {
return dropIndicator;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
import {
addNoteAtPoint,
getSurfaceBlock,
} from '@blocksuite/affine-block-surface';
import type { EmbedCardStyle, NoteBlockModel } from '@blocksuite/affine-model';
import {
EMBED_CARD_HEIGHT,
Expand Down Expand Up @@ -28,8 +32,6 @@ import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
import { Bound, Point } from '@blocksuite/global/utils';
import { Job, Slice, type SliceSnapshot } from '@blocksuite/store';

import type { EdgelessRootBlockComponent } from '../../../edgeless/index.js';
import { addNoteAtPoint } from '../../../edgeless/utils/common.js';
import { DropIndicator } from '../components/drop-indicator.js';
import { AFFINE_DRAG_HANDLE_WIDGET } from '../consts.js';
import type { AffineDragHandleWidget } from '../drag-handle.js';
Expand All @@ -39,16 +41,19 @@ import { surfaceRefToEmbed } from '../middleware/surface-ref-to-embed.js';
import { containBlock, includeTextSelection } from '../utils.js';

export class DragEventWatcher {
private get _gfx() {
return this.widget.std.get(GfxControllerIdentifier);
}

private readonly _computeEdgelessBound = (
x: number,
y: number,
width: number,
height: number
) => {
const controller = this._std.get(GfxControllerIdentifier);
const border = 2;
const noteScale = this.widget.noteScale.peek();
const { viewport } = controller;
const { viewport } = this._gfx;
const { left: viewportLeft, top: viewportTop } = viewport;
const currentViewBound = new Bound(
x - viewportLeft,
Expand Down Expand Up @@ -335,10 +340,9 @@ export class DragEventWatcher {
const state = context.get('dndState');
// If drop a note, should do nothing
const snapshot = this._deserializeSnapshot(state);
const edgelessRoot = this.widget
.rootComponent as EdgelessRootBlockComponent;
const surfaceBlockModel = getSurfaceBlock(this.widget.doc);

if (!snapshot) {
if (!snapshot || !surfaceBlockModel) {
return;
}

Expand All @@ -358,7 +362,7 @@ export class DragEventWatcher {
const std = this._std;
const job = this._getJob();
job
.snapshotToSlice(snapshot, std.doc, edgelessRoot.surfaceBlockModel.id)
.snapshotToSlice(snapshot, std.doc, surfaceBlockModel.id)
.catch(console.error);
};

Expand Down Expand Up @@ -404,9 +408,9 @@ export class DragEventWatcher {
}
}

const { left: viewportLeft, top: viewportTop } = edgelessRoot.viewport;
const { left: viewportLeft, top: viewportTop } = this._gfx.viewport;
const newNoteId = addNoteAtPoint(
edgelessRoot.std,
this._std,
new Point(state.raw.x - viewportLeft, state.raw.y - viewportTop),
{
scale: this.widget.noteScale.peek(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class EdgelessWatcher {
private readonly _handleEdgelessToolUpdated = (
newTool: GfxToolsFullOptionValue
) => {
// @ts-expect-error FIXME: resolve after gfx tool refactor
if (newTool.type === 'default') {
this.checkTopLevelBlockSelection();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { PageViewportService } from '@blocksuite/affine-shared/services';
import { getScrollContainer } from '@blocksuite/affine-shared/utils';

import type { PageRootBlockComponent } from '../../../page/page-root-block.js';
import type { AffineDragHandleWidget } from '../drag-handle.js';

export class PageWatcher {
get pageRoot() {
return this.widget.rootComponent as PageRootBlockComponent;
get pageViewportService() {
return this.widget.std.get(PageViewportService);
}

constructor(readonly widget: AffineDragHandleWidget) {}

watch() {
const { pageRoot } = this;
const { disposables } = this.widget;
const scrollContainer = getScrollContainer(pageRoot);
const scrollContainer = getScrollContainer(this.widget.rootComponent);

disposables.add(
this.widget.doc.slots.blockUpdated.on(() => this.widget.hide())
);

disposables.add(
pageRoot.slots.viewportUpdated.on(() => {
this.pageViewportService.on(() => {
this.widget.hide();
if (this.widget.dropIndicator) {
this.widget.dropIndicator.rect = null;
Expand Down
Loading

0 comments on commit cec4a4b

Please sign in to comment.