1
1
import {
2
2
type ExternalGetDataFeedbackArgs ,
3
3
type fromExternalData ,
4
+ monitorForElements ,
5
+ type MonitorGetFeedback ,
4
6
type toExternalData ,
5
7
} from '@affine/component' ;
6
8
import { createPageModeSpecs } from '@affine/core/components/blocksuite/block-suite-editor/specs/page' ;
7
9
import type { AffineDNDData } from '@affine/core/types/dnd' ;
8
10
import { BlockStdScope } from '@blocksuite/affine/block-std' ;
9
- import { DndApiExtensionIdentifier } from '@blocksuite/affine/blocks' ;
11
+ import {
12
+ DndApiExtensionIdentifier ,
13
+ type DragBlockPayload ,
14
+ } from '@blocksuite/affine/blocks' ;
10
15
import { type SliceSnapshot } from '@blocksuite/affine/store' ;
11
16
import { Service } from '@toeverything/infra' ;
12
17
@@ -19,6 +24,10 @@ type EntityResolver = (data: string) => Entity | null;
19
24
20
25
type ExternalDragPayload = ExternalGetDataFeedbackArgs [ 'source' ] ;
21
26
27
+ type MixedDNDData = AffineDNDData & {
28
+ draggable : DragBlockPayload ;
29
+ } ;
30
+
22
31
export class DndService extends Service {
23
32
constructor (
24
33
private readonly docsService : DocsService ,
@@ -53,6 +62,90 @@ export class DndService extends Service {
53
62
return null ;
54
63
} ) ;
55
64
} ) ;
65
+
66
+ this . setupBlocksuiteAdapter ( ) ;
67
+ }
68
+
69
+ private setupBlocksuiteAdapter ( ) {
70
+ /**
71
+ * Migrate from affine to blocksuite
72
+ * For now, we only support doc
73
+ */
74
+ const affineToBlocksuite = ( args : MonitorGetFeedback < MixedDNDData > ) => {
75
+ const data = args . source . data ;
76
+ if ( data . entity && ! data . bsEntity ) {
77
+ if ( data . entity . type !== 'doc' ) {
78
+ return ;
79
+ }
80
+ const dndAPI = this . getBlocksuiteDndAPI ( ) ;
81
+ if ( ! dndAPI ) {
82
+ return ;
83
+ }
84
+ const snapshotSlice = dndAPI . fromEntity ( {
85
+ docId : data . entity . id ,
86
+ flavour : 'affine:embed-linked-doc' ,
87
+ } ) ;
88
+ if ( ! snapshotSlice ) {
89
+ return ;
90
+ }
91
+ data . bsEntity = {
92
+ type : 'blocks' ,
93
+ modelIds : [ ] ,
94
+ snapshot : snapshotSlice ,
95
+ } ;
96
+ }
97
+ } ;
98
+
99
+ /**
100
+ * Migrate from blocksuite to affine
101
+ */
102
+ const blocksuiteToAffine = ( args : MonitorGetFeedback < MixedDNDData > ) => {
103
+ const data = args . source . data ;
104
+ if ( ! data . entity && data . bsEntity ) {
105
+ if ( data . bsEntity . type !== 'blocks' || ! data . bsEntity . snapshot ) {
106
+ return ;
107
+ }
108
+ const dndAPI = this . getBlocksuiteDndAPI ( ) ;
109
+ if ( ! dndAPI ) {
110
+ return ;
111
+ }
112
+ const entity = this . resolveBlockSnapshot ( data . bsEntity . snapshot ) ;
113
+ if ( ! entity ) {
114
+ return ;
115
+ }
116
+ data . entity = entity ;
117
+ }
118
+ } ;
119
+
120
+ function adaptDragEvent ( args : MonitorGetFeedback < MixedDNDData > ) {
121
+ affineToBlocksuite ( args ) ;
122
+ blocksuiteToAffine ( args ) ;
123
+ }
124
+
125
+ function canMonitor ( args : MonitorGetFeedback < MixedDNDData > ) {
126
+ return (
127
+ args . source . data . entity ?. type === 'doc' ||
128
+ ( args . source . data . bsEntity ?. type === 'blocks' &&
129
+ ! ! args . source . data . bsEntity . snapshot )
130
+ ) ;
131
+ }
132
+
133
+ this . disposables . push (
134
+ monitorForElements ( {
135
+ canMonitor : ( args : MonitorGetFeedback < MixedDNDData > ) => {
136
+ if ( canMonitor ( args ) ) {
137
+ // HACK ahead:
138
+ // canMonitor shall be used a pure function, which means
139
+ // we may need to adapt the drag event to make sure the data is applied onDragStart.
140
+ // However, canMonitor in blocksuite is also called BEFORE onDragStart,
141
+ // so we need to adapt it here in onMonitor
142
+ adaptDragEvent ( args ) ;
143
+ return true ;
144
+ }
145
+ return false ;
146
+ } ,
147
+ } )
148
+ ) ;
56
149
}
57
150
58
151
private readonly resolvers : ( (
@@ -161,6 +254,9 @@ export class DndService extends Service {
161
254
return null ;
162
255
} ;
163
256
257
+ /**
258
+ * @deprecated Blocksuite DND is now using pragmatic-dnd as well
259
+ */
164
260
private readonly resolveBlocksuiteExternalData = (
165
261
source : ExternalDragPayload
166
262
) : AffineDNDData [ 'draggable' ] | null => {
0 commit comments