edytor 0.0.11 → 0.1.0-next.16

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 (371) hide show
  1. package/README.md +77 -197
  2. package/dist/block/block.svelte.d.ts +156 -69
  3. package/dist/block/block.svelte.js +324 -355
  4. package/dist/block/block.utils.d.ts +191 -24
  5. package/dist/block/block.utils.js +327 -460
  6. package/dist/block/contentRange.d.ts +4 -0
  7. package/dist/block/contentRange.js +20 -0
  8. package/dist/block/inlineBlock.svelte.d.ts +26 -19
  9. package/dist/block/inlineBlock.svelte.js +91 -39
  10. package/dist/clipboard/clipboard.d.ts +4 -0
  11. package/dist/clipboard/clipboard.js +4 -0
  12. package/dist/clipboard/createClipboardFragment.d.ts +3 -0
  13. package/dist/clipboard/createClipboardFragment.js +103 -0
  14. package/dist/clipboard/fragmentData.d.ts +6 -0
  15. package/dist/clipboard/fragmentData.js +74 -0
  16. package/dist/clipboard/htmlFlow.d.ts +22 -0
  17. package/dist/clipboard/htmlFlow.js +167 -0
  18. package/dist/clipboard/insertClipboardFragment.d.ts +18 -0
  19. package/dist/clipboard/insertClipboardFragment.js +48 -0
  20. package/dist/clipboard/serializeClipboardFragment.d.ts +7 -0
  21. package/dist/clipboard/serializeClipboardFragment.js +53 -0
  22. package/dist/clipboard/textBlocks.d.ts +23 -0
  23. package/dist/clipboard/textBlocks.js +103 -0
  24. package/dist/clipboard/types.d.ts +20 -0
  25. package/dist/clipboard/types.js +2 -0
  26. package/dist/cloudflare/DocumentRoom.d.ts +586 -0
  27. package/dist/cloudflare/DocumentRoom.js +1706 -0
  28. package/dist/cloudflare/index.d.ts +8 -0
  29. package/dist/cloudflare/index.js +8 -0
  30. package/dist/cloudflare/routeDocumentSocket.d.ts +33 -0
  31. package/dist/cloudflare/routeDocumentSocket.js +51 -0
  32. package/dist/collaboration/RemoteSelections.svelte +94 -0
  33. package/dist/collaboration/RemoteSelections.svelte.d.ts +7 -0
  34. package/dist/collaboration/awarenessSelection.d.ts +127 -0
  35. package/dist/collaboration/awarenessSelection.js +199 -0
  36. package/dist/collaboration/documentSync.d.ts +20 -0
  37. package/dist/collaboration/documentSync.js +13 -0
  38. package/dist/collaboration/index.d.ts +3 -0
  39. package/dist/collaboration/index.js +3 -0
  40. package/dist/collaboration/providers.d.ts +13 -0
  41. package/dist/collaboration/providers.js +21 -0
  42. package/dist/collaboration/remoteSelection.d.ts +21 -0
  43. package/dist/collaboration/remoteSelection.js +159 -0
  44. package/dist/components/Block.svelte +223 -15
  45. package/dist/components/Block.svelte.d.ts +4 -2
  46. package/dist/components/Content.svelte +128 -32
  47. package/dist/components/Content.svelte.d.ts +6 -2
  48. package/dist/components/Edytor.svelte +308 -110
  49. package/dist/components/Edytor.svelte.d.ts +64 -20
  50. package/dist/components/InlineBlock.svelte +38 -7
  51. package/dist/components/InlineBlock.svelte.d.ts +5 -2
  52. package/dist/components/Mark.svelte +29 -13
  53. package/dist/components/Mark.svelte.d.ts +4 -4
  54. package/dist/components/Suggestion.svelte +48 -0
  55. package/dist/components/Suggestion.svelte.d.ts +7 -0
  56. package/dist/components/SuggestionRanges.svelte +58 -0
  57. package/dist/components/SuggestionRanges.svelte.d.ts +7 -0
  58. package/dist/components/Text.svelte +107 -14
  59. package/dist/components/Text.svelte.d.ts +8 -1
  60. package/dist/constants.d.ts +0 -2
  61. package/dist/constants.js +0 -2
  62. package/dist/crdt/admission.d.ts +141 -0
  63. package/dist/crdt/admission.js +147 -0
  64. package/dist/crdt/anchors.d.ts +47 -0
  65. package/dist/crdt/anchors.js +42 -0
  66. package/dist/crdt/attribution/attribution.d.ts +169 -0
  67. package/dist/crdt/attribution/attribution.js +136 -0
  68. package/dist/crdt/attribution/block.d.ts +200 -0
  69. package/dist/crdt/attribution/block.js +327 -0
  70. package/dist/crdt/attribution/index.d.ts +9 -0
  71. package/dist/crdt/attribution/index.js +9 -0
  72. package/dist/crdt/data.d.ts +81 -0
  73. package/dist/crdt/data.js +383 -0
  74. package/dist/crdt/document.d.ts +590 -0
  75. package/dist/crdt/document.js +1160 -0
  76. package/dist/crdt/edytor-doc.d.ts +752 -0
  77. package/dist/crdt/edytor-doc.js +2382 -0
  78. package/dist/crdt/engine-api.d.ts +153 -0
  79. package/dist/crdt/engine.d.ts +37 -0
  80. package/dist/crdt/engine.js +50 -0
  81. package/dist/crdt/flow.d.ts +104 -0
  82. package/dist/crdt/flow.js +229 -0
  83. package/dist/crdt/index.d.ts +630 -0
  84. package/dist/crdt/index.js +168 -0
  85. package/dist/crdt/migration/legacy-schema.d.ts +61 -0
  86. package/dist/crdt/migration/legacy-schema.js +149 -0
  87. package/dist/crdt/migration/migrate.d.ts +67 -0
  88. package/dist/crdt/migration/migrate.js +219 -0
  89. package/dist/crdt/nodes.d.ts +120 -0
  90. package/dist/crdt/nodes.js +56 -0
  91. package/dist/crdt/placement/model.d.ts +383 -0
  92. package/dist/crdt/placement/model.js +811 -0
  93. package/dist/crdt/placement/rank.d.ts +57 -0
  94. package/dist/crdt/placement/rank.js +209 -0
  95. package/dist/crdt/protocols/auth.d.ts +28 -0
  96. package/dist/crdt/protocols/auth.js +43 -0
  97. package/dist/crdt/protocols/awareness.d.ts +87 -0
  98. package/dist/crdt/protocols/awareness.js +271 -0
  99. package/dist/crdt/protocols/envelope.d.ts +75 -0
  100. package/dist/crdt/protocols/envelope.js +89 -0
  101. package/dist/crdt/protocols/observable.d.ts +19 -0
  102. package/dist/crdt/protocols/observable.js +26 -0
  103. package/dist/crdt/protocols/sync.d.ts +82 -0
  104. package/dist/crdt/protocols/sync.js +288 -0
  105. package/dist/crdt/providers/container.d.ts +23 -0
  106. package/dist/crdt/providers/container.js +64 -0
  107. package/dist/crdt/providers/index.d.ts +282 -0
  108. package/dist/crdt/providers/index.js +118 -0
  109. package/dist/crdt/providers/indexeddb.d.ts +196 -0
  110. package/dist/crdt/providers/indexeddb.js +332 -0
  111. package/dist/crdt/providers/room.d.ts +193 -0
  112. package/dist/crdt/providers/room.js +444 -0
  113. package/dist/crdt/providers/websocket.d.ts +223 -0
  114. package/dist/crdt/providers/websocket.js +601 -0
  115. package/dist/crdt/rand.d.ts +22 -0
  116. package/dist/crdt/rand.js +22 -0
  117. package/dist/crdt/rangeDelete.d.ts +85 -0
  118. package/dist/crdt/rangeDelete.js +126 -0
  119. package/dist/crdt/schema.d.ts +96 -0
  120. package/dist/crdt/schema.js +79 -0
  121. package/dist/crdt/semantics.d.ts +81 -0
  122. package/dist/crdt/semantics.js +57 -0
  123. package/dist/crdt/structs.d.ts +106 -0
  124. package/dist/crdt/structs.js +119 -0
  125. package/dist/crdt/text/deletes.d.ts +23 -0
  126. package/dist/crdt/text/deletes.js +608 -0
  127. package/dist/crdt/text/model.d.ts +280 -0
  128. package/dist/crdt/text/model.js +554 -0
  129. package/dist/crdt/text/runs.d.ts +212 -0
  130. package/dist/crdt/text/runs.js +1142 -0
  131. package/dist/crdt/vendor/yjs/API-NOTES.md +59 -0
  132. package/dist/crdt/vendor/yjs/LICENSE +23 -0
  133. package/dist/crdt/vendor/yjs/UPSTREAM.md +653 -0
  134. package/dist/crdt/vendor/yjs/dts/global.d.ts +52 -0
  135. package/dist/crdt/vendor/yjs/dts/index.d.ts +25 -0
  136. package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +38 -0
  137. package/dist/crdt/vendor/yjs/dts/structs/GC.d.ts +25 -0
  138. package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +748 -0
  139. package/dist/crdt/vendor/yjs/dts/structs/Skip.d.ts +30 -0
  140. package/dist/crdt/vendor/yjs/dts/utils/BlockSet.d.ts +34 -0
  141. package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +198 -0
  142. package/dist/crdt/vendor/yjs/dts/utils/EventHandler.d.ts +17 -0
  143. package/dist/crdt/vendor/yjs/dts/utils/ID.d.ts +20 -0
  144. package/dist/crdt/vendor/yjs/dts/utils/RangeCursor.d.ts +198 -0
  145. package/dist/crdt/vendor/yjs/dts/utils/RelativePosition.d.ts +80 -0
  146. package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +61 -0
  147. package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +129 -0
  148. package/dist/crdt/vendor/yjs/dts/utils/UndoManager.d.ts +205 -0
  149. package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +170 -0
  150. package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +164 -0
  151. package/dist/crdt/vendor/yjs/dts/utils/YEvent.d.ts +93 -0
  152. package/dist/crdt/vendor/yjs/dts/utils/content-helper.d.ts +1 -0
  153. package/dist/crdt/vendor/yjs/dts/utils/encoding-helpers.d.ts +5 -0
  154. package/dist/crdt/vendor/yjs/dts/utils/encoding.d.ts +26 -0
  155. package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +407 -0
  156. package/dist/crdt/vendor/yjs/dts/utils/isParentOf.d.ts +1 -0
  157. package/dist/crdt/vendor/yjs/dts/utils/meta.d.ts +25 -0
  158. package/dist/crdt/vendor/yjs/dts/utils/renderer-helpers.d.ts +98 -0
  159. package/dist/crdt/vendor/yjs/dts/utils/schemas.d.ts +2 -0
  160. package/dist/crdt/vendor/yjs/dts/utils/transaction-helpers.d.ts +15 -0
  161. package/dist/crdt/vendor/yjs/dts/utils/updates.d.ts +70 -0
  162. package/dist/crdt/vendor/yjs/dts/ynode.d.ts +655 -0
  163. package/dist/crdt/vendor/yjs/global.d.ts +52 -0
  164. package/dist/crdt/vendor/yjs/src/index.js +64 -0
  165. package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +64 -0
  166. package/dist/crdt/vendor/yjs/src/structs/GC.js +75 -0
  167. package/dist/crdt/vendor/yjs/src/structs/Item.js +1538 -0
  168. package/dist/crdt/vendor/yjs/src/structs/Skip.js +72 -0
  169. package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +291 -0
  170. package/dist/crdt/vendor/yjs/src/utils/Doc.js +255 -0
  171. package/dist/crdt/vendor/yjs/src/utils/EventHandler.js +75 -0
  172. package/dist/crdt/vendor/yjs/src/utils/ID.js +59 -0
  173. package/dist/crdt/vendor/yjs/src/utils/RangeCursor.js +407 -0
  174. package/dist/crdt/vendor/yjs/src/utils/RelativePosition.js +301 -0
  175. package/dist/crdt/vendor/yjs/src/utils/StructStore.js +134 -0
  176. package/dist/crdt/vendor/yjs/src/utils/Transaction.js +458 -0
  177. package/dist/crdt/vendor/yjs/src/utils/UndoManager.js +554 -0
  178. package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +284 -0
  179. package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +323 -0
  180. package/dist/crdt/vendor/yjs/src/utils/YEvent.js +158 -0
  181. package/dist/crdt/vendor/yjs/src/utils/content-helper.js +0 -0
  182. package/dist/crdt/vendor/yjs/src/utils/encoding-helpers.js +110 -0
  183. package/dist/crdt/vendor/yjs/src/utils/encoding.js +662 -0
  184. package/dist/crdt/vendor/yjs/src/utils/ids.js +1504 -0
  185. package/dist/crdt/vendor/yjs/src/utils/isParentOf.js +19 -0
  186. package/dist/crdt/vendor/yjs/src/utils/meta.js +74 -0
  187. package/dist/crdt/vendor/yjs/src/utils/renderer-helpers.js +186 -0
  188. package/dist/crdt/vendor/yjs/src/utils/schemas.js +3 -0
  189. package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +391 -0
  190. package/dist/crdt/vendor/yjs/src/utils/updates.js +264 -0
  191. package/dist/crdt/vendor/yjs/src/ynode.js +2897 -0
  192. package/dist/dnd/pragmatic.d.ts +22 -0
  193. package/dist/dnd/pragmatic.js +26 -0
  194. package/dist/edytor.svelte.d.ts +323 -54
  195. package/dist/edytor.svelte.js +771 -197
  196. package/dist/edytor.utils.d.ts +49 -2
  197. package/dist/edytor.utils.js +65 -76
  198. package/dist/events/beforeInputCommands.d.ts +21 -0
  199. package/dist/events/beforeInputCommands.js +328 -0
  200. package/dist/events/beforeInputDeleteCommands.d.ts +3 -0
  201. package/dist/events/beforeInputDeleteCommands.js +245 -0
  202. package/dist/events/dataTransferPayload.d.ts +6 -0
  203. package/dist/events/dataTransferPayload.js +9 -0
  204. package/dist/events/domTextOffset.d.ts +12 -0
  205. package/dist/events/domTextOffset.js +52 -0
  206. package/dist/events/events.utils.d.ts +3 -0
  207. package/dist/events/events.utils.js +13 -0
  208. package/dist/events/nativeInteractiveControl.d.ts +31 -0
  209. package/dist/events/nativeInteractiveControl.js +98 -0
  210. package/dist/events/onBeforeInput.d.ts +10 -1
  211. package/dist/events/onBeforeInput.js +449 -330
  212. package/dist/events/onCopy.d.ts +7 -0
  213. package/dist/events/onCopy.js +30 -0
  214. package/dist/events/onCut.d.ts +8 -0
  215. package/dist/events/onCut.js +13 -0
  216. package/dist/events/onDrop.d.ts +16 -0
  217. package/dist/events/onDrop.js +158 -0
  218. package/dist/events/onFocus.d.ts +4 -0
  219. package/dist/events/onFocus.js +166 -0
  220. package/dist/events/onInput.d.ts +20 -0
  221. package/dist/events/onInput.js +249 -0
  222. package/dist/events/onKeyDown.js +191 -11
  223. package/dist/events/onPaste.d.ts +3 -0
  224. package/dist/events/onPaste.js +108 -0
  225. package/dist/events/wordBoundary.d.ts +2 -0
  226. package/dist/events/wordBoundary.js +58 -0
  227. package/dist/index.d.ts +38 -1
  228. package/dist/index.js +36 -1
  229. package/dist/kinds.d.ts +100 -0
  230. package/dist/kinds.js +198 -0
  231. package/dist/plugins/arrowMove/arrowMove.d.ts +1 -1
  232. package/dist/plugins/arrowMove/arrowMove.js +30 -65
  233. package/dist/plugins/blockHandles/BlockHandle.svelte +152 -0
  234. package/dist/plugins/blockHandles/BlockHandle.svelte.d.ts +12 -0
  235. package/dist/plugins/blockHandles/BlockHandleController.svelte.d.ts +208 -0
  236. package/dist/plugins/blockHandles/BlockHandleController.svelte.js +823 -0
  237. package/dist/plugins/blockHandles/BlockHandles.svelte +151 -0
  238. package/dist/plugins/blockHandles/BlockHandles.svelte.d.ts +20 -0
  239. package/dist/plugins/blockHandles/autoScroll.d.ts +8 -0
  240. package/dist/plugins/blockHandles/autoScroll.js +25 -0
  241. package/dist/plugins/blockHandles/blockHandlesPlugin.d.ts +37 -0
  242. package/dist/plugins/blockHandles/blockHandlesPlugin.js +100 -0
  243. package/dist/plugins/blockHandles/dragPreview.d.ts +33 -0
  244. package/dist/plugins/blockHandles/dragPreview.js +228 -0
  245. package/dist/plugins/blockMenu/BlockMenu.svelte +301 -0
  246. package/dist/plugins/blockMenu/BlockMenu.svelte.d.ts +9 -0
  247. package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +102 -0
  248. package/dist/plugins/blockMenu/BlockMenuController.svelte.js +245 -0
  249. package/dist/plugins/blockMenu/blockMenuPlugin.d.ts +11 -0
  250. package/dist/plugins/blockMenu/blockMenuPlugin.js +89 -0
  251. package/dist/plugins/code/CodePlugin.svelte +210 -163
  252. package/dist/plugins/code/CodePlugin.svelte.d.ts +1 -3
  253. package/dist/plugins/code/code.css +92 -0
  254. package/dist/plugins/icons.d.ts +2 -0
  255. package/dist/plugins/icons.js +31 -0
  256. package/dist/plugins/image/ImageEmpty.svelte +69 -0
  257. package/dist/plugins/image/ImageEmpty.svelte.d.ts +8 -0
  258. package/dist/plugins/image/ImagePlugin.svelte +74 -12
  259. package/dist/plugins/image/ImagePlugin.svelte.d.ts +15 -0
  260. package/dist/plugins/image/image.d.ts +2 -0
  261. package/dist/plugins/image/image.js +7 -0
  262. package/dist/plugins/index.d.ts +14 -1
  263. package/dist/plugins/index.js +10 -1
  264. package/dist/plugins/keepInView.d.ts +4 -0
  265. package/dist/plugins/keepInView.js +6 -0
  266. package/dist/plugins/markdownShortcuts.d.ts +3 -0
  267. package/dist/plugins/markdownShortcuts.js +104 -0
  268. package/dist/plugins/mention/MentionPlugin.svelte +28 -31
  269. package/dist/plugins/richtext/RichTextPlugin.svelte +411 -200
  270. package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +8 -7
  271. package/dist/plugins/richtext/richTextOperations.d.ts +53 -0
  272. package/dist/plugins/richtext/richTextOperations.js +200 -0
  273. package/dist/plugins/slashMenu/SlashMenu.svelte +297 -0
  274. package/dist/plugins/slashMenu/SlashMenu.svelte.d.ts +11 -0
  275. package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +56 -0
  276. package/dist/plugins/slashMenu/SlashMenuController.svelte.js +275 -0
  277. package/dist/plugins/slashMenu/slashMenuPlugin.d.ts +25 -0
  278. package/dist/plugins/slashMenu/slashMenuPlugin.js +105 -0
  279. package/dist/plugins/suggestions/SuggestionBars.svelte +142 -0
  280. package/dist/plugins/suggestions/SuggestionBars.svelte.d.ts +10 -0
  281. package/dist/plugins/suggestions/suggestionsPlugin.d.ts +28 -0
  282. package/dist/plugins/suggestions/suggestionsPlugin.js +53 -0
  283. package/dist/plugins/toolbar/Toolbar.svelte +341 -0
  284. package/dist/plugins/toolbar/Toolbar.svelte.d.ts +9 -0
  285. package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +85 -0
  286. package/dist/plugins/toolbar/ToolbarController.svelte.js +150 -0
  287. package/dist/plugins/toolbar/toolbarPlugin.d.ts +16 -0
  288. package/dist/plugins/toolbar/toolbarPlugin.js +40 -0
  289. package/dist/plugins.d.ts +249 -40
  290. package/dist/plugins.js +11 -5
  291. package/dist/selection/domSelection.d.ts +29 -0
  292. package/dist/selection/domSelection.js +230 -0
  293. package/dist/selection/replaceSelection.d.ts +143 -0
  294. package/dist/selection/replaceSelection.js +316 -0
  295. package/dist/selection/selection.svelte.d.ts +275 -37
  296. package/dist/selection/selection.svelte.js +1162 -331
  297. package/dist/selection/selection.utils.d.ts +35 -4
  298. package/dist/selection/selection.utils.js +309 -100
  299. package/dist/selection/visibility.d.ts +88 -0
  300. package/dist/selection/visibility.js +140 -0
  301. package/dist/session/attempt.d.ts +190 -0
  302. package/dist/session/attempt.js +188 -0
  303. package/dist/session/bindings.d.ts +16 -0
  304. package/dist/session/bindings.js +262 -0
  305. package/dist/session/commands.d.ts +158 -0
  306. package/dist/session/commands.js +601 -0
  307. package/dist/session/composition.svelte.d.ts +114 -0
  308. package/dist/session/composition.svelte.js +489 -0
  309. package/dist/session/editing/text.d.ts +33 -0
  310. package/dist/session/editing/text.js +36 -0
  311. package/dist/session/handles.d.ts +63 -0
  312. package/dist/session/handles.js +123 -0
  313. package/dist/session/history.d.ts +49 -0
  314. package/dist/session/history.js +131 -0
  315. package/dist/session/keymap.d.ts +42 -0
  316. package/dist/session/keymap.js +144 -0
  317. package/dist/session/moves.d.ts +32 -0
  318. package/dist/session/moves.js +116 -0
  319. package/dist/session/navigation.d.ts +51 -0
  320. package/dist/session/navigation.js +312 -0
  321. package/dist/session/props.d.ts +28 -0
  322. package/dist/session/props.js +162 -0
  323. package/dist/session/selection.d.ts +126 -0
  324. package/dist/session/selection.js +227 -0
  325. package/dist/session/suggestions.svelte.d.ts +125 -0
  326. package/dist/session/suggestions.svelte.js +329 -0
  327. package/dist/session/virtual.d.ts +33 -0
  328. package/dist/session/virtual.js +182 -0
  329. package/dist/surface/attributes.d.ts +36 -0
  330. package/dist/surface/attributes.js +143 -0
  331. package/dist/surface/cells.d.ts +103 -0
  332. package/dist/surface/cells.js +215 -0
  333. package/dist/surface/observer.svelte.d.ts +70 -0
  334. package/dist/surface/observer.svelte.js +969 -0
  335. package/dist/surface/overlay.d.ts +33 -0
  336. package/dist/surface/overlay.js +91 -0
  337. package/dist/surface/pin.svelte.d.ts +56 -0
  338. package/dist/surface/pin.svelte.js +108 -0
  339. package/dist/surface/projector.svelte.d.ts +69 -0
  340. package/dist/surface/projector.svelte.js +486 -0
  341. package/dist/text/deltas.d.ts +14 -3
  342. package/dist/text/deltas.js +27 -90
  343. package/dist/text/text.svelte.d.ts +43 -31
  344. package/dist/text/text.svelte.js +88 -69
  345. package/dist/text/text.utils.d.ts +7 -2
  346. package/dist/text/text.utils.js +121 -97
  347. package/dist/themes/notion.css +473 -0
  348. package/dist/utils/diffText.d.ts +15 -0
  349. package/dist/utils/diffText.js +26 -0
  350. package/dist/utils/json.d.ts +90 -3
  351. package/dist/utils/json.js +369 -2
  352. package/dist/utils.d.ts +3 -1
  353. package/dist/utils.js +2 -0
  354. package/package.json +112 -50
  355. package/dist/block/content.svelte.d.ts +0 -14
  356. package/dist/block/content.svelte.js +0 -40
  357. package/dist/components/ReadonlyEditor.svelte +0 -46
  358. package/dist/components/ReadonlyEditor.svelte.d.ts +0 -4
  359. package/dist/components/readonlyElements.svelte.d.ts +0 -82
  360. package/dist/components/readonlyElements.svelte.js +0 -144
  361. package/dist/dnd.svelte.d.ts +0 -17
  362. package/dist/dnd.svelte.js +0 -125
  363. package/dist/hotkeys.d.ts +0 -27
  364. package/dist/hotkeys.js +0 -282
  365. package/dist/localProvider.d.ts +0 -82
  366. package/dist/localProvider.js +0 -267
  367. package/dist/plugins/code/prism.css +0 -141
  368. package/dist/utils/jsx.d.ts +0 -25
  369. package/dist/utils/jsx.js +0 -66
  370. package/dist/utils/serialize.js +0 -1
  371. /package/dist/{utils/serialize.d.ts → crdt/engine-api.js} +0 -0
