@portabletext/editor 3.3.3 → 3.3.5

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 (309) hide show
  1. package/lib/_chunks-dts/index.d.ts +21 -1667
  2. package/lib/index.js +511 -9010
  3. package/lib/index.js.map +1 -1
  4. package/package.json +14 -15
  5. package/src/behaviors/_exports/index.ts +0 -1
  6. package/src/behaviors/behavior.abstract.annotation.ts +0 -77
  7. package/src/behaviors/behavior.abstract.decorator.ts +0 -39
  8. package/src/behaviors/behavior.abstract.delete.ts +0 -273
  9. package/src/behaviors/behavior.abstract.deserialize.ts +0 -232
  10. package/src/behaviors/behavior.abstract.insert.ts +0 -525
  11. package/src/behaviors/behavior.abstract.keyboard.ts +0 -189
  12. package/src/behaviors/behavior.abstract.list-item.ts +0 -70
  13. package/src/behaviors/behavior.abstract.move.ts +0 -79
  14. package/src/behaviors/behavior.abstract.select.ts +0 -118
  15. package/src/behaviors/behavior.abstract.serialize.ts +0 -96
  16. package/src/behaviors/behavior.abstract.split.ts +0 -170
  17. package/src/behaviors/behavior.abstract.style.ts +0 -55
  18. package/src/behaviors/behavior.abstract.ts +0 -139
  19. package/src/behaviors/behavior.config.ts +0 -7
  20. package/src/behaviors/behavior.core.annotations.ts +0 -62
  21. package/src/behaviors/behavior.core.block-element.ts +0 -116
  22. package/src/behaviors/behavior.core.block-objects.ts +0 -285
  23. package/src/behaviors/behavior.core.decorators.ts +0 -44
  24. package/src/behaviors/behavior.core.dnd.ts +0 -356
  25. package/src/behaviors/behavior.core.insert-break.ts +0 -266
  26. package/src/behaviors/behavior.core.insert.ts +0 -52
  27. package/src/behaviors/behavior.core.lists.ts +0 -691
  28. package/src/behaviors/behavior.core.ts +0 -44
  29. package/src/behaviors/behavior.perform-event.ts +0 -354
  30. package/src/behaviors/behavior.types.action.ts +0 -102
  31. package/src/behaviors/behavior.types.behavior.ts +0 -83
  32. package/src/behaviors/behavior.types.event.ts +0 -667
  33. package/src/behaviors/behavior.types.guard.ts +0 -11
  34. package/src/behaviors/index.ts +0 -17
  35. package/src/converters/converter.json.ts +0 -53
  36. package/src/converters/converter.portable-text.deserialize.test.ts +0 -680
  37. package/src/converters/converter.portable-text.ts +0 -75
  38. package/src/converters/converter.text-html.deserialize.test.ts +0 -406
  39. package/src/converters/converter.text-html.serialize.test.ts +0 -246
  40. package/src/converters/converter.text-html.ts +0 -87
  41. package/src/converters/converter.text-markdown.ts +0 -67
  42. package/src/converters/converter.text-plain.test.ts +0 -245
  43. package/src/converters/converter.text-plain.ts +0 -126
  44. package/src/converters/converter.types.ts +0 -72
  45. package/src/converters/converters.core.ts +0 -18
  46. package/src/editor/Editable.tsx +0 -1012
  47. package/src/editor/PortableTextEditor.tsx +0 -791
  48. package/src/editor/components/drop-indicator.tsx +0 -17
  49. package/src/editor/components/render-block-object.tsx +0 -121
  50. package/src/editor/components/render-default-object.tsx +0 -21
  51. package/src/editor/components/render-element.tsx +0 -88
  52. package/src/editor/components/render-inline-object.tsx +0 -129
  53. package/src/editor/components/render-leaf.tsx +0 -64
  54. package/src/editor/components/render-span.tsx +0 -303
  55. package/src/editor/components/render-text-block.tsx +0 -265
  56. package/src/editor/components/render-text.tsx +0 -18
  57. package/src/editor/components/use-core-block-element-behaviors.ts +0 -39
  58. package/src/editor/create-editor.ts +0 -323
  59. package/src/editor/create-slate-editor.tsx +0 -64
  60. package/src/editor/editor-actor-context.ts +0 -4
  61. package/src/editor/editor-context.tsx +0 -7
  62. package/src/editor/editor-dom.ts +0 -220
  63. package/src/editor/editor-machine.ts +0 -751
  64. package/src/editor/editor-provider.tsx +0 -111
  65. package/src/editor/editor-schema.ts +0 -6
  66. package/src/editor/editor-selector.ts +0 -89
  67. package/src/editor/editor-snapshot.ts +0 -68
  68. package/src/editor/event-to-change.tsx +0 -49
  69. package/src/editor/hooks/usePortableTextEditor.ts +0 -25
  70. package/src/editor/hooks/usePortableTextEditorSelection.tsx +0 -28
  71. package/src/editor/mutation-machine.ts +0 -322
  72. package/src/editor/plugins/create-with-event-listeners.ts +0 -271
  73. package/src/editor/plugins/createWithEditableAPI.ts +0 -529
  74. package/src/editor/plugins/createWithHotKeys.ts +0 -68
  75. package/src/editor/plugins/createWithObjectKeys.ts +0 -289
  76. package/src/editor/plugins/createWithPatches.ts +0 -272
  77. package/src/editor/plugins/createWithPortableTextMarkModel.ts +0 -559
  78. package/src/editor/plugins/createWithSchemaTypes.ts +0 -121
  79. package/src/editor/plugins/slate-plugin.update-selection.ts +0 -51
  80. package/src/editor/plugins/slate-plugin.update-value.ts +0 -46
  81. package/src/editor/plugins/with-plugins.ts +0 -69
  82. package/src/editor/range-decorations-machine.ts +0 -421
  83. package/src/editor/relay-actor-context.ts +0 -4
  84. package/src/editor/relay-machine.ts +0 -152
  85. package/src/editor/sync-machine.ts +0 -961
  86. package/src/editor/use-editor.ts +0 -27
  87. package/src/editor/validate-selection-machine.test.ts +0 -47
  88. package/src/editor/validate-selection-machine.ts +0 -149
  89. package/src/editor/weakMaps.ts +0 -15
  90. package/src/editor/with-normalizing-node.ts +0 -14
  91. package/src/editor/with-performing-behavior-operation.ts +0 -21
  92. package/src/editor/withChanges.ts +0 -13
  93. package/src/editor/without-normalizing-conditional.ts +0 -13
  94. package/src/editor/withoutPatching.ts +0 -14
  95. package/src/editor.ts +0 -59
  96. package/src/history/behavior.operation.history.redo.ts +0 -67
  97. package/src/history/behavior.operation.history.undo.ts +0 -71
  98. package/src/history/event.history.undo.test.tsx +0 -672
  99. package/src/history/history.preserving-keys.test.tsx +0 -112
  100. package/src/history/remote-patches.ts +0 -20
  101. package/src/history/slate-plugin.history.ts +0 -142
  102. package/src/history/slate-plugin.redoing.ts +0 -21
  103. package/src/history/slate-plugin.undoing.ts +0 -21
  104. package/src/history/slate-plugin.without-history.ts +0 -23
  105. package/src/history/transform-operation.ts +0 -245
  106. package/src/history/undo-redo-collaboration.test.tsx +0 -541
  107. package/src/history/undo-redo.feature +0 -125
  108. package/src/history/undo-redo.test.tsx +0 -195
  109. package/src/history/undo-step.ts +0 -148
  110. package/src/index.ts +0 -107
  111. package/src/internal-utils/__tests__/ranges.test.ts +0 -23
  112. package/src/internal-utils/__tests__/values.test.ts +0 -110
  113. package/src/internal-utils/apply-operation-to-portable-text.test.ts +0 -1861
  114. package/src/internal-utils/apply-operation-to-portable-text.ts +0 -615
  115. package/src/internal-utils/applyPatch.ts +0 -644
  116. package/src/internal-utils/block-keys.ts +0 -9
  117. package/src/internal-utils/build-index-maps.test.ts +0 -464
  118. package/src/internal-utils/build-index-maps.ts +0 -131
  119. package/src/internal-utils/collapse-selection.ts +0 -36
  120. package/src/internal-utils/compound-client-rect.ts +0 -28
  121. package/src/internal-utils/create-placeholder-block.ts +0 -21
  122. package/src/internal-utils/create-test-snapshot.ts +0 -28
  123. package/src/internal-utils/debug.ts +0 -12
  124. package/src/internal-utils/editor-selection.test.ts +0 -44
  125. package/src/internal-utils/editor-selection.ts +0 -56
  126. package/src/internal-utils/event-position.ts +0 -318
  127. package/src/internal-utils/global-scope.ts +0 -27
  128. package/src/internal-utils/globally-scoped-context.ts +0 -39
  129. package/src/internal-utils/is-hotkey.test.ts +0 -114
  130. package/src/internal-utils/is-hotkey.ts +0 -209
  131. package/src/internal-utils/mime-type.ts +0 -1
  132. package/src/internal-utils/move-range-by-operation.ts +0 -19
  133. package/src/internal-utils/operation-to-patches.test.ts +0 -522
  134. package/src/internal-utils/operation-to-patches.ts +0 -571
  135. package/src/internal-utils/portable-text-node.ts +0 -209
  136. package/src/internal-utils/schema.ts +0 -8
  137. package/src/internal-utils/selection-block-keys.ts +0 -20
  138. package/src/internal-utils/selection-focus-text.ts +0 -40
  139. package/src/internal-utils/selection-text.test.ts +0 -32
  140. package/src/internal-utils/selection-text.ts +0 -21
  141. package/src/internal-utils/selection.ts +0 -77
  142. package/src/internal-utils/sibling-utils.ts +0 -55
  143. package/src/internal-utils/slate-utils.test.tsx +0 -121
  144. package/src/internal-utils/slate-utils.ts +0 -417
  145. package/src/internal-utils/split-string.ts +0 -12
  146. package/src/internal-utils/stop-actor.ts +0 -43
  147. package/src/internal-utils/string-overlap.test.ts +0 -14
  148. package/src/internal-utils/string-overlap.ts +0 -28
  149. package/src/internal-utils/string-utils.ts +0 -7
  150. package/src/internal-utils/text-block-key.test.ts +0 -41
  151. package/src/internal-utils/text-block-key.ts +0 -26
  152. package/src/internal-utils/text-marks.test.ts +0 -41
  153. package/src/internal-utils/text-marks.ts +0 -22
  154. package/src/internal-utils/text-selection.test.ts +0 -211
  155. package/src/internal-utils/text-selection.ts +0 -121
  156. package/src/internal-utils/to-slate-range.test.ts +0 -278
  157. package/src/internal-utils/to-slate-range.ts +0 -171
  158. package/src/internal-utils/validateValue.ts +0 -443
  159. package/src/internal-utils/value-annotations.ts +0 -33
  160. package/src/internal-utils/values.test.ts +0 -282
  161. package/src/internal-utils/values.ts +0 -266
  162. package/src/keyboard-shortcuts/default-keyboard-shortcuts.ts +0 -146
  163. package/src/operations/behavior.operation.annotation.add.ts +0 -99
  164. package/src/operations/behavior.operation.annotation.remove.ts +0 -150
  165. package/src/operations/behavior.operation.block.set.ts +0 -104
  166. package/src/operations/behavior.operation.block.unset.ts +0 -54
  167. package/src/operations/behavior.operation.child.set.ts +0 -107
  168. package/src/operations/behavior.operation.child.unset.ts +0 -116
  169. package/src/operations/behavior.operation.decorator.add.ts +0 -131
  170. package/src/operations/behavior.operation.delete.ts +0 -294
  171. package/src/operations/behavior.operation.insert.block.ts +0 -495
  172. package/src/operations/behavior.operation.insert.child.ts +0 -129
  173. package/src/operations/behavior.operation.insert.text.ts +0 -8
  174. package/src/operations/behavior.operation.move.backward.ts +0 -12
  175. package/src/operations/behavior.operation.move.block.ts +0 -44
  176. package/src/operations/behavior.operation.move.forward.ts +0 -11
  177. package/src/operations/behavior.operation.select.ts +0 -27
  178. package/src/operations/behavior.operations.ts +0 -221
  179. package/src/plugins/_exports/index.ts +0 -1
  180. package/src/plugins/index.ts +0 -3
  181. package/src/plugins/plugin.behavior.tsx +0 -24
  182. package/src/plugins/plugin.editor-ref.tsx +0 -17
  183. package/src/plugins/plugin.event-listener.tsx +0 -68
  184. package/src/plugins/plugin.internal.auto-close-brackets.test.tsx +0 -71
  185. package/src/plugins/plugin.internal.auto-close-brackets.ts +0 -62
  186. package/src/plugins/plugin.internal.change-ref.tsx +0 -19
  187. package/src/plugins/plugin.internal.portable-text-editor-ref.tsx +0 -16
  188. package/src/plugins/plugin.internal.slate-editor-ref.tsx +0 -15
  189. package/src/priority/priority.core.ts +0 -3
  190. package/src/priority/priority.sort.test.ts +0 -319
  191. package/src/priority/priority.sort.ts +0 -123
  192. package/src/priority/priority.types.ts +0 -24
  193. package/src/selectors/_exports/index.ts +0 -1
  194. package/src/selectors/drag-selection.test.ts +0 -578
  195. package/src/selectors/drag-selection.ts +0 -118
  196. package/src/selectors/index.ts +0 -54
  197. package/src/selectors/selector.get-active-annotation-marks.ts +0 -12
  198. package/src/selectors/selector.get-active-annotations.ts +0 -36
  199. package/src/selectors/selector.get-active-decorators.ts +0 -29
  200. package/src/selectors/selector.get-active-list-item.ts +0 -38
  201. package/src/selectors/selector.get-active-style.ts +0 -38
  202. package/src/selectors/selector.get-anchor-block.ts +0 -22
  203. package/src/selectors/selector.get-anchor-child.ts +0 -36
  204. package/src/selectors/selector.get-anchor-span.ts +0 -17
  205. package/src/selectors/selector.get-anchor-text-block.ts +0 -18
  206. package/src/selectors/selector.get-block-offsets.ts +0 -34
  207. package/src/selectors/selector.get-caret-word-selection.test.ts +0 -284
  208. package/src/selectors/selector.get-caret-word-selection.ts +0 -134
  209. package/src/selectors/selector.get-first-block.ts +0 -14
  210. package/src/selectors/selector.get-focus-block-object.ts +0 -18
  211. package/src/selectors/selector.get-focus-block.ts +0 -23
  212. package/src/selectors/selector.get-focus-child.ts +0 -36
  213. package/src/selectors/selector.get-focus-inline-object.ts +0 -17
  214. package/src/selectors/selector.get-focus-list-block.ts +0 -18
  215. package/src/selectors/selector.get-focus-span.ts +0 -18
  216. package/src/selectors/selector.get-focus-text-block.ts +0 -18
  217. package/src/selectors/selector.get-last-block.ts +0 -16
  218. package/src/selectors/selector.get-mark-state.test.ts +0 -325
  219. package/src/selectors/selector.get-mark-state.ts +0 -263
  220. package/src/selectors/selector.get-next-block.ts +0 -29
  221. package/src/selectors/selector.get-next-inline-object.ts +0 -53
  222. package/src/selectors/selector.get-next-inline-objects.ts +0 -50
  223. package/src/selectors/selector.get-next-span.ts +0 -56
  224. package/src/selectors/selector.get-previous-block.ts +0 -29
  225. package/src/selectors/selector.get-previous-inline-object.ts +0 -50
  226. package/src/selectors/selector.get-previous-inline-objects.ts +0 -47
  227. package/src/selectors/selector.get-previous-span.ts +0 -53
  228. package/src/selectors/selector.get-selected-blocks.ts +0 -61
  229. package/src/selectors/selector.get-selected-spans.test.ts +0 -347
  230. package/src/selectors/selector.get-selected-spans.ts +0 -155
  231. package/src/selectors/selector.get-selected-text-blocks.ts +0 -73
  232. package/src/selectors/selector.get-selected-value.test.ts +0 -834
  233. package/src/selectors/selector.get-selected-value.ts +0 -66
  234. package/src/selectors/selector.get-selection-end-block.ts +0 -33
  235. package/src/selectors/selector.get-selection-end-child.ts +0 -33
  236. package/src/selectors/selector.get-selection-end-point.ts +0 -17
  237. package/src/selectors/selector.get-selection-start-block.ts +0 -33
  238. package/src/selectors/selector.get-selection-start-child.ts +0 -33
  239. package/src/selectors/selector.get-selection-start-point.ts +0 -17
  240. package/src/selectors/selector.get-selection-text.test.ts +0 -421
  241. package/src/selectors/selector.get-selection-text.ts +0 -27
  242. package/src/selectors/selector.get-selection.ts +0 -9
  243. package/src/selectors/selector.get-text-after.ts +0 -46
  244. package/src/selectors/selector.get-text-before.ts +0 -46
  245. package/src/selectors/selector.get-value.ts +0 -11
  246. package/src/selectors/selector.is-active-annotation.test.ts +0 -320
  247. package/src/selectors/selector.is-active-annotation.ts +0 -52
  248. package/src/selectors/selector.is-active-decorator.test.ts +0 -136
  249. package/src/selectors/selector.is-active-decorator.ts +0 -24
  250. package/src/selectors/selector.is-active-list-item.ts +0 -13
  251. package/src/selectors/selector.is-active-style.ts +0 -13
  252. package/src/selectors/selector.is-at-the-end-of-block.ts +0 -30
  253. package/src/selectors/selector.is-at-the-start-of-block.ts +0 -30
  254. package/src/selectors/selector.is-overlapping-selection.test.ts +0 -304
  255. package/src/selectors/selector.is-overlapping-selection.ts +0 -181
  256. package/src/selectors/selector.is-point-after-selection.ts +0 -97
  257. package/src/selectors/selector.is-point-before-selection.ts +0 -97
  258. package/src/selectors/selector.is-selecting-entire-blocks.ts +0 -43
  259. package/src/selectors/selector.is-selection-collapsed.ts +0 -17
  260. package/src/selectors/selector.is-selection-expanded.test.ts +0 -63
  261. package/src/selectors/selector.is-selection-expanded.ts +0 -9
  262. package/src/test/_exports/index.ts +0 -1
  263. package/src/test/gherkin-parameter-types.ts +0 -112
  264. package/src/test/index.ts +0 -1
  265. package/src/test/vitest/_exports/index.ts +0 -1
  266. package/src/test/vitest/index.ts +0 -3
  267. package/src/test/vitest/step-context.ts +0 -13
  268. package/src/test/vitest/step-definitions.tsx +0 -960
  269. package/src/test/vitest/test-editor.tsx +0 -198
  270. package/src/type-utils.ts +0 -29
  271. package/src/types/block-offset.ts +0 -9
  272. package/src/types/block-with-optional-key.ts +0 -25
  273. package/src/types/editor.ts +0 -509
  274. package/src/types/options.ts +0 -13
  275. package/src/types/paths.ts +0 -35
  276. package/src/types/slate-editor.ts +0 -50
  277. package/src/types/slate.ts +0 -27
  278. package/src/utils/_exports/index.ts +0 -1
  279. package/src/utils/asserters.ts +0 -9
  280. package/src/utils/index.ts +0 -24
  281. package/src/utils/key-generator.ts +0 -33
  282. package/src/utils/parse-blocks.test.ts +0 -836
  283. package/src/utils/parse-blocks.ts +0 -504
  284. package/src/utils/util.at-the-beginning-of-block.ts +0 -32
  285. package/src/utils/util.block-offset-to-block-selection-point.ts +0 -28
  286. package/src/utils/util.block-offset-to-selection-point.ts +0 -33
  287. package/src/utils/util.block-offset.test.ts +0 -375
  288. package/src/utils/util.block-offset.ts +0 -136
  289. package/src/utils/util.block-offsets-to-selection.ts +0 -38
  290. package/src/utils/util.child-selection-point-to-block-offset.ts +0 -51
  291. package/src/utils/util.get-block-end-point.ts +0 -35
  292. package/src/utils/util.get-block-start-point.ts +0 -31
  293. package/src/utils/util.get-selection-end-point.ts +0 -20
  294. package/src/utils/util.get-selection-start-point.ts +0 -20
  295. package/src/utils/util.get-text-block-text.ts +0 -8
  296. package/src/utils/util.is-empty-text-block.ts +0 -21
  297. package/src/utils/util.is-equal-selection-points.ts +0 -13
  298. package/src/utils/util.is-equal-selections.ts +0 -20
  299. package/src/utils/util.is-keyed-segment.ts +0 -8
  300. package/src/utils/util.is-selection-collapsed.ts +0 -16
  301. package/src/utils/util.is-selection-expanded.ts +0 -13
  302. package/src/utils/util.merge-text-blocks.ts +0 -40
  303. package/src/utils/util.reverse-selection.ts +0 -26
  304. package/src/utils/util.selection-point-to-block-offset.ts +0 -30
  305. package/src/utils/util.selection-point.ts +0 -22
  306. package/src/utils/util.slice-blocks.ts +0 -221
  307. package/src/utils/util.slice-text-block.test.ts +0 -190
  308. package/src/utils/util.slice-text-block.ts +0 -89
  309. package/src/utils/util.split-text-block.ts +0 -54
