@portabletext/editor 1.51.0 → 1.52.1
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-cjs/selection-point.cjs +2 -25
- package/lib/_chunks-cjs/selection-point.cjs.map +1 -1
- package/lib/_chunks-es/selection-point.js +2 -25
- package/lib/_chunks-es/selection-point.js.map +1 -1
- 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 +465 -384
- 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 +486 -405
- 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 +11 -11
- 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/components/render-element.tsx +27 -46
- 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/editor/plugins/createWithSchemaTypes.ts +21 -1
- package/src/internal-utils/create-test-snapshot.ts +0 -1
- package/src/internal-utils/event-position.ts +41 -27
- package/src/internal-utils/parse-blocks.ts +26 -15
- 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,
|
|
@@ -2,11 +2,7 @@ import {useSelector} from '@xstate/react'
|
|
|
2
2
|
import {useContext, type ReactElement} from 'react'
|
|
3
3
|
import type {Element as SlateElement} from 'slate'
|
|
4
4
|
import type {RenderElementProps} from 'slate-react'
|
|
5
|
-
import {
|
|
6
|
-
parseBlockObject,
|
|
7
|
-
parseInlineObject,
|
|
8
|
-
parseTextBlock,
|
|
9
|
-
} from '../../internal-utils/parse-blocks'
|
|
5
|
+
import {isTextBlock} from '../../internal-utils/parse-blocks'
|
|
10
6
|
import type {
|
|
11
7
|
RenderBlockFunction,
|
|
12
8
|
RenderChildFunction,
|
|
@@ -35,22 +31,19 @@ export function RenderElement(props: {
|
|
|
35
31
|
'__inline' in props.element && props.element.__inline === true
|
|
36
32
|
|
|
37
33
|
if (isInline) {
|
|
38
|
-
const inlineObject =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_key: props.element._key,
|
|
46
|
-
_type: props.element._type,
|
|
47
|
-
...('value' in props.element && typeof props.element.value === 'object'
|
|
48
|
-
? props.element.value
|
|
49
|
-
: {}),
|
|
50
|
-
},
|
|
51
|
-
})
|
|
34
|
+
const inlineObject = {
|
|
35
|
+
_key: props.element._key,
|
|
36
|
+
_type: props.element._type,
|
|
37
|
+
...('value' in props.element && typeof props.element.value === 'object'
|
|
38
|
+
? props.element.value
|
|
39
|
+
: {}),
|
|
40
|
+
}
|
|
52
41
|
|
|
53
|
-
if (
|
|
42
|
+
if (
|
|
43
|
+
!schema.inlineObjects.find(
|
|
44
|
+
(inlineObject) => inlineObject.name === props.element._type,
|
|
45
|
+
)
|
|
46
|
+
) {
|
|
54
47
|
console.error(
|
|
55
48
|
`Unable to find Inline Object "${props.element._type}" in Schema`,
|
|
56
49
|
)
|
|
@@ -74,16 +67,7 @@ export function RenderElement(props: {
|
|
|
74
67
|
)
|
|
75
68
|
}
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
context: {
|
|
79
|
-
keyGenerator: () => '',
|
|
80
|
-
schema,
|
|
81
|
-
},
|
|
82
|
-
options: {refreshKeys: false, validateFields: false},
|
|
83
|
-
block: props.element,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
if (textBlock) {
|
|
70
|
+
if (isTextBlock({schema}, props.element)) {
|
|
87
71
|
return (
|
|
88
72
|
<RenderTextBlock
|
|
89
73
|
attributes={props.attributes}
|
|
@@ -93,29 +77,26 @@ export function RenderElement(props: {
|
|
|
93
77
|
renderListItem={props.renderListItem}
|
|
94
78
|
renderStyle={props.renderStyle}
|
|
95
79
|
spellCheck={props.spellCheck}
|
|
96
|
-
textBlock={
|
|
80
|
+
textBlock={props.element}
|
|
97
81
|
>
|
|
98
82
|
{props.children}
|
|
99
83
|
</RenderTextBlock>
|
|
100
84
|
)
|
|
101
85
|
}
|
|
102
86
|
|
|
103
|
-
const blockObject =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
_key: props.element._key,
|
|
111
|
-
_type: props.element._type,
|
|
112
|
-
...('value' in props.element && typeof props.element.value === 'object'
|
|
113
|
-
? props.element.value
|
|
114
|
-
: {}),
|
|
115
|
-
},
|
|
116
|
-
})
|
|
87
|
+
const blockObject = {
|
|
88
|
+
_key: props.element._key,
|
|
89
|
+
_type: props.element._type,
|
|
90
|
+
...('value' in props.element && typeof props.element.value === 'object'
|
|
91
|
+
? props.element.value
|
|
92
|
+
: {}),
|
|
93
|
+
}
|
|
117
94
|
|
|
118
|
-
if (
|
|
95
|
+
if (
|
|
96
|
+
!schema.blockObjects.find(
|
|
97
|
+
(blockObject) => blockObject.name === props.element._type,
|
|
98
|
+
)
|
|
99
|
+
) {
|
|
119
100
|
console.error(
|
|
120
101
|
`Unable to find Block Object "${props.element._type}" in Schema`,
|
|
121
102
|
)
|
|
@@ -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
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
PortableTextSpan,
|
|
4
4
|
PortableTextTextBlock,
|
|
5
5
|
} from '@sanity/types'
|
|
6
|
-
import {Transforms, type Element} from 'slate'
|
|
6
|
+
import {Editor, Transforms, type Element} from 'slate'
|
|
7
7
|
import {debugWithName} from '../../internal-utils/debug'
|
|
8
8
|
import {
|
|
9
9
|
isListBlock,
|
|
@@ -27,15 +27,31 @@ export function createWithSchemaTypes({
|
|
|
27
27
|
editor: PortableTextSlateEditor,
|
|
28
28
|
): PortableTextSlateEditor {
|
|
29
29
|
editor.isTextBlock = (value: unknown): value is PortableTextTextBlock => {
|
|
30
|
+
if (Editor.isEditor(value)) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
|
|
30
34
|
return isTextBlock(editorActor.getSnapshot().context, value)
|
|
31
35
|
}
|
|
32
36
|
editor.isTextSpan = (value: unknown): value is PortableTextSpan => {
|
|
37
|
+
if (Editor.isEditor(value)) {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
return isSpan(editorActor.getSnapshot().context, value)
|
|
34
42
|
}
|
|
35
43
|
editor.isListBlock = (value: unknown): value is PortableTextListBlock => {
|
|
44
|
+
if (Editor.isEditor(value)) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
return isListBlock(editorActor.getSnapshot().context, value)
|
|
37
49
|
}
|
|
38
50
|
editor.isVoid = (element: Element): boolean => {
|
|
51
|
+
if (Editor.isEditor(element)) {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
|
|
39
55
|
return (
|
|
40
56
|
editorActor.getSnapshot().context.schema.block.name !== element._type &&
|
|
41
57
|
(editorActor
|
|
@@ -49,6 +65,10 @@ export function createWithSchemaTypes({
|
|
|
49
65
|
)
|
|
50
66
|
}
|
|
51
67
|
editor.isInline = (element: Element): boolean => {
|
|
68
|
+
if (Editor.isEditor(element)) {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
|
|
52
72
|
const inlineSchemaTypes = editorActor
|
|
53
73
|
.getSnapshot()
|
|
54
74
|
.context.schema.inlineObjects.map((obj) => obj.name)
|
|
@@ -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
|
|
|
@@ -97,13 +97,19 @@ export function isTextBlock(
|
|
|
97
97
|
context: Pick<EditorContext, 'schema'>,
|
|
98
98
|
block: unknown,
|
|
99
99
|
): block is PortableTextTextBlock {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
if (!isTypedObject(block)) {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (block._type !== context.schema.block.name) {
|
|
105
|
+
return false
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!Array.isArray(block.children)) {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return true
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
export function parseTextBlock({
|
|
@@ -249,14 +255,19 @@ export function isSpan(
|
|
|
249
255
|
context: Pick<EditorContext, 'schema'>,
|
|
250
256
|
child: unknown,
|
|
251
257
|
): child is PortableTextSpan {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
if (!isTypedObject(child)) {
|
|
259
|
+
return false
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (child._type !== context.schema.span.name) {
|
|
263
|
+
return false
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (typeof child.text !== 'string') {
|
|
267
|
+
return false
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return true
|
|
260
271
|
}
|
|
261
272
|
|
|
262
273
|
export function parseSpan({
|