@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
@@ -61,15 +61,8 @@ export function createWithEventListeners(
61
61
  }
62
62
  })
63
63
 
64
- const {
65
- deleteBackward,
66
- deleteForward,
67
- insertBreak,
68
- insertData,
69
- insertText,
70
- select,
71
- setFragmentData,
72
- } = editor
64
+ const {deleteBackward, deleteForward, insertBreak, insertText, select} =
65
+ editor
73
66
 
74
67
  editor.deleteBackward = (unit) => {
75
68
  if (isApplyingBehaviorActions(editor)) {
@@ -121,20 +114,8 @@ export function createWithEventListeners(
121
114
  return
122
115
  }
123
116
 
124
- editor.insertData = (dataTransfer) => {
125
- if (isApplyingBehaviorActions(editor)) {
126
- insertData(dataTransfer)
127
- return
128
- }
129
-
130
- editorActor.send({
131
- type: 'behavior event',
132
- behaviorEvent: {
133
- type: 'deserialize',
134
- dataTransfer,
135
- },
136
- editor,
137
- })
117
+ editor.insertData = () => {
118
+ console.warn('Unexpected call to .insertData(...)')
138
119
  return
139
120
  }
140
121
 
@@ -236,23 +217,8 @@ export function createWithEventListeners(
236
217
  return
237
218
  }
238
219
 
239
- editor.setFragmentData = (dataTransfer, originEvent) => {
240
- if (isApplyingBehaviorActions(editor)) {
241
- setFragmentData(dataTransfer)
242
- return
243
- }
244
-
245
- dataTransfer.clearData()
246
-
247
- editorActor.send({
248
- type: 'behavior event',
249
- behaviorEvent: {
250
- type: 'serialize',
251
- dataTransfer,
252
- originEvent: originEvent ?? 'unknown',
253
- },
254
- editor,
255
- })
220
+ editor.setFragmentData = () => {
221
+ console.warn('Unexpected call to .setFragmentData(...)')
256
222
  return
257
223
  }
258
224
 
@@ -13,11 +13,13 @@ export function createTestSnapshot(snapshot: {
13
13
  snapshot.context?.schema ?? compileSchemaDefinition(defineSchema({})),
14
14
  keyGenerator: snapshot.context?.keyGenerator ?? createTestKeyGenerator(),
15
15
  activeDecorators: snapshot.context?.activeDecorators ?? [],
16
+ readOnly: snapshot.context?.readOnly ?? false,
16
17
  value: snapshot.context?.value ?? [],
17
18
  selection: snapshot.context?.selection ?? null,
18
19
  },
19
20
  beta: {
20
21
  hasTag: snapshot.beta?.hasTag ?? (() => false),
22
+ internalDrag: undefined,
21
23
  },
22
24
  }
23
25
  }
@@ -0,0 +1,210 @@
1
+ import {Editor, type BaseRange} from 'slate'
2
+ import {DOMEditor, isDOMNode} from 'slate-dom'
3
+ import {ReactEditor} from 'slate-react'
4
+ import type {EditorSelection, EditorSnapshot} from '..'
5
+ import * as selectors from '../selectors'
6
+ import type {PortableTextSlateEditor} from '../types/editor'
7
+ import * as utils from '../utils'
8
+ import {toPortableTextRange} from './ranges'
9
+
10
+ export type EventPosition = {
11
+ block: 'start' | 'end'
12
+ /**
13
+ * Did the event origin from the editor DOM node itself or from a child node?
14
+ */
15
+ isEditor: boolean
16
+ selection: NonNullable<EditorSelection>
17
+ }
18
+ export type EventPositionBlock = EventPosition['block']
19
+
20
+ export function getEventPosition({
21
+ snapshot,
22
+ slateEditor,
23
+ event,
24
+ }: {
25
+ snapshot: EditorSnapshot
26
+ slateEditor: PortableTextSlateEditor
27
+ event: DragEvent | ClipboardEvent | MouseEvent
28
+ }): EventPosition | undefined {
29
+ if (!DOMEditor.hasTarget(slateEditor, event.target)) {
30
+ return undefined
31
+ }
32
+
33
+ const node = DOMEditor.toSlateNode(slateEditor, event.target)
34
+
35
+ if (isClipboardEvent(event)) {
36
+ const selection = snapshot.context.selection
37
+
38
+ if (!selection) {
39
+ return undefined
40
+ }
41
+
42
+ return {
43
+ block: 'end',
44
+ isEditor: Editor.isEditor(node),
45
+ selection,
46
+ }
47
+ }
48
+
49
+ const block = getEventPositionBlock({slateEditor, event})
50
+ const selection = getEventPositionSelection({snapshot, slateEditor, event})
51
+
52
+ if (!block || !selection) {
53
+ return undefined
54
+ }
55
+
56
+ return {
57
+ block,
58
+ isEditor: Editor.isEditor(node),
59
+ selection,
60
+ }
61
+ }
62
+
63
+ function getEventPositionBlock({
64
+ slateEditor,
65
+ event,
66
+ }: {
67
+ slateEditor: PortableTextSlateEditor
68
+ event: DragEvent | MouseEvent
69
+ }): EventPositionBlock | undefined {
70
+ if (!ReactEditor.hasTarget(slateEditor, event.target)) {
71
+ return undefined
72
+ }
73
+
74
+ const node = ReactEditor.toSlateNode(slateEditor, event.target)
75
+ const element = ReactEditor.toDOMNode(slateEditor, node)
76
+ const elementRect = element.getBoundingClientRect()
77
+ const top = elementRect.top
78
+ const height = elementRect.height
79
+ const location = Math.abs(top - event.pageY)
80
+
81
+ return location < height / 2 ? 'start' : 'end'
82
+ }
83
+
84
+ function getEventPositionSelection({
85
+ snapshot,
86
+ slateEditor,
87
+ event,
88
+ }: {
89
+ snapshot: EditorSnapshot
90
+ slateEditor: PortableTextSlateEditor
91
+ event: DragEvent | MouseEvent
92
+ }): EditorSelection {
93
+ const range = getSlateRangeFromEvent(slateEditor, event)
94
+
95
+ const selection = range
96
+ ? toPortableTextRange(
97
+ snapshot.context.value,
98
+ range,
99
+ snapshot.context.schema,
100
+ )
101
+ : null
102
+
103
+ if (!selection) {
104
+ return selection
105
+ }
106
+
107
+ const collapsedSelection = selectors.isSelectionCollapsed({
108
+ ...snapshot,
109
+ context: {
110
+ ...snapshot.context,
111
+ selection,
112
+ },
113
+ })
114
+ const focusTextBlock = selectors.getFocusTextBlock({
115
+ ...snapshot,
116
+ context: {
117
+ ...snapshot.context,
118
+ selection,
119
+ },
120
+ })
121
+ const focusSpan = selectors.getFocusSpan({
122
+ ...snapshot,
123
+ context: {
124
+ ...snapshot.context,
125
+ selection,
126
+ },
127
+ })
128
+
129
+ if (
130
+ event.type === 'dragstart' &&
131
+ collapsedSelection &&
132
+ focusTextBlock &&
133
+ focusSpan
134
+ ) {
135
+ // Looks like we are dragging an empty span. Let's drag the entire block
136
+ // instead
137
+
138
+ const blockStartPoint = utils.getBlockStartPoint(focusTextBlock)
139
+ const blockEndPoint = utils.getBlockEndPoint(focusTextBlock)
140
+
141
+ return {
142
+ anchor: blockStartPoint,
143
+ focus: blockEndPoint,
144
+ }
145
+ }
146
+
147
+ return selection
148
+ }
149
+
150
+ function getSlateRangeFromEvent(
151
+ editor: PortableTextSlateEditor,
152
+ event: DragEvent | MouseEvent,
153
+ ) {
154
+ if (!event.target) {
155
+ return undefined
156
+ }
157
+
158
+ if (!isDOMNode(event.target)) {
159
+ return undefined
160
+ }
161
+
162
+ const window = DOMEditor.getWindow(editor)
163
+
164
+ let domRange: Range | undefined
165
+
166
+ if (window.document.caretPositionFromPoint !== undefined) {
167
+ const position = window.document.caretPositionFromPoint(
168
+ event.clientX,
169
+ event.clientY,
170
+ )
171
+
172
+ if (position) {
173
+ domRange = window.document.createRange()
174
+ domRange.setStart(position.offsetNode, position.offset)
175
+ domRange.setEnd(position.offsetNode, position.offset)
176
+ }
177
+ } else if (window.document.caretRangeFromPoint !== undefined) {
178
+ // Use WebKit-proprietary fallback method
179
+ domRange =
180
+ window.document.caretRangeFromPoint(event.clientX, event.clientY) ??
181
+ undefined
182
+ } else {
183
+ console.warn(
184
+ 'Neither caretPositionFromPoint nor caretRangeFromPoint is supported',
185
+ )
186
+ return undefined
187
+ }
188
+
189
+ if (!domRange) {
190
+ return undefined
191
+ }
192
+
193
+ let range: BaseRange | undefined
194
+
195
+ try {
196
+ range = DOMEditor.toSlateRange(editor, domRange, {
197
+ exactMatch: false,
198
+ // It can still throw even with this option set to true
199
+ suppressThrow: false,
200
+ })
201
+ } catch {}
202
+
203
+ return range
204
+ }
205
+
206
+ function isClipboardEvent(
207
+ event: DragEvent | ClipboardEvent | MouseEvent,
208
+ ): event is ClipboardEvent {
209
+ return event.type === 'copy' || event.type === 'cut' || event.type === 'paste'
210
+ }
@@ -0,0 +1,56 @@
1
+ import {Editor, Node, type Path} from 'slate'
2
+ import type {PortableTextSlateEditor} from '../types/editor'
3
+
4
+ export function getFocusBlock({
5
+ editor,
6
+ }: {
7
+ editor: PortableTextSlateEditor
8
+ }): [node: Node, path: Path] | [undefined, undefined] {
9
+ if (!editor.selection) {
10
+ return [undefined, undefined]
11
+ }
12
+
13
+ const focusBlock = Array.from(
14
+ Editor.nodes(editor, {
15
+ at: editor.selection.focus.path.slice(0, 1),
16
+ match: (n) => !Editor.isEditor(n),
17
+ }),
18
+ ).at(0)
19
+
20
+ return focusBlock ?? [undefined, undefined]
21
+ }
22
+
23
+ export function getFocusChild({
24
+ editor,
25
+ }: {
26
+ editor: PortableTextSlateEditor
27
+ }): [node: Node, path: Path] | [undefined, undefined] {
28
+ const [focusBlock, focusBlockPath] = getFocusBlock({editor})
29
+ const childIndex = editor.selection?.focus.path.at(1)
30
+
31
+ if (!focusBlock || !focusBlockPath || childIndex === undefined) {
32
+ return [undefined, undefined]
33
+ }
34
+
35
+ const focusChild = Node.child(focusBlock, childIndex)
36
+
37
+ return focusChild
38
+ ? [focusChild, [...focusBlockPath, childIndex]]
39
+ : [undefined, undefined]
40
+ }
41
+
42
+ export function getLastBlock({
43
+ editor,
44
+ }: {
45
+ editor: PortableTextSlateEditor
46
+ }): [node: Node, path: Path] | [undefined, undefined] {
47
+ const lastBlock = Array.from(
48
+ Editor.nodes(editor, {
49
+ match: (n) => !Editor.isEditor(n),
50
+ at: [],
51
+ reverse: true,
52
+ }),
53
+ ).at(0)
54
+
55
+ return lastBlock ?? [undefined, undefined]
56
+ }
@@ -1,24 +1,10 @@
1
- import type {Editor, Element, Range} from 'slate'
1
+ import type {Editor, Range} from 'slate'
2
2
  import type {EditorSelection} from '..'
3
3
 
4
4
  // Is the editor currently receiving remote changes that are being applied to the content?
5
5
  export const IS_PROCESSING_REMOTE_CHANGES: WeakMap<Editor, boolean> =
6
6
  new WeakMap()
7
7
 
8
- // Is the editor dragging something?
9
- export const IS_DRAGGING: WeakMap<Editor, boolean> = new WeakMap()
10
- // Is the editor dragging a element?
11
- export const IS_DRAGGING_BLOCK_ELEMENT: WeakMap<Editor, Element> = new WeakMap()
12
-
13
- // When dragging elements, this will be the target element
14
- export const IS_DRAGGING_ELEMENT_TARGET: WeakMap<Editor, Element> =
15
- new WeakMap()
16
- // Target position for dragging over a block
17
- export const IS_DRAGGING_BLOCK_TARGET_POSITION: WeakMap<
18
- Editor,
19
- 'top' | 'bottom'
20
- > = new WeakMap()
21
-
22
8
  export const KEY_TO_SLATE_ELEMENT: WeakMap<Editor, any | undefined> =
23
9
  new WeakMap()
24
10
  export const KEY_TO_VALUE_ELEMENT: WeakMap<Editor, any | undefined> =
@@ -1,3 +1,4 @@
1
+ export {isSelectingEntireBlocks} from './selector.is-selecting-entire-blocks'
1
2
  export {getActiveAnnotations} from './selector.get-active-annotations'
2
3
  export {getActiveListItem} from './selector.get-active-list-item'
3
4
  export {getActiveStyle} from './selector.get-active-style'
@@ -7,6 +8,7 @@ export {getAnchorSpan} from './selector.get-anchor-span'
7
8
  export {getAnchorTextBlock} from './selector.get-anchor-text-block'
8
9
  export {getBlockOffsets} from './selector.get-block-offsets'
9
10
  export {getCaretWordSelection} from './selector.get-caret-word-selection'
11
+ export {getFocusInlineObject} from './selector.get-focus-inline-object'
10
12
  export {getNextInlineObject} from './selector.get-next-inline-object'
11
13
  export {getPreviousInlineObject} from './selector.get-previous-inline-object'
12
14
  export {getSelectedSlice} from './selector.get-selected-slice'
@@ -0,0 +1,21 @@
1
+ import {
2
+ isPortableTextSpan,
3
+ type KeyedSegment,
4
+ type PortableTextObject,
5
+ } from '@sanity/types'
6
+ import type {EditorSelector} from '../editor/editor-selector'
7
+ import {getFocusChild} from './selectors'
8
+
9
+ /**
10
+ * @public
11
+ */
12
+ export const getFocusInlineObject: EditorSelector<
13
+ | {node: PortableTextObject; path: [KeyedSegment, 'children', KeyedSegment]}
14
+ | undefined
15
+ > = (snapshot) => {
16
+ const focusChild = getFocusChild(snapshot)
17
+
18
+ return focusChild && !isPortableTextSpan(focusChild.node)
19
+ ? {node: focusChild.node, path: focusChild.path}
20
+ : undefined
21
+ }
@@ -0,0 +1,171 @@
1
+ import {describe, expect, test} from 'vitest'
2
+ import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
3
+ import type {EditorSelection} from '../types/editor'
4
+ import {isOverlappingSelection} from './selector.is-overlapping-selection'
5
+
6
+ function snapshot(selection: EditorSelection) {
7
+ return createTestSnapshot({
8
+ context: {
9
+ selection,
10
+ value: [
11
+ {_type: 'image', _key: 'k0'},
12
+ {
13
+ _type: 'block',
14
+ _key: 'k1',
15
+ children: [
16
+ {_type: 'span', _key: 'k3', text: 'foo'},
17
+ {_type: 'stock-ticker', _key: 'k4'},
18
+ {_type: 'span', _key: 'k5', text: 'bar'},
19
+ ],
20
+ },
21
+ {_type: 'image', _key: 'k2'},
22
+ ],
23
+ },
24
+ })
25
+ }
26
+
27
+ describe(isOverlappingSelection.name, () => {
28
+ test('null', () => {
29
+ expect(isOverlappingSelection(null)(snapshot(null))).toBe(false)
30
+ })
31
+
32
+ test('fully selected block object', () => {
33
+ expect(
34
+ isOverlappingSelection({
35
+ anchor: {path: [{_key: 'k0'}], offset: 0},
36
+ focus: {path: [{_key: 'k0'}], offset: 0},
37
+ })(
38
+ snapshot({
39
+ anchor: {path: [{_key: 'k0'}], offset: 0},
40
+ focus: {path: [{_key: 'k0'}], offset: 0},
41
+ }),
42
+ ),
43
+ ).toBe(true)
44
+ })
45
+
46
+ test('block object inside selection', () => {
47
+ expect(
48
+ isOverlappingSelection({
49
+ anchor: {path: [{_key: 'k0'}], offset: 0},
50
+ focus: {path: [{_key: 'k0'}], offset: 0},
51
+ })(
52
+ snapshot({
53
+ anchor: {path: [{_key: 'k0'}], offset: 0},
54
+ focus: {path: [{_key: 'k2'}], offset: 0},
55
+ }),
56
+ ),
57
+ ).toBe(true)
58
+ })
59
+
60
+ test('fully selected inline object', () => {
61
+ expect(
62
+ isOverlappingSelection({
63
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
64
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
65
+ })(
66
+ snapshot({
67
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
68
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
69
+ }),
70
+ ),
71
+ ).toBe(true)
72
+ })
73
+
74
+ test('inline object inside selection', () => {
75
+ expect(
76
+ isOverlappingSelection({
77
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
78
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
79
+ })(
80
+ snapshot({
81
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
82
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
83
+ }),
84
+ ),
85
+ ).toBe(true)
86
+ })
87
+
88
+ test('selection right before', () => {
89
+ expect(
90
+ isOverlappingSelection({
91
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 0},
92
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
93
+ })(
94
+ snapshot({
95
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
96
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
97
+ }),
98
+ ),
99
+ ).toBe(false)
100
+ })
101
+
102
+ test('selection overlapping from the start', () => {
103
+ expect(
104
+ isOverlappingSelection({
105
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 0},
106
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 3},
107
+ })(
108
+ snapshot({
109
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
110
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
111
+ }),
112
+ ),
113
+ ).toBe(true)
114
+ })
115
+
116
+ test('selection right after', () => {
117
+ expect(
118
+ isOverlappingSelection({
119
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
120
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 2},
121
+ })(
122
+ snapshot({
123
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
124
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
125
+ }),
126
+ ),
127
+ ).toBe(false)
128
+ })
129
+
130
+ test('selection overlapping from the end', () => {
131
+ expect(
132
+ isOverlappingSelection({
133
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 0},
134
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 2},
135
+ })(
136
+ snapshot({
137
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
138
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 1},
139
+ }),
140
+ ),
141
+ ).toBe(true)
142
+ })
143
+
144
+ test('before inline object', () => {
145
+ expect(
146
+ isOverlappingSelection({
147
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
148
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k3'}], offset: 2},
149
+ })(
150
+ snapshot({
151
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
152
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
153
+ }),
154
+ ),
155
+ ).toBe(false)
156
+ })
157
+
158
+ test('after inline object', () => {
159
+ expect(
160
+ isOverlappingSelection({
161
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 2},
162
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k5'}], offset: 2},
163
+ })(
164
+ snapshot({
165
+ anchor: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
166
+ focus: {path: [{_key: 'k1'}, 'children', {_key: 'k4'}], offset: 0},
167
+ }),
168
+ ),
169
+ ).toBe(false)
170
+ })
171
+ })