@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.
- package/lib/_chunks-cjs/behavior.core.cjs +84 -49
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/behavior.markdown.cjs +1 -1
- package/lib/_chunks-cjs/editor-provider.cjs +919 -526
- package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
- package/lib/_chunks-cjs/{util.block-offsets-to-selection.cjs → parse-blocks.cjs} +36 -21
- package/lib/_chunks-cjs/parse-blocks.cjs.map +1 -0
- package/lib/_chunks-cjs/selector.get-text-before.cjs +2 -2
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/{selector.is-active-style.cjs → selector.is-overlapping-selection.cjs} +144 -3
- package/lib/_chunks-cjs/selector.is-overlapping-selection.cjs.map +1 -0
- package/lib/_chunks-cjs/util.slice-blocks.cjs +12 -0
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +84 -49
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/behavior.markdown.js +1 -1
- package/lib/_chunks-es/editor-provider.js +911 -517
- package/lib/_chunks-es/editor-provider.js.map +1 -1
- package/lib/_chunks-es/{util.block-offsets-to-selection.js → parse-blocks.js} +37 -22
- package/lib/_chunks-es/parse-blocks.js.map +1 -0
- package/lib/_chunks-es/selector.get-text-before.js +1 -2
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
- package/lib/_chunks-es/{selector.is-active-style.js → selector.is-overlapping-selection.js} +146 -5
- package/lib/_chunks-es/selector.is-overlapping-selection.js.map +1 -0
- package/lib/_chunks-es/util.slice-blocks.js +12 -0
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/behaviors/index.d.cts +10535 -4689
- package/lib/behaviors/index.d.ts +10535 -4689
- package/lib/index.cjs +582 -209
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +5297 -1178
- package/lib/index.d.ts +5297 -1178
- package/lib/index.js +591 -213
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.cjs +2 -2
- package/lib/plugins/index.cjs.map +1 -1
- package/lib/plugins/index.d.cts +5297 -1178
- package/lib/plugins/index.d.ts +5297 -1178
- package/lib/plugins/index.js +2 -2
- package/lib/selectors/index.cjs +21 -103
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +5313 -1178
- package/lib/selectors/index.d.ts +5313 -1178
- package/lib/selectors/index.js +13 -96
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.cjs +4 -4
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +5297 -1178
- package/lib/utils/index.d.ts +5297 -1178
- package/lib/utils/index.js +3 -4
- package/lib/utils/index.js.map +1 -1
- package/package.json +15 -14
- package/src/behavior-actions/behavior.action.blur.ts +8 -0
- package/src/behavior-actions/behavior.action.decorator.add.ts +2 -1
- package/src/behavior-actions/behavior.action.delete.backward.ts +7 -0
- package/src/behavior-actions/behavior.action.delete.block.ts +24 -0
- package/src/behavior-actions/behavior.action.delete.forward.ts +7 -0
- package/src/behavior-actions/behavior.action.delete.text.ts +2 -1
- package/src/behavior-actions/behavior.action.delete.ts +1 -3
- package/src/behavior-actions/behavior.action.deserialization.failure.ts +9 -0
- package/src/behavior-actions/behavior.action.deserialization.success.ts +16 -0
- package/src/behavior-actions/behavior.action.effect.ts +7 -0
- package/src/behavior-actions/behavior.action.focus.ts +8 -0
- package/src/behavior-actions/behavior.action.insert-blocks.ts +118 -74
- package/src/behavior-actions/behavior.action.insert-break.ts +1 -0
- package/src/behavior-actions/{behavior.action.insert-block-object.ts → behavior.action.insert.block-object.ts} +9 -14
- package/src/behavior-actions/behavior.action.insert.block.ts +247 -2
- package/src/behavior-actions/behavior.action.insert.text-block.ts +33 -0
- package/src/behavior-actions/behavior.action.insert.text.ts +7 -0
- package/src/behavior-actions/behavior.action.move.block-down.ts +48 -0
- package/src/behavior-actions/behavior.action.move.block-up.ts +53 -0
- package/src/behavior-actions/behavior.action.move.block.ts +16 -0
- package/src/behavior-actions/behavior.action.noop.ts +5 -0
- package/src/behavior-actions/behavior.action.select.next-block.ts +44 -0
- package/src/behavior-actions/behavior.action.select.previous-block.ts +48 -0
- package/src/behavior-actions/behavior.action.select.ts +15 -0
- package/src/behavior-actions/behavior.action.serialization.failure.ts +9 -0
- package/src/behavior-actions/behavior.action.serialization.success.ts +14 -0
- package/src/behavior-actions/behavior.actions.ts +54 -212
- package/src/behaviors/behavior.core.block-objects.ts +35 -6
- package/src/behaviors/behavior.core.insert-break.ts +1 -0
- package/src/behaviors/behavior.core.ts +2 -0
- package/src/behaviors/behavior.default.ts +241 -33
- package/src/behaviors/behavior.types.ts +138 -20
- package/src/converters/converter.portable-text.ts +5 -2
- package/src/converters/converter.text-html.serialize.test.ts +4 -4
- package/src/converters/converter.text-html.ts +5 -2
- package/src/converters/converter.text-plain.test.ts +6 -6
- package/src/converters/converter.text-plain.ts +5 -2
- package/src/converters/converter.types.ts +3 -3
- package/src/editor/Editable.tsx +403 -48
- package/src/editor/components/Element.tsx +133 -18
- package/src/editor/components/use-draggable.ts +34 -102
- package/src/editor/editor-machine.ts +66 -10
- package/src/editor/editor-selector.ts +2 -0
- package/src/editor/editor-snapshot.ts +17 -0
- package/src/editor/plugins/create-with-event-listeners.ts +6 -40
- package/src/internal-utils/create-test-snapshot.ts +2 -0
- package/src/internal-utils/event-position.ts +210 -0
- package/src/internal-utils/slate-utils.ts +56 -0
- package/src/internal-utils/weakMaps.ts +1 -15
- package/src/selectors/index.ts +2 -0
- package/src/selectors/selector.get-focus-inline-object.ts +21 -0
- package/src/selectors/selector.is-overlapping-selection.test.ts +171 -0
- package/src/selectors/selector.is-overlapping-selection.ts +108 -4
- package/src/selectors/selector.is-point-after-selection.ts +3 -1
- package/src/selectors/selector.is-point-before-selection.ts +3 -1
- package/src/selectors/selector.is-selecting-entire-blocks.ts +34 -0
- package/lib/_chunks-cjs/selector.is-active-style.cjs.map +0 -1
- package/lib/_chunks-cjs/util.block-offsets-to-selection.cjs.map +0 -1
- package/lib/_chunks-cjs/util.reverse-selection.cjs +0 -14
- package/lib/_chunks-cjs/util.reverse-selection.cjs.map +0 -1
- package/lib/_chunks-es/selector.is-active-style.js.map +0 -1
- package/lib/_chunks-es/util.block-offsets-to-selection.js.map +0 -1
- package/lib/_chunks-es/util.reverse-selection.js +0 -15
- package/lib/_chunks-es/util.reverse-selection.js.map +0 -1
- package/src/behavior-actions/behavior.action-utils.insert-block.ts +0 -61
- package/src/editor/__tests__/handleClick.test.tsx +0 -277
- package/src/editor/components/use-droppable.ts +0 -135
|
@@ -5,8 +5,11 @@ import type {
|
|
|
5
5
|
PortableTextTextBlock,
|
|
6
6
|
} from '@sanity/types'
|
|
7
7
|
import {
|
|
8
|
+
useContext,
|
|
9
|
+
useEffect,
|
|
8
10
|
useMemo,
|
|
9
11
|
useRef,
|
|
12
|
+
useState,
|
|
10
13
|
type FunctionComponent,
|
|
11
14
|
type JSX,
|
|
12
15
|
type ReactElement,
|
|
@@ -18,9 +21,12 @@ import {
|
|
|
18
21
|
useSlateStatic,
|
|
19
22
|
type RenderElementProps,
|
|
20
23
|
} from 'slate-react'
|
|
24
|
+
import {defineBehavior} from '../../behaviors'
|
|
21
25
|
import {debugWithName} from '../../internal-utils/debug'
|
|
26
|
+
import type {EventPositionBlock} from '../../internal-utils/event-position'
|
|
22
27
|
import {fromSlateValue} from '../../internal-utils/values'
|
|
23
28
|
import {KEY_TO_VALUE_ELEMENT} from '../../internal-utils/weakMaps'
|
|
29
|
+
import * as selectors from '../../selectors'
|
|
24
30
|
import type {
|
|
25
31
|
BlockRenderProps,
|
|
26
32
|
PortableTextMemberSchemaTypes,
|
|
@@ -29,10 +35,10 @@ import type {
|
|
|
29
35
|
RenderListItemFunction,
|
|
30
36
|
RenderStyleFunction,
|
|
31
37
|
} from '../../types/editor'
|
|
38
|
+
import {EditorActorContext} from '../editor-actor-context'
|
|
32
39
|
import {DefaultBlockObject, DefaultInlineObject} from './DefaultObject'
|
|
33
40
|
import {DropIndicator} from './drop-indicator'
|
|
34
41
|
import {useDraggable} from './use-draggable'
|
|
35
|
-
import {useDroppable} from './use-droppable'
|
|
36
42
|
|
|
37
43
|
const debug = debugWithName('components:Element')
|
|
38
44
|
const debugRenders = false
|
|
@@ -72,24 +78,135 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
72
78
|
renderStyle,
|
|
73
79
|
spellCheck,
|
|
74
80
|
}) => {
|
|
75
|
-
const
|
|
81
|
+
const editorActor = useContext(EditorActorContext)
|
|
82
|
+
const slateEditor = useSlateStatic()
|
|
76
83
|
const selected = useSelected()
|
|
77
84
|
const blockRef = useRef<HTMLDivElement | null>(null)
|
|
78
85
|
const inlineBlockObjectRef = useRef(null)
|
|
79
86
|
const focused =
|
|
80
|
-
(selected &&
|
|
87
|
+
(selected &&
|
|
88
|
+
slateEditor.selection &&
|
|
89
|
+
Range.isCollapsed(slateEditor.selection)) ||
|
|
81
90
|
false
|
|
82
|
-
const
|
|
83
|
-
|
|
91
|
+
const [dragPositionBlock, setDragPositionBlock] =
|
|
92
|
+
useState<EventPositionBlock>()
|
|
93
|
+
const draggable = useDraggable({element, readOnly, blockRef})
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
const behavior = defineBehavior({
|
|
97
|
+
on: 'drag.dragover',
|
|
98
|
+
guard: ({snapshot, event}) => {
|
|
99
|
+
const dropFocusBlock = selectors.getFocusBlock({
|
|
100
|
+
...snapshot,
|
|
101
|
+
context: {
|
|
102
|
+
...snapshot.context,
|
|
103
|
+
selection: event.position.selection,
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
if (!dropFocusBlock || dropFocusBlock.node._key !== element._key) {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const dragOrigin = snapshot.beta.internalDrag?.origin
|
|
112
|
+
|
|
113
|
+
if (!dragOrigin) {
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const draggedBlocks = selectors.getSelectedBlocks({
|
|
118
|
+
...snapshot,
|
|
119
|
+
context: {
|
|
120
|
+
...snapshot.context,
|
|
121
|
+
selection: dragOrigin.selection,
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
if (
|
|
126
|
+
draggedBlocks.some(
|
|
127
|
+
(draggedBlock) => draggedBlock.node._key === element._key,
|
|
128
|
+
)
|
|
129
|
+
) {
|
|
130
|
+
return false
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const draggingEntireBlocks = selectors.isSelectingEntireBlocks({
|
|
134
|
+
...snapshot,
|
|
135
|
+
context: {
|
|
136
|
+
...snapshot.context,
|
|
137
|
+
selection: dragOrigin.selection,
|
|
138
|
+
},
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
return draggingEntireBlocks
|
|
142
|
+
},
|
|
143
|
+
actions: [
|
|
144
|
+
({event}) => [
|
|
145
|
+
{
|
|
146
|
+
type: 'effect',
|
|
147
|
+
effect: () => {
|
|
148
|
+
setDragPositionBlock(event.position.block)
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'noop',
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
],
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
editorActor.send({
|
|
159
|
+
type: 'add behavior',
|
|
160
|
+
behavior,
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
return () => {
|
|
164
|
+
editorActor.send({
|
|
165
|
+
type: 'remove behavior',
|
|
166
|
+
behavior,
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}, [editorActor, element._key])
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
const behavior = defineBehavior({
|
|
173
|
+
on: 'drag.*',
|
|
174
|
+
guard: ({event}) => {
|
|
175
|
+
return event.type !== 'drag.dragover'
|
|
176
|
+
},
|
|
177
|
+
actions: [
|
|
178
|
+
() => [
|
|
179
|
+
{
|
|
180
|
+
type: 'effect',
|
|
181
|
+
effect: () => {
|
|
182
|
+
setDragPositionBlock(undefined)
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
],
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
editorActor.send({
|
|
190
|
+
type: 'add behavior',
|
|
191
|
+
behavior,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return () => {
|
|
195
|
+
editorActor.send({
|
|
196
|
+
type: 'remove behavior',
|
|
197
|
+
behavior,
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
}, [editorActor])
|
|
84
201
|
|
|
85
202
|
const value = useMemo(
|
|
86
203
|
() =>
|
|
87
204
|
fromSlateValue(
|
|
88
205
|
[element],
|
|
89
206
|
schemaTypes.block.name,
|
|
90
|
-
KEY_TO_VALUE_ELEMENT.get(
|
|
207
|
+
KEY_TO_VALUE_ELEMENT.get(slateEditor),
|
|
91
208
|
)[0],
|
|
92
|
-
[
|
|
209
|
+
[slateEditor, element, schemaTypes.block.name],
|
|
93
210
|
)
|
|
94
211
|
|
|
95
212
|
let renderedBlock = children
|
|
@@ -107,9 +224,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
107
224
|
}
|
|
108
225
|
|
|
109
226
|
// Test for inline objects first
|
|
110
|
-
if (
|
|
111
|
-
const path = ReactEditor.findPath(
|
|
112
|
-
const [block] = Editor.node(
|
|
227
|
+
if (slateEditor.isInline(element)) {
|
|
228
|
+
const path = ReactEditor.findPath(slateEditor, element)
|
|
229
|
+
const [block] = Editor.node(slateEditor, path, {depth: 1})
|
|
113
230
|
const schemaType = schemaTypes.inlineObjects.find(
|
|
114
231
|
(_type) => _type.name === element._type,
|
|
115
232
|
)
|
|
@@ -192,7 +309,7 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
192
309
|
className += ` pt-list-item pt-list-item-${element.listItem} pt-list-item-level-${level || 1}`
|
|
193
310
|
}
|
|
194
311
|
|
|
195
|
-
if (
|
|
312
|
+
if (slateEditor.isListBlock(value) && isListItem && element.listItem) {
|
|
196
313
|
const listType = schemaTypes.lists.find(
|
|
197
314
|
(item) => item.value === element.listItem,
|
|
198
315
|
)
|
|
@@ -246,11 +363,10 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
246
363
|
{...attributes}
|
|
247
364
|
className={className}
|
|
248
365
|
spellCheck={spellCheck}
|
|
249
|
-
{...droppable.droppableProps}
|
|
250
366
|
>
|
|
251
|
-
{
|
|
367
|
+
{dragPositionBlock === 'start' ? <DropIndicator /> : null}
|
|
252
368
|
<div ref={blockRef}>{propsOrDefaultRendered}</div>
|
|
253
|
-
{
|
|
369
|
+
{dragPositionBlock === 'end' ? <DropIndicator /> : null}
|
|
254
370
|
</div>
|
|
255
371
|
)
|
|
256
372
|
}
|
|
@@ -274,7 +390,7 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
274
390
|
const block = fromSlateValue(
|
|
275
391
|
[element],
|
|
276
392
|
schemaTypes.block.name,
|
|
277
|
-
KEY_TO_VALUE_ELEMENT.get(
|
|
393
|
+
KEY_TO_VALUE_ELEMENT.get(slateEditor),
|
|
278
394
|
)[0]
|
|
279
395
|
|
|
280
396
|
let renderedBlockFromProps: JSX.Element | undefined
|
|
@@ -309,10 +425,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
309
425
|
key={element._key}
|
|
310
426
|
{...attributes}
|
|
311
427
|
className={className}
|
|
312
|
-
{...droppable.droppableProps}
|
|
313
428
|
{...draggable.draggableProps}
|
|
314
429
|
>
|
|
315
|
-
{
|
|
430
|
+
{dragPositionBlock === 'start' ? <DropIndicator /> : null}
|
|
316
431
|
{children}
|
|
317
432
|
<div ref={blockRef} contentEditable={false}>
|
|
318
433
|
{renderedBlockFromProps ? (
|
|
@@ -321,7 +436,7 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
321
436
|
<DefaultBlockObject value={value} />
|
|
322
437
|
)}
|
|
323
438
|
</div>
|
|
324
|
-
{
|
|
439
|
+
{dragPositionBlock === 'end' ? <DropIndicator /> : null}
|
|
325
440
|
</div>
|
|
326
441
|
)
|
|
327
442
|
}
|
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useCallback,
|
|
3
|
+
useContext,
|
|
3
4
|
useEffect,
|
|
4
|
-
useRef,
|
|
5
5
|
useState,
|
|
6
6
|
type DragEvent,
|
|
7
7
|
type RefObject,
|
|
8
8
|
} from 'react'
|
|
9
|
-
import
|
|
9
|
+
import type {Element as SlateElement} from 'slate'
|
|
10
10
|
import {ReactEditor, useSlateStatic} from 'slate-react'
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
IS_DRAGGING_BLOCK_ELEMENT,
|
|
15
|
-
IS_DRAGGING_BLOCK_TARGET_POSITION,
|
|
16
|
-
IS_DRAGGING_ELEMENT_TARGET,
|
|
17
|
-
} from '../../internal-utils/weakMaps'
|
|
18
|
-
|
|
19
|
-
const debug = debugWithName('useDraggable')
|
|
11
|
+
import {getEventPosition} from '../../internal-utils/event-position'
|
|
12
|
+
import {EditorActorContext} from '../editor-actor-context'
|
|
13
|
+
import {getEditorSnapshot} from '../editor-selector'
|
|
20
14
|
|
|
21
15
|
type Draggable = {
|
|
22
16
|
draggableProps: {
|
|
23
17
|
draggable: boolean
|
|
24
18
|
onDragStart?: (event: DragEvent) => void
|
|
25
|
-
onDrag?: (event: DragEvent) => void
|
|
26
19
|
onDragEnd?: (event: DragEvent) => void
|
|
27
20
|
}
|
|
28
21
|
}
|
|
@@ -32,8 +25,8 @@ export function useDraggable(props: {
|
|
|
32
25
|
readOnly: boolean
|
|
33
26
|
blockRef: RefObject<HTMLDivElement | null>
|
|
34
27
|
}): Draggable {
|
|
28
|
+
const editorActor = useContext(EditorActorContext)
|
|
35
29
|
const editor = useSlateStatic()
|
|
36
|
-
const dragGhostRef = useRef<HTMLElement>(undefined)
|
|
37
30
|
const [blockElement, setBlockElement] = useState<HTMLElement | null>(null)
|
|
38
31
|
|
|
39
32
|
useEffect(
|
|
@@ -46,95 +39,26 @@ export function useDraggable(props: {
|
|
|
46
39
|
[editor, props.element, props.blockRef],
|
|
47
40
|
)
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const targetBlock = IS_DRAGGING_ELEMENT_TARGET.get(editor)
|
|
53
|
-
if (targetBlock) {
|
|
54
|
-
IS_DRAGGING.set(editor, false)
|
|
55
|
-
event.preventDefault()
|
|
56
|
-
event.stopPropagation()
|
|
57
|
-
IS_DRAGGING_ELEMENT_TARGET.delete(editor)
|
|
58
|
-
if (dragGhostRef.current) {
|
|
59
|
-
debug('Removing drag ghost')
|
|
60
|
-
document.body.removeChild(dragGhostRef.current)
|
|
61
|
-
}
|
|
62
|
-
const dragPosition = IS_DRAGGING_BLOCK_TARGET_POSITION.get(editor)
|
|
63
|
-
IS_DRAGGING_BLOCK_TARGET_POSITION.delete(editor)
|
|
64
|
-
let targetPath = ReactEditor.findPath(editor, targetBlock)
|
|
65
|
-
const myPath = ReactEditor.findPath(editor, props.element)
|
|
66
|
-
const isBefore = Path.isBefore(myPath, targetPath)
|
|
67
|
-
if (dragPosition === 'bottom' && !isBefore) {
|
|
68
|
-
// If it is already at the bottom, don't do anything.
|
|
69
|
-
if (targetPath[0] >= editor.children.length - 1) {
|
|
70
|
-
debug('target is already at the bottom, not moving')
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
const originalPath = targetPath
|
|
74
|
-
targetPath = Path.next(targetPath)
|
|
75
|
-
debug(
|
|
76
|
-
`Adjusting targetPath from ${JSON.stringify(originalPath)} to ${JSON.stringify(
|
|
77
|
-
targetPath,
|
|
78
|
-
)}`,
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
if (
|
|
82
|
-
dragPosition === 'top' &&
|
|
83
|
-
isBefore &&
|
|
84
|
-
targetPath[0] !== editor.children.length - 1
|
|
85
|
-
) {
|
|
86
|
-
const originalPath = targetPath
|
|
87
|
-
targetPath = Path.previous(targetPath)
|
|
88
|
-
debug(
|
|
89
|
-
`Adjusting targetPath from ${JSON.stringify(originalPath)} to ${JSON.stringify(
|
|
90
|
-
targetPath,
|
|
91
|
-
)}`,
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
if (Path.equals(targetPath, myPath)) {
|
|
95
|
-
event.preventDefault()
|
|
96
|
-
debug('targetPath and myPath is the same, not moving')
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
debug(
|
|
100
|
-
`Moving element ${props.element._key} from path ${JSON.stringify(myPath)} to ${JSON.stringify(
|
|
101
|
-
targetPath,
|
|
102
|
-
)} (${dragPosition})`,
|
|
103
|
-
)
|
|
104
|
-
Transforms.moveNodes(editor, {at: myPath, to: targetPath})
|
|
105
|
-
editor.onChange()
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
debug('No target element, not doing anything')
|
|
109
|
-
},
|
|
110
|
-
[editor, props.element],
|
|
111
|
-
)
|
|
42
|
+
const handleDragEnd = useCallback(() => {
|
|
43
|
+
editorActor.send({type: 'dragend'})
|
|
44
|
+
}, [editorActor])
|
|
112
45
|
|
|
113
|
-
|
|
114
|
-
const handleDrag = useCallback(
|
|
46
|
+
const handleDragStart = useCallback(
|
|
115
47
|
(event: DragEvent) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
48
|
+
const position = getEventPosition({
|
|
49
|
+
snapshot: getEditorSnapshot({
|
|
50
|
+
editorActorSnapshot: editorActor.getSnapshot(),
|
|
51
|
+
slateEditorInstance: editor,
|
|
52
|
+
}),
|
|
53
|
+
slateEditor: editor,
|
|
54
|
+
event: event.nativeEvent,
|
|
55
|
+
})
|
|
121
56
|
|
|
122
|
-
if (
|
|
123
|
-
|
|
57
|
+
if (!position) {
|
|
58
|
+
console.error('Could not find position for dragstart event')
|
|
59
|
+
return
|
|
124
60
|
}
|
|
125
|
-
},
|
|
126
|
-
[editor, props.element],
|
|
127
|
-
)
|
|
128
61
|
|
|
129
|
-
// Note: this is called for the dragging block
|
|
130
|
-
const handleDragStart = useCallback(
|
|
131
|
-
(event: DragEvent) => {
|
|
132
|
-
debug('Drag start')
|
|
133
|
-
IS_DRAGGING.set(editor, true)
|
|
134
|
-
if (event.dataTransfer) {
|
|
135
|
-
event.dataTransfer.setData('application/portable-text', 'something')
|
|
136
|
-
event.dataTransfer.effectAllowed = 'move'
|
|
137
|
-
}
|
|
138
62
|
// Clone blockElement so that it will not be visually clipped by scroll-containers etc.
|
|
139
63
|
// The application that uses the portable-text-editor may indicate the element used as
|
|
140
64
|
// drag ghost by adding a truthy data attribute 'data-pt-drag-ghost-element' to a HTML element.
|
|
@@ -151,7 +75,6 @@ export function useDraggable(props: {
|
|
|
151
75
|
dragGhost.setAttribute('data-dragged', '')
|
|
152
76
|
|
|
153
77
|
if (document.body) {
|
|
154
|
-
dragGhostRef.current = dragGhost
|
|
155
78
|
dragGhost.style.position = 'absolute'
|
|
156
79
|
dragGhost.style.left = '-99999px'
|
|
157
80
|
dragGhost.style.boxSizing = 'border-box'
|
|
@@ -162,11 +85,22 @@ export function useDraggable(props: {
|
|
|
162
85
|
dragGhost.style.width = `${rect.width}px`
|
|
163
86
|
dragGhost.style.height = `${rect.height}px`
|
|
164
87
|
event.dataTransfer.setDragImage(dragGhost, x, y)
|
|
88
|
+
|
|
89
|
+
editorActor.send({
|
|
90
|
+
type: 'dragstart',
|
|
91
|
+
origin: position,
|
|
92
|
+
ghost: dragGhost,
|
|
93
|
+
})
|
|
94
|
+
return
|
|
165
95
|
}
|
|
96
|
+
|
|
97
|
+
editorActor.send({
|
|
98
|
+
type: 'dragstart',
|
|
99
|
+
origin: position,
|
|
100
|
+
})
|
|
166
101
|
}
|
|
167
|
-
handleDrag(event)
|
|
168
102
|
},
|
|
169
|
-
[blockElement, editor,
|
|
103
|
+
[blockElement, editor, editorActor],
|
|
170
104
|
)
|
|
171
105
|
|
|
172
106
|
if (props.readOnly) {
|
|
@@ -174,7 +108,6 @@ export function useDraggable(props: {
|
|
|
174
108
|
draggableProps: {
|
|
175
109
|
draggable: false,
|
|
176
110
|
onDragStart: undefined,
|
|
177
|
-
onDrag: undefined,
|
|
178
111
|
onDragEnd: undefined,
|
|
179
112
|
},
|
|
180
113
|
}
|
|
@@ -184,7 +117,6 @@ export function useDraggable(props: {
|
|
|
184
117
|
draggableProps: {
|
|
185
118
|
draggable: true,
|
|
186
119
|
onDragStart: handleDragStart,
|
|
187
|
-
onDrag: handleDrag,
|
|
188
120
|
onDragEnd: handleDragEnd,
|
|
189
121
|
},
|
|
190
122
|
}
|
|
@@ -14,13 +14,17 @@ import {coreBehaviors} from '../behaviors/behavior.core'
|
|
|
14
14
|
import {defaultBehaviors} from '../behaviors/behavior.default'
|
|
15
15
|
import {
|
|
16
16
|
isCustomBehaviorEvent,
|
|
17
|
+
isDragBehaviorEvent,
|
|
18
|
+
isMouseBehaviorEvent,
|
|
17
19
|
type Behavior,
|
|
18
20
|
type CustomBehaviorEvent,
|
|
21
|
+
type DataBehaviorEvent,
|
|
19
22
|
type InternalBehaviorAction,
|
|
20
23
|
type NativeBehaviorEvent,
|
|
21
24
|
type SyntheticBehaviorEvent,
|
|
22
25
|
} from '../behaviors/behavior.types'
|
|
23
26
|
import type {Converter} from '../converters/converter.types'
|
|
27
|
+
import type {EventPosition} from '../internal-utils/event-position'
|
|
24
28
|
import type {NamespaceEvent} from '../type-utils'
|
|
25
29
|
import type {
|
|
26
30
|
EditorSelection,
|
|
@@ -181,7 +185,10 @@ export type InternalEditorEvent =
|
|
|
181
185
|
}
|
|
182
186
|
| {
|
|
183
187
|
type: 'behavior event'
|
|
184
|
-
behaviorEvent:
|
|
188
|
+
behaviorEvent:
|
|
189
|
+
| DataBehaviorEvent
|
|
190
|
+
| SyntheticBehaviorEvent
|
|
191
|
+
| NativeBehaviorEvent
|
|
185
192
|
editor: PortableTextSlateEditor
|
|
186
193
|
defaultActionCallback?: () => void
|
|
187
194
|
nativeEvent?: {preventDefault: () => void}
|
|
@@ -199,7 +206,7 @@ export type InternalEditorEvent =
|
|
|
199
206
|
| NamespaceEvent<EditorEmittedEvent, 'notify'>
|
|
200
207
|
| NamespaceEvent<UnsetEvent, 'notify'>
|
|
201
208
|
| SyntheticBehaviorEvent
|
|
202
|
-
| {type: 'dragstart'}
|
|
209
|
+
| {type: 'dragstart'; origin: EventPosition; ghost?: HTMLElement}
|
|
203
210
|
| {type: 'dragend'}
|
|
204
211
|
| {type: 'drop'}
|
|
205
212
|
|
|
@@ -232,6 +239,10 @@ export const editorMachine = setup({
|
|
|
232
239
|
maxBlocks: number | undefined
|
|
233
240
|
selection: EditorSelection
|
|
234
241
|
value: Array<PortableTextBlock> | undefined
|
|
242
|
+
internalDrag?: {
|
|
243
|
+
ghost?: HTMLElement
|
|
244
|
+
origin: EventPosition
|
|
245
|
+
}
|
|
235
246
|
},
|
|
236
247
|
events: {} as InternalEditorEvent,
|
|
237
248
|
emitted: {} as InternalEditorEmittedEvent,
|
|
@@ -313,10 +324,13 @@ export const editorMachine = setup({
|
|
|
313
324
|
|
|
314
325
|
const defaultAction =
|
|
315
326
|
event.type === 'custom behavior event' ||
|
|
327
|
+
isDragBehaviorEvent(event.behaviorEvent) ||
|
|
316
328
|
event.behaviorEvent.type === 'copy' ||
|
|
329
|
+
event.behaviorEvent.type === 'cut' ||
|
|
317
330
|
event.behaviorEvent.type === 'deserialize' ||
|
|
318
331
|
event.behaviorEvent.type === 'key.down' ||
|
|
319
332
|
event.behaviorEvent.type === 'key.up' ||
|
|
333
|
+
isMouseBehaviorEvent(event.behaviorEvent) ||
|
|
320
334
|
event.behaviorEvent.type === 'paste' ||
|
|
321
335
|
event.behaviorEvent.type === 'serialize'
|
|
322
336
|
? undefined
|
|
@@ -332,10 +346,20 @@ export const editorMachine = setup({
|
|
|
332
346
|
const eventBehaviors = [
|
|
333
347
|
...context.behaviors.values(),
|
|
334
348
|
...defaultBehaviors,
|
|
335
|
-
].filter(
|
|
336
|
-
(behavior)
|
|
337
|
-
|
|
338
|
-
|
|
349
|
+
].filter((behavior) => {
|
|
350
|
+
if (behavior.on === '*') {
|
|
351
|
+
return true
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (isDragBehaviorEvent(event.behaviorEvent)) {
|
|
355
|
+
return (
|
|
356
|
+
behavior.on === 'drag.*' ||
|
|
357
|
+
behavior.on === event.behaviorEvent.type
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return behavior.on === event.behaviorEvent.type
|
|
362
|
+
})
|
|
339
363
|
|
|
340
364
|
if (eventBehaviors.length === 0) {
|
|
341
365
|
if (defaultActionCallback) {
|
|
@@ -360,7 +384,10 @@ export const editorMachine = setup({
|
|
|
360
384
|
withApplyingBehaviorActions(event.editor, () => {
|
|
361
385
|
try {
|
|
362
386
|
performAction({
|
|
363
|
-
context
|
|
387
|
+
context: {
|
|
388
|
+
keyGenerator: context.keyGenerator,
|
|
389
|
+
schema: context.schema,
|
|
390
|
+
},
|
|
364
391
|
action: defaultAction,
|
|
365
392
|
})
|
|
366
393
|
} catch (error) {
|
|
@@ -379,8 +406,10 @@ export const editorMachine = setup({
|
|
|
379
406
|
converters: [...context.converters],
|
|
380
407
|
editor: event.editor,
|
|
381
408
|
keyGenerator: context.keyGenerator,
|
|
409
|
+
readOnly: self.getSnapshot().matches({'edit mode': 'read only'}),
|
|
382
410
|
schema: context.schema,
|
|
383
411
|
hasTag: (tag) => self.getSnapshot().hasTag(tag),
|
|
412
|
+
internalDrag: context.internalDrag,
|
|
384
413
|
})
|
|
385
414
|
|
|
386
415
|
let behaviorOverwritten = false
|
|
@@ -440,7 +469,13 @@ export const editorMachine = setup({
|
|
|
440
469
|
}
|
|
441
470
|
|
|
442
471
|
try {
|
|
443
|
-
performAction({
|
|
472
|
+
performAction({
|
|
473
|
+
context: {
|
|
474
|
+
keyGenerator: context.keyGenerator,
|
|
475
|
+
schema: context.schema,
|
|
476
|
+
},
|
|
477
|
+
action: internalAction,
|
|
478
|
+
})
|
|
444
479
|
} catch (error) {
|
|
445
480
|
console.error(
|
|
446
481
|
new Error(
|
|
@@ -483,7 +518,10 @@ export const editorMachine = setup({
|
|
|
483
518
|
withApplyingBehaviorActions(event.editor, () => {
|
|
484
519
|
try {
|
|
485
520
|
performAction({
|
|
486
|
-
context
|
|
521
|
+
context: {
|
|
522
|
+
keyGenerator: context.keyGenerator,
|
|
523
|
+
schema: context.schema,
|
|
524
|
+
},
|
|
487
525
|
action: defaultAction,
|
|
488
526
|
})
|
|
489
527
|
} catch (error) {
|
|
@@ -656,10 +694,28 @@ export const editorMachine = setup({
|
|
|
656
694
|
states: {
|
|
657
695
|
'idle': {
|
|
658
696
|
on: {
|
|
659
|
-
dragstart: {
|
|
697
|
+
dragstart: {
|
|
698
|
+
actions: [
|
|
699
|
+
assign({
|
|
700
|
+
internalDrag: ({event}) => ({
|
|
701
|
+
ghost: event.ghost,
|
|
702
|
+
origin: event.origin,
|
|
703
|
+
}),
|
|
704
|
+
}),
|
|
705
|
+
],
|
|
706
|
+
target: 'dragging internally',
|
|
707
|
+
},
|
|
660
708
|
},
|
|
661
709
|
},
|
|
662
710
|
'dragging internally': {
|
|
711
|
+
exit: [
|
|
712
|
+
({context}) => {
|
|
713
|
+
if (context.internalDrag?.ghost) {
|
|
714
|
+
document.body.removeChild(context.internalDrag.ghost)
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
assign({internalDrag: undefined}),
|
|
718
|
+
],
|
|
663
719
|
tags: ['dragging internally'],
|
|
664
720
|
on: {
|
|
665
721
|
dragend: {target: 'idle'},
|
|
@@ -73,12 +73,14 @@ export function getEditorSnapshot({
|
|
|
73
73
|
slateEditorInstance,
|
|
74
74
|
}),
|
|
75
75
|
keyGenerator: editorActorSnapshot.context.keyGenerator,
|
|
76
|
+
readOnly: editorActorSnapshot.matches({'edit mode': 'read only'}),
|
|
76
77
|
schema: editorActorSnapshot.context.schema,
|
|
77
78
|
selection: editorActorSnapshot.context.selection,
|
|
78
79
|
value: getValue({editorActorSnapshot, slateEditorInstance}),
|
|
79
80
|
},
|
|
80
81
|
beta: {
|
|
81
82
|
hasTag: (tag) => editorActorSnapshot.hasTag(tag),
|
|
83
|
+
internalDrag: editorActorSnapshot.context.internalDrag,
|
|
82
84
|
},
|
|
83
85
|
}
|
|
84
86
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
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'
|
|
3
4
|
import {toPortableTextRange} from '../internal-utils/ranges'
|
|
4
5
|
import {fromSlateValue} from '../internal-utils/values'
|
|
5
6
|
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
@@ -15,6 +16,7 @@ export type EditorContext = {
|
|
|
15
16
|
activeDecorators: Array<string>
|
|
16
17
|
converters: Array<Converter>
|
|
17
18
|
keyGenerator: () => string
|
|
19
|
+
readOnly: boolean
|
|
18
20
|
schema: EditorSchema
|
|
19
21
|
selection: EditorSelection
|
|
20
22
|
value: Array<PortableTextBlock>
|
|
@@ -31,6 +33,11 @@ export type EditorSnapshot = {
|
|
|
31
33
|
*/
|
|
32
34
|
beta: {
|
|
33
35
|
hasTag: HasTag
|
|
36
|
+
internalDrag:
|
|
37
|
+
| {
|
|
38
|
+
origin: EventPosition
|
|
39
|
+
}
|
|
40
|
+
| undefined
|
|
34
41
|
}
|
|
35
42
|
}
|
|
36
43
|
|
|
@@ -38,14 +45,22 @@ export function createEditorSnapshot({
|
|
|
38
45
|
converters,
|
|
39
46
|
editor,
|
|
40
47
|
keyGenerator,
|
|
48
|
+
readOnly,
|
|
41
49
|
schema,
|
|
42
50
|
hasTag,
|
|
51
|
+
internalDrag,
|
|
43
52
|
}: {
|
|
44
53
|
converters: Array<Converter>
|
|
45
54
|
editor: PortableTextSlateEditor
|
|
46
55
|
keyGenerator: () => string
|
|
56
|
+
readOnly: boolean
|
|
47
57
|
schema: EditorSchema
|
|
48
58
|
hasTag: HasTag
|
|
59
|
+
internalDrag:
|
|
60
|
+
| {
|
|
61
|
+
origin: EventPosition
|
|
62
|
+
}
|
|
63
|
+
| undefined
|
|
49
64
|
}) {
|
|
50
65
|
const value = fromSlateValue(
|
|
51
66
|
editor.children,
|
|
@@ -61,6 +76,7 @@ export function createEditorSnapshot({
|
|
|
61
76
|
}),
|
|
62
77
|
converters,
|
|
63
78
|
keyGenerator,
|
|
79
|
+
readOnly,
|
|
64
80
|
schema,
|
|
65
81
|
selection,
|
|
66
82
|
value,
|
|
@@ -70,6 +86,7 @@ export function createEditorSnapshot({
|
|
|
70
86
|
context,
|
|
71
87
|
beta: {
|
|
72
88
|
hasTag,
|
|
89
|
+
internalDrag,
|
|
73
90
|
},
|
|
74
91
|
} satisfies EditorSnapshot
|
|
75
92
|
}
|