@portabletext/editor 1.51.0 → 1.52.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.
- package/lib/_chunks-es/selector.is-selection-expanded.js +1 -1
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +26 -5
- package/lib/behaviors/index.d.ts +26 -5
- package/lib/behaviors/index.js.map +1 -1
- package/lib/index.cjs +434 -309
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +360 -31
- package/lib/index.d.ts +360 -31
- package/lib/index.js +455 -330
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +26 -5
- package/lib/plugins/index.d.ts +26 -5
- package/lib/selectors/index.d.cts +0 -14
- package/lib/selectors/index.d.ts +0 -14
- package/lib/utils/index.d.cts +0 -14
- package/lib/utils/index.d.ts +0 -14
- package/package.json +3 -3
- package/src/behaviors/behavior.abstract.delete.ts +0 -1
- package/src/behaviors/behavior.abstract.ts +0 -113
- package/src/behaviors/behavior.core.block-element.ts +9 -3
- package/src/behaviors/behavior.core.dnd.ts +328 -1
- package/src/behaviors/behavior.perform-event.ts +10 -0
- package/src/behaviors/behavior.types.action.ts +2 -0
- package/src/behaviors/behavior.types.event.ts +4 -0
- package/src/behaviors/behavior.types.guard.ts +2 -0
- package/src/converters/converter.portable-text.ts +2 -7
- package/src/converters/converter.text-html.ts +1 -3
- package/src/converters/converter.text-plain.ts +3 -5
- package/src/editor/Editable.tsx +6 -133
- package/src/editor/editor-machine.ts +15 -8
- package/src/editor/editor-selector.ts +0 -1
- package/src/editor/editor-snapshot.ts +0 -13
- package/src/internal-utils/create-test-snapshot.ts +0 -1
- package/src/internal-utils/event-position.ts +41 -27
- package/src/internal-utils/selection-elements.ts +108 -0
- package/src/operations/behavior.operation.decorator.add.ts +0 -1
package/src/editor/Editable.tsx
CHANGED
|
@@ -23,18 +23,14 @@ import {
|
|
|
23
23
|
type RenderElementProps,
|
|
24
24
|
type RenderLeafProps,
|
|
25
25
|
} from 'slate-react'
|
|
26
|
-
import {getCompoundClientRect} from '../internal-utils/compound-client-rect'
|
|
27
26
|
import {debugWithName} from '../internal-utils/debug'
|
|
28
|
-
import {getDragSelection} from '../internal-utils/drag-selection'
|
|
29
27
|
import {getEventPosition} from '../internal-utils/event-position'
|
|
30
28
|
import {parseBlocks} from '../internal-utils/parse-blocks'
|
|
31
29
|
import {toSlateRange} from '../internal-utils/ranges'
|
|
32
30
|
import {normalizeSelection} from '../internal-utils/selection'
|
|
33
|
-
import {getSelectionDomNodes} from '../internal-utils/selection-elements'
|
|
34
31
|
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
35
32
|
import {fromSlateValue} from '../internal-utils/values'
|
|
36
33
|
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
37
|
-
import * as selectors from '../selectors'
|
|
38
34
|
import type {
|
|
39
35
|
EditorSelection,
|
|
40
36
|
OnCopyFn,
|
|
@@ -50,13 +46,10 @@ import type {
|
|
|
50
46
|
ScrollSelectionIntoViewFunction,
|
|
51
47
|
} from '../types/editor'
|
|
52
48
|
import type {HotkeyOptions} from '../types/options'
|
|
53
|
-
import {isSelectionCollapsed} from '../utils'
|
|
54
|
-
import {getSelectionEndPoint} from '../utils/util.get-selection-end-point'
|
|
55
49
|
import {RenderElement} from './components/render-element'
|
|
56
50
|
import {RenderLeaf} from './components/render-leaf'
|
|
57
51
|
import {RenderText, type RenderTextProps} from './components/render-text'
|
|
58
52
|
import {EditorActorContext} from './editor-actor-context'
|
|
59
|
-
import {getEditorSnapshot} from './editor-selector'
|
|
60
53
|
import {usePortableTextEditor} from './hooks/usePortableTextEditor'
|
|
61
54
|
import {createWithHotkeys} from './plugins/createWithHotKeys'
|
|
62
55
|
import {PortableTextEditor} from './PortableTextEditor'
|
|
@@ -811,131 +804,9 @@ export const PortableTextEditable = forwardRef<
|
|
|
811
804
|
return
|
|
812
805
|
}
|
|
813
806
|
|
|
814
|
-
const snapshot = getEditorSnapshot({
|
|
815
|
-
editorActorSnapshot: editorActor.getSnapshot(),
|
|
816
|
-
slateEditorInstance: slateEditor,
|
|
817
|
-
})
|
|
818
|
-
const dragSelection = getDragSelection({
|
|
819
|
-
eventSelection: position.selection,
|
|
820
|
-
snapshot,
|
|
821
|
-
})
|
|
822
|
-
|
|
823
|
-
const selectingEntireBlocks = selectors.isSelectingEntireBlocks({
|
|
824
|
-
...snapshot,
|
|
825
|
-
context: {
|
|
826
|
-
...snapshot.context,
|
|
827
|
-
selection: dragSelection,
|
|
828
|
-
},
|
|
829
|
-
})
|
|
830
|
-
|
|
831
|
-
const dragGhost = document.createElement('div')
|
|
832
|
-
|
|
833
|
-
const draggedDomNodes = getSelectionDomNodes({
|
|
834
|
-
snapshot: {
|
|
835
|
-
...snapshot,
|
|
836
|
-
context: {
|
|
837
|
-
...snapshot.context,
|
|
838
|
-
selection: dragSelection,
|
|
839
|
-
},
|
|
840
|
-
},
|
|
841
|
-
slateEditor,
|
|
842
|
-
})
|
|
843
|
-
|
|
844
|
-
if (selectingEntireBlocks) {
|
|
845
|
-
// Clone the DOM Nodes so they won't be visually clipped by scroll-containers etc.
|
|
846
|
-
const clonedBlockNodes = draggedDomNodes.blockNodes.map((node) =>
|
|
847
|
-
node.cloneNode(true),
|
|
848
|
-
)
|
|
849
|
-
|
|
850
|
-
for (const block of clonedBlockNodes) {
|
|
851
|
-
if (block instanceof HTMLElement) {
|
|
852
|
-
block.style.position = 'relative'
|
|
853
|
-
}
|
|
854
|
-
dragGhost.appendChild(block)
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// A custom drag ghost element can be configured using this data attribute
|
|
858
|
-
const customGhost = dragGhost.querySelector(
|
|
859
|
-
'[data-pt-drag-ghost-element]',
|
|
860
|
-
)
|
|
861
|
-
if (customGhost) {
|
|
862
|
-
dragGhost.replaceChildren(customGhost)
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// Setting the `data-dragged` attribute so the consumer can style the element while it’s dragged
|
|
866
|
-
dragGhost.setAttribute('data-dragged', '')
|
|
867
|
-
|
|
868
|
-
dragGhost.style.position = 'absolute'
|
|
869
|
-
dragGhost.style.left = '-99999px'
|
|
870
|
-
dragGhost.style.boxSizing = 'border-box'
|
|
871
|
-
document.body.appendChild(dragGhost)
|
|
872
|
-
|
|
873
|
-
if (customGhost) {
|
|
874
|
-
const customGhostRect = customGhost.getBoundingClientRect()
|
|
875
|
-
const x = event.clientX - customGhostRect.left
|
|
876
|
-
const y = event.clientY - customGhostRect.top
|
|
877
|
-
dragGhost.style.width = `${customGhostRect.width}px`
|
|
878
|
-
dragGhost.style.height = `${customGhostRect.height}px`
|
|
879
|
-
event.dataTransfer.setDragImage(dragGhost, x, y)
|
|
880
|
-
} else {
|
|
881
|
-
const blocksDomRect = getCompoundClientRect(
|
|
882
|
-
draggedDomNodes.blockNodes,
|
|
883
|
-
)
|
|
884
|
-
const x = event.clientX - blocksDomRect.left
|
|
885
|
-
const y = event.clientY - blocksDomRect.top
|
|
886
|
-
dragGhost.style.width = `${blocksDomRect.width}px`
|
|
887
|
-
dragGhost.style.height = `${blocksDomRect.height}px`
|
|
888
|
-
event.dataTransfer.setDragImage(dragGhost, x, y)
|
|
889
|
-
}
|
|
890
|
-
} else {
|
|
891
|
-
const clonedChildNodes = draggedDomNodes.childNodes.map((node) =>
|
|
892
|
-
node.cloneNode(true),
|
|
893
|
-
)
|
|
894
|
-
|
|
895
|
-
for (const child of clonedChildNodes) {
|
|
896
|
-
dragGhost.appendChild(child)
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
dragGhost.style.position = 'absolute'
|
|
900
|
-
dragGhost.style.left = '-99999px'
|
|
901
|
-
dragGhost.style.boxSizing = 'border-box'
|
|
902
|
-
document.body.appendChild(dragGhost)
|
|
903
|
-
|
|
904
|
-
const childrenDomRect = getCompoundClientRect(
|
|
905
|
-
draggedDomNodes.childNodes,
|
|
906
|
-
)
|
|
907
|
-
const x = event.clientX - childrenDomRect.left
|
|
908
|
-
const y = event.clientY - childrenDomRect.top
|
|
909
|
-
dragGhost.style.width = `${childrenDomRect.width}px`
|
|
910
|
-
dragGhost.style.height = `${childrenDomRect.height}px`
|
|
911
|
-
|
|
912
|
-
event.dataTransfer.setDragImage(dragGhost, x, y)
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
// Select drag selection
|
|
916
|
-
// If the selection is expanded then we just select the end of the
|
|
917
|
-
// selection
|
|
918
|
-
editorActor.send({
|
|
919
|
-
type: 'behavior event',
|
|
920
|
-
behaviorEvent: {
|
|
921
|
-
type: 'select',
|
|
922
|
-
at: isSelectionCollapsed(dragSelection)
|
|
923
|
-
? dragSelection
|
|
924
|
-
: {
|
|
925
|
-
anchor: getSelectionEndPoint(dragSelection),
|
|
926
|
-
focus: getSelectionEndPoint(dragSelection),
|
|
927
|
-
backward: false,
|
|
928
|
-
},
|
|
929
|
-
},
|
|
930
|
-
editor: slateEditor,
|
|
931
|
-
})
|
|
932
|
-
|
|
933
807
|
editorActor.send({
|
|
934
808
|
type: 'dragstart',
|
|
935
|
-
origin:
|
|
936
|
-
selection: dragSelection,
|
|
937
|
-
},
|
|
938
|
-
ghost: dragGhost,
|
|
809
|
+
origin: position,
|
|
939
810
|
})
|
|
940
811
|
|
|
941
812
|
editorActor.send({
|
|
@@ -943,11 +814,11 @@ export const PortableTextEditable = forwardRef<
|
|
|
943
814
|
behaviorEvent: {
|
|
944
815
|
type: 'drag.dragstart',
|
|
945
816
|
originEvent: {
|
|
817
|
+
clientX: event.clientX,
|
|
818
|
+
clientY: event.clientY,
|
|
946
819
|
dataTransfer: event.dataTransfer,
|
|
947
820
|
},
|
|
948
|
-
position
|
|
949
|
-
selection: dragSelection,
|
|
950
|
-
},
|
|
821
|
+
position,
|
|
951
822
|
},
|
|
952
823
|
editor: slateEditor,
|
|
953
824
|
})
|
|
@@ -1079,6 +950,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1079
950
|
originEvent: {
|
|
1080
951
|
dataTransfer: event.dataTransfer,
|
|
1081
952
|
},
|
|
953
|
+
dragOrigin: editorActor.getSnapshot().context.internalDrag?.origin,
|
|
1082
954
|
position,
|
|
1083
955
|
},
|
|
1084
956
|
editor: slateEditor,
|
|
@@ -1117,6 +989,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1117
989
|
originEvent: {
|
|
1118
990
|
dataTransfer: event.dataTransfer,
|
|
1119
991
|
},
|
|
992
|
+
dragOrigin: editorActor.getSnapshot().context.internalDrag?.origin,
|
|
1120
993
|
position,
|
|
1121
994
|
},
|
|
1122
995
|
editor: slateEditor,
|
|
@@ -114,10 +114,14 @@ export type InternalEditorEvent =
|
|
|
114
114
|
}
|
|
115
115
|
| MutationEvent
|
|
116
116
|
| InternalPatchEvent
|
|
117
|
+
| {
|
|
118
|
+
type: 'set drag ghost'
|
|
119
|
+
ghost: HTMLElement
|
|
120
|
+
}
|
|
117
121
|
| {
|
|
118
122
|
type: 'dragstart'
|
|
119
|
-
origin: Pick<EventPosition, 'selection'>
|
|
120
123
|
ghost?: HTMLElement
|
|
124
|
+
origin: Pick<EventPosition, 'selection'>
|
|
121
125
|
}
|
|
122
126
|
| {type: 'dragend'}
|
|
123
127
|
| {type: 'drop'}
|
|
@@ -148,9 +152,9 @@ export const editorMachine = setup({
|
|
|
148
152
|
selection: EditorSelection
|
|
149
153
|
initialValue: Array<PortableTextBlock> | undefined
|
|
150
154
|
internalDrag?: {
|
|
151
|
-
ghost?: HTMLElement
|
|
152
155
|
origin: Pick<EventPosition, 'selection'>
|
|
153
156
|
}
|
|
157
|
+
dragGhost?: HTMLElement
|
|
154
158
|
slateEditor?: PortableTextSlateEditor
|
|
155
159
|
},
|
|
156
160
|
events: {} as InternalEditorEvent,
|
|
@@ -273,9 +277,9 @@ export const editorMachine = setup({
|
|
|
273
277
|
keyGenerator: context.keyGenerator,
|
|
274
278
|
readOnly: self.getSnapshot().matches({'edit mode': 'read only'}),
|
|
275
279
|
schema: context.schema,
|
|
276
|
-
internalDrag: context.internalDrag,
|
|
277
280
|
}),
|
|
278
281
|
nativeEvent: event.nativeEvent,
|
|
282
|
+
sendBack: (event) => self.send(event),
|
|
279
283
|
})
|
|
280
284
|
} catch (error) {
|
|
281
285
|
console.error(
|
|
@@ -322,6 +326,9 @@ export const editorMachine = setup({
|
|
|
322
326
|
emit(({event}) => ({...event, type: 'selection'})),
|
|
323
327
|
],
|
|
324
328
|
},
|
|
329
|
+
'set drag ghost': {
|
|
330
|
+
actions: assign({dragGhost: ({event}) => event.ghost}),
|
|
331
|
+
},
|
|
325
332
|
},
|
|
326
333
|
type: 'parallel',
|
|
327
334
|
states: {
|
|
@@ -427,7 +434,6 @@ export const editorMachine = setup({
|
|
|
427
434
|
actions: [
|
|
428
435
|
assign({
|
|
429
436
|
internalDrag: ({event}) => ({
|
|
430
|
-
ghost: event.ghost,
|
|
431
437
|
origin: event.origin,
|
|
432
438
|
}),
|
|
433
439
|
}),
|
|
@@ -495,20 +501,21 @@ export const editorMachine = setup({
|
|
|
495
501
|
debug('exit: edit mode->editable->dragging internally')
|
|
496
502
|
},
|
|
497
503
|
({context}) => {
|
|
498
|
-
if (context.
|
|
504
|
+
if (context.dragGhost) {
|
|
499
505
|
try {
|
|
500
|
-
context.
|
|
501
|
-
context.
|
|
506
|
+
context.dragGhost.parentNode?.removeChild(
|
|
507
|
+
context.dragGhost,
|
|
502
508
|
)
|
|
503
509
|
} catch (error) {
|
|
504
510
|
console.error(
|
|
505
511
|
new Error(
|
|
506
|
-
`Removing the
|
|
512
|
+
`Removing the drag ghost failed due to: ${error.message}`,
|
|
507
513
|
),
|
|
508
514
|
)
|
|
509
515
|
}
|
|
510
516
|
}
|
|
511
517
|
},
|
|
518
|
+
assign({dragGhost: undefined}),
|
|
512
519
|
assign({internalDrag: undefined}),
|
|
513
520
|
],
|
|
514
521
|
tags: ['dragging internally'],
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {PortableTextBlock} from '@sanity/types'
|
|
2
2
|
import type {Converter} from '../converters/converter.types'
|
|
3
|
-
import type {EventPosition} from '../internal-utils/event-position'
|
|
4
3
|
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
5
4
|
import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
|
|
6
5
|
import type {EditorSchema} from './editor-schema'
|
|
@@ -31,11 +30,6 @@ export type EditorSnapshot = {
|
|
|
31
30
|
beta: {
|
|
32
31
|
activeAnnotations: Array<string>
|
|
33
32
|
activeDecorators: Array<string>
|
|
34
|
-
internalDrag:
|
|
35
|
-
| {
|
|
36
|
-
origin: Pick<EventPosition, 'selection'>
|
|
37
|
-
}
|
|
38
|
-
| undefined
|
|
39
33
|
}
|
|
40
34
|
}
|
|
41
35
|
|
|
@@ -45,18 +39,12 @@ export function createEditorSnapshot({
|
|
|
45
39
|
keyGenerator,
|
|
46
40
|
readOnly,
|
|
47
41
|
schema,
|
|
48
|
-
internalDrag,
|
|
49
42
|
}: {
|
|
50
43
|
converters: Array<Converter>
|
|
51
44
|
editor: PortableTextSlateEditor
|
|
52
45
|
keyGenerator: () => string
|
|
53
46
|
readOnly: boolean
|
|
54
47
|
schema: EditorSchema
|
|
55
|
-
internalDrag:
|
|
56
|
-
| {
|
|
57
|
-
origin: Pick<EventPosition, 'selection'>
|
|
58
|
-
}
|
|
59
|
-
| undefined
|
|
60
48
|
}) {
|
|
61
49
|
const selection = editor.selection
|
|
62
50
|
? slateRangeToSelection({
|
|
@@ -87,7 +75,6 @@ export function createEditorSnapshot({
|
|
|
87
75
|
markState: editor.markState,
|
|
88
76
|
schema,
|
|
89
77
|
}),
|
|
90
|
-
internalDrag,
|
|
91
78
|
},
|
|
92
79
|
} satisfies EditorSnapshot
|
|
93
80
|
}
|
|
@@ -35,79 +35,93 @@ export function getEventPosition({
|
|
|
35
35
|
return undefined
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const eventNode = getEventNode({slateEditor, event})
|
|
39
39
|
|
|
40
|
-
if (!
|
|
40
|
+
if (!eventNode) {
|
|
41
41
|
return undefined
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const
|
|
44
|
+
const eventBlock = getNodeBlock({
|
|
45
45
|
editor: slateEditor,
|
|
46
46
|
schema: editorActor.getSnapshot().context.schema,
|
|
47
|
-
node,
|
|
47
|
+
node: eventNode,
|
|
48
48
|
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
const eventPositionBlock = getEventPositionBlock({
|
|
50
|
+
node: eventNode,
|
|
51
|
+
slateEditor,
|
|
52
|
+
event,
|
|
53
|
+
})
|
|
54
|
+
const eventSelection = getEventSelection({
|
|
52
55
|
schema: editorActor.getSnapshot().context.schema,
|
|
53
56
|
slateEditor,
|
|
54
57
|
event,
|
|
55
58
|
})
|
|
56
59
|
|
|
57
|
-
if (
|
|
60
|
+
if (
|
|
61
|
+
eventBlock &&
|
|
62
|
+
eventPositionBlock &&
|
|
63
|
+
!eventSelection &&
|
|
64
|
+
!Editor.isEditor(eventNode)
|
|
65
|
+
) {
|
|
66
|
+
// If we for some reason can't find the event selection, then we default to
|
|
67
|
+
// selecting the entire block that the event originates from.
|
|
58
68
|
return {
|
|
59
|
-
block:
|
|
69
|
+
block: eventPositionBlock,
|
|
60
70
|
isEditor: false,
|
|
61
71
|
selection: {
|
|
62
72
|
anchor: utils.getBlockStartPoint({
|
|
63
73
|
context: editorActor.getSnapshot().context,
|
|
64
74
|
block: {
|
|
65
|
-
node:
|
|
66
|
-
path: [{_key:
|
|
75
|
+
node: eventBlock,
|
|
76
|
+
path: [{_key: eventBlock._key}],
|
|
67
77
|
},
|
|
68
78
|
}),
|
|
69
79
|
focus: utils.getBlockEndPoint({
|
|
70
80
|
context: editorActor.getSnapshot().context,
|
|
71
81
|
block: {
|
|
72
|
-
node:
|
|
73
|
-
path: [{_key:
|
|
82
|
+
node: eventBlock,
|
|
83
|
+
path: [{_key: eventBlock._key}],
|
|
74
84
|
},
|
|
75
85
|
}),
|
|
76
86
|
},
|
|
77
87
|
}
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
if (!
|
|
90
|
+
if (!eventPositionBlock || !eventSelection) {
|
|
81
91
|
return undefined
|
|
82
92
|
}
|
|
83
93
|
|
|
84
|
-
const
|
|
94
|
+
const eventSelectionFocusBlockKey = getBlockKeyFromSelectionPoint(
|
|
95
|
+
eventSelection.focus,
|
|
96
|
+
)
|
|
85
97
|
|
|
86
|
-
if (
|
|
98
|
+
if (eventSelectionFocusBlockKey === undefined) {
|
|
87
99
|
return undefined
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
if (
|
|
91
|
-
utils.isSelectionCollapsed(
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
utils.isSelectionCollapsed(eventSelection) &&
|
|
104
|
+
eventBlock &&
|
|
105
|
+
eventSelectionFocusBlockKey !== eventBlock._key
|
|
94
106
|
) {
|
|
107
|
+
// If the event block and event selection somehow don't match, then the
|
|
108
|
+
// event block takes precedence.
|
|
95
109
|
return {
|
|
96
|
-
block:
|
|
110
|
+
block: eventPositionBlock,
|
|
97
111
|
isEditor: false,
|
|
98
112
|
selection: {
|
|
99
113
|
anchor: utils.getBlockStartPoint({
|
|
100
114
|
context: editorActor.getSnapshot().context,
|
|
101
115
|
block: {
|
|
102
|
-
node:
|
|
103
|
-
path: [{_key:
|
|
116
|
+
node: eventBlock,
|
|
117
|
+
path: [{_key: eventBlock._key}],
|
|
104
118
|
},
|
|
105
119
|
}),
|
|
106
120
|
focus: utils.getBlockEndPoint({
|
|
107
121
|
context: editorActor.getSnapshot().context,
|
|
108
122
|
block: {
|
|
109
|
-
node:
|
|
110
|
-
path: [{_key:
|
|
123
|
+
node: eventBlock,
|
|
124
|
+
path: [{_key: eventBlock._key}],
|
|
111
125
|
},
|
|
112
126
|
}),
|
|
113
127
|
},
|
|
@@ -115,9 +129,9 @@ export function getEventPosition({
|
|
|
115
129
|
}
|
|
116
130
|
|
|
117
131
|
return {
|
|
118
|
-
block:
|
|
119
|
-
isEditor: Editor.isEditor(
|
|
120
|
-
selection,
|
|
132
|
+
block: eventPositionBlock,
|
|
133
|
+
isEditor: Editor.isEditor(eventNode),
|
|
134
|
+
selection: eventSelection,
|
|
121
135
|
}
|
|
122
136
|
}
|
|
123
137
|
|
|
@@ -1,9 +1,96 @@
|
|
|
1
1
|
import {Editor} from 'slate'
|
|
2
2
|
import {DOMEditor} from 'slate-dom'
|
|
3
3
|
import type {EditorSnapshot} from '..'
|
|
4
|
+
import type {BehaviorEvent} from '../behaviors'
|
|
5
|
+
import type {PickFromUnion} from '../type-utils'
|
|
4
6
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
5
7
|
import {toSlateRange} from './ranges'
|
|
6
8
|
|
|
9
|
+
export type EditorDom = {
|
|
10
|
+
getBlockNodes: (snapshot: EditorSnapshot) => Array<Node>
|
|
11
|
+
getChildNodes: (snapshot: EditorSnapshot) => Array<Node>
|
|
12
|
+
/**
|
|
13
|
+
* Let the Editor set the drag ghost. This is to be sure that it will get
|
|
14
|
+
* properly removed again when the drag ends.
|
|
15
|
+
*/
|
|
16
|
+
setDragGhost: ({
|
|
17
|
+
event,
|
|
18
|
+
ghost,
|
|
19
|
+
}: {
|
|
20
|
+
event: PickFromUnion<BehaviorEvent, 'type', 'drag.dragstart'>
|
|
21
|
+
ghost: {
|
|
22
|
+
element: HTMLElement
|
|
23
|
+
x: number
|
|
24
|
+
y: number
|
|
25
|
+
}
|
|
26
|
+
}) => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createEditorDom(
|
|
30
|
+
sendBack: (event: {type: 'set drag ghost'; ghost: HTMLElement}) => void,
|
|
31
|
+
slateEditor: PortableTextSlateEditor,
|
|
32
|
+
): EditorDom {
|
|
33
|
+
return {
|
|
34
|
+
getBlockNodes: (snapshot) => getBlockNodes(slateEditor, snapshot),
|
|
35
|
+
getChildNodes: (snapshot) => getChildNodes(slateEditor, snapshot),
|
|
36
|
+
setDragGhost: ({event, ghost}) => setDragGhost({sendBack, event, ghost}),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getBlockNodes(
|
|
41
|
+
slateEditor: PortableTextSlateEditor,
|
|
42
|
+
snapshot: EditorSnapshot,
|
|
43
|
+
) {
|
|
44
|
+
if (!snapshot.context.selection) {
|
|
45
|
+
return []
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const range = toSlateRange(snapshot.context.selection, slateEditor)
|
|
49
|
+
|
|
50
|
+
if (!range) {
|
|
51
|
+
return []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const blockEntries = Array.from(
|
|
55
|
+
Editor.nodes(slateEditor, {
|
|
56
|
+
at: range,
|
|
57
|
+
mode: 'highest',
|
|
58
|
+
match: (n) => !Editor.isEditor(n),
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return blockEntries.map(([blockNode]) =>
|
|
63
|
+
DOMEditor.toDOMNode(slateEditor, blockNode),
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getChildNodes(
|
|
68
|
+
slateEditor: PortableTextSlateEditor,
|
|
69
|
+
snapshot: EditorSnapshot,
|
|
70
|
+
) {
|
|
71
|
+
if (!snapshot.context.selection) {
|
|
72
|
+
return []
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const range = toSlateRange(snapshot.context.selection, slateEditor)
|
|
76
|
+
|
|
77
|
+
if (!range) {
|
|
78
|
+
return []
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const childEntries = Array.from(
|
|
82
|
+
Editor.nodes(slateEditor, {
|
|
83
|
+
at: range,
|
|
84
|
+
mode: 'lowest',
|
|
85
|
+
match: (n) => !Editor.isEditor(n),
|
|
86
|
+
}),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return childEntries.map(([childNode]) =>
|
|
90
|
+
DOMEditor.toDOMNode(slateEditor, childNode),
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
7
94
|
export type SelectionDomNodes = {
|
|
8
95
|
blockNodes: Array<Node>
|
|
9
96
|
childNodes: Array<Node>
|
|
@@ -59,3 +146,24 @@ export function getSelectionDomNodes({
|
|
|
59
146
|
),
|
|
60
147
|
}
|
|
61
148
|
}
|
|
149
|
+
|
|
150
|
+
function setDragGhost({
|
|
151
|
+
sendBack,
|
|
152
|
+
event,
|
|
153
|
+
ghost,
|
|
154
|
+
}: {
|
|
155
|
+
sendBack: (event: {type: 'set drag ghost'; ghost: HTMLElement}) => void
|
|
156
|
+
event: PickFromUnion<BehaviorEvent, 'type', 'drag.dragstart'>
|
|
157
|
+
ghost: {
|
|
158
|
+
element: HTMLElement
|
|
159
|
+
x: number
|
|
160
|
+
y: number
|
|
161
|
+
}
|
|
162
|
+
}) {
|
|
163
|
+
event.originEvent.dataTransfer.setDragImage(ghost.element, ghost.x, ghost.y)
|
|
164
|
+
|
|
165
|
+
sendBack({
|
|
166
|
+
type: 'set drag ghost',
|
|
167
|
+
ghost: ghost.element,
|
|
168
|
+
})
|
|
169
|
+
}
|