refactor: rewrite blocksuite dnd (#9595)

### Changed

- Refactored BlockSuite drag-and-drop using @atlaskit/pragmatic-drag-and-drop/element/adapter.
- Updated block dragging to use the new drag-and-drop infrastructure.

### BlockSuite DND API

Access the BlockSuite drag-and-drop API via `std.dnd`. This is a lightweight wrapper around pragmatic-drag-and-drop, offering convenient generic types and more intuitive option names.

#### Drag payload structure
There's some constrain about drag payload. The whole drag payload looks like this:

```typescript
type DragPayload = {
  entity: {
    type: string
  },
  from: {
    at: 'blocksuite',
    docId: string
  }
}
```
- The `from` field is auto-generated—no need for manual handling.
- The `entity` field is customizable, but it must include a `type`.

All drag-and-drop methods accept a generic type for entity, ensuring more accurate payloads in event handlers.

```typescript
type BlockEntity = {
  type: 'blocks',
  blockIds: string[]
}

dnd.draggable<BlockEntity>({
  element: someElement,
  setDragData: () => {
    // the return type must satisfy the generic type
    // in this case, it's BlockEntity
    return {
      type: 'blocks',
      blockIds: []
    }
  }
});

dnd.monitor<BlockEntity>({
  // the arguments is same for other event handler
  onDrag({ source }) {
    // the type of this is BlockEntity
    source.data.entity
  }
})
```

#### Drop payload
When hover on droppable target. You can set drop payload as well. All drag-and-drop methods accept a second generic type for drop payload.

The drop payload is customizable. Additionally, the DND system will add an `edge` field to the final payload object, indicating the nearest edge of the drop target relative to the current drag position.

```typescript
type DropPayload = {
  blockId: string;
}

dnd.dropTarget<BlockEntity, DropPayload>({
  getData() {
    // the type should be DropPayload
    return {
      blockId: 'someId'
    }
  }
});

dnd.monitor<BlockEntity, DropPayload>({
  // drag over on drop target
  onDrag({ location }) {
    const target = location.current.dropTargets[0];

    // the type is DropPayload
    target.data;
    // retrieve the nearest edge of the drop target relative to the current drop position.
    target.data.edge;
  }
})
```
This commit is contained in:
doouding
2025-01-16 12:36:58 +00:00
parent 3828144849
commit 99717196c5
30 changed files with 1207 additions and 561 deletions
+14 -1
View File
@@ -270,7 +270,7 @@ __metadata:
"@affine/electron-api": "workspace:*"
"@affine/graphql": "workspace:*"
"@affine/i18n": "workspace:*"
"@atlaskit/pragmatic-drag-and-drop": "patch:@atlaskit/pragmatic-drag-and-drop@npm%3A1.4.0#~/.yarn/patches/@atlaskit-pragmatic-drag-and-drop-npm-1.4.0-75c45f52d3.patch"
"@atlaskit/pragmatic-drag-and-drop": "npm:^1.4.0"
"@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3"
"@blocksuite/affine": "workspace:*"
"@blocksuite/icons": "npm:2.2.2"
@@ -1217,6 +1217,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"
@@ -3833,6 +3843,9 @@ __metadata:
version: 0.0.0-use.local
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:*"
"@blocksuite/store": "workspace:*"