@portabletext/editor 1.36.6 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +84 -49
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/behavior.markdown.cjs +1 -1
  4. package/lib/_chunks-cjs/editor-provider.cjs +919 -526
  5. package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
  6. package/lib/_chunks-cjs/{util.block-offsets-to-selection.cjs → parse-blocks.cjs} +36 -21
  7. package/lib/_chunks-cjs/parse-blocks.cjs.map +1 -0
  8. package/lib/_chunks-cjs/selector.get-text-before.cjs +2 -2
  9. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  10. package/lib/_chunks-cjs/{selector.is-active-style.cjs → selector.is-overlapping-selection.cjs} +144 -3
  11. package/lib/_chunks-cjs/selector.is-overlapping-selection.cjs.map +1 -0
  12. package/lib/_chunks-cjs/util.slice-blocks.cjs +12 -0
  13. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  14. package/lib/_chunks-es/behavior.core.js +84 -49
  15. package/lib/_chunks-es/behavior.core.js.map +1 -1
  16. package/lib/_chunks-es/behavior.markdown.js +1 -1
  17. package/lib/_chunks-es/editor-provider.js +911 -517
  18. package/lib/_chunks-es/editor-provider.js.map +1 -1
  19. package/lib/_chunks-es/{util.block-offsets-to-selection.js → parse-blocks.js} +37 -22
  20. package/lib/_chunks-es/parse-blocks.js.map +1 -0
  21. package/lib/_chunks-es/selector.get-text-before.js +1 -2
  22. package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
  23. package/lib/_chunks-es/{selector.is-active-style.js → selector.is-overlapping-selection.js} +146 -5
  24. package/lib/_chunks-es/selector.is-overlapping-selection.js.map +1 -0
  25. package/lib/_chunks-es/util.slice-blocks.js +12 -0
  26. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  27. package/lib/behaviors/index.d.cts +10535 -4689
  28. package/lib/behaviors/index.d.ts +10535 -4689
  29. package/lib/index.cjs +582 -209
  30. package/lib/index.cjs.map +1 -1
  31. package/lib/index.d.cts +5297 -1178
  32. package/lib/index.d.ts +5297 -1178
  33. package/lib/index.js +591 -213
  34. package/lib/index.js.map +1 -1
  35. package/lib/plugins/index.cjs +2 -2
  36. package/lib/plugins/index.cjs.map +1 -1
  37. package/lib/plugins/index.d.cts +5297 -1178
  38. package/lib/plugins/index.d.ts +5297 -1178
  39. package/lib/plugins/index.js +2 -2
  40. package/lib/selectors/index.cjs +21 -103
  41. package/lib/selectors/index.cjs.map +1 -1
  42. package/lib/selectors/index.d.cts +5313 -1178
  43. package/lib/selectors/index.d.ts +5313 -1178
  44. package/lib/selectors/index.js +13 -96
  45. package/lib/selectors/index.js.map +1 -1
  46. package/lib/utils/index.cjs +4 -4
  47. package/lib/utils/index.cjs.map +1 -1
  48. package/lib/utils/index.d.cts +5297 -1178
  49. package/lib/utils/index.d.ts +5297 -1178
  50. package/lib/utils/index.js +3 -4
  51. package/lib/utils/index.js.map +1 -1
  52. package/package.json +15 -14
  53. package/src/behavior-actions/behavior.action.blur.ts +8 -0
  54. package/src/behavior-actions/behavior.action.decorator.add.ts +2 -1
  55. package/src/behavior-actions/behavior.action.delete.backward.ts +7 -0
  56. package/src/behavior-actions/behavior.action.delete.block.ts +24 -0
  57. package/src/behavior-actions/behavior.action.delete.forward.ts +7 -0
  58. package/src/behavior-actions/behavior.action.delete.text.ts +2 -1
  59. package/src/behavior-actions/behavior.action.delete.ts +1 -3
  60. package/src/behavior-actions/behavior.action.deserialization.failure.ts +9 -0
  61. package/src/behavior-actions/behavior.action.deserialization.success.ts +16 -0
  62. package/src/behavior-actions/behavior.action.effect.ts +7 -0
  63. package/src/behavior-actions/behavior.action.focus.ts +8 -0
  64. package/src/behavior-actions/behavior.action.insert-blocks.ts +118 -74
  65. package/src/behavior-actions/behavior.action.insert-break.ts +1 -0
  66. package/src/behavior-actions/{behavior.action.insert-block-object.ts → behavior.action.insert.block-object.ts} +9 -14
  67. package/src/behavior-actions/behavior.action.insert.block.ts +247 -2
  68. package/src/behavior-actions/behavior.action.insert.text-block.ts +33 -0
  69. package/src/behavior-actions/behavior.action.insert.text.ts +7 -0
  70. package/src/behavior-actions/behavior.action.move.block-down.ts +48 -0
  71. package/src/behavior-actions/behavior.action.move.block-up.ts +53 -0
  72. package/src/behavior-actions/behavior.action.move.block.ts +16 -0
  73. package/src/behavior-actions/behavior.action.noop.ts +5 -0
  74. package/src/behavior-actions/behavior.action.select.next-block.ts +44 -0
  75. package/src/behavior-actions/behavior.action.select.previous-block.ts +48 -0
  76. package/src/behavior-actions/behavior.action.select.ts +15 -0
  77. package/src/behavior-actions/behavior.action.serialization.failure.ts +9 -0
  78. package/src/behavior-actions/behavior.action.serialization.success.ts +14 -0
  79. package/src/behavior-actions/behavior.actions.ts +54 -212
  80. package/src/behaviors/behavior.core.block-objects.ts +35 -6
  81. package/src/behaviors/behavior.core.insert-break.ts +1 -0
  82. package/src/behaviors/behavior.core.ts +2 -0
  83. package/src/behaviors/behavior.default.ts +241 -33
  84. package/src/behaviors/behavior.types.ts +138 -20
  85. package/src/converters/converter.portable-text.ts +5 -2
  86. package/src/converters/converter.text-html.serialize.test.ts +4 -4
  87. package/src/converters/converter.text-html.ts +5 -2
  88. package/src/converters/converter.text-plain.test.ts +6 -6
  89. package/src/converters/converter.text-plain.ts +5 -2
  90. package/src/converters/converter.types.ts +3 -3
  91. package/src/editor/Editable.tsx +403 -48
  92. package/src/editor/components/Element.tsx +133 -18
  93. package/src/editor/components/use-draggable.ts +34 -102
  94. package/src/editor/editor-machine.ts +66 -10
  95. package/src/editor/editor-selector.ts +2 -0
  96. package/src/editor/editor-snapshot.ts +17 -0
  97. package/src/editor/plugins/create-with-event-listeners.ts +6 -40
  98. package/src/internal-utils/create-test-snapshot.ts +2 -0
  99. package/src/internal-utils/event-position.ts +210 -0
  100. package/src/internal-utils/slate-utils.ts +56 -0
  101. package/src/internal-utils/weakMaps.ts +1 -15
  102. package/src/selectors/index.ts +2 -0
  103. package/src/selectors/selector.get-focus-inline-object.ts +21 -0
  104. package/src/selectors/selector.is-overlapping-selection.test.ts +171 -0
  105. package/src/selectors/selector.is-overlapping-selection.ts +108 -4
  106. package/src/selectors/selector.is-point-after-selection.ts +3 -1
  107. package/src/selectors/selector.is-point-before-selection.ts +3 -1
  108. package/src/selectors/selector.is-selecting-entire-blocks.ts +34 -0
  109. package/lib/_chunks-cjs/selector.is-active-style.cjs.map +0 -1
  110. package/lib/_chunks-cjs/util.block-offsets-to-selection.cjs.map +0 -1
  111. package/lib/_chunks-cjs/util.reverse-selection.cjs +0 -14
  112. package/lib/_chunks-cjs/util.reverse-selection.cjs.map +0 -1
  113. package/lib/_chunks-es/selector.is-active-style.js.map +0 -1
  114. package/lib/_chunks-es/util.block-offsets-to-selection.js.map +0 -1
  115. package/lib/_chunks-es/util.reverse-selection.js +0 -15
  116. package/lib/_chunks-es/util.reverse-selection.js.map +0 -1
  117. package/src/behavior-actions/behavior.action-utils.insert-block.ts +0 -61
  118. package/src/editor/__tests__/handleClick.test.tsx +0 -277
  119. package/src/editor/components/use-droppable.ts +0 -135
