refactor(editor): toc dragging with std.dnd (#9883)

Close [BS-2458](https://linear.app/affine-design/issue/BS-2458/toc-dnd重构)

### What Changes
- Refactor toc note card dnd with `std.dnd`
- Extract note display mode change to command `changeNoteDisplayMode`
  - It will reorder notes when the display mode changed from `EdgelessOnly` to page mode visible (a.k.a `DocOnly` or `Both`)
This commit is contained in:
L-Sun
2025-01-24 13:27:17 +00:00
parent 351816b343
commit 829980bace
17 changed files with 689 additions and 687 deletions

View File

@@ -0,0 +1,61 @@
import { NoteDisplayMode } from '@blocksuite/affine-model';
import { matchFlavours } from '@blocksuite/affine-shared/utils';
import type { Command } from '@blocksuite/block-std';
export const changeNoteDisplayMode: Command<
never,
never,
{ noteId: string; mode: NoteDisplayMode; stopCapture?: boolean }
> = (ctx, next) => {
const { std, noteId, mode, stopCapture } = ctx;
const noteBlockModel = std.store.getBlock(noteId)?.model;
if (!noteBlockModel || !matchFlavours(noteBlockModel, ['affine:note']))
return;
const currentMode = noteBlockModel.displayMode;
if (currentMode === mode) return;
if (stopCapture) std.store.captureSync();
// Update the order in the note list in its parent, for example
// 1. Both mode note | 1. Both mode note
// 2. Page mode note | 2. Page mode note
// ---------------------------- |-> 3. the changed note (Both or Page)
// 3. Edgeless mode note | ---------------------------
// 4. the changing edgeless note -| 4. Edgeless mode note
const parent = std.store.getParent(noteBlockModel);
if (parent) {
const notes = parent.children.filter(child =>
matchFlavours(child, ['affine:note'])
);
const firstEdgelessOnlyNote = notes.find(
note => note.displayMode === NoteDisplayMode.EdgelessOnly
);
const lastPageVisibleNote = notes.findLast(
note => note.displayMode !== NoteDisplayMode.EdgelessOnly
);
if (currentMode === NoteDisplayMode.EdgelessOnly) {
std.store.moveBlocks(
[noteBlockModel],
parent,
lastPageVisibleNote ?? firstEdgelessOnlyNote,
lastPageVisibleNote ? false : true
);
} else if (mode === NoteDisplayMode.EdgelessOnly) {
std.store.moveBlocks(
[noteBlockModel],
parent,
firstEdgelessOnlyNote ?? lastPageVisibleNote,
firstEdgelessOnlyNote ? true : false
);
}
}
std.store.updateBlock(noteBlockModel, {
displayMode: mode,
});
return next();
};

View File

@@ -8,6 +8,7 @@ import {
import type { BlockCommands } from '@blocksuite/block-std';
import { updateBlockType } from './block-type.js';
import { changeNoteDisplayMode } from './change-note-display-mode.js';
import { dedentBlock } from './dedent-block.js';
import { dedentBlockToRoot } from './dedent-block-to-root.js';
import { dedentBlocks } from './dedent-blocks.js';
@@ -37,4 +38,5 @@ export const commands: BlockCommands = {
dedentBlocks,
dedentBlockToRoot,
dedentBlocksToRoot,
changeNoteDisplayMode,
};

View File

@@ -2,6 +2,7 @@ import type { BlockComponent } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
import type { updateBlockType } from './commands/block-type';
import type { changeNoteDisplayMode } from './commands/change-note-display-mode';
import type { dedentBlock } from './commands/dedent-block';
import type { dedentBlockToRoot } from './commands/dedent-block-to-root';
import type { dedentBlocks } from './commands/dedent-blocks';
@@ -40,6 +41,7 @@ declare global {
indentBlock: typeof indentBlock;
updateBlockType: typeof updateBlockType;
dedentBlockToRoot: typeof dedentBlockToRoot;
changeNoteDisplayMode: typeof changeNoteDisplayMode;
}
interface CommandContext {
focusBlock?: BlockComponent | null;