@portabletext/editor 3.3.3 → 3.3.4

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 (306) hide show
  1. package/package.json +11 -12
  2. package/src/behaviors/_exports/index.ts +0 -1
  3. package/src/behaviors/behavior.abstract.annotation.ts +0 -77
  4. package/src/behaviors/behavior.abstract.decorator.ts +0 -39
  5. package/src/behaviors/behavior.abstract.delete.ts +0 -273
  6. package/src/behaviors/behavior.abstract.deserialize.ts +0 -232
  7. package/src/behaviors/behavior.abstract.insert.ts +0 -525
  8. package/src/behaviors/behavior.abstract.keyboard.ts +0 -189
  9. package/src/behaviors/behavior.abstract.list-item.ts +0 -70
  10. package/src/behaviors/behavior.abstract.move.ts +0 -79
  11. package/src/behaviors/behavior.abstract.select.ts +0 -118
  12. package/src/behaviors/behavior.abstract.serialize.ts +0 -96
  13. package/src/behaviors/behavior.abstract.split.ts +0 -170
  14. package/src/behaviors/behavior.abstract.style.ts +0 -55
  15. package/src/behaviors/behavior.abstract.ts +0 -139
  16. package/src/behaviors/behavior.config.ts +0 -7
  17. package/src/behaviors/behavior.core.annotations.ts +0 -62
  18. package/src/behaviors/behavior.core.block-element.ts +0 -116
  19. package/src/behaviors/behavior.core.block-objects.ts +0 -285
  20. package/src/behaviors/behavior.core.decorators.ts +0 -44
  21. package/src/behaviors/behavior.core.dnd.ts +0 -356
  22. package/src/behaviors/behavior.core.insert-break.ts +0 -266
  23. package/src/behaviors/behavior.core.insert.ts +0 -52
  24. package/src/behaviors/behavior.core.lists.ts +0 -691
  25. package/src/behaviors/behavior.core.ts +0 -44
  26. package/src/behaviors/behavior.perform-event.ts +0 -354
  27. package/src/behaviors/behavior.types.action.ts +0 -102
  28. package/src/behaviors/behavior.types.behavior.ts +0 -83
  29. package/src/behaviors/behavior.types.event.ts +0 -667
  30. package/src/behaviors/behavior.types.guard.ts +0 -11
  31. package/src/behaviors/index.ts +0 -17
  32. package/src/converters/converter.json.ts +0 -53
  33. package/src/converters/converter.portable-text.deserialize.test.ts +0 -680
  34. package/src/converters/converter.portable-text.ts +0 -75
  35. package/src/converters/converter.text-html.deserialize.test.ts +0 -406
  36. package/src/converters/converter.text-html.serialize.test.ts +0 -246
  37. package/src/converters/converter.text-html.ts +0 -87
  38. package/src/converters/converter.text-markdown.ts +0 -67
  39. package/src/converters/converter.text-plain.test.ts +0 -245
  40. package/src/converters/converter.text-plain.ts +0 -126
  41. package/src/converters/converter.types.ts +0 -72
  42. package/src/converters/converters.core.ts +0 -18
  43. package/src/editor/Editable.tsx +0 -1012
  44. package/src/editor/PortableTextEditor.tsx +0 -791
  45. package/src/editor/components/drop-indicator.tsx +0 -17
  46. package/src/editor/components/render-block-object.tsx +0 -121
  47. package/src/editor/components/render-default-object.tsx +0 -21
  48. package/src/editor/components/render-element.tsx +0 -88
  49. package/src/editor/components/render-inline-object.tsx +0 -129
  50. package/src/editor/components/render-leaf.tsx +0 -64
  51. package/src/editor/components/render-span.tsx +0 -303
  52. package/src/editor/components/render-text-block.tsx +0 -265
  53. package/src/editor/components/render-text.tsx +0 -18
  54. package/src/editor/components/use-core-block-element-behaviors.ts +0 -39
  55. package/src/editor/create-editor.ts +0 -323
  56. package/src/editor/create-slate-editor.tsx +0 -64
  57. package/src/editor/editor-actor-context.ts +0 -4
  58. package/src/editor/editor-context.tsx +0 -7
  59. package/src/editor/editor-dom.ts +0 -220
  60. package/src/editor/editor-machine.ts +0 -751
  61. package/src/editor/editor-provider.tsx +0 -111
  62. package/src/editor/editor-schema.ts +0 -6
  63. package/src/editor/editor-selector.ts +0 -89
  64. package/src/editor/editor-snapshot.ts +0 -68
  65. package/src/editor/event-to-change.tsx +0 -49
  66. package/src/editor/hooks/usePortableTextEditor.ts +0 -25
  67. package/src/editor/hooks/usePortableTextEditorSelection.tsx +0 -28
  68. package/src/editor/mutation-machine.ts +0 -322
  69. package/src/editor/plugins/create-with-event-listeners.ts +0 -271
  70. package/src/editor/plugins/createWithEditableAPI.ts +0 -529
  71. package/src/editor/plugins/createWithHotKeys.ts +0 -68
  72. package/src/editor/plugins/createWithObjectKeys.ts +0 -289
  73. package/src/editor/plugins/createWithPatches.ts +0 -272
  74. package/src/editor/plugins/createWithPortableTextMarkModel.ts +0 -559
  75. package/src/editor/plugins/createWithSchemaTypes.ts +0 -121
  76. package/src/editor/plugins/slate-plugin.update-selection.ts +0 -51
  77. package/src/editor/plugins/slate-plugin.update-value.ts +0 -46
  78. package/src/editor/plugins/with-plugins.ts +0 -69
  79. package/src/editor/range-decorations-machine.ts +0 -421
  80. package/src/editor/relay-actor-context.ts +0 -4
  81. package/src/editor/relay-machine.ts +0 -152
  82. package/src/editor/sync-machine.ts +0 -961
  83. package/src/editor/use-editor.ts +0 -27
  84. package/src/editor/validate-selection-machine.test.ts +0 -47
  85. package/src/editor/validate-selection-machine.ts +0 -149
  86. package/src/editor/weakMaps.ts +0 -15
  87. package/src/editor/with-normalizing-node.ts +0 -14
  88. package/src/editor/with-performing-behavior-operation.ts +0 -21
  89. package/src/editor/withChanges.ts +0 -13
  90. package/src/editor/without-normalizing-conditional.ts +0 -13
  91. package/src/editor/withoutPatching.ts +0 -14
  92. package/src/editor.ts +0 -59
  93. package/src/history/behavior.operation.history.redo.ts +0 -67
  94. package/src/history/behavior.operation.history.undo.ts +0 -71
  95. package/src/history/event.history.undo.test.tsx +0 -672
  96. package/src/history/history.preserving-keys.test.tsx +0 -112
  97. package/src/history/remote-patches.ts +0 -20
  98. package/src/history/slate-plugin.history.ts +0 -142
  99. package/src/history/slate-plugin.redoing.ts +0 -21
  100. package/src/history/slate-plugin.undoing.ts +0 -21
  101. package/src/history/slate-plugin.without-history.ts +0 -23
  102. package/src/history/transform-operation.ts +0 -245
  103. package/src/history/undo-redo-collaboration.test.tsx +0 -541
  104. package/src/history/undo-redo.feature +0 -125
  105. package/src/history/undo-redo.test.tsx +0 -195
  106. package/src/history/undo-step.ts +0 -148
  107. package/src/index.ts +0 -107
  108. package/src/internal-utils/__tests__/ranges.test.ts +0 -23
  109. package/src/internal-utils/__tests__/values.test.ts +0 -110
  110. package/src/internal-utils/apply-operation-to-portable-text.test.ts +0 -1861
  111. package/src/internal-utils/apply-operation-to-portable-text.ts +0 -615
  112. package/src/internal-utils/applyPatch.ts +0 -644
  113. package/src/internal-utils/block-keys.ts +0 -9
  114. package/src/internal-utils/build-index-maps.test.ts +0 -464
  115. package/src/internal-utils/build-index-maps.ts +0 -131
  116. package/src/internal-utils/collapse-selection.ts +0 -36
  117. package/src/internal-utils/compound-client-rect.ts +0 -28
  118. package/src/internal-utils/create-placeholder-block.ts +0 -21
  119. package/src/internal-utils/create-test-snapshot.ts +0 -28
  120. package/src/internal-utils/debug.ts +0 -12
  121. package/src/internal-utils/editor-selection.test.ts +0 -44
  122. package/src/internal-utils/editor-selection.ts +0 -56
  123. package/src/internal-utils/event-position.ts +0 -318
  124. package/src/internal-utils/global-scope.ts +0 -27
  125. package/src/internal-utils/globally-scoped-context.ts +0 -39
  126. package/src/internal-utils/is-hotkey.test.ts +0 -114
  127. package/src/internal-utils/is-hotkey.ts +0 -209
  128. package/src/internal-utils/mime-type.ts +0 -1
  129. package/src/internal-utils/move-range-by-operation.ts +0 -19
  130. package/src/internal-utils/operation-to-patches.test.ts +0 -522
  131. package/src/internal-utils/operation-to-patches.ts +0 -571
  132. package/src/internal-utils/portable-text-node.ts +0 -209
  133. package/src/internal-utils/schema.ts +0 -8
  134. package/src/internal-utils/selection-block-keys.ts +0 -20
  135. package/src/internal-utils/selection-focus-text.ts +0 -40
  136. package/src/internal-utils/selection-text.test.ts +0 -32
  137. package/src/internal-utils/selection-text.ts +0 -21
  138. package/src/internal-utils/selection.ts +0 -77
  139. package/src/internal-utils/sibling-utils.ts +0 -55
  140. package/src/internal-utils/slate-utils.test.tsx +0 -121
  141. package/src/internal-utils/slate-utils.ts +0 -417
  142. package/src/internal-utils/split-string.ts +0 -12
  143. package/src/internal-utils/stop-actor.ts +0 -43
  144. package/src/internal-utils/string-overlap.test.ts +0 -14
  145. package/src/internal-utils/string-overlap.ts +0 -28
  146. package/src/internal-utils/string-utils.ts +0 -7
  147. package/src/internal-utils/text-block-key.test.ts +0 -41
  148. package/src/internal-utils/text-block-key.ts +0 -26
  149. package/src/internal-utils/text-marks.test.ts +0 -41
  150. package/src/internal-utils/text-marks.ts +0 -22
  151. package/src/internal-utils/text-selection.test.ts +0 -211
  152. package/src/internal-utils/text-selection.ts +0 -121
  153. package/src/internal-utils/to-slate-range.test.ts +0 -278
  154. package/src/internal-utils/to-slate-range.ts +0 -171
  155. package/src/internal-utils/validateValue.ts +0 -443
  156. package/src/internal-utils/value-annotations.ts +0 -33
  157. package/src/internal-utils/values.test.ts +0 -282
  158. package/src/internal-utils/values.ts +0 -266
  159. package/src/keyboard-shortcuts/default-keyboard-shortcuts.ts +0 -146
  160. package/src/operations/behavior.operation.annotation.add.ts +0 -99
  161. package/src/operations/behavior.operation.annotation.remove.ts +0 -150
  162. package/src/operations/behavior.operation.block.set.ts +0 -104
  163. package/src/operations/behavior.operation.block.unset.ts +0 -54
  164. package/src/operations/behavior.operation.child.set.ts +0 -107
  165. package/src/operations/behavior.operation.child.unset.ts +0 -116
  166. package/src/operations/behavior.operation.decorator.add.ts +0 -131
  167. package/src/operations/behavior.operation.delete.ts +0 -294
  168. package/src/operations/behavior.operation.insert.block.ts +0 -495
  169. package/src/operations/behavior.operation.insert.child.ts +0 -129
  170. package/src/operations/behavior.operation.insert.text.ts +0 -8
  171. package/src/operations/behavior.operation.move.backward.ts +0 -12
  172. package/src/operations/behavior.operation.move.block.ts +0 -44
  173. package/src/operations/behavior.operation.move.forward.ts +0 -11
  174. package/src/operations/behavior.operation.select.ts +0 -27
  175. package/src/operations/behavior.operations.ts +0 -221
  176. package/src/plugins/_exports/index.ts +0 -1
  177. package/src/plugins/index.ts +0 -3
  178. package/src/plugins/plugin.behavior.tsx +0 -24
  179. package/src/plugins/plugin.editor-ref.tsx +0 -17
  180. package/src/plugins/plugin.event-listener.tsx +0 -68
  181. package/src/plugins/plugin.internal.auto-close-brackets.test.tsx +0 -71
  182. package/src/plugins/plugin.internal.auto-close-brackets.ts +0 -62
  183. package/src/plugins/plugin.internal.change-ref.tsx +0 -19
  184. package/src/plugins/plugin.internal.portable-text-editor-ref.tsx +0 -16
  185. package/src/plugins/plugin.internal.slate-editor-ref.tsx +0 -15
  186. package/src/priority/priority.core.ts +0 -3
  187. package/src/priority/priority.sort.test.ts +0 -319
  188. package/src/priority/priority.sort.ts +0 -123
  189. package/src/priority/priority.types.ts +0 -24
  190. package/src/selectors/_exports/index.ts +0 -1
  191. package/src/selectors/drag-selection.test.ts +0 -578
  192. package/src/selectors/drag-selection.ts +0 -118
  193. package/src/selectors/index.ts +0 -54
  194. package/src/selectors/selector.get-active-annotation-marks.ts +0 -12
  195. package/src/selectors/selector.get-active-annotations.ts +0 -36
  196. package/src/selectors/selector.get-active-decorators.ts +0 -29
  197. package/src/selectors/selector.get-active-list-item.ts +0 -38
  198. package/src/selectors/selector.get-active-style.ts +0 -38
  199. package/src/selectors/selector.get-anchor-block.ts +0 -22
  200. package/src/selectors/selector.get-anchor-child.ts +0 -36
  201. package/src/selectors/selector.get-anchor-span.ts +0 -17
  202. package/src/selectors/selector.get-anchor-text-block.ts +0 -18
  203. package/src/selectors/selector.get-block-offsets.ts +0 -34
  204. package/src/selectors/selector.get-caret-word-selection.test.ts +0 -284
  205. package/src/selectors/selector.get-caret-word-selection.ts +0 -134
  206. package/src/selectors/selector.get-first-block.ts +0 -14
  207. package/src/selectors/selector.get-focus-block-object.ts +0 -18
  208. package/src/selectors/selector.get-focus-block.ts +0 -23
  209. package/src/selectors/selector.get-focus-child.ts +0 -36
  210. package/src/selectors/selector.get-focus-inline-object.ts +0 -17
  211. package/src/selectors/selector.get-focus-list-block.ts +0 -18
  212. package/src/selectors/selector.get-focus-span.ts +0 -18
  213. package/src/selectors/selector.get-focus-text-block.ts +0 -18
  214. package/src/selectors/selector.get-last-block.ts +0 -16
  215. package/src/selectors/selector.get-mark-state.test.ts +0 -325
  216. package/src/selectors/selector.get-mark-state.ts +0 -263
  217. package/src/selectors/selector.get-next-block.ts +0 -29
  218. package/src/selectors/selector.get-next-inline-object.ts +0 -53
  219. package/src/selectors/selector.get-next-inline-objects.ts +0 -50
  220. package/src/selectors/selector.get-next-span.ts +0 -56
  221. package/src/selectors/selector.get-previous-block.ts +0 -29
  222. package/src/selectors/selector.get-previous-inline-object.ts +0 -50
  223. package/src/selectors/selector.get-previous-inline-objects.ts +0 -47
  224. package/src/selectors/selector.get-previous-span.ts +0 -53
  225. package/src/selectors/selector.get-selected-blocks.ts +0 -61
  226. package/src/selectors/selector.get-selected-spans.test.ts +0 -347
  227. package/src/selectors/selector.get-selected-spans.ts +0 -155
  228. package/src/selectors/selector.get-selected-text-blocks.ts +0 -73
  229. package/src/selectors/selector.get-selected-value.test.ts +0 -834
  230. package/src/selectors/selector.get-selected-value.ts +0 -66
  231. package/src/selectors/selector.get-selection-end-block.ts +0 -33
  232. package/src/selectors/selector.get-selection-end-child.ts +0 -33
  233. package/src/selectors/selector.get-selection-end-point.ts +0 -17
  234. package/src/selectors/selector.get-selection-start-block.ts +0 -33
  235. package/src/selectors/selector.get-selection-start-child.ts +0 -33
  236. package/src/selectors/selector.get-selection-start-point.ts +0 -17
  237. package/src/selectors/selector.get-selection-text.test.ts +0 -421
  238. package/src/selectors/selector.get-selection-text.ts +0 -27
  239. package/src/selectors/selector.get-selection.ts +0 -9
  240. package/src/selectors/selector.get-text-after.ts +0 -46
  241. package/src/selectors/selector.get-text-before.ts +0 -46
  242. package/src/selectors/selector.get-value.ts +0 -11
  243. package/src/selectors/selector.is-active-annotation.test.ts +0 -320
  244. package/src/selectors/selector.is-active-annotation.ts +0 -52
  245. package/src/selectors/selector.is-active-decorator.test.ts +0 -136
  246. package/src/selectors/selector.is-active-decorator.ts +0 -24
  247. package/src/selectors/selector.is-active-list-item.ts +0 -13
  248. package/src/selectors/selector.is-active-style.ts +0 -13
  249. package/src/selectors/selector.is-at-the-end-of-block.ts +0 -30
  250. package/src/selectors/selector.is-at-the-start-of-block.ts +0 -30
  251. package/src/selectors/selector.is-overlapping-selection.test.ts +0 -304
  252. package/src/selectors/selector.is-overlapping-selection.ts +0 -181
  253. package/src/selectors/selector.is-point-after-selection.ts +0 -97
  254. package/src/selectors/selector.is-point-before-selection.ts +0 -97
  255. package/src/selectors/selector.is-selecting-entire-blocks.ts +0 -43
  256. package/src/selectors/selector.is-selection-collapsed.ts +0 -17
  257. package/src/selectors/selector.is-selection-expanded.test.ts +0 -63
  258. package/src/selectors/selector.is-selection-expanded.ts +0 -9
  259. package/src/test/_exports/index.ts +0 -1
  260. package/src/test/gherkin-parameter-types.ts +0 -112
  261. package/src/test/index.ts +0 -1
  262. package/src/test/vitest/_exports/index.ts +0 -1
  263. package/src/test/vitest/index.ts +0 -3
  264. package/src/test/vitest/step-context.ts +0 -13
  265. package/src/test/vitest/step-definitions.tsx +0 -960
  266. package/src/test/vitest/test-editor.tsx +0 -198
  267. package/src/type-utils.ts +0 -29
  268. package/src/types/block-offset.ts +0 -9
  269. package/src/types/block-with-optional-key.ts +0 -25
  270. package/src/types/editor.ts +0 -509
  271. package/src/types/options.ts +0 -13
  272. package/src/types/paths.ts +0 -35
  273. package/src/types/slate-editor.ts +0 -50
  274. package/src/types/slate.ts +0 -27
  275. package/src/utils/_exports/index.ts +0 -1
  276. package/src/utils/asserters.ts +0 -9
  277. package/src/utils/index.ts +0 -24
  278. package/src/utils/key-generator.ts +0 -33
  279. package/src/utils/parse-blocks.test.ts +0 -836
  280. package/src/utils/parse-blocks.ts +0 -504
  281. package/src/utils/util.at-the-beginning-of-block.ts +0 -32
  282. package/src/utils/util.block-offset-to-block-selection-point.ts +0 -28
  283. package/src/utils/util.block-offset-to-selection-point.ts +0 -33
  284. package/src/utils/util.block-offset.test.ts +0 -375
  285. package/src/utils/util.block-offset.ts +0 -136
  286. package/src/utils/util.block-offsets-to-selection.ts +0 -38
  287. package/src/utils/util.child-selection-point-to-block-offset.ts +0 -51
  288. package/src/utils/util.get-block-end-point.ts +0 -35
  289. package/src/utils/util.get-block-start-point.ts +0 -31
  290. package/src/utils/util.get-selection-end-point.ts +0 -20
  291. package/src/utils/util.get-selection-start-point.ts +0 -20
  292. package/src/utils/util.get-text-block-text.ts +0 -8
  293. package/src/utils/util.is-empty-text-block.ts +0 -21
  294. package/src/utils/util.is-equal-selection-points.ts +0 -13
  295. package/src/utils/util.is-equal-selections.ts +0 -20
  296. package/src/utils/util.is-keyed-segment.ts +0 -8
  297. package/src/utils/util.is-selection-collapsed.ts +0 -16
  298. package/src/utils/util.is-selection-expanded.ts +0 -13
  299. package/src/utils/util.merge-text-blocks.ts +0 -40
  300. package/src/utils/util.reverse-selection.ts +0 -26
  301. package/src/utils/util.selection-point-to-block-offset.ts +0 -30
  302. package/src/utils/util.selection-point.ts +0 -22
  303. package/src/utils/util.slice-blocks.ts +0 -221
  304. package/src/utils/util.slice-text-block.test.ts +0 -190
  305. package/src/utils/util.slice-text-block.ts +0 -89
  306. package/src/utils/util.split-text-block.ts +0 -54