@@ -129,19 +129,7 @@ const raiseDeserializationSuccessOrFailure = defineBehavior({
129
129
  raise({
130
130
  ...deserializeEvent,
131
131
  dataTransfer: event.dataTransfer,
132
- }),
133
- ],
134
- ],
135
- })
136
-
137
- const raiseInsertBlocks = defineBehavior({
138
- on: 'deserialization.success',
139
- actions: [
140
- ({event}) => [
141
- raise({
142
- type: 'insert.blocks',
143
- blocks: event.data,
144
- placement: 'auto',
132
+ originEvent: event.originEvent,
145
133
  }),
146
134
  ],
147
135
  ],
@@ -155,7 +143,13 @@ const raiseSerializationSuccessOrFailure = defineBehavior({
155
143
  }
156
144
 
157
145
  const serializeEvents = snapshot.context.converters.map((converter) =>
158
- converter.serialize({snapshot, event}),
146
+ converter.serialize({
147
+ snapshot,
148
+ event: {
149
+ ...event,
150
+ originEvent: event.originEvent.type,
151
+ },
152
+ }),
159
153
  )
160
154
 
161
155
  if (serializeEvents.length === 0) {
@@ -166,30 +160,246 @@ const raiseSerializationSuccessOrFailure = defineBehavior({
166
160
  },
167
161
  actions: [
168
162
  ({event}, serializeEvents) =>
169
- serializeEvents.map((serializeEvent) =>
170
- raise({
163
+ serializeEvents.map((serializeEvent) => {
164
+ return raise({
171
165
  ...serializeEvent,
166
+ originEvent: event.originEvent,
172
167
  dataTransfer: event.dataTransfer,
173
- }),
174
- ),
175
- ],
176
- })
177
-
178
- const raiseDataTransferSet = defineBehavior({
179
- on: 'serialization.success',
180
- actions: [
181
- ({event}) => [
182
- raise({
183
- type: 'data transfer.set',
184
- data: event.data,
185
- dataTransfer: event.dataTransfer,
186
- mimeType: event.mimeType,
168
+ })
187
169
  }),
188
- ],
189
170
  ],
190
171
  })
191
172
 
192
173
  export const defaultBehaviors = [
174
+ defineBehavior({
175
+ on: 'copy',
176
+ guard: ({snapshot}) => {
177
+ const focusSpan = selectors.getFocusSpan(snapshot)
178
+ const selectionCollapsed = selectors.isSelectionCollapsed(snapshot)
179
+
180
+ return focusSpan && selectionCollapsed
181
+ },
182
+ actions: [() => [{type: 'noop'}]],
183
+ }),
184
+ defineBehavior({
185
+ on: 'copy',
186
+ actions: [
187
+ ({event}) => [
188
+ raise({
189
+ type: 'serialize',
190
+ dataTransfer: event.data,
191
+ originEvent: event,
192
+ }),
193
+ ],
194
+ ],
195
+ }),
196
+ defineBehavior({
197
+ on: 'cut',
198
+ guard: ({snapshot}) => {
199
+ const focusSpan = selectors.getFocusSpan(snapshot)
200
+ const selectionCollapsed = selectors.isSelectionCollapsed(snapshot)
201
+
202
+ return focusSpan && selectionCollapsed
203
+ },
204
+ actions: [() => [{type: 'noop'}]],
205
+ }),
206
+ defineBehavior({
207
+ on: 'cut',
208
+ guard: ({snapshot}) => {
209
+ return snapshot.context.selection
210
+ ? {
211
+ selection: snapshot.context.selection,
212
+ }
213
+ : false
214
+ },
215
+ actions: [
216
+ ({event}, {selection}) => [
217
+ raise({
218
+ type: 'serialize',
219
+ dataTransfer: event.dataTransfer,
220
+ originEvent: event,
221
+ }),
222
+ raise({
223
+ type: 'delete',
224
+ selection,
225
+ }),
226
+ ],
227
+ ],
228
+ }),
229
+ defineBehavior({
230
+ on: 'drag.dragstart',
231
+ actions: [
232
+ ({event}) => [
233
+ raise({
234
+ type: 'serialize',
235
+ dataTransfer: event.dataTransfer,
236
+ originEvent: event,
237
+ }),
238
+ ],
239
+ ],
240
+ }),
241
+ defineBehavior({
242
+ on: 'serialization.success',
243
+ actions: [
244
+ ({event}) => [
245
+ raise({
246
+ type: 'data transfer.set',
247
+ data: event.data,
248
+ dataTransfer: event.dataTransfer,
249
+ mimeType: event.mimeType,
250
+ }),
251
+ ],
252
+ ],
253
+ }),
254
+ defineBehavior({
255
+ on: 'drag.drop',
256
+ guard: ({snapshot, event}) => {
257
+ const dragOrigin = snapshot.beta.internalDrag?.origin
258
+ const dropPosition = event.position.selection
259
+ const droppingOnDragOrigin = dragOrigin
260
+ ? selectors.isOverlappingSelection(dropPosition)({
261
+ ...snapshot,
262
+ context: {
263
+ ...snapshot.context,
264
+ selection: dragOrigin.selection,
265
+ },
266
+ })
267
+ : false
268
+ return droppingOnDragOrigin
269
+ },
270
+ actions: [() => [{type: 'noop'}]],
271
+ }),
272
+ defineBehavior({
273
+ on: 'drag.drop',
274
+ actions: [
275
+ ({event}) => [
276
+ raise({
277
+ type: 'deserialize',
278
+ dataTransfer: event.dataTransfer,
279
+ originEvent: event,
280
+ }),
281
+ ],
282
+ ],
283
+ }),
284
+ defineBehavior({
285
+ on: 'deserialization.success',
286
+ guard: ({snapshot, event}) => {
287
+ if (
288
+ event.originEvent.type !== 'drag.drop' ||
289
+ snapshot.beta.internalDrag === undefined
290
+ ) {
291
+ return false
292
+ }
293
+
294
+ const dragOrigin = snapshot.beta.internalDrag.origin
295
+ const dropPosition = event.originEvent.position.selection
296
+ const droppingOnDragOrigin = dragOrigin
297
+ ? selectors.isOverlappingSelection(dropPosition)({
298
+ ...snapshot,
299
+ context: {
300
+ ...snapshot.context,
301
+ selection: dragOrigin.selection,
302
+ },
303
+ })
304
+ : false
305
+
306
+ const draggingEntireBlocks = selectors.isSelectingEntireBlocks({
307
+ ...snapshot,
308
+ context: {
309
+ ...snapshot.context,
310
+ selection: dragOrigin.selection,
311
+ },
312
+ })
313
+
314
+ const draggedBlocks = selectors.getSelectedBlocks({
315
+ ...snapshot,
316
+ context: {
317
+ ...snapshot.context,
318
+ selection: dragOrigin.selection,
319
+ },
320
+ })
321
+
322
+ if (!droppingOnDragOrigin) {
323
+ return {draggingEntireBlocks, draggedBlocks, dragOrigin}
324
+ }
325
+
326
+ return false
327
+ },
328
+ actions: [
329
+ ({event}, {draggingEntireBlocks, draggedBlocks, dragOrigin}) => [
330
+ raise({
331
+ type: 'insert.blocks',
332
+ blocks: event.data,
333
+ placement: draggingEntireBlocks
334
+ ? event.originEvent.position.block === 'start'
335
+ ? 'before'
336
+ : event.originEvent.position.block === 'end'
337
+ ? 'after'
338
+ : 'auto'
339
+ : 'auto',
340
+ }),
341
+ ...(draggingEntireBlocks
342
+ ? draggedBlocks.map((block) =>
343
+ raise({
344
+ type: 'delete.block',
345
+ blockPath: block.path,
346
+ }),
347
+ )
348
+ : [
349
+ raise({
350
+ type: 'delete',
351
+ selection: dragOrigin.selection,
352
+ }),
353
+ ]),
354
+ ],
355
+ ],
356
+ }),
357
+ defineBehavior({
358
+ on: 'deserialization.success',
359
+ actions: [
360
+ ({event}) => [
361
+ raise({
362
+ type: 'insert.blocks',
363
+ blocks: event.data,
364
+ placement: 'auto',
365
+ }),
366
+ ],
367
+ ],
368
+ }),
369
+ defineBehavior({
370
+ on: 'paste',
371
+ guard: ({snapshot}) => {
372
+ return snapshot.context.selection &&
373
+ selectors.isSelectionExpanded(snapshot)
374
+ ? {selection: snapshot.context.selection}
375
+ : false
376
+ },
377
+ actions: [
378
+ ({event}, {selection}) => [
379
+ raise({
380
+ type: 'delete',
381
+ selection,
382
+ }),
383
+ raise({
384
+ type: 'deserialize',
385
+ dataTransfer: event.data,
386
+ originEvent: event,
387
+ }),
388
+ ],
389
+ ],
390
+ }),
391
+ defineBehavior({
392
+ on: 'paste',
393
+ actions: [
394
+ ({event}) => [
395
+ raise({
396
+ type: 'deserialize',
397
+ dataTransfer: event.data,
398
+ originEvent: event,
399
+ }),
400
+ ],
401
+ ],
402
+ }),
193
403
  toggleAnnotationOff,
194
404
  toggleAnnotationOn,
195
405
  toggleDecoratorOff,
@@ -199,8 +409,6 @@ export const defaultBehaviors = [
199
409
  toggleStyleOff,
200
410
  toggleStyleOn,
201
411
  raiseDeserializationSuccessOrFailure,
202
- raiseInsertBlocks,
203
412
  raiseSerializationSuccessOrFailure,
204
- raiseDataTransferSet,
205
413
  raiseInsertSoftBreak,
206
414
  ]
@@ -7,6 +7,7 @@ import type {TextUnit} from 'slate'
7
7
  import type {TextInsertTextOptions} from 'slate/dist/interfaces/transforms/text'
8
8
  import type {ConverterEvent} from '../converters/converter.types'
9
9
  import type {EditorContext, EditorSnapshot} from '../editor/editor-snapshot'
10
+ import type {EventPosition} from '../internal-utils/event-position'
10
11
  import type {MIMEType} from '../internal-utils/mime-type'
11
12
  import type {OmitFromUnion, PickFromUnion} from '../type-utils'
12
13
  import type {BlockOffset} from '../types/block-offset'
@@ -101,11 +102,11 @@ export type SyntheticBehaviorEvent =
101
102
  | {
102
103
  type: 'insert.blocks'
103
104
  blocks: Array<PortableTextBlock>
104
- placement: 'auto' | 'after' | 'before'
105
+ placement: InsertPlacement
105
106
  }
106
107
  | {
107
108
  type: 'insert.block object'
108
- placement: 'auto' | 'after' | 'before'
109
+ placement: InsertPlacement
109
110
  blockObject: {
110
111
  name: string
111
112
  value?: {[prop: string]: unknown}
@@ -127,7 +128,8 @@ export type SyntheticBehaviorEvent =
127
128
  | {
128
129
  type: 'insert.block'
129
130
  block: PortableTextBlock
130
- placement: 'auto' | 'after' | 'before'
131
+ placement: InsertPlacement
132
+ select?: 'start' | 'end' | 'none'
131
133
  }
132
134
  | {
133
135
  type: 'insert.span'
@@ -145,7 +147,7 @@ export type SyntheticBehaviorEvent =
145
147
  }
146
148
  | {
147
149
  type: 'insert.text block'
148
- placement: 'auto' | 'after' | 'before'
150
+ placement: InsertPlacement
149
151
  textBlock?: {
150
152
  children?: PortableTextTextBlock['children']
151
153
  }
@@ -181,9 +183,11 @@ export type SyntheticBehaviorEvent =
181
183
  }
182
184
  | {
183
185
  type: 'select.previous block'
186
+ select?: 'start' | 'end'
184
187
  }
185
188
  | {
186
189
  type: 'select.next block'
190
+ select?: 'start' | 'end'
187
191
  }
188
192
  | {
189
193
  type: 'style.add'
@@ -200,11 +204,117 @@ export type SyntheticBehaviorEvent =
200
204
  | (PickFromUnion<
201
205
  ConverterEvent,
202
206
  'type',
203
- | 'deserialization.failure'
204
- | 'deserialization.success'
205
- | 'serialization.failure'
206
- | 'serialization.success'
207
- > & {dataTransfer: DataTransfer})
207
+ 'deserialization.failure' | 'deserialization.success'
208
+ > & {
209
+ dataTransfer: DataTransfer
210
+ originEvent: Omit<
211
+ PickFromUnion<NativeBehaviorEvent, 'type', 'drag.drop' | 'paste'>,
212
+ 'dataTransfer'
213
+ >
214
+ })
215
+ | {
216
+ type: 'serialization.success'
217
+ mimeType: MIMEType
218
+ data: string
219
+ dataTransfer: DataTransfer
220
+ originEvent: Omit<
221
+ PickFromUnion<
222
+ NativeBehaviorEvent,
223
+ 'type',
224
+ 'copy' | 'cut' | 'drag.dragstart'
225
+ >,
226
+ 'dataTransfer'
227
+ >
228
+ }
229
+ | {
230
+ type: 'serialization.failure'
231
+ mimeType: MIMEType
232
+ reason: string
233
+ dataTransfer: DataTransfer
234
+ originEvent: Omit<
235
+ PickFromUnion<
236
+ NativeBehaviorEvent,
237
+ 'type',
238
+ 'copy' | 'cut' | 'drag.dragstart'
239
+ >,
240
+ 'dataTransfer'
241
+ >
242
+ }
243
+
244
+ export type InsertPlacement = 'auto' | 'after' | 'before'
245
+
246
+ type DragBehaviorEvent =
247
+ | {
248
+ type: 'drag.dragstart'
249
+ dataTransfer: DataTransfer
250
+ position: EventPosition
251
+ }
252
+ | {
253
+ type: 'drag.drag'
254
+ dataTransfer: DataTransfer
255
+ }
256
+ | {
257
+ type: 'drag.dragend'
258
+ dataTransfer: DataTransfer
259
+ }
260
+ | {
261
+ type: 'drag.dragenter'
262
+ dataTransfer: DataTransfer
263
+ position: EventPosition
264
+ }
265
+ | {
266
+ type: 'drag.dragover'
267
+ dataTransfer: DataTransfer
268
+ position: EventPosition
269
+ }
270
+ | {
271
+ type: 'drag.drop'
272
+ dataTransfer: DataTransfer
273
+ position: EventPosition
274
+ }
275
+ | {
276
+ type: 'drag.dragleave'
277
+ dataTransfer: DataTransfer
278
+ }
279
+
280
+ export function isDragBehaviorEvent(
281
+ event: BehaviorEvent,
282
+ ): event is DragBehaviorEvent {
283
+ return event.type.startsWith('drag.')
284
+ }
285
+
286
+ export type DataBehaviorEvent =
287
+ | {
288
+ type: 'deserialize'
289
+ dataTransfer: DataTransfer
290
+ originEvent: Omit<
291
+ PickFromUnion<NativeBehaviorEvent, 'type', 'drag.drop' | 'paste'>,
292
+ 'dataTransfer'
293
+ >
294
+ }
295
+ | {
296
+ type: 'serialize'
297
+ dataTransfer: DataTransfer
298
+ originEvent: Omit<
299
+ PickFromUnion<
300
+ NativeBehaviorEvent,
301
+ 'type',
302
+ 'copy' | 'cut' | 'drag.dragstart'
303
+ >,
304
+ 'dataTransfer'
305
+ >
306
+ }
307
+
308
+ export type MouseBehaviorEvent = {
309
+ type: 'mouse.click'
310
+ position: EventPosition
311
+ }
312
+
313
+ export function isMouseBehaviorEvent(
314
+ event: BehaviorEvent,
315
+ ): event is MouseBehaviorEvent {
316
+ return event.type.startsWith('mouse.')
317
+ }
208
318
 
209
319
  /**
210
320
  * @beta
@@ -213,10 +323,12 @@ export type NativeBehaviorEvent =
213
323
  | {
214
324
  type: 'copy'
215
325
  data: DataTransfer
326
+ position: EventPosition
216
327
  }
217
328
  | {
218
- type: 'deserialize'
329
+ type: 'cut'
219
330
  dataTransfer: DataTransfer
331
+ position: EventPosition
220
332
  }
221
333
  | {
222
334
  type: 'key.down'
@@ -232,15 +344,13 @@ export type NativeBehaviorEvent =
232
344
  'key' | 'code' | 'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey'
233
345
  >
234
346
  }
347
+ | MouseBehaviorEvent
235
348
  | {
236
349
  type: 'paste'
237
350
  data: DataTransfer
351
+ position: EventPosition
238
352
  }
239
- | {
240
- type: 'serialize'
241
- originEvent: 'copy' | 'cut' | 'drag' | 'unknown'
242
- dataTransfer: DataTransfer
243
- }
353
+ | DragBehaviorEvent
244
354
 
245
355
  /**
246
356
  * @beta
@@ -266,7 +376,7 @@ export type BehaviorAction =
266
376
  | SyntheticBehaviorEvent
267
377
  | {
268
378
  type: 'raise'
269
- event: SyntheticBehaviorEvent | CustomBehaviorEvent
379
+ event: DataBehaviorEvent | SyntheticBehaviorEvent | CustomBehaviorEvent
270
380
  }
271
381
  | {
272
382
  type: 'noop'
@@ -288,7 +398,7 @@ export type InternalBehaviorAction = OmitFromUnion<
288
398
  * @beta
289
399
  */
290
400
  export function raise(
291
- event: SyntheticBehaviorEvent | CustomBehaviorEvent,
401
+ event: DataBehaviorEvent | SyntheticBehaviorEvent | CustomBehaviorEvent,
292
402
  ): PickFromUnion<BehaviorAction, 'type', 'raise'> {
293
403
  return {type: 'raise', event}
294
404
  }
@@ -298,9 +408,11 @@ export function raise(
298
408
  */
299
409
  export type BehaviorEvent =
300
410
  | SyntheticBehaviorEvent
411
+ | DataBehaviorEvent
301
412
  | NativeBehaviorEvent
302
413
  | CustomBehaviorEvent
303
414
  | {type: '*'}
415
+ | {type: 'drag.*'}
304
416
 
305
417
  /**
306
418
  * @beta
@@ -310,7 +422,9 @@ export type Behavior<
310
422
  TGuardResponse = true,
311
423
  TBehaviorEvent extends BehaviorEvent = TBehaviorEventType extends '*'
312
424
  ? BehaviorEvent
313
- : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>,
425
+ : TBehaviorEventType extends 'drag.*'
426
+ ? DragBehaviorEvent
427
+ : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>,
314
428
  > = {
315
429
  /**
316
430
  * The internal editor event that triggers this behavior.
@@ -388,7 +502,9 @@ export function defineBehavior<
388
502
  ? CustomBehaviorEvent<TPayload, TType>
389
503
  : TBehaviorEventType extends '*'
390
504
  ? OmitFromUnion<BehaviorEvent, 'type', '*'>
391
- : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>
505
+ : TBehaviorEventType extends `drag.*`
506
+ ? DragBehaviorEvent
507
+ : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>
392
508
  >,
393
509
  ): Behavior
394
510
  export function defineBehavior<
@@ -400,7 +516,9 @@ export function defineBehavior<
400
516
  ? CustomBehaviorEvent<TPayload, TType>
401
517
  : TBehaviorEventType extends '*'
402
518
  ? OmitFromUnion<BehaviorEvent, 'type', '*'>
403
- : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>,
519
+ : TBehaviorEventType extends `drag.*`
520
+ ? DragBehaviorEvent
521
+ : PickFromUnion<BehaviorEvent, 'type', TBehaviorEventType>,
404
522
  >(
405
523
  behavior: Behavior<TBehaviorEventType, TGuardResponse, TBehaviorEvent>,
406
524
  ): Behavior {
@@ -5,7 +5,10 @@ import {defineConverter} from './converter.types'
5
5
  export const converterPortableText = defineConverter({
6
6
  mimeType: 'application/x-portable-text',
7
7
  serialize: ({snapshot, event}) => {
8
- if (!snapshot.context.selection) {
8
+ const selection =
9
+ snapshot.beta.internalDrag?.origin.selection ?? snapshot.context.selection
10
+
11
+ if (!selection) {
9
12
  return {
10
13
  type: 'serialization.failure',
11
14
  mimeType: 'application/x-portable-text',
@@ -16,7 +19,7 @@ export const converterPortableText = defineConverter({
16
19
 
17
20
  const blocks = sliceBlocks({
18
21
  blocks: snapshot.context.value,
19
- selection: snapshot.context.selection,
22
+ selection,
20
23
  })
21
24
 
22
25
  return {
@@ -110,7 +110,7 @@ describe(converterTextHtml.serialize.name, () => {
110
110
  }),
111
111
  event: {
112
112
  type: 'serialize',
113
- originEvent: 'unknown',
113
+ originEvent: 'copy',
114
114
  },
115
115
  }),
116
116
  ).toMatchObject({
@@ -133,7 +133,7 @@ describe(converterTextHtml.serialize.name, () => {
133
133
  }),
134
134
  event: {
135
135
  type: 'serialize',
136
- originEvent: 'unknown',
136
+ originEvent: 'copy',
137
137
  },
138
138
  }),
139
139
  ).toMatchObject({
@@ -164,7 +164,7 @@ describe(converterTextHtml.serialize.name, () => {
164
164
  }),
165
165
  event: {
166
166
  type: 'serialize',
167
- originEvent: 'unknown',
167
+ originEvent: 'copy',
168
168
  },
169
169
  }),
170
170
  ).toMatchObject({
@@ -222,7 +222,7 @@ describe(converterTextHtml.serialize.name, () => {
222
222
  }),
223
223
  event: {
224
224
  type: 'serialize',
225
- originEvent: 'unknown',
225
+ originEvent: 'copy',
226
226
  },
227
227
  }),
228
228
  ).toMatchObject({
@@ -7,7 +7,10 @@ import {defineConverter} from './converter.types'
7
7
  export const converterTextHtml = defineConverter({
8
8
  mimeType: 'text/html',
9
9
  serialize: ({snapshot, event}) => {
10
- if (!snapshot.context.selection) {
10
+ const selection =
11
+ snapshot.beta.internalDrag?.origin.selection ?? snapshot.context.selection
12
+
13
+ if (!selection) {
11
14
  return {
12
15
  type: 'serialization.failure',
13
16
  mimeType: 'text/html',
@@ -18,7 +21,7 @@ export const converterTextHtml = defineConverter({
18
21
 
19
22
  const blocks = sliceBlocks({
20
23
  blocks: snapshot.context.value,
21
- selection: snapshot.context.selection,
24
+ selection,
22
25
  })
23
26
 
24
27
  const html = toHTML(blocks, {
@@ -100,7 +100,7 @@ test(converterTextPlain.serialize.name, () => {
100
100
  }),
101
101
  event: {
102
102
  type: 'serialize',
103
- originEvent: 'unknown',
103
+ originEvent: 'copy',
104
104
  },
105
105
  }),
106
106
  ).toMatchObject({
@@ -124,7 +124,7 @@ test(converterTextPlain.serialize.name, () => {
124
124
  }),
125
125
  event: {
126
126
  type: 'serialize',
127
- originEvent: 'unknown',
127
+ originEvent: 'copy',
128
128
  },
129
129
  }),
130
130
  ).toMatchObject({
@@ -148,7 +148,7 @@ test(converterTextPlain.serialize.name, () => {
148
148
  }),
149
149
  event: {
150
150
  type: 'serialize',
151
- originEvent: 'unknown',
151
+ originEvent: 'copy',
152
152
  },
153
153
  }),
154
154
  ).toMatchObject({
@@ -178,7 +178,7 @@ test(converterTextPlain.serialize.name, () => {
178
178
  }),
179
179
  event: {
180
180
  type: 'serialize',
181
- originEvent: 'unknown',
181
+ originEvent: 'copy',
182
182
  },
183
183
  }),
184
184
  ).toMatchObject({
@@ -202,7 +202,7 @@ test(converterTextPlain.serialize.name, () => {
202
202
  }),
203
203
  event: {
204
204
  type: 'serialize',
205
- originEvent: 'unknown',
205
+ originEvent: 'copy',
206
206
  },
207
207
  }),
208
208
  ).toMatchObject({
@@ -232,7 +232,7 @@ test(converterTextPlain.serialize.name, () => {
232
232
  }),
233
233
  event: {
234
234
  type: 'serialize',
235
- originEvent: 'unknown',
235
+ originEvent: 'copy',
236
236
  },
237
237
  }),
238
238
  ).toMatchObject({