@@ -1,615 +0,0 @@
1
- import type {PortableTextBlock} from '@sanity/types'
2
- import {Element, Path, type Node, type Operation} from 'slate'
3
- import type {EditorSchema} from '../editor/editor-schema'
4
- import type {EditorContext} from '../editor/editor-snapshot'
5
- import type {OmitFromUnion} from '../type-utils'
6
- import {
7
- getBlock,
8
- getNode,
9
- getParent,
10
- getSpan,
11
- isEditorNode,
12
- isObjectNode,
13
- isPartialSpanNode,
14
- isSpanNode,
15
- isTextBlockNode,
16
- type EditorNode,
17
- type ObjectNode,
18
- type SpanNode,
19
- type TextBlockNode,
20
- } from './portable-text-node'
21
-
22
- export function applyOperationToPortableText(
23
- context: Pick<EditorContext, 'schema'>,
24
- value: Array<PortableTextBlock>,
25
- operation: OmitFromUnion<Operation, 'type', 'set_selection'>,
26
- ): Array<PortableTextBlock> {
27
- const root = {children: value} as EditorNode<EditorSchema>
28
-
29
- try {
30
- const newRoot = applyOperationToPortableTextImmutable(
31
- context,
32
- root,
33
- operation,
34
- )
35
- return newRoot.children as Array<PortableTextBlock>
36
- } catch (e) {
37
- console.error(e)
38
- return value
39
- }
40
- }
41
-
42
- function applyOperationToPortableTextImmutable(
43
- context: Pick<EditorContext, 'schema'>,
44
- root: EditorNode<EditorSchema>,
45
- operation: OmitFromUnion<Operation, 'type', 'set_selection'>,
46
- ): EditorNode<EditorSchema> {
47
- switch (operation.type) {
48
- case 'insert_node': {
49
- const {path, node: insertedNode} = operation
50
- const parent = getParent(context, root, path)
51
- const index = path[path.length - 1]
52
-
53
- if (!parent) {
54
- return root
55
- }
56
-
57
- if (index > parent.children.length) {
58
- return root
59
- }
60
-
61
- if (path.length === 1) {
62
- // Inserting block at the root
63
-
64
- if (isTextBlockNode(context, insertedNode)) {
65
- // Text blocks can be inserted as is
66
- const newBlock = {
67
- ...insertedNode,
68
- children: insertedNode.children.map((child) => {
69
- if ('__inline' in child) {
70
- // Except for inline object children which need to have their
71
- // `value` spread onto the block
72
- return {
73
- _key: child._key,
74
- _type: child._type,
75
- ...('value' in child && typeof child.value === 'object'
76
- ? child.value
77
- : {}),
78
- }
79
- }
80
-
81
- return child
82
- }),
83
- }
84
-
85
- return {
86
- ...root,
87
- children: insertChildren(root.children, index, newBlock),
88
- }
89
- }
90
-
91
- if (Element.isElement(insertedNode) && !('__inline' in insertedNode)) {
92
- // Void blocks have to have their `value` spread onto the block
93
- const newBlock = {
94
- _key: insertedNode._key,
95
- _type: insertedNode._type,
96
- ...('value' in insertedNode &&
97
- typeof insertedNode.value === 'object'
98
- ? insertedNode.value
99
- : {}),
100
- }
101
-
102
- return {
103
- ...root,
104
- children: insertChildren(root.children, index, newBlock),
105
- }
106
- }
107
- }
108
-
109
- if (path.length === 2) {
110
- // Inserting children into blocks
111
- const blockIndex = path[0]
112
-
113
- if (!isTextBlockNode(context, parent)) {
114
- // Only text blocks can have children
115
- return root
116
- }
117
-
118
- let newChild: SpanNode<EditorSchema> | ObjectNode | undefined
119
-
120
- if (isPartialSpanNode(insertedNode)) {
121
- // Text nodes can be inserted as is
122
- newChild = insertedNode
123
- } else if ('__inline' in insertedNode) {
124
- // Void children have to have their `value` spread onto the block
125
- newChild = {
126
- _key: insertedNode._key,
127
- _type: insertedNode._type,
128
- ...('value' in insertedNode &&
129
- typeof insertedNode.value === 'object'
130
- ? insertedNode.value
131
- : {}),
132
- }
133
- } else {
134
- return root
135
- }
136
-
137
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
138
- ...block,
139
- children: insertChildren(block.children, index, newChild),
140
- }))
141
- }
142
-
143
- return root
144
- }
145
-
146
- case 'insert_text': {
147
- const {path, offset, text} = operation
148
- if (text.length === 0) {
149
- return root
150
- }
151
-
152
- const span = getSpan(context, root, path)
153
- if (!span) {
154
- return root
155
- }
156
-
157
- const blockIndex = path[0]
158
- const childIndex = path[1]
159
- const before = span.text.slice(0, offset)
160
- const after = span.text.slice(offset)
161
- const newSpan = {...span, text: before + text + after}
162
-
163
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
164
- ...block,
165
- children: replaceChild(block.children, childIndex, newSpan),
166
- }))
167
- }
168
-
169
- case 'merge_node': {
170
- const {path} = operation
171
-
172
- const lastPathIndex = path.at(-1)
173
-
174
- if (lastPathIndex === 0) {
175
- return root
176
- }
177
-
178
- const node = getNode(context, root, path)
179
- const prevPath = Path.previous(path)
180
- const prev = getNode(context, root, prevPath)
181
- const parent = getParent(context, root, path)
182
-
183
- if (!node || !prev || !parent) {
184
- return root
185
- }
186
-
187
- const index = path[path.length - 1]
188
-
189
- if (isPartialSpanNode(node) && isPartialSpanNode(prev)) {
190
- // Merging spans
191
- const blockIndex = path[0]
192
- const newPrev = {...prev, text: prev.text + node.text}
193
-
194
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => {
195
- const newChildren = replaceChild(
196
- block.children,
197
- index - 1,
198
- newPrev as never,
199
- )
200
- return {
201
- ...block,
202
- children: removeChildren(newChildren, index),
203
- }
204
- })
205
- }
206
-
207
- if (isTextBlockNode(context, node) && isTextBlockNode(context, prev)) {
208
- // Merging blocks
209
- const newPrev = {
210
- ...prev,
211
- children: [...prev.children, ...node.children],
212
- }
213
- const newChildren = replaceChild(root.children, index - 1, newPrev)
214
- return {
215
- ...root,
216
- children: removeChildren(newChildren, index),
217
- }
218
- }
219
-
220
- return root
221
- }
222
-
223
- case 'move_node': {
224
- const {path, newPath} = operation
225
-
226
- if (Path.isAncestor(path, newPath)) {
227
- return root
228
- }
229
-
230
- const node = getNode(context, root, path)
231
- const parent = getParent(context, root, path)
232
- const index = path[path.length - 1]
233
-
234
- if (!node || !parent) {
235
- return root
236
- }
237
-
238
- // First, remove the node from its current position
239
- let newRoot: EditorNode<EditorSchema>
240
-
241
- if (path.length === 1) {
242
- // Removing block from root
243
- newRoot = {
244
- ...root,
245
- children: removeChildren(root.children, index),
246
- }
247
- } else if (path.length === 2) {
248
- // Removing child from block
249
- const blockIndex = path[0]
250
- newRoot = updateTextBlockAtIndex(
251
- context,
252
- root,
253
- blockIndex,
254
- (block) => ({
255
- ...block,
256
- children: removeChildren(block.children, index),
257
- }),
258
- )
259
- } else {
260
- return root
261
- }
262
-
263
- // This is tricky, but since the `path` and `newPath` both refer to
264
- // the same snapshot in time, there's a mismatch. After either
265
- // removing the original position, the second step's path can be out
266
- // of date. So instead of using the `op.newPath` directly, we
267
- // transform `op.path` to ascertain what the `newPath` would be after
268
- // the operation was applied.
269
- const truePath = Path.transform(path, operation)!
270
- const newIndex = truePath[truePath.length - 1]
271
-
272
- if (truePath.length === 1) {
273
- // Inserting block at root
274
- return {
275
- ...newRoot,
276
- children: insertChildren(newRoot.children, newIndex, node as never),
277
- }
278
- }
279
-
280
- if (truePath.length === 2) {
281
- // Inserting child into block
282
- const newBlockIndex = truePath[0]
283
- const newParent = newRoot.children[newBlockIndex]
284
-
285
- if (!newParent || !isTextBlockNode(context, newParent)) {
286
- return root
287
- }
288
-
289
- return updateTextBlockAtIndex(
290
- context,
291
- newRoot,
292
- newBlockIndex,
293
- (block) => ({
294
- ...block,
295
- children: insertChildren(block.children, newIndex, node as never),
296
- }),
297
- )
298
- }
299
-
300
- return root
301
- }
302
-
303
- case 'remove_node': {
304
- const {path} = operation
305
- const index = path[path.length - 1]
306
- const parent = getParent(context, root, path)
307
-
308
- if (!parent) {
309
- return root
310
- }
311
-
312
- if (path.length === 1) {
313
- // Removing block from root
314
- return {
315
- ...root,
316
- children: removeChildren(root.children, index),
317
- }
318
- }
319
-
320
- if (path.length === 2) {
321
- // Removing child from block
322
- const blockIndex = path[0]
323
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
324
- ...block,
325
- children: removeChildren(block.children, index),
326
- }))
327
- }
328
-
329
- return root
330
- }
331
-
332
- case 'remove_text': {
333
- const {path, offset, text} = operation
334
-
335
- if (text.length === 0) {
336
- return root
337
- }
338
-
339
- const span = getSpan(context, root, path)
340
-
341
- if (!span) {
342
- return root
343
- }
344
-
345
- const blockIndex = path[0]
346
- const childIndex = path[1]
347
- const before = span.text.slice(0, offset)
348
- const after = span.text.slice(offset + text.length)
349
- const newSpan = {...span, text: before + after}
350
-
351
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
352
- ...block,
353
- children: replaceChild(block.children, childIndex, newSpan as never),
354
- }))
355
- }
356
-
357
- case 'set_node': {
358
- const {path, properties, newProperties} = operation
359
-
360
- const node = getNode(context, root, path)
361
-
362
- if (!node) {
363
- return root
364
- }
365
-
366
- if (isEditorNode(node)) {
367
- return root
368
- }
369
-
370
- if (isObjectNode(context, node)) {
371
- const valueBefore = (
372
- 'value' in properties && typeof properties.value === 'object'
373
- ? properties.value
374
- : {}
375
- ) as Partial<Node>
376
- const valueAfter = (
377
- 'value' in newProperties && typeof newProperties.value === 'object'
378
- ? newProperties.value
379
- : {}
380
- ) as Partial<Node>
381
-
382
- const newNode = {...node}
383
-
384
- for (const key in newProperties) {
385
- if (key === 'value') {
386
- continue
387
- }
388
-
389
- const value = newProperties[key as keyof Partial<Node>]
390
-
391
- if (value == null) {
392
- delete newNode[key]
393
- } else {
394
- newNode[key] = value
395
- }
396
- }
397
-
398
- for (const key in properties) {
399
- if (key === 'value') {
400
- continue
401
- }
402
-
403
- if (!newProperties.hasOwnProperty(key)) {
404
- delete newNode[key]
405
- }
406
- }
407
-
408
- for (const key in valueAfter) {
409
- const value = valueAfter[key as keyof Partial<Node>]
410
-
411
- if (value == null) {
412
- delete newNode[key]
413
- } else {
414
- newNode[key] = value
415
- }
416
- }
417
-
418
- for (const key in valueBefore) {
419
- if (!valueAfter.hasOwnProperty(key)) {
420
- delete newNode[key]
421
- }
422
- }
423
-
424
- if (path.length === 1) {
425
- return {
426
- ...root,
427
- children: replaceChild(root.children, path[0], newNode),
428
- }
429
- }
430
-
431
- if (path.length === 2) {
432
- return updateTextBlockAtIndex(context, root, path[0], (block) => ({
433
- ...block,
434
- children: replaceChild(block.children, path[1], newNode),
435
- }))
436
- }
437
-
438
- return root
439
- }
440
-
441
- if (isTextBlockNode(context, node)) {
442
- const newNode = {...node}
443
-
444
- for (const key in newProperties) {
445
- if (key === 'children' || key === 'text') {
446
- continue
447
- }
448
-
449
- const value = newProperties[key as keyof Partial<Node>]
450
-
451
- if (value == null) {
452
- delete newNode[key]
453
- } else {
454
- newNode[key] = value
455
- }
456
- }
457
-
458
- // properties that were previously defined, but are now missing, must be deleted
459
- for (const key in properties) {
460
- if (!newProperties.hasOwnProperty(key)) {
461
- delete newNode[key]
462
- }
463
- }
464
-
465
- return {
466
- ...root,
467
- children: replaceChild(root.children, path[0], newNode),
468
- }
469
- }
470
-
471
- if (isPartialSpanNode(node)) {
472
- const newNode = {...node}
473
-
474
- for (const key in newProperties) {
475
- if (key === 'text') {
476
- continue
477
- }
478
-
479
- const value = newProperties[key as keyof Partial<Node>]
480
-
481
- if (value == null) {
482
- delete newNode[key]
483
- } else {
484
- newNode[key] = value
485
- }
486
- }
487
-
488
- // properties that were previously defined, but are now missing, must be deleted
489
- for (const key in properties) {
490
- if (!newProperties.hasOwnProperty(key)) {
491
- delete newNode[key]
492
- }
493
- }
494
-
495
- return updateTextBlockAtIndex(context, root, path[0], (block) => ({
496
- ...block,
497
- children: replaceChild(block.children, path[1], newNode),
498
- }))
499
- }
500
-
501
- return root
502
- }
503
-
504
- case 'split_node': {
505
- const {path, position, properties} = operation
506
-
507
- if (path.length === 0) {
508
- return root
509
- }
510
-
511
- const parent = getParent(context, root, path)
512
- const index = path[path.length - 1]
513
-
514
- if (!parent) {
515
- return root
516
- }
517
-
518
- if (isEditorNode(parent)) {
519
- const block = getBlock(root, path)
520
-
521
- if (!block || !isTextBlockNode(context, block)) {
522
- return root
523
- }
524
-
525
- const before = block.children.slice(0, position)
526
- const after = block.children.slice(position)
527
- const updatedTextBlockNode = {...block, children: before}
528
-
529
- // _key is deliberately left out
530
- const newTextBlockNode = {
531
- ...properties,
532
- children: after,
533
- _type: context.schema.block.name,
534
- }
535
-
536
- return {
537
- ...root,
538
- children: insertChildren(
539
- replaceChild(root.children, index, updatedTextBlockNode),
540
- index + 1,
541
- newTextBlockNode,
542
- ),
543
- }
544
- }
545
-
546
- if (isTextBlockNode(context, parent)) {
547
- const node = getNode(context, root, path)
548
-
549
- if (!node || !isSpanNode(context, node)) {
550
- return root
551
- }
552
-
553
- const blockIndex = path[0]
554
- const before = node.text.slice(0, position)
555
- const after = node.text.slice(position)
556
- const updatedSpanNode = {...node, text: before}
557
-
558
- // _key is deliberately left out
559
- const newSpanNode = {
560
- ...properties,
561
- text: after,
562
- }
563
-
564
- return updateTextBlockAtIndex(context, root, blockIndex, (block) => {
565
- return {
566
- ...block,
567
- children: insertChildren(
568
- replaceChild(block.children, index, updatedSpanNode),
569
- index + 1,
570
- newSpanNode,
571
- ),
572
- }
573
- })
574
- }
575
-
576
- return root
577
- }
578
- }
579
- }
580
-
581
- function insertChildren<T>(children: T[], index: number, ...nodes: T[]): T[] {
582
- return [...children.slice(0, index), ...nodes, ...children.slice(index)]
583
- }
584
-
585
- function removeChildren<T>(children: T[], index: number, count = 1): T[] {
586
- return [...children.slice(0, index), ...children.slice(index + count)]
587
- }
588
-
589
- function replaceChild<T>(children: T[], index: number, newChild: T): T[] {
590
- return [...children.slice(0, index), newChild, ...children.slice(index + 1)]
591
- }
592
-
593
- function updateTextBlockAtIndex(
594
- context: Pick<EditorContext, 'schema'>,
595
- root: EditorNode<EditorSchema>,
596
- blockIndex: number,
597
- updater: (block: TextBlockNode<EditorSchema>) => TextBlockNode<EditorSchema>,
598
- ): EditorNode<EditorSchema> {
599
- const block = root.children.at(blockIndex)
600
-
601
- if (!block) {
602
- return root
603
- }
604
-
605
- if (!isTextBlockNode(context, block)) {
606
- return root
607
- }
608
-
609
- const newBlock = updater(block)
610
-
611
- return {
612
- ...root,
613
- children: replaceChild(root.children, blockIndex, newBlock),
614
- }
615
- }