@@ -1,961 +0,0 @@
1
- import type {Patch} from '@portabletext/patches'
2
- import {isSpan} from '@portabletext/schema'
3
- import type {PortableTextBlock} from '@sanity/types'
4
- import {isEqual} from 'lodash'
5
- import {deleteText, Editor, Transforms, type Descendant, type Node} from 'slate'
6
- import type {ActorRefFrom} from 'xstate'
7
- import {
8
- and,
9
- assertEvent,
10
- assign,
11
- emit,
12
- fromCallback,
13
- not,
14
- raise,
15
- setup,
16
- type AnyEventObject,
17
- type CallbackLogicFunction,
18
- } from 'xstate'
19
- import {pluginWithoutHistory} from '../history/slate-plugin.without-history'
20
- import {debugWithName} from '../internal-utils/debug'
21
- import {validateValue} from '../internal-utils/validateValue'
22
- import {toSlateBlock, VOID_CHILD_KEY} from '../internal-utils/values'
23
- import type {PickFromUnion} from '../type-utils'
24
- import type {InvalidValueResolution} from '../types/editor'
25
- import type {PortableTextSlateEditor} from '../types/slate-editor'
26
- import type {EditorSchema} from './editor-schema'
27
- import {isChangingRemotely, withRemoteChanges} from './withChanges'
28
- import {withoutPatching} from './withoutPatching'
29
-
30
- const debug = debugWithName('sync machine')
31
-
32
- type SyncValueEvent =
33
- | {
34
- type: 'patch'
35
- patch: Patch
36
- }
37
- | {
38
- type: 'invalid value'
39
- resolution: InvalidValueResolution | null
40
- value: Array<PortableTextBlock> | undefined
41
- }
42
- | {
43
- type: 'value changed'
44
- value: Array<PortableTextBlock> | undefined
45
- }
46
- | {
47
- type: 'done syncing'
48
- value: Array<PortableTextBlock> | undefined
49
- }
50
-
51
- const syncValueCallback: CallbackLogicFunction<
52
- AnyEventObject,
53
- SyncValueEvent,
54
- {
55
- context: {
56
- keyGenerator: () => string
57
- previousValue: Array<PortableTextBlock> | undefined
58
- readOnly: boolean
59
- schema: EditorSchema
60
- }
61
- slateEditor: PortableTextSlateEditor
62
- streamBlocks: boolean
63
- value: Array<PortableTextBlock> | undefined
64
- }
65
- > = ({sendBack, input}) => {
66
- updateValue({
67
- context: input.context,
68
- sendBack,
69
- slateEditor: input.slateEditor,
70
- value: input.value,
71
- streamBlocks: input.streamBlocks,
72
- })
73
- }
74
-
75
- const syncValueLogic = fromCallback(syncValueCallback)
76
-
77
- export type SyncActor = ActorRefFrom<typeof syncMachine>
78
-
79
- /**
80
- * Sync value with the editor state
81
- *
82
- * Normally nothing here should apply, and the editor and the real world are perfectly aligned.
83
- *
84
- * Inconsistencies could happen though, so we need to check the editor state when the value changes.
85
- *
86
- * For performance reasons, it makes sense to also do the content validation here, as we already
87
- * iterate over the value and can validate only the new content that is actually changed.
88
- *
89
- * @internal
90
- */
91
- export const syncMachine = setup({
92
- types: {
93
- context: {} as {
94
- initialValue: Array<PortableTextBlock> | undefined
95
- initialValueSynced: boolean
96
- isProcessingLocalChanges: boolean
97
- keyGenerator: () => string
98
- schema: EditorSchema
99
- readOnly: boolean
100
- slateEditor: PortableTextSlateEditor
101
- pendingValue: Array<PortableTextBlock> | undefined
102
- previousValue: Array<PortableTextBlock> | undefined
103
- },
104
- input: {} as {
105
- initialValue: Array<PortableTextBlock> | undefined
106
- keyGenerator: () => string
107
- schema: EditorSchema
108
- readOnly: boolean
109
- slateEditor: PortableTextSlateEditor
110
- },
111
- events: {} as
112
- | {
113
- type: 'has pending mutations'
114
- }
115
- | {
116
- type: 'mutation'
117
- }
118
- | {
119
- type: 'update value'
120
- value: Array<PortableTextBlock> | undefined
121
- }
122
- | {
123
- type: 'update readOnly'
124
- readOnly: boolean
125
- }
126
- | SyncValueEvent,
127
- emitted: {} as
128
- | PickFromUnion<
129
- SyncValueEvent,
130
- 'type',
131
- 'invalid value' | 'patch' | 'value changed'
132
- >
133
- | {type: 'done syncing value'}
134
- | {type: 'syncing value'},
135
- },
136
- actions: {
137
- 'assign initial value synced': assign({
138
- initialValueSynced: true,
139
- }),
140
- 'assign readOnly': assign({
141
- readOnly: ({event}) => {
142
- assertEvent(event, 'update readOnly')
143
- return event.readOnly
144
- },
145
- }),
146
- 'assign pending value': assign({
147
- pendingValue: ({event}) => {
148
- assertEvent(event, 'update value')
149
- return event.value
150
- },
151
- }),
152
- 'clear pending value': assign({
153
- pendingValue: undefined,
154
- }),
155
- 'assign previous value': assign({
156
- previousValue: ({event}) => {
157
- assertEvent(event, 'done syncing')
158
- return event.value
159
- },
160
- }),
161
- 'emit done syncing value': emit({
162
- type: 'done syncing value',
163
- }),
164
- 'emit syncing value': emit({
165
- type: 'syncing value',
166
- }),
167
- },
168
- guards: {
169
- 'initial value synced': ({context}) => context.initialValueSynced,
170
- 'is busy': ({context}) => {
171
- const isProcessingLocalChanges = context.isProcessingLocalChanges
172
- const isChanging = isChangingRemotely(context.slateEditor) ?? false
173
- const isBusy = isProcessingLocalChanges || isChanging
174
-
175
- debug('isBusy', {isBusy, isProcessingLocalChanges, isChanging})
176
-
177
- return isBusy
178
- },
179
- 'is empty value': ({event}) => {
180
- return event.type === 'update value' && event.value === undefined
181
- },
182
- 'is empty array': ({event}) => {
183
- return (
184
- event.type === 'update value' &&
185
- Array.isArray(event.value) &&
186
- event.value.length === 0
187
- )
188
- },
189
- 'is new value': ({context, event}) => {
190
- return (
191
- event.type === 'update value' && context.previousValue !== event.value
192
- )
193
- },
194
- 'value changed while syncing': ({context, event}) => {
195
- assertEvent(event, 'done syncing')
196
- return context.pendingValue !== event.value
197
- },
198
- 'pending value equals previous value': ({context}) => {
199
- return isEqual(context.pendingValue, context.previousValue)
200
- },
201
- },
202
- actors: {
203
- 'sync value': syncValueLogic,
204
- },
205
- }).createMachine({
206
- id: 'sync',
207
- context: ({input}) => ({
208
- initialValue: input.initialValue,
209
- initialValueSynced: false,
210
- isProcessingLocalChanges: false,
211
- keyGenerator: input.keyGenerator,
212
- schema: input.schema,
213
- readOnly: input.readOnly,
214
- slateEditor: input.slateEditor,
215
- pendingValue: undefined,
216
- previousValue: undefined,
217
- }),
218
- entry: [
219
- raise(({context}) => {
220
- return {type: 'update value', value: context.initialValue}
221
- }),
222
- ],
223
- on: {
224
- 'has pending mutations': {
225
- actions: assign({
226
- isProcessingLocalChanges: true,
227
- }),
228
- },
229
- 'mutation': {
230
- actions: assign({
231
- isProcessingLocalChanges: false,
232
- }),
233
- },
234
- 'update readOnly': {
235
- actions: ['assign readOnly'],
236
- },
237
- },
238
- initial: 'idle',
239
- states: {
240
- idle: {
241
- entry: [
242
- () => {
243
- debug('entry: syncing->idle')
244
- },
245
- ],
246
- exit: [
247
- () => {
248
- debug('exit: syncing->idle')
249
- },
250
- ],
251
- on: {
252
- 'update value': [
253
- {
254
- guard: and(['is empty value', not('initial value synced')]),
255
- actions: ['assign initial value synced', 'emit done syncing value'],
256
- },
257
- {
258
- guard: and(['is empty array', not('initial value synced')]),
259
- actions: [
260
- 'assign initial value synced',
261
- emit({type: 'value changed', value: []}),
262
- 'emit done syncing value',
263
- ],
264
- },
265
- {
266
- guard: and(['is busy', 'is new value']),
267
- target: 'busy',
268
- actions: ['assign pending value'],
269
- },
270
- {
271
- guard: 'is new value',
272
- target: 'syncing',
273
- actions: ['assign pending value'],
274
- },
275
- {
276
- guard: not('initial value synced'),
277
- actions: [
278
- () => {
279
- debug('no new value – setting initial value as synced')
280
- },
281
- 'assign initial value synced',
282
- 'emit done syncing value',
283
- ],
284
- },
285
- {
286
- actions: [
287
- () => {
288
- debug('no new value and initial value already synced')
289
- },
290
- ],
291
- },
292
- ],
293
- },
294
- },
295
- busy: {
296
- entry: [
297
- () => {
298
- debug('entry: syncing->busy')
299
- },
300
- ],
301
- exit: [
302
- () => {
303
- debug('exit: syncing->busy')
304
- },
305
- ],
306
- after: {
307
- 1000: [
308
- {
309
- guard: 'is busy',
310
- target: '.',
311
- reenter: true,
312
- actions: [
313
- () => {
314
- debug('reenter: syncing->busy')
315
- },
316
- ],
317
- },
318
- {
319
- target: 'syncing',
320
- },
321
- ],
322
- },
323
- on: {
324
- 'update value': [
325
- {
326
- guard: 'is new value',
327
- actions: ['assign pending value'],
328
- },
329
- ],
330
- },
331
- },
332
- syncing: {
333
- entry: [
334
- () => {
335
- debug('entry: syncing->syncing')
336
- },
337
- 'emit syncing value',
338
- ],
339
- exit: [
340
- () => {
341
- debug('exit: syncing->syncing')
342
- },
343
- 'emit done syncing value',
344
- ],
345
- invoke: {
346
- src: 'sync value',
347
- id: 'sync value',
348
- input: ({context}) => {
349
- return {
350
- context: {
351
- keyGenerator: context.keyGenerator,
352
- previousValue: context.previousValue,
353
- readOnly: context.readOnly,
354
- schema: context.schema,
355
- },
356
- slateEditor: context.slateEditor,
357
- streamBlocks: !context.initialValueSynced,
358
- value: context.pendingValue,
359
- }
360
- },
361
- },
362
- on: {
363
- 'update value': {
364
- guard: 'is new value',
365
- actions: ['assign pending value'],
366
- },
367
- 'patch': {
368
- actions: [emit(({event}) => event)],
369
- },
370
- 'invalid value': {
371
- actions: [emit(({event}) => event)],
372
- },
373
- 'value changed': {
374
- actions: [emit(({event}) => event)],
375
- },
376
- 'done syncing': [
377
- {
378
- guard: 'value changed while syncing',
379
- actions: ['assign previous value', 'assign initial value synced'],
380
- target: 'syncing',
381
- reenter: true,
382
- },
383
- {
384
- target: 'idle',
385
- actions: [
386
- 'clear pending value',
387
- 'assign previous value',
388
- 'assign initial value synced',
389
- ],
390
- },
391
- ],
392
- },
393
- },
394
- },
395
- })
396
-
397
- async function updateValue({
398
- context,
399
- sendBack,
400
- slateEditor,
401
- streamBlocks,
402
- value,
403
- }: {
404
- context: {
405
- keyGenerator: () => string
406
- previousValue: Array<PortableTextBlock> | undefined
407
- readOnly: boolean
408
- schema: EditorSchema
409
- }
410
- sendBack: (event: SyncValueEvent) => void
411
- slateEditor: PortableTextSlateEditor
412
- streamBlocks: boolean
413
- value: PortableTextBlock[] | undefined
414
- }) {
415
- let doneSyncing = false
416
- let isChanged = false
417
- let isValid = true
418
-
419
- const hadSelection = !!slateEditor.selection
420
-
421
- if (!value || value.length === 0) {
422
- debug('Value is empty')
423
-
424
- clearEditor({
425
- slateEditor,
426
- doneSyncing,
427
- })
428
-
429
- isChanged = true
430
- }
431
-
432
- // Remove, replace or add nodes according to what is changed.
433
- if (value && value.length > 0) {
434
- if (streamBlocks) {
435
- await new Promise<void>((resolve) => {
436
- if (doneSyncing) {
437
- resolve()
438
- return
439
- }
440
-
441
- isChanged = removeExtraBlocks({
442
- slateEditor,
443
- value,
444
- })
445
-
446
- const processBlocks = async () => {
447
- for await (const [
448
- currentBlock,
449
- currentBlockIndex,
450
- ] of getStreamedBlocks({
451
- value,
452
- })) {
453
- const {blockChanged, blockValid} = syncBlock({
454
- context,
455
- sendBack,
456
- block: currentBlock,
457
- index: currentBlockIndex,
458
- slateEditor,
459
- value,
460
- })
461
-
462
- isChanged = blockChanged || isChanged
463
- isValid = isValid && blockValid
464
-
465
- if (!isValid) {
466
- break
467
- }
468
- }
469
-
470
- resolve()
471
- }
472
-
473
- processBlocks()
474
- })
475
- } else {
476
- if (doneSyncing) {
477
- return
478
- }
479
-
480
- isChanged = removeExtraBlocks({
481
- slateEditor,
482
- value,
483
- })
484
-
485
- let index = 0
486
-
487
- for (const block of value) {
488
- const {blockChanged, blockValid} = syncBlock({
489
- context,
490
- sendBack,
491
- block,
492
- index,
493
- slateEditor,
494
- value,
495
- })
496
-
497
- isChanged = blockChanged || isChanged
498
- isValid = isValid && blockValid
499
-
500
- if (!blockValid) {
501
- break
502
- }
503
-
504
- index++
505
- }
506
- }
507
- }
508
-
509
- if (!isValid) {
510
- debug('Invalid value, returning')
511
-
512
- doneSyncing = true
513
-
514
- sendBack({type: 'done syncing', value})
515
-
516
- return
517
- }
518
-
519
- if (isChanged) {
520
- debug('Server value changed, syncing editor')
521
- try {
522
- slateEditor.onChange()
523
- } catch (err) {
524
- console.error(err)
525
-
526
- sendBack({
527
- type: 'invalid value',
528
- resolution: null,
529
- value,
530
- })
531
-
532
- doneSyncing = true
533
-
534
- sendBack({type: 'done syncing', value})
535
-
536
- return
537
- }
538
-
539
- if (hadSelection && !slateEditor.selection) {
540
- Transforms.select(slateEditor, {
541
- anchor: {path: [0, 0], offset: 0},
542
- focus: {path: [0, 0], offset: 0},
543
- })
544
-
545
- slateEditor.onChange()
546
- }
547
-
548
- sendBack({type: 'value changed', value})
549
- } else {
550
- debug('Server value and editor value is equal, no need to sync.')
551
- }
552
-
553
- doneSyncing = true
554
-
555
- sendBack({type: 'done syncing', value})
556
- }
557
-
558
- async function* getStreamedBlocks({value}: {value: Array<PortableTextBlock>}) {
559
- let index = 0
560
- for await (const block of value) {
561
- if (index % 10 === 0) {
562
- await new Promise<void>((resolve) => setTimeout(resolve, 0))
563
- }
564
- yield [block, index] as const
565
- index++
566
- }
567
- }
568
-
569
- /**
570
- * Remove all blocks and insert a placeholder block
571
- */
572
- function clearEditor({
573
- slateEditor,
574
- doneSyncing,
575
- }: {
576
- slateEditor: PortableTextSlateEditor
577
- doneSyncing: boolean
578
- }) {
579
- Editor.withoutNormalizing(slateEditor, () => {
580
- pluginWithoutHistory(slateEditor, () => {
581
- withRemoteChanges(slateEditor, () => {
582
- withoutPatching(slateEditor, () => {
583
- if (doneSyncing) {
584
- return
585
- }
586
-
587
- const childrenLength = slateEditor.children.length
588
-
589
- slateEditor.children.forEach((_, index) => {
590
- Transforms.removeNodes(slateEditor, {
591
- at: [childrenLength - 1 - index],
592
- })
593
- })
594
- })
595
- })
596
- })
597
- })
598
- }
599
-
600
- /**
601
- * Compare the length of the value and the length of the editor's children, and
602
- * remove blocks that have become superfluous
603
- */
604
- function removeExtraBlocks({
605
- slateEditor,
606
- value,
607
- }: {
608
- slateEditor: PortableTextSlateEditor
609
- value: Array<PortableTextBlock>
610
- }) {
611
- let isChanged = false
612
-
613
- Editor.withoutNormalizing(slateEditor, () => {
614
- withRemoteChanges(slateEditor, () => {
615
- withoutPatching(slateEditor, () => {
616
- const childrenLength = slateEditor.children.length
617
-
618
- if (value.length < childrenLength) {
619
- for (let i = childrenLength - 1; i > value.length - 1; i--) {
620
- Transforms.removeNodes(slateEditor, {
621
- at: [i],
622
- })
623
- }
624
-
625
- isChanged = true
626
- }
627
- })
628
- })
629
- })
630
-
631
- return isChanged
632
- }
633
-
634
- function syncBlock({
635
- context,
636
- sendBack,
637
- block,
638
- index,
639
- slateEditor,
640
- value,
641
- }: {
642
- context: {
643
- keyGenerator: () => string
644
- previousValue: Array<PortableTextBlock> | undefined
645
- readOnly: boolean
646
- schema: EditorSchema
647
- }
648
- sendBack: (event: SyncValueEvent) => void
649
- block: PortableTextBlock
650
- index: number
651
- slateEditor: PortableTextSlateEditor
652
- value: Array<PortableTextBlock>
653
- }) {
654
- const oldBlock = slateEditor.children.at(index)
655
-
656
- if (!oldBlock) {
657
- // Insert the new block
658
- const validation = validateValue(
659
- [block],
660
- context.schema,
661
- context.keyGenerator,
662
- )
663
-
664
- if (debug.enabled) {
665
- debug('Validating and inserting new block in the end of the value', block)
666
- }
667
-
668
- if (validation.valid || validation.resolution?.autoResolve) {
669
- const slateBlock = toSlateBlock(block, {
670
- schemaTypes: context.schema,
671
- })
672
-
673
- Editor.withoutNormalizing(slateEditor, () => {
674
- withRemoteChanges(slateEditor, () => {
675
- withoutPatching(slateEditor, () => {
676
- Transforms.insertNodes(slateEditor, slateBlock, {
677
- at: [index],
678
- })
679
- })
680
- })
681
- })
682
-
683
- return {
684
- blockChanged: true,
685
- blockValid: true,
686
- }
687
- }
688
-
689
- debug('Invalid', validation)
690
-
691
- sendBack({
692
- type: 'invalid value',
693
- resolution: validation.resolution,
694
- value,
695
- })
696
-
697
- return {
698
- blockChanged: false,
699
- blockValid: false,
700
- }
701
- }
702
-
703
- if (isEqual(block, oldBlock)) {
704
- // Nothing to sync, skipping the block
705
- return {
706
- blockChanged: false,
707
- blockValid: true,
708
- }
709
- }
710
-
711
- const validationValue = [value[index]]
712
- const validation = validateValue(
713
- validationValue,
714
- context.schema,
715
- context.keyGenerator,
716
- )
717
-
718
- // Resolve validations that can be resolved automatically, without involving the user (but only if the value was changed)
719
- if (
720
- !validation.valid &&
721
- validation.resolution?.autoResolve &&
722
- validation.resolution?.patches.length > 0
723
- ) {
724
- // Only apply auto resolution if the value has been populated before and is different from the last one.
725
- if (
726
- !context.readOnly &&
727
- context.previousValue &&
728
- context.previousValue !== value
729
- ) {
730
- // Give a console warning about the fact that it did an auto resolution
731
- console.warn(
732
- `${validation.resolution.action} for block with _key '${validationValue[0]._key}'. ${validation.resolution?.description}`,
733
- )
734
- validation.resolution.patches.forEach((patch) => {
735
- sendBack({type: 'patch', patch})
736
- })
737
- }
738
- }
739
-
740
- if (validation.valid || validation.resolution?.autoResolve) {
741
- if (oldBlock._key === block._key) {
742
- if (debug.enabled) {
743
- debug('Updating block', oldBlock, block)
744
- }
745
-
746
- Editor.withoutNormalizing(slateEditor, () => {
747
- withRemoteChanges(slateEditor, () => {
748
- withoutPatching(slateEditor, () => {
749
- updateBlock({
750
- context,
751
- slateEditor,
752
- oldBlock,
753
- block,
754
- index,
755
- })
756
- })
757
- })
758
- })
759
- } else {
760
- if (debug.enabled) {
761
- debug('Replacing block', oldBlock, block)
762
- }
763
-
764
- Editor.withoutNormalizing(slateEditor, () => {
765
- withRemoteChanges(slateEditor, () => {
766
- withoutPatching(slateEditor, () => {
767
- replaceBlock({
768
- context,
769
- slateEditor,
770
- block,
771
- index,
772
- })
773
- })
774
- })
775
- })
776
- }
777
-
778
- return {
779
- blockChanged: true,
780
- blockValid: true,
781
- }
782
- } else {
783
- sendBack({
784
- type: 'invalid value',
785
- resolution: validation.resolution,
786
- value,
787
- })
788
-
789
- return {
790
- blockChanged: false,
791
- blockValid: false,
792
- }
793
- }
794
- }
795
-
796
- function replaceBlock({
797
- context,
798
- slateEditor,
799
- block,
800
- index,
801
- }: {
802
- context: {
803
- keyGenerator: () => string
804
- previousValue: Array<PortableTextBlock> | undefined
805
- readOnly: boolean
806
- schema: EditorSchema
807
- }
808
- slateEditor: PortableTextSlateEditor
809
- block: PortableTextBlock
810
- index: number
811
- }) {
812
- const slateBlock = toSlateBlock(block, {
813
- schemaTypes: context.schema,
814
- })
815
-
816
- // While replacing the block and the current selection focus is on the replaced block,
817
- // temporarily deselect the editor then optimistically try to restore the selection afterwards.
818
- const currentSelection = slateEditor.selection
819
- const selectionFocusOnBlock =
820
- currentSelection && currentSelection.focus.path[0] === index
821
-
822
- if (selectionFocusOnBlock) {
823
- Transforms.deselect(slateEditor)
824
- }
825
-
826
- Transforms.removeNodes(slateEditor, {at: [index]})
827
- Transforms.insertNodes(slateEditor, slateBlock, {at: [index]})
828
-
829
- slateEditor.onChange()
830
-
831
- if (selectionFocusOnBlock) {
832
- Transforms.select(slateEditor, currentSelection)
833
- }
834
- }
835
-
836
- function updateBlock({
837
- context,
838
- slateEditor,
839
- oldBlock,
840
- block,
841
- index,
842
- }: {
843
- context: {
844
- keyGenerator: () => string
845
- previousValue: Array<PortableTextBlock> | undefined
846
- readOnly: boolean
847
- schema: EditorSchema
848
- }
849
- slateEditor: PortableTextSlateEditor
850
- oldBlock: Descendant
851
- block: PortableTextBlock
852
- index: number
853
- }) {
854
- const slateBlock = toSlateBlock(block, {
855
- schemaTypes: context.schema,
856
- })
857
-
858
- // Update the root props on the block
859
- Transforms.setNodes(slateEditor, slateBlock as Partial<Node>, {
860
- at: [index],
861
- })
862
-
863
- // Text block's need to have their children updated as well (setNode does not target a node's children)
864
- if (
865
- slateEditor.isTextBlock(slateBlock) &&
866
- slateEditor.isTextBlock(oldBlock)
867
- ) {
868
- const oldBlockChildrenLength = oldBlock.children.length
869
- if (slateBlock.children.length < oldBlockChildrenLength) {
870
- // Remove any children that have become superfluous
871
- Array.from(
872
- Array(oldBlockChildrenLength - slateBlock.children.length),
873
- ).forEach((_, index) => {
874
- const childIndex = oldBlockChildrenLength - 1 - index
875
-
876
- if (childIndex > 0) {
877
- debug('Removing child')
878
-
879
- Transforms.removeNodes(slateEditor, {
880
- at: [index, childIndex],
881
- })
882
- }
883
- })
884
- }
885
-
886
- slateBlock.children.forEach((currentBlockChild, currentBlockChildIndex) => {
887
- const oldBlockChild = oldBlock.children[currentBlockChildIndex]
888
- const isChildChanged = !isEqual(currentBlockChild, oldBlockChild)
889
- const isTextChanged = !isEqual(
890
- currentBlockChild.text,
891
- oldBlockChild?.text,
892
- )
893
- const path = [index, currentBlockChildIndex]
894
-
895
- if (isChildChanged) {
896
- // Update if this is the same child
897
- if (currentBlockChild._key === oldBlockChild?._key) {
898
- debug('Updating changed child', currentBlockChild, oldBlockChild)
899
-
900
- Transforms.setNodes(slateEditor, currentBlockChild as Partial<Node>, {
901
- at: path,
902
- })
903
-
904
- const isSpanNode =
905
- isSpan({schema: context.schema}, currentBlockChild) &&
906
- isSpan({schema: context.schema}, oldBlockChild)
907
-
908
- if (isSpanNode && isTextChanged) {
909
- if (oldBlockChild.text.length > 0) {
910
- deleteText(slateEditor, {
911
- at: {
912
- focus: {path, offset: 0},
913
- anchor: {path, offset: oldBlockChild.text.length},
914
- },
915
- })
916
- }
917
-
918
- Transforms.insertText(slateEditor, currentBlockChild.text, {
919
- at: path,
920
- })
921
-
922
- slateEditor.onChange()
923
- } else if (!isSpanNode) {
924
- // If it's a inline block, also update the void text node key
925
- debug('Updating changed inline object child', currentBlockChild)
926
-
927
- Transforms.setNodes(
928
- slateEditor,
929
- {_key: VOID_CHILD_KEY},
930
- {
931
- at: [...path, 0],
932
- voids: true,
933
- },
934
- )
935
- }
936
- } else if (oldBlockChild) {
937
- // Replace the child if _key's are different
938
- debug('Replacing child', currentBlockChild)
939
-
940
- Transforms.removeNodes(slateEditor, {
941
- at: [index, currentBlockChildIndex],
942
- })
943
- Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
944
- at: [index, currentBlockChildIndex],
945
- })
946
-
947
- slateEditor.onChange()
948
- } else if (!oldBlockChild) {
949
- // Insert it if it didn't exist before
950
- debug('Inserting new child', currentBlockChild)
951
-
952
- Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
953
- at: [index, currentBlockChildIndex],
954
- })
955
-
956
- slateEditor.onChange()
957
- }
958
- }
959
- })
960
- }
961
- }