@@ -1,499 +1,366 @@
1
- import { Block } from './block.svelte.js';
2
- import { Text } from '../text/text.svelte.js';
3
- import { prevent } from '../utils.js';
1
+ import { id } from '../utils.js';
2
+ import { cloneJson, jsonBlockToSpec, jsonContentToItems } from '../utils/json.js';
4
3
  import { InlineBlock } from './inlineBlock.svelte.js';
5
- import * as Y from 'yjs';
6
- export function batch(operation, func) {
7
- return function (payload) {
8
- let finalPayload = payload;
9
- for (const plugin of this.edytor.plugins) {
10
- // @ts-expect-error
11
- const normalizedPayload = plugin.onBeforeOperation?.({
12
- operation,
13
- payload,
14
- block: this,
15
- prevent
16
- });
17
- if (normalizedPayload) {
18
- finalPayload = normalizedPayload;
19
- break;
20
- }
21
- }
22
- const result = this.edytor.transact(() => func.bind(this)(finalPayload));
23
- for (const plugin of this.edytor.plugins) {
24
- plugin.onAfterOperation?.({
25
- operation,
26
- payload,
27
- block: this
28
- });
29
- }
30
- return result;
4
+ /**
5
+ * Bind an operation onto its wrapper: every call is dispatched as a command
6
+ * (`session/commands.ts`): admission, hooks before any write (on the command
7
+ * and, when `prepare` answers one document plan, on each planned step), one
8
+ * transaction, normalization, the result. `func` receives the prepared plan
9
+ * and answers the op's document result; `resolve` turns it into wrappers
10
+ * after the commit patched them.
11
+ */
12
+ export function batch(operation, func, prepare, resolve) {
13
+ return function (...[payload]) {
14
+ const out = this.edytor.dispatcher.dispatch(operation, payload, { block: this }, (p, plan) => func.call(this, p, plan), prepare && ((p) => prepare.call(this, p)));
15
+ return resolve ? resolve.call(this, out, payload) : out;
31
16
  };
32
17
  }
33
- export function addChildBlock({ block, index = this.yChildren.length }) {
34
- const newBlock = new Block({ parent: this, edytor: this.edytor, block });
35
- this.yChildren.insert(index, [newBlock.yBlock]);
36
- return newBlock;
18
+ /**
19
+ * The handle of block `id` (null: refused at preparation, or gone; undefined:
20
+ * the command did not run). Inside an outer transaction too: the index shows
21
+ * the block that transaction created.
22
+ */
23
+ export function blockOf(id) {
24
+ return id === undefined ? undefined : (id && this.edytor.idToBlock.get(id)) || null;
37
25
  }
38
- export function addChildBlocks({ blocks, index = this.yChildren.length }) {
39
- const newBlocks = blocks.map((block) => new Block({ parent: this, edytor: this.edytor, block }));
40
- this.yChildren.insert(index, newBlocks.map((block) => block.yBlock));
41
- return newBlocks;
42
- }
43
- export function insertBlockAfter({ block }) {
44
- if (!this.parent) {
26
+ const REFUSED = { status: 'refused', ids: [] };
27
+ /**
28
+ * An op's body over its prepared plan: write it and request normalization of
29
+ * the blocks it touched (captured before the write). Answers the applied
30
+ * plan, or null when it was refused.
31
+ */
32
+ const applyPlan = (block, plan, touched) => {
33
+ if (!('writes' in plan))
45
34
  return null;
46
- }
47
- this.yChildren.delete(0, this.children.length);
48
- return this.parent.addChildBlock({
49
- block: {
50
- ...block,
51
- children: this.value.children
52
- },
53
- index: this.index + 1
54
- });
35
+ block.edytor.facade.apply(plan);
36
+ for (const parent of touched)
37
+ parent?.normalizeChildren();
38
+ return plan;
39
+ };
40
+ /** The document's name for `block`'s child list: `null` for the root. */
41
+ const ref = (block) => (block.isRoot ? null : block.id);
42
+ /**
43
+ * Dispatch `operation` on `block` as the one plan `prepare` answers (a
44
+ * composed command: hooks see it and each planned step, one transaction).
45
+ * `then` runs in that transaction once the plan applied, with the payload
46
+ * hooks left. Answers the applied plan, or null when refused.
47
+ */
48
+ export const dispatchPlan = (block, operation, payload, prepare, touched = [block.parent], then) => block.edytor.dispatcher.dispatch(operation, payload, { block }, (p, plan = prepare(p)) => {
49
+ const applied = applyPlan(block, plan, touched);
50
+ if (applied)
51
+ then?.(p);
52
+ return applied;
53
+ }, prepare) ?? null;
54
+ /** One child at `index` (a default-kind block without `block`); see {@link addChildBlocks}. */
55
+ export function addChildBlock({ block, index }) {
56
+ const blocks = [block || { type: this.edytor.defaultChild(this) }];
57
+ return addChildBlocks.call(this, { blocks, index })[0];
55
58
  }
56
- export function insertBlockBefore({ block }) {
57
- if (!this.parent) {
58
- return null;
59
- }
60
- return this.parent.addChildBlock({
61
- block: {
62
- ...block,
63
- children: this.value.children
64
- },
65
- index: this.index
66
- });
59
+ /** Children at `index`, clamped to the child list (at its end by default); ids kept or minted. */
60
+ export function addChildBlocks({ blocks, index = this.children.length }) {
61
+ index = Math.max(0, Math.min(index, this.children.length));
62
+ const specs = blocks.map((block) => ({ ...block, id: block.id ?? id('b') }));
63
+ this.insertChildren(index, specs);
64
+ this.normalizeChildren();
65
+ return specs.map((spec) => this.edytor.idToBlock.block(spec.id));
67
66
  }
68
- export function splitBlock({ index, text }) {
69
- if (!text || !this.parent) {
70
- return null;
71
- }
72
- const splittedContent = text.splitText({ index });
73
- const indexOfContent = this.content.indexOf(text);
74
- const remainingContent = this.content.slice(indexOfContent + 1).map((part) => part.value);
75
- const content = [splittedContent, ...remainingContent].flat();
76
- const hasChildren = this.children.length >= 1;
77
- // Add the current children to the new block if any
78
- this.yContent.delete(indexOfContent + 1, this.content.length - indexOfContent - 1);
79
- const newBlock = this.parent.addChildBlock({
80
- block: {
81
- type: this.edytor.getDefaultBlock(this.parent),
82
- content,
83
- children: this.value.children
84
- },
85
- index: this.parent.children.indexOf(this) + 1
86
- });
87
- // If the block has children, we need to remove its children and insert them into the new block
88
- if (hasChildren) {
89
- this.yChildren.delete(0, this.children.length);
90
- }
91
- return newBlock;
67
+ /** Insert `block` as a sibling of `this`, `after` it or before it. */
68
+ const prepareSibling = (self, block, after) => self.parent
69
+ ? self.edytor.facade.prepare.insertBlocks({ parent: ref(self.parent), index: self.index + (after ? 1 : 0) }, [jsonBlockToSpec(block)])
70
+ : REFUSED;
71
+ export function prepareInsertAfter({ block }) {
72
+ return prepareSibling(this, block, true);
92
73
  }
93
- export function removeBlock({ keepChildren = false } = { keepChildren: false }) {
94
- if (!this.parent) {
95
- return;
96
- }
97
- // Get the current index from yChildren array since this.index may be stale when removing multiple blocks at once
98
- const index = this.parent.yChildren.toArray().indexOf(this.yBlock);
99
- if (this.yBlock._item?.deleted) {
100
- return;
101
- }
102
- this.parent.yChildren.delete(index, 1);
103
- if (keepChildren && this.hasChildren) {
104
- this.parent.yChildren.insert(this.index, this.value.children.map((child) => {
105
- const newBlock = new Block({
106
- parent: this.parent,
107
- edytor: this.edytor,
108
- block: child
109
- });
110
- return newBlock.yBlock;
111
- }));
112
- }
74
+ export function prepareInsertBefore({ block }) {
75
+ return prepareSibling(this, block, false);
113
76
  }
114
- export function mergeBlockBackward() {
115
- if (!this.parent) {
116
- return null;
117
- }
118
- const { closestPreviousBlock, isEmpty } = this;
119
- const { children = [] } = this.value;
120
- if (!closestPreviousBlock) {
121
- return this.isEmpty ? this.mergeBlockForward() : null;
122
- }
123
- // Add the current content to the previous block content
124
- closestPreviousBlock.pushContentIntoBlock({ value: this.content });
125
- if (!isEmpty) {
126
- // If the current block has children, we need to unnest them and insert them into the current parent
127
- if (children.length > 0) {
128
- // Unnest children if any
129
- this.parent.yChildren.insert(this.index, children.map((child) => {
130
- const newBlock = new Block({
131
- parent: this.parent,
132
- edytor: this.edytor,
133
- block: child
134
- });
135
- return newBlock.yBlock;
136
- }));
137
- }
138
- }
139
- // Remove the current block from its position
140
- this.parent.yChildren.delete(this.index + this.children.length, 1);
141
- return closestPreviousBlock;
77
+ /** Apply `plan` under `this`'s parent; the id it answers first (inserted or surviving). */
78
+ function resultOf(plan) {
79
+ return applyPlan(this, plan, [this.parent])?.ids[0] ?? null;
142
80
  }
143
- export function mergeBlockForward() {
144
- if (!this.parent) {
145
- return null;
146
- }
147
- const nextBlock = this.closestNextBlock;
148
- if (!nextBlock) {
149
- return null;
150
- }
151
- this.pushContentIntoBlock({ value: nextBlock.content });
152
- if (nextBlock.children.length > 0 && nextBlock.parent) {
153
- nextBlock.parent.yChildren.insert(nextBlock.index + 1, nextBlock.children.map((child) => {
154
- const newBlock = new Block({
155
- parent: nextBlock.parent,
156
- edytor: this.edytor,
157
- block: child.value
158
- });
159
- return newBlock.yBlock;
160
- }));
161
- }
162
- nextBlock.parent?.yChildren.delete(nextBlock.index, 1);
163
- return nextBlock;
81
+ export function insertBlockAfter(payload, plan = prepareInsertAfter.call(this, payload)) {
82
+ return resultOf.call(this, plan);
164
83
  }
165
- export function moveBlock({ path }) {
166
- if (!path.length || path.some((p) => isNaN(p) || p < 0) || !this.parent) {
167
- return null;
168
- }
169
- const lastIndex = path.pop();
170
- let currentBlock = this.edytor.root;
171
- while (path.length > 0) {
172
- const index = path.shift();
173
- if (typeof index !== 'number' || isNaN(index))
174
- break;
175
- currentBlock = currentBlock.children[index];
176
- }
177
- if (!currentBlock) {
178
- return null;
179
- }
180
- this.edytor.idToBlock.delete(this.id);
181
- this.parent.yChildren.delete(this.index, 1);
182
- const newBlock = new Block({
183
- parent: currentBlock,
184
- edytor: this.edytor,
185
- block: this.value
186
- });
187
- currentBlock.yChildren.insert(lastIndex, [newBlock.yBlock]);
188
- return newBlock;
84
+ export function insertBlockBefore(payload, plan = prepareInsertBefore.call(this, payload)) {
85
+ return resultOf.call(this, plan);
189
86
  }
190
- export function unNestBlock() {
191
- const { parent, index } = this;
192
- if (!parent) {
193
- return null;
194
- }
195
- const grandParent = parent.parent;
196
- if (!grandParent) {
197
- return null;
198
- }
199
- const newBlock = new Block({
200
- parent: grandParent,
201
- edytor: this.edytor,
202
- block: this.value
203
- });
204
- grandParent.yChildren.insert(parent.index + 1, [newBlock.yBlock]);
205
- parent.yChildren.delete(index, 1);
206
- return newBlock;
207
- }
208
- export function nestBlock() {
209
- const previousBlock = this.previousBlock;
210
- if (!previousBlock ||
211
- previousBlock?.definition?.void ||
212
- previousBlock?.definition?.island ||
213
- !this.parent) {
214
- return null;
215
- }
216
- const newBlock = new Block({
217
- parent: previousBlock,
218
- edytor: this.edytor,
219
- block: { ...this.value, children: [] }
220
- });
221
- previousBlock.yChildren.insert(previousBlock.children.length, [newBlock.yBlock]);
222
- if (this.value.children && this.value.children.length) {
223
- previousBlock.yChildren.insert(previousBlock.children.length + 1, this.value.children.map((child) => {
224
- const newBlock = new Block({
225
- parent: previousBlock,
226
- edytor: this.edytor,
227
- block: child
228
- });
229
- return newBlock.yBlock;
230
- }));
231
- }
232
- this.parent.yChildren.delete(this.index, 1);
233
- return newBlock;
87
+ export function prepareDuplicate() {
88
+ if (!this.parent || !this.isInTree)
89
+ return REFUSED;
90
+ return this.edytor.facade.prepare.duplicateBlock(this.id, (_, kind) => id(kind === 'block' ? 'b' : 'i'));
234
91
  }
235
- export function setBlock({ value }) {
236
- this.edytor.doc.transact(() => {
237
- if (value.type) {
238
- this.type = value.type;
239
- }
240
- if (value.data) {
241
- this.yBlock.set('data', value.data);
242
- }
243
- if (value.content) {
244
- let newContentCount = value.content.length;
245
- let oldContentCount = this.content.length;
246
- const contentToRemove = oldContentCount - newContentCount;
247
- contentToRemove && this.yContent.delete(newContentCount, contentToRemove);
248
- const groupedContent = groupContent(value.content);
249
- this.yContent.insert(0, groupedContent.map((part) => {
250
- if ('type' in part) {
251
- const newInlineBlock = new InlineBlock({
252
- parent: this,
253
- block: part
254
- });
255
- return newInlineBlock.yBlock;
256
- }
257
- else {
258
- const newText = new Text({
259
- parent: this,
260
- content: part
261
- });
262
- return newText.yText;
263
- }
264
- }));
265
- }
266
- else {
267
- this.yContent.delete(0, this.content.length);
268
- }
269
- if (value.children) {
270
- let newChildrenCount = value.children.length;
271
- let oldChildrenCount = this.children.length;
272
- const childrenToRemove = oldChildrenCount - newChildrenCount;
273
- this.children = value.children.map((child, i) => {
274
- const existingChild = this.children[i];
275
- if (existingChild) {
276
- existingChild.setBlock({ value: child });
277
- return existingChild;
278
- }
279
- else {
280
- return this.addChildBlock({ block: child, index: i });
281
- }
282
- });
283
- childrenToRemove && this.yChildren.delete(newChildrenCount, childrenToRemove);
284
- }
285
- else {
286
- this.yChildren.delete(0, this.children.length);
287
- }
92
+ export function duplicateBlock(_ = {}, plan = prepareDuplicate.call(this)) {
93
+ return resultOf.call(this, plan);
94
+ }
95
+ export function prepareSplit({ index, text }) {
96
+ if (!text || !this.parent || !this.model)
97
+ return REFUSED;
98
+ // G5: the sibling takes its parent's default child type and no data — a
99
+ // list-like kind (`continues`) keeps its own, with its first preset's data.
100
+ const { continues, presets } = this.definition;
101
+ const tail = continues
102
+ ? { type: this.type, data: { ...(presets?.[0]?.data ?? {}) } }
103
+ : { type: this.edytor.defaultChild(this.parent), data: {} };
104
+ const offset = text.segStart + index;
105
+ return this.edytor.facade.prepare.splitBlock(this.model.id, offset, id('b'), tail);
106
+ }
107
+ /**
108
+ * A split whose children stay with the block (a container's header): the
109
+ * tail, of `tail`'s kind, becomes the block's first child (`child`) or its
110
+ * next sibling. One plan: the document's split step, placed here, without
111
+ * the move that gives the tail the children.
112
+ */
113
+ export function prepareSplitKeepingChildren({ index, text }, tail, child) {
114
+ if (!text || !this.parent || !this.model)
115
+ return REFUSED;
116
+ const { facade } = this.edytor;
117
+ const born = id('b');
118
+ const split = facade.prepare.splitBlock(this.model.id, text.segStart + index, born, tail);
119
+ const step = 'writes' in split ? split.writes[0] : undefined;
120
+ if (step?.op !== 'splitBlock')
121
+ return REFUSED;
122
+ if (!child)
123
+ return facade.compose({ ...split, writes: [step] });
124
+ // The rank of a first child, and the document's answer on placing the kind there.
125
+ const slot = facade.prepare.insertBlocks({ parent: this.model.id, index: 0 }, [
126
+ { id: born, type: tail.type }
127
+ ]);
128
+ const first = 'writes' in slot ? slot.writes[0] : undefined;
129
+ if (first?.op !== 'insertBlocks')
130
+ return REFUSED;
131
+ const placed = { ...step, parent: this.model.id, rank: first.ranks[0] };
132
+ return facade.compose({ ...split, writes: [placed] });
133
+ }
134
+ export function splitBlock(payload, plan = prepareSplit.call(this, payload)) {
135
+ return applyPlan(this, plan, [this.parent])?.effect.creates[0] ?? null;
136
+ }
137
+ export function prepareRemove({ keepChildren = true } = {}) {
138
+ if (!this.parent || !this.model || !this.isInTree)
139
+ return REFUSED;
140
+ return this.edytor.facade.prepare.deleteBlock(this.model.id, { keepChildren });
141
+ }
142
+ export function removeBlock(payload = {}, plan = prepareRemove.call(this, payload)) {
143
+ applyPlan(this, plan, [this.parent]);
144
+ }
145
+ export function prepareMergeBackward() {
146
+ return this.parent && this.model
147
+ ? this.edytor.facade.prepare.mergeBackward(this.model.id)
148
+ : REFUSED;
149
+ }
150
+ export function prepareMergeForward() {
151
+ return this.parent && this.model
152
+ ? this.edytor.facade.prepare.mergeForward(this.model.id)
153
+ : REFUSED;
154
+ }
155
+ export function mergeBlockBackward(_ = {}, plan = prepareMergeBackward.call(this)) {
156
+ return resultOf.call(this, plan);
157
+ }
158
+ export function mergeBlockForward(_ = {}, plan = prepareMergeForward.call(this)) {
159
+ return resultOf.call(this, plan);
160
+ }
161
+ /** The destination parent a view-tree path (`[...parentPath, index]`) names. */
162
+ const parentAt = (edytor, path) => {
163
+ let parent = edytor.root;
164
+ for (const index of path.slice(0, -1))
165
+ parent = parent?.children[index];
166
+ return [parent, path.at(-1)];
167
+ };
168
+ export function prepareMove({ path }) {
169
+ // Admission: the caller path is a view-tree address — validate its shape
170
+ // and resolve it to the destination PARENT block + index. Structural
171
+ // permission is the document's (`canPlace`: island seals, void/island
172
+ // destinations, moves into the block's own subtree).
173
+ if (!path.length || path.some((p) => isNaN(p) || p < 0) || !this.parent)
174
+ return REFUSED;
175
+ const [parent, index] = parentAt(this.edytor, path);
176
+ if (!parent || !this.model)
177
+ return REFUSED;
178
+ return this.edytor.facade.prepare.moveBlock(this.model.id, { parent: ref(parent), index });
179
+ }
180
+ export function moveBlock(payload, plan = prepareMove.call(this, payload)) {
181
+ return applyPlan(this, plan, [this.parent, parentAt(this.edytor, payload.path)[0]]) ? this : null;
182
+ }
183
+ /**
184
+ * Grouped move — the operation-layer counterpart of `moveBlock` for
185
+ * drags/multi-moves (D5). `path` is the same view-tree address shape:
186
+ * the prefix resolves the destination PARENT block, the last element is
187
+ * the FINAL index — already discounted for the moved members by the
188
+ * caller (the `facade.moveBlocks` contract, which counts the
189
+ * destination's children with the moved members excluded). Structural
190
+ * permission stays in the facade.
191
+ */
192
+ export function prepareMoves({ blocks, path }) {
193
+ if (!path.length || path.some((p) => isNaN(p) || p < 0) || !blocks.length)
194
+ return REFUSED;
195
+ const [parent, index] = parentAt(this.edytor, path);
196
+ if (!parent || blocks.some((block) => block.isRoot))
197
+ return REFUSED;
198
+ return this.edytor.facade.prepare.moveBlocks(blocks.map((block) => block.id), { parent: ref(parent), index });
199
+ }
200
+ export function moveBlocks(payload, plan = prepareMoves.call(this, payload)) {
201
+ const { blocks, path } = payload;
202
+ const parents = new Set([...blocks.map((block) => block.parent), parentAt(this.edytor, path)[0]]);
203
+ return applyPlan(this, plan, [...parents]) ? blocks : [];
204
+ }
205
+ /**
206
+ * The facade owns the refusal rules (`unNestBlock`: top-level blocks,
207
+ * island-sealed blocks and sealed destinations).
208
+ */
209
+ export function prepareUnNest() {
210
+ return this.parent && this.model
211
+ ? this.edytor.facade.prepare.unNestBlock(this.model.id)
212
+ : REFUSED;
213
+ }
214
+ export function unNestBlock(_ = {}, plan = prepareUnNest.call(this)) {
215
+ return applyPlan(this, plan, [this.parent, this.parent?.parent, this]) ? this : null;
216
+ }
217
+ /**
218
+ * Admission resolves the nest target — the previous sibling — and the
219
+ * facade owns permission: `nestBlock` refuses void/island/inside-island
220
+ * targets and island-sealed sources (`canPlace`).
221
+ */
222
+ export function prepareNest() {
223
+ const target = this.previousBlock?.id;
224
+ return this.parent && this.model && target != null
225
+ ? this.edytor.facade.prepare.nestBlock(this.model.id, target)
226
+ : REFUSED;
227
+ }
228
+ export function nestBlock(_ = {}, plan = prepareNest.call(this)) {
229
+ return applyPlan(this, plan, [this.parent, this.previousBlock]) ? this : null;
230
+ }
231
+ export function prepareSet({ value }) {
232
+ if (!this.model)
233
+ return REFUSED;
234
+ // Spec preparation is pure JSON → `ContentItem`/`BlockSpec` conversion:
235
+ // the document stores the items verbatim and derives the content
236
+ // invariant on projection.
237
+ return this.edytor.facade.prepare.setBlock(this.model.id, {
238
+ ...(value.type !== undefined ? { type: value.type } : {}),
239
+ ...(value.data !== undefined ? { data: cloneJson(value.data) } : {}),
240
+ ...(value.content !== undefined ? { content: jsonContentToItems(value.content) } : {}),
241
+ ...(value.children !== undefined
242
+ ? { children: value.children.map((child) => jsonBlockToSpec(child)) }
243
+ : {})
288
244
  });
289
245
  }
246
+ export function setBlock(payload, plan = prepareSet.call(this, payload)) {
247
+ if (!applyPlan(this, plan, [this]))
248
+ return;
249
+ this.normalizeContent();
250
+ }
290
251
  export function pushContentIntoBlock({ value }) {
291
- const content = this.content.filter((part) => part instanceof Text ? !part.yText._item?.deleted : !part.yBlock._item?.deleted);
292
- let index = content.length;
252
+ const model = this.model;
253
+ if (!model)
254
+ return;
293
255
  for (const part of value) {
294
256
  if (part instanceof InlineBlock) {
295
- // is an inline block needed to be added
296
- const newInlineBlock = new InlineBlock({
297
- parent: this,
298
- block: part
299
- });
300
- this.yContent.insert(index, [newInlineBlock.yBlock]);
301
- index++;
257
+ const { id, type, data } = part;
258
+ model.insertInline(model.length, { id, type, ...(data ? { data: cloneJson(data) } : {}) });
302
259
  }
303
260
  else {
304
- const lastPart = content[index - 1];
305
- if (lastPart instanceof Text) {
306
- const delta = part.yText.toDelta();
307
- lastPart.yText.applyDelta([{ retain: lastPart.yText.length }, ...delta]);
308
- }
309
- else {
310
- const newText = new Text({
311
- parent: this,
312
- content: part.value
313
- });
314
- this.yContent.insert(index, [newText.yText]);
315
- index++;
316
- }
261
+ for (const { text, marks } of part.value)
262
+ if (text.length)
263
+ model.insertText(model.length, text, marks);
317
264
  }
318
265
  }
319
- console.log(this.yContent.toArray());
266
+ this.normalizeContent();
320
267
  }
321
- export function removeInlineBlock({ index }) {
268
+ export function prepareRemoveInline({ index }) {
322
269
  const part = this.content.at(index);
323
- if (part && part instanceof InlineBlock) {
324
- this.yContent.delete(index, 1);
270
+ return part instanceof InlineBlock && this.model
271
+ ? this.edytor.facade.prepare.removeInline(this.model.id, part.id)
272
+ : REFUSED;
273
+ }
274
+ export function removeInlineBlock(payload, plan = prepareRemoveInline.call(this, payload)) {
275
+ if (applyPlan(this, plan, []))
325
276
  this.normalizeContent();
326
- }
327
277
  }
328
- export const groupContent = (content) => {
329
- const isInlineJSONBlock = (part) => {
330
- return part ? 'type' in part : false;
331
- };
332
- // this function group JSONBlock.content texts together in order to avoid having successive inline Y.Text as it would be ineficient.
333
- if (!content)
334
- return [[{ text: '' }]];
335
- const groupedContent = content.reduce((acc, part) => {
336
- const isInlineBlock = 'type' in part;
337
- if (isInlineBlock) {
338
- if (isInlineJSONBlock(acc.at(-1))) {
339
- // Make sure that two consecutive inline blocks are separated by a text block
340
- acc.push([{ text: '' }]);
341
- }
342
- acc.push(part);
343
- }
344
- else {
345
- const lastPart = acc.at(-1);
346
- if (acc.length && lastPart && Array.isArray(lastPart)) {
347
- lastPart.push(part);
348
- }
349
- else {
350
- acc.push([part]);
351
- }
352
- }
353
- return acc;
354
- }, []);
355
- if (isInlineJSONBlock(groupedContent.at(0))) {
356
- // Make sure that the first part is an inline block
357
- groupedContent.unshift([{ text: '' }]);
358
- }
359
- if (isInlineJSONBlock(groupedContent.at(-1))) {
360
- // Make sure that the last part is a text block
361
- groupedContent.push([{ text: '' }]);
362
- }
363
- return groupedContent;
364
- };
278
+ export function preparePatch({ ops, atom }) {
279
+ const target = this.isRoot ? null : atom === undefined ? this.id : { block: this.id, atom };
280
+ return this.edytor.facade.prepare.patchData(target, ops);
281
+ }
282
+ export function patchData(payload, plan = preparePatch.call(this, payload)) {
283
+ applyPlan(this, plan, []);
284
+ }
285
+ /**
286
+ * Insert an inline atom at `index` of `text`. Answers the atom's id; the
287
+ * batched operation resolves it to the text after the atom once committed
288
+ * ({@link textAfterAtom}), where the caret's pending marks follow.
289
+ */
365
290
  export function addInlineBlock({ index, block, text }) {
366
- // TODO
367
- const newInlineBlock = new InlineBlock({
368
- parent: this,
369
- block
370
- });
371
- const newText = new Text({
372
- parent: this,
373
- content: text.splitText({ index })
291
+ const atom = { ...block, id: block.id ?? id('i') };
292
+ this.model?.insertInline(text.segStart + index, {
293
+ id: atom.id,
294
+ type: atom.type,
295
+ ...(atom.data ? { data: cloneJson(atom.data) } : {})
374
296
  });
375
- this.yContent.insert(text.index + 1, [newInlineBlock.yBlock, newText.yText]);
376
297
  this.normalizeContent();
377
- return newText;
298
+ return atom.id;
378
299
  }
300
+ /** The text after atom `atom` of this block; the caret's pending marks follow it there (L4). */
301
+ export function textAfterAtom(atom) {
302
+ if (atom === undefined)
303
+ return undefined;
304
+ const at = this.content.findIndex((part) => part.id === atom);
305
+ const after = at < 0 ? undefined : this.content[at + 1];
306
+ if (!after || after instanceof InlineBlock)
307
+ return null;
308
+ const { selection } = this.edytor;
309
+ const pending = selection.pending;
310
+ const caret = pending && selection.textValue(after, 0);
311
+ if (caret && caret.kind === 'text')
312
+ selection.select(Object.freeze({ ...caret, pending }));
313
+ return after;
314
+ }
315
+ /**
316
+ * Normalization runs at the end of the command's transaction
317
+ * (`Dispatcher.drain`): a normalizer reads handles over the index; when a
318
+ * plugin hook answers work, the work runs in the same transaction and the
319
+ * block is requested again (bounded by the dispatcher's pass limit, D25).
320
+ */
379
321
  export function normalizeContent() {
380
- const content = this.yContent.toArray().filter((part) => !part._item?.deleted);
381
- // Ensure content starts with Text
382
- if (content.length === 0 || !(content[0] instanceof Y.Text)) {
383
- const emptyText = new Text({
384
- parent: this,
385
- content: [{ text: '' }]
386
- });
387
- this.yContent.insert(0, [emptyText.yText]);
388
- return this.normalizeContent();
389
- }
390
- // Ensure content ends with Text
391
- if (!(content[content.length - 1] instanceof Y.Text)) {
392
- const emptyText = new Text({
393
- parent: this,
394
- content: [{ text: '' }]
395
- });
396
- this.yContent.insert(content.length, [emptyText.yText]);
397
- return this.normalizeContent();
398
- }
399
- // First handle consecutive text blocks
400
- const consecutiveTexts = content.reduce((acc, part, index) => {
401
- const nextPart = content[index + 1];
402
- if (part instanceof Y.Text && nextPart instanceof Y.Text) {
403
- acc.push([part, nextPart]);
404
- }
405
- return acc;
406
- }, []);
407
- if (consecutiveTexts.length > 0) {
408
- const [first, second] = consecutiveTexts[0];
409
- const delta = second.toDelta();
410
- first.applyDelta([{ retain: first.length }, ...delta]);
411
- this.yContent.delete(content.indexOf(second), 1);
412
- return this.normalizeContent();
413
- }
414
- // Then handle consecutive inline blocks
415
- const consecutiveInlineBlocks = content.reduce((acc, part, index) => {
416
- const nextPart = content[index + 1];
417
- if (part instanceof Y.Map && nextPart instanceof Y.Map) {
418
- acc.push([part, nextPart]);
419
- }
420
- return acc;
421
- }, []);
422
- if (consecutiveInlineBlocks.length > 0) {
423
- const [first, second] = consecutiveInlineBlocks[0];
424
- const emptyText = new Text({
425
- parent: this,
426
- content: [{ text: '' }]
427
- });
428
- const index = content.indexOf(second);
429
- this.yContent.insert(index, [emptyText.yText]);
430
- return this.normalizeContent();
431
- }
432
- const pluginNormalization = this.definition?.normalizeContent?.({ block: this });
433
- if (pluginNormalization) {
434
- pluginNormalization();
322
+ if (this.edytor.dispatcher.defer(this, normalizeContent))
323
+ return;
324
+ // The v14 content model maintains the part invariants by construction —
325
+ // projected content always derives to text-first/text-last/non-adjacent
326
+ // parts — so the only remaining normalization is the plugin hook.
327
+ const work = this.definition?.normalizeContent?.({ block: this });
328
+ if (work) {
329
+ this.edytor.dispatcher.write(work);
435
330
  this.normalizeContent();
436
331
  }
437
332
  }
438
- export function suggestText({ value }) {
439
- if (typeof value === 'string') {
440
- this.suggestions = [[{ text: value }]];
441
- }
442
- else if (value) {
443
- this.suggestions = groupContent(value);
444
- }
445
- else {
446
- this.suggestions = null;
333
+ export function normalizeChildren() {
334
+ if (this.edytor.dispatcher.defer(this, normalizeChildren))
335
+ return;
336
+ // An emptied root writes nothing: the view shows its virtual paragraph (`doc.empty.virtual`).
337
+ const work = this.definition?.normalizeChildren?.({ block: this });
338
+ if (work) {
339
+ this.edytor.dispatcher.write(work);
340
+ this.normalizeChildren();
447
341
  }
448
342
  }
343
+ /** @deprecated A thin wrapper over an `{ end: block.id }` suggestion (`edytor.suggestions`). */
344
+ export function suggestText({ value }) {
345
+ this.suggestions =
346
+ typeof value === 'string'
347
+ ? [[{ text: value }]]
348
+ : (value?.map((part) => ('type' in part ? part : [part])) ?? null);
349
+ }
350
+ /** @deprecated Accepts this block's latest `{ end }` suggestion (`suggestion.accept()`). */
449
351
  export function acceptSuggestedText() {
450
- if (!this.suggestions) {
451
- return;
452
- }
453
- const editableSuggestions = this.suggestions.map((part) => {
454
- if ('type' in part) {
455
- return new InlineBlock({
456
- parent: this,
457
- block: part.value
458
- });
459
- }
460
- else {
461
- return new Text({
462
- parent: this,
463
- content: part.value
464
- });
465
- }
466
- });
467
- this.yContent.insert(this.content.length, editableSuggestions.map((suggestion) => 'yBlock' in suggestion ? suggestion.yBlock : suggestion.yText));
468
- this.suggestions = null;
469
- this.normalizeContent();
352
+ this.edytor.suggestions.at(this.id).end.at(-1)?.accept();
470
353
  }
471
- export function deleteContentAtRange({ start, end }) {
472
- const [startIndex, startOffset] = start;
473
- const [endIndex, endOffset] = end;
474
- let numberToDelete = 0;
475
- this.content.slice(startIndex, endIndex + 1).forEach((part, index) => {
476
- const isFirstPart = index === 0;
477
- const isLastPart = index === endIndex - startIndex;
478
- if (part instanceof Text) {
479
- if (isFirstPart) {
480
- // Delete from offset to end
481
- part.yText.delete(startOffset, part.yText.length - startOffset);
482
- }
483
- else if (isLastPart) {
484
- // Delete from start to offset
485
- part.yText.delete(0, endOffset);
486
- }
487
- else {
488
- numberToDelete++;
489
- // Delete entire text element
490
- }
491
- }
492
- else {
493
- // For inline blocks, always delete the entire element
494
- numberToDelete++;
495
- }
496
- });
497
- this.yContent.delete(startIndex + 1, numberToDelete);
498
- this.normalizeContent();
354
+ export function prepareDeleteRange({ start: [startIndex, startOffset], end: [endIndex, endOffset] }) {
355
+ const parts = this.edytor.idToBlock.parts(this.id);
356
+ const [startPart, endPart] = [parts.at(startIndex), parts.at(endIndex)];
357
+ if (!startPart || !endPart || !this.model)
358
+ return REFUSED;
359
+ const at = startPart.start + startOffset;
360
+ const length = Math.max(0, endPart.start + endOffset - at);
361
+ return this.edytor.facade.prepare.deleteText(this.model.id, at, length);
362
+ }
363
+ export function deleteContentAtRange(payload, plan = prepareDeleteRange.call(this, payload)) {
364
+ if (applyPlan(this, plan, []))
365
+ this.normalizeContent();
499
366
  }