edytor 2.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +19 -4
  2. package/dist/block/block.svelte.js +2 -4
  3. package/dist/clipboard/htmlFlow.d.ts +20 -7
  4. package/dist/clipboard/htmlFlow.js +23 -15
  5. package/dist/clipboard/serializeClipboardFragment.d.ts +37 -4
  6. package/dist/clipboard/serializeClipboardFragment.js +6 -4
  7. package/dist/clipboard/textBlocks.d.ts +8 -0
  8. package/dist/clipboard/textBlocks.js +6 -2
  9. package/dist/cloudflare/DocumentRoom.d.ts +13 -9
  10. package/dist/cloudflare/DocumentRoom.js +10 -6
  11. package/dist/cloudflare/room/admission.js +3 -3
  12. package/dist/cloudflare/room/context.d.ts +28 -27
  13. package/dist/cloudflare/room/context.js +2 -2
  14. package/dist/cloudflare/room/purge.d.ts +6 -3
  15. package/dist/cloudflare/room/purge.js +44 -19
  16. package/dist/cloudflare/room/updates.d.ts +3 -4
  17. package/dist/cloudflare/room/updates.js +6 -8
  18. package/dist/cloudflare/routeDocumentSocket.d.ts +17 -0
  19. package/dist/cloudflare/routeDocumentSocket.js +53 -0
  20. package/dist/collaboration/comments/client.d.ts +1 -1
  21. package/dist/collaboration/comments/client.js +1 -1
  22. package/dist/collaboration/remoteSelection.js +3 -3
  23. package/dist/components/Edytor.svelte +2 -10
  24. package/dist/components/Edytor.svelte.d.ts +1 -3
  25. package/dist/crdt/admission.d.ts +5 -10
  26. package/dist/crdt/admission.js +5 -11
  27. package/dist/crdt/attribution/attribution.d.ts +31 -12
  28. package/dist/crdt/attribution/attribution.js +56 -18
  29. package/dist/crdt/attribution/block.d.ts +3 -3
  30. package/dist/crdt/attribution/block.js +7 -8
  31. package/dist/crdt/attribution/index.d.ts +1 -1
  32. package/dist/crdt/attribution/index.js +1 -1
  33. package/dist/crdt/data.d.ts +62 -31
  34. package/dist/crdt/data.js +211 -103
  35. package/dist/crdt/doc/delete.d.ts +1 -1
  36. package/dist/crdt/doc/delete.js +13 -30
  37. package/dist/crdt/doc/funnel.d.ts +7 -6
  38. package/dist/crdt/doc/funnel.js +39 -33
  39. package/dist/crdt/doc/gate.d.ts +3 -20
  40. package/dist/crdt/doc/gate.js +2 -41
  41. package/dist/crdt/doc/history.d.ts +25 -9
  42. package/dist/crdt/doc/history.js +152 -42
  43. package/dist/crdt/doc/layout.js +11 -22
  44. package/dist/crdt/doc/meta.js +12 -17
  45. package/dist/crdt/doc/moves.d.ts +1 -1
  46. package/dist/crdt/doc/moves.js +52 -32
  47. package/dist/crdt/doc/reads.js +2 -2
  48. package/dist/crdt/doc/seed.js +2 -2
  49. package/dist/crdt/doc/split-merge.js +12 -15
  50. package/dist/crdt/doc/steps.d.ts +25 -13
  51. package/dist/crdt/doc/steps.js +52 -122
  52. package/dist/crdt/doc/types.d.ts +21 -9
  53. package/dist/crdt/document.d.ts +21 -19
  54. package/dist/crdt/document.js +26 -23
  55. package/dist/crdt/edytor-doc.d.ts +66 -68
  56. package/dist/crdt/edytor-doc.js +21 -20
  57. package/dist/crdt/engine-api.d.ts +33 -1
  58. package/dist/crdt/engine.d.ts +0 -1
  59. package/dist/crdt/engine.js +1 -4
  60. package/dist/crdt/flow.d.ts +1 -1
  61. package/dist/crdt/flow.js +25 -27
  62. package/dist/crdt/index.d.ts +29 -28
  63. package/dist/crdt/index.js +3 -3
  64. package/dist/crdt/placement/display.d.ts +5 -30
  65. package/dist/crdt/placement/display.js +39 -144
  66. package/dist/crdt/placement/keys.d.ts +58 -0
  67. package/dist/crdt/placement/keys.js +90 -0
  68. package/dist/crdt/placement/model.d.ts +119 -118
  69. package/dist/crdt/placement/model.js +242 -142
  70. package/dist/crdt/placement/resolve.d.ts +123 -35
  71. package/dist/crdt/placement/resolve.js +187 -153
  72. package/dist/crdt/placement/slots.d.ts +134 -0
  73. package/dist/crdt/placement/slots.js +152 -0
  74. package/dist/crdt/protocol.d.ts +2 -2
  75. package/dist/crdt/protocol.js +2 -2
  76. package/dist/crdt/providers/index.d.ts +1 -1
  77. package/dist/crdt/providers/room.d.ts +26 -11
  78. package/dist/crdt/providers/room.js +77 -27
  79. package/dist/crdt/providers/websocket.d.ts +1 -1
  80. package/dist/crdt/providers/websocket.js +33 -32
  81. package/dist/crdt/purge.d.ts +17 -8
  82. package/dist/crdt/purge.js +236 -126
  83. package/dist/crdt/restore.d.ts +2 -2
  84. package/dist/crdt/restore.js +18 -34
  85. package/dist/crdt/schema.d.ts +22 -21
  86. package/dist/crdt/schema.js +29 -23
  87. package/dist/crdt/semantics.js +3 -1
  88. package/dist/crdt/storage.d.ts +1 -1
  89. package/dist/crdt/storage.js +1 -1
  90. package/dist/crdt/structs.d.ts +15 -15
  91. package/dist/crdt/structs.js +8 -22
  92. package/dist/crdt/text/index/cache.js +4 -0
  93. package/dist/crdt/text/index/claims.js +12 -0
  94. package/dist/crdt/text/index/fold.d.ts +2 -3
  95. package/dist/crdt/text/index/fold.js +194 -44
  96. package/dist/crdt/text/index/layout.js +5 -8
  97. package/dist/crdt/text/index/placement.d.ts +26 -18
  98. package/dist/crdt/text/index/placement.js +404 -138
  99. package/dist/crdt/text/index/records.d.ts +3 -3
  100. package/dist/crdt/text/index/records.js +24 -31
  101. package/dist/crdt/text/index/shared.d.ts +11 -3
  102. package/dist/crdt/text/index/shared.js +12 -3
  103. package/dist/crdt/text/index/state.d.ts +21 -17
  104. package/dist/crdt/text/index/state.js +15 -17
  105. package/dist/crdt/text/index/streams.d.ts +10 -5
  106. package/dist/crdt/text/index/streams.js +78 -27
  107. package/dist/crdt/text/items.d.ts +10 -3
  108. package/dist/crdt/text/items.js +7 -0
  109. package/dist/crdt/text/model.d.ts +77 -62
  110. package/dist/crdt/text/model.js +84 -169
  111. package/dist/crdt/text/ranges.d.ts +1 -1
  112. package/dist/crdt/text/ranges.js +3 -3
  113. package/dist/crdt/text/rows.d.ts +13 -7
  114. package/dist/crdt/text/rows.js +24 -7
  115. package/dist/crdt/text/runs.d.ts +17 -12
  116. package/dist/crdt/text/runs.js +24 -7
  117. package/dist/crdt/text/streams.d.ts +26 -13
  118. package/dist/crdt/text/streams.js +41 -14
  119. package/dist/crdt/vendor/yjs/UPSTREAM.md +568 -21
  120. package/dist/crdt/vendor/yjs/dts/global.d.ts +2 -0
  121. package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
  122. package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +7 -0
  123. package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +194 -10
  124. package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +6 -3
  125. package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +5 -18
  126. package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +15 -1
  127. package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +14 -6
  128. package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +33 -6
  129. package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +1 -65
  130. package/dist/crdt/vendor/yjs/dts/utils/marks.d.ts +6 -1
  131. package/dist/crdt/vendor/yjs/dts/ynode.d.ts +43 -7
  132. package/dist/crdt/vendor/yjs/global.d.ts +2 -0
  133. package/dist/crdt/vendor/yjs/src/index.js +1 -1
  134. package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +10 -0
  135. package/dist/crdt/vendor/yjs/src/structs/Item.js +610 -51
  136. package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +18 -9
  137. package/dist/crdt/vendor/yjs/src/utils/Doc.js +5 -3
  138. package/dist/crdt/vendor/yjs/src/utils/StructStore.js +5 -0
  139. package/dist/crdt/vendor/yjs/src/utils/Transaction.js +36 -13
  140. package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +88 -18
  141. package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +119 -32
  142. package/dist/crdt/vendor/yjs/src/utils/encoding.js +13 -1
  143. package/dist/crdt/vendor/yjs/src/utils/ids.js +7 -7
  144. package/dist/crdt/vendor/yjs/src/utils/marks.js +193 -8
  145. package/dist/crdt/vendor/yjs/src/utils/redo.js +1 -1
  146. package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +1 -1
  147. package/dist/crdt/vendor/yjs/src/utils/updates.js +3 -3
  148. package/dist/crdt/vendor/yjs/src/ynode.js +177 -12
  149. package/dist/dnd/autoScroll.d.ts +15 -7
  150. package/dist/dnd/autoScroll.js +10 -15
  151. package/dist/dnd/dropIndicator.js +2 -5
  152. package/dist/dnd/external.d.ts +6 -0
  153. package/dist/dnd/external.js +17 -0
  154. package/dist/dnd/geometry.d.ts +2 -0
  155. package/dist/dnd/geometry.js +3 -4
  156. package/dist/dnd/placement.d.ts +1 -1
  157. package/dist/dnd/pragmatic.d.ts +3 -1
  158. package/dist/dnd/pragmatic.js +12 -2
  159. package/dist/dnd/vendor/pragmatic/UPSTREAM.md +51 -18
  160. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.d.ts +4 -0
  161. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.js +6 -0
  162. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.d.ts +0 -2
  163. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.js +4 -22
  164. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter-types.d.ts +26 -0
  165. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.d.ts +30 -0
  166. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.js +203 -0
  167. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-items.js +13 -0
  168. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-types.js +9 -0
  169. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/is-an-available-type.js +19 -0
  170. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.d.ts +4 -0
  171. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.js +6 -0
  172. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/honey-pot-fix/make-honey-pot-fix.js +4 -16
  173. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/internal-types.d.ts +1 -8
  174. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-drop-target.js +5 -6
  175. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-monitor.js +2 -3
  176. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.d.ts +1 -1
  177. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +6 -24
  178. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.d.ts +2 -0
  179. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.js +5 -0
  180. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.d.ts +3 -0
  181. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.js +12 -0
  182. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/native-types.d.ts +12 -0
  183. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window-in-safari.js +10 -0
  184. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window.js +55 -0
  185. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.d.ts +4 -0
  186. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.js +8 -0
  187. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/internal-types.d.ts +0 -4
  188. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/get-scroll-by.js +16 -72
  189. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/try-scroll.js +1 -9
  190. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/configuration.js +4 -29
  191. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/get-scroll-change.js +2 -3
  192. package/dist/edytor.svelte.d.ts +2 -5
  193. package/dist/edytor.svelte.js +21 -32
  194. package/dist/events/beforeInputCommands.js +2 -2
  195. package/dist/events/onBeforeInput.js +1 -1
  196. package/dist/events/onDrop.d.ts +0 -6
  197. package/dist/events/onDrop.js +10 -23
  198. package/dist/events/onInput.d.ts +0 -12
  199. package/dist/events/onInput.js +1 -67
  200. package/dist/events/onPageHide.d.ts +3 -0
  201. package/dist/events/onPageHide.js +16 -0
  202. package/dist/export/forms.d.ts +627 -0
  203. package/dist/export/forms.js +749 -0
  204. package/dist/export/index.d.ts +170 -0
  205. package/dist/export/index.js +161 -0
  206. package/dist/export/markdown.d.ts +41 -0
  207. package/dist/export/markdown.js +585 -0
  208. package/dist/export/markdownWriter.d.ts +9 -0
  209. package/dist/export/markdownWriter.js +133 -0
  210. package/dist/export/mdx.d.ts +15 -0
  211. package/dist/export/mdx.js +33 -0
  212. package/dist/index.d.ts +3 -3
  213. package/dist/index.js +1 -1
  214. package/dist/kinds.js +1 -1
  215. package/dist/plugins/anchored.svelte.d.ts +21 -25
  216. package/dist/plugins/anchored.svelte.js +23 -39
  217. package/dist/plugins/blockHandles/BlockHandleController.svelte.js +24 -32
  218. package/dist/plugins/blockHandles/dragPreview.d.ts +26 -7
  219. package/dist/plugins/blockHandles/dragPreview.js +33 -0
  220. package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +5 -0
  221. package/dist/plugins/blockMenu/BlockMenuController.svelte.js +7 -2
  222. package/dist/plugins/blockMenu/blockMenuPlugin.js +5 -50
  223. package/dist/plugins/chrome.d.ts +27 -5
  224. package/dist/plugins/chrome.js +24 -9
  225. package/dist/plugins/code/CodePlugin.svelte +12 -9
  226. package/dist/plugins/code/header.svelte.js +7 -11
  227. package/dist/plugins/code/languageMenu.svelte.d.ts +5 -2
  228. package/dist/plugins/code/languageMenu.svelte.js +13 -20
  229. package/dist/plugins/columns/ColumnsPlugin.svelte +7 -20
  230. package/dist/plugins/columns/resize.svelte.d.ts +2 -3
  231. package/dist/plugins/columns/resize.svelte.js +2 -5
  232. package/dist/plugins/comments/CommentsController.svelte.d.ts +6 -0
  233. package/dist/plugins/comments/CommentsController.svelte.js +20 -0
  234. package/dist/plugins/equation/EquationPlugin.svelte +12 -22
  235. package/dist/plugins/equation/equation.svelte.d.ts +7 -15
  236. package/dist/plugins/equation/equation.svelte.js +13 -50
  237. package/dist/plugins/equation/tex.d.ts +17 -0
  238. package/dist/plugins/equation/tex.js +42 -0
  239. package/dist/plugins/fileDrop.d.ts +38 -23
  240. package/dist/plugins/fileDrop.js +82 -76
  241. package/dist/plugins/find/FindController.svelte.d.ts +5 -0
  242. package/dist/plugins/find/FindController.svelte.js +14 -14
  243. package/dist/plugins/find/findPlugin.js +1 -15
  244. package/dist/plugins/image/ImageChrome.svelte +8 -2
  245. package/dist/plugins/image/ImagePlugin.svelte +15 -52
  246. package/dist/plugins/image/controls.svelte.js +16 -2
  247. package/dist/plugins/image/toolbar.svelte.d.ts +5 -4
  248. package/dist/plugins/image/toolbar.svelte.js +21 -31
  249. package/dist/plugins/index.d.ts +1 -1
  250. package/dist/plugins/list.svelte.d.ts +9 -0
  251. package/dist/plugins/list.svelte.js +18 -0
  252. package/dist/plugins/marquee/marqueePlugin.js +0 -4
  253. package/dist/plugins/media/AudioPlugin.svelte +1 -1
  254. package/dist/plugins/media/BookmarkPlugin.svelte +6 -97
  255. package/dist/plugins/media/EmbedPlugin.svelte +5 -90
  256. package/dist/plugins/media/EmptySlot.svelte +36 -20
  257. package/dist/plugins/media/EmptySlot.svelte.d.ts +6 -15
  258. package/dist/plugins/media/FilePlugin.svelte +1 -19
  259. package/dist/plugins/media/MediaEmpty.svelte +2 -55
  260. package/dist/plugins/media/MediaEmpty.svelte.d.ts +18 -14
  261. package/dist/plugins/media/SourceBlock.svelte +142 -52
  262. package/dist/plugins/media/SourceBlock.svelte.d.ts +10 -4
  263. package/dist/plugins/media/VideoPlugin.svelte +1 -1
  264. package/dist/plugins/media/empty.svelte.js +2 -7
  265. package/dist/plugins/media/media.d.ts +2 -63
  266. package/dist/plugins/media/media.js +1 -194
  267. package/dist/plugins/media/sources.d.ts +60 -0
  268. package/dist/plugins/media/sources.js +165 -0
  269. package/dist/plugins/media/urlPaste.svelte.d.ts +2 -1
  270. package/dist/plugins/media/urlPaste.svelte.js +12 -21
  271. package/dist/plugins/mention/MentionPlugin.svelte +8 -35
  272. package/dist/plugins/page/PagePlugin.svelte +2 -9
  273. package/dist/plugins/page/page.js +1 -1
  274. package/dist/plugins/pageLink/PageLinkPlugin.svelte +6 -13
  275. package/dist/plugins/richtext/RichTextPlugin.svelte +85 -197
  276. package/dist/plugins/richtext/body.js +1 -1
  277. package/dist/plugins/richtext/calloutIcons.svelte.d.ts +2 -2
  278. package/dist/plugins/richtext/calloutIcons.svelte.js +5 -7
  279. package/dist/plugins/richtext/richTextOperations.d.ts +1 -19
  280. package/dist/plugins/richtext/richTextOperations.js +3 -49
  281. package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +2 -0
  282. package/dist/plugins/slashMenu/SlashMenuController.svelte.js +7 -0
  283. package/dist/plugins/slashMenu/slashMenuPlugin.js +5 -14
  284. package/dist/plugins/table/TableChrome.svelte +2 -3
  285. package/dist/plugins/table/TablePlugin.svelte +20 -54
  286. package/dist/plugins/table/chrome.svelte.d.ts +5 -2
  287. package/dist/plugins/table/chrome.svelte.js +30 -54
  288. package/dist/plugins/table/table.js +3 -3
  289. package/dist/plugins/toc/TocPlugin.svelte +2 -4
  290. package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +7 -0
  291. package/dist/plugins/toolbar/ToolbarController.svelte.js +20 -13
  292. package/dist/plugins/toolbar/toolbarPlugin.js +19 -53
  293. package/dist/plugins/triggers/TriggerController.svelte.d.ts +7 -2
  294. package/dist/plugins/triggers/TriggerController.svelte.js +11 -4
  295. package/dist/plugins/triggers/place.js +1 -2
  296. package/dist/plugins/triggers/triggers.d.ts +6 -1
  297. package/dist/plugins/triggers/triggers.js +12 -13
  298. package/dist/plugins/uploads.svelte.d.ts +5 -2
  299. package/dist/plugins/uploads.svelte.js +25 -15
  300. package/dist/plugins.d.ts +26 -0
  301. package/dist/plugins.js +0 -24
  302. package/dist/selection/replaceSelection.js +2 -2
  303. package/dist/selection/selection.svelte.d.ts +4 -10
  304. package/dist/selection/selection.svelte.js +7 -11
  305. package/dist/session/bindings.js +1 -1
  306. package/dist/session/commands.d.ts +7 -11
  307. package/dist/session/commands.js +13 -19
  308. package/dist/session/inputRules.js +1 -1
  309. package/dist/session/navigation.js +1 -1
  310. package/dist/session/suggestions.svelte.d.ts +0 -11
  311. package/dist/session/suggestions.svelte.js +15 -3
  312. package/dist/session/uploads.d.ts +8 -8
  313. package/dist/surface/lines.js +1 -3
  314. package/dist/surface/observer.svelte.d.ts +17 -1
  315. package/dist/surface/observer.svelte.js +74 -19
  316. package/dist/surface/overlay.d.ts +0 -14
  317. package/dist/surface/overlay.js +0 -25
  318. package/dist/surface/projector.svelte.d.ts +15 -3
  319. package/dist/surface/projector.svelte.js +60 -9
  320. package/dist/text/text.svelte.js +3 -13
  321. package/dist/utils/sanitize.d.ts +38 -0
  322. package/dist/utils/sanitize.js +82 -0
  323. package/dist/utils.d.ts +2 -0
  324. package/dist/utils.js +5 -0
  325. package/package.json +19 -2
  326. package/dist/crdt/placement/rank.d.ts +0 -87
  327. package/dist/crdt/placement/rank.js +0 -332
  328. package/dist/crdt/placement/source.d.ts +0 -43
  329. package/dist/crdt/placement/source.js +0 -66
  330. package/dist/crdt/text/delete-index.d.ts +0 -129
  331. package/dist/crdt/text/delete-index.js +0 -365
  332. package/dist/crdt/text/deletes.d.ts +0 -76
  333. package/dist/crdt/text/deletes.js +0 -362
  334. package/dist/crdt/text/index/anchored.d.ts +0 -17
  335. package/dist/crdt/text/index/anchored.js +0 -197
  336. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/max-z-index.js +0 -3
  337. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/supports-popover.js +0 -16
  338. package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/is-axis-allowed.js +0 -3
  339. package/dist/plugins/code/LanguageMenu.svelte +0 -25
  340. package/dist/plugins/code/LanguageMenu.svelte.d.ts +0 -9
  341. package/dist/plugins/equation/EquationEditor.svelte +0 -27
  342. package/dist/plugins/equation/EquationEditor.svelte.d.ts +0 -9
  343. package/dist/plugins/image/ImageToolbarHost.svelte +0 -37
  344. package/dist/plugins/image/ImageToolbarHost.svelte.d.ts +0 -9
  345. package/dist/plugins/richtext/CalloutIconPicker.svelte +0 -26
  346. package/dist/plugins/richtext/CalloutIconPicker.svelte.d.ts +0 -9
@@ -1,6 +1,5 @@
1
1
  import { attach } from '../chrome.js';
2
2
  import { mediaKinds } from '../../crdt/semantics.js';
3
- import { sanitizeLinkHref } from '../richtext/richTextOperations.js';
4
3
  import { escapeHtml } from '../../clipboard/serializeClipboardFragment.js';
5
4
  import { keywordsOf, labelsOf, mediaEnglish } from '../../labels.js';
6
5
  import { MEDIA_ICONS } from './empty.svelte.js';
@@ -56,197 +55,5 @@ export const mediaPlugin = (kind, keywords, own) => (edytor) => {
56
55
  }
57
56
  };
58
57
  };
59
- /**
60
- * A web page's URL a media block may store or render: the link sanitizer's
61
- * reading of it (`sanitizeLinkHref`: ASCII control characters and spaces stripped,
62
- * tab/newline anywhere), then only an absolute `http:`/`https:` URL with a
63
- * host. `null` for anything else: a script or `data:` URL, a `mailto:`, a
64
- * relative path, a bare domain.
65
- */
66
- export const safeWebUrl = (value) => {
67
- const href = sanitizeLinkHref(value);
68
- if (href === null)
69
- return null;
70
- try {
71
- const url = new URL(href);
72
- return (url.protocol === 'http:' || url.protocol === 'https:') && url.host ? href : null;
73
- }
74
- catch {
75
- return null;
76
- }
77
- };
78
- /**
79
- * A media file's source (a video, an audio track, an attachment): a
80
- * {@link safeWebUrl}, or a `blob:` URL an upload answered. Never `data:`:
81
- * an inline file would be stored in the document and sent in every update.
82
- */
83
- export const safeMediaSrc = (value) => {
84
- const blob = typeof value === 'string' ? /^blob:(.*)$/is.exec(value.trim()) : null;
85
- const origin = blob && safeWebUrl(blob[1]);
86
- return origin ? `blob:${origin}` : safeWebUrl(value);
87
- };
88
- /** The frame's `sandbox`: scripts and the provider's own origin, popups that leave it; no top navigation, modals, downloads or forms. */
89
- export const EMBED_SANDBOX = 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-presentation';
90
- /** The frame's permissions (`allow`): what a player needs, nothing that reads the viewer. */
91
- export const EMBED_ALLOW = 'fullscreen; picture-in-picture; encrypted-media; clipboard-write';
92
- const ID = /^[\w-]{1,128}$/;
93
- const HASH = /^[\da-f]{1,32}$/i;
94
- /** `url`'s path segments (empty ones dropped) when its host is one of `hosts`, else none. */
95
- const on = (url, ...hosts) => hosts.includes(url.hostname.toLowerCase()) ? url.pathname.split('/').filter(Boolean) : [];
96
- /** A YouTube start time (`t=42`, `t=42s`, `start=42`) in seconds. */
97
- const youtubeStart = (url) => {
98
- const t = url.searchParams.get('t') ?? url.searchParams.get('start');
99
- return t && /^\d{1,6}s?$/.test(t) ? `?start=${parseInt(t, 10)}` : '';
100
- };
101
- const youtube = {
102
- name: 'YouTube',
103
- embed: (url) => {
104
- const [first, second] = on(url, 'youtu.be', 'youtube.com', 'www.youtube.com', 'm.youtube.com', 'music.youtube.com', 'www.youtube-nocookie.com');
105
- const id = url.hostname.toLowerCase() === 'youtu.be'
106
- ? first
107
- : first === 'watch'
108
- ? url.searchParams.get('v')
109
- : first && ['shorts', 'embed', 'live'].includes(first)
110
- ? second
111
- : undefined;
112
- return id && /^[\w-]{11}$/.test(id)
113
- ? `https://www.youtube-nocookie.com/embed/${id}${youtubeStart(url)}`
114
- : null;
115
- }
116
- };
117
- const vimeo = {
118
- name: 'Vimeo',
119
- embed: (url) => {
120
- const [player, ...video] = on(url, 'player.vimeo.com');
121
- const [id, hash] = player === 'video' ? video : on(url, 'vimeo.com', 'www.vimeo.com');
122
- if (!id || !/^\d{1,12}$/.test(id))
123
- return null;
124
- const h = hash && HASH.test(hash) ? hash : url.searchParams.get('h');
125
- return `https://player.vimeo.com/video/${id}${h && HASH.test(h) ? `?h=${h}` : ''}`;
126
- }
127
- };
128
- const loom = {
129
- name: 'Loom',
130
- embed: (url) => {
131
- const [kind, id] = on(url, 'loom.com', 'www.loom.com');
132
- return (kind === 'share' || kind === 'embed') && id && /^[\da-f]{32}$/i.test(id)
133
- ? `https://www.loom.com/embed/${id}`
134
- : null;
135
- }
136
- };
137
- const figma = {
138
- name: 'Figma',
139
- embed: (url) => {
140
- const [kind, key] = on(url, 'figma.com', 'www.figma.com');
141
- return key &&
142
- ID.test(key) &&
143
- ['file', 'design', 'proto', 'board', 'slides', 'deck'].includes(kind)
144
- ? `https://www.figma.com/embed?embed_host=edytor&url=${encodeURIComponent(url.href)}`
145
- : null;
146
- }
147
- };
148
- const codepen = {
149
- name: 'CodePen',
150
- embed: (url) => {
151
- const [user, kind, id] = on(url, 'codepen.io');
152
- return user && ID.test(user) && (kind === 'pen' || kind === 'embed') && id && ID.test(id)
153
- ? `https://codepen.io/${user}/embed/${id}?default-tab=result`
154
- : null;
155
- },
156
- height: 400
157
- };
158
- const spotify = {
159
- name: 'Spotify',
160
- embed: (url) => {
161
- let parts = on(url, 'open.spotify.com');
162
- if (parts[0] === 'embed' || /^intl-[a-z-]+$/i.test(parts[0] ?? ''))
163
- parts = parts.slice(1);
164
- const [kind, id] = parts;
165
- return ['track', 'album', 'playlist', 'episode', 'show', 'artist'].includes(kind) &&
166
- id &&
167
- /^[A-Za-z0-9]{1,64}$/.test(id)
168
- ? `https://open.spotify.com/embed/${kind}/${id}`
169
- : null;
170
- },
171
- height: 352
172
- };
173
- /**
174
- * The default allowlist: YouTube (through `youtube-nocookie.com`), Vimeo,
175
- * Loom, Figma, CodePen and Spotify. A link no provider plays renders no
176
- * frame. Extend it with `createEmbedPlugin({ providers: [...EMBED_PROVIDERS, mine] })`.
177
- */
178
- export const EMBED_PROVIDERS = Object.freeze([
179
- youtube,
180
- vimeo,
181
- loom,
182
- figma,
183
- codepen,
184
- spotify
185
- ]);
186
- /**
187
- * `url` is on the page's own origin (in a browser): a frame there with
188
- * `allow-scripts` and `allow-same-origin` could remove its own sandbox.
189
- */
190
- const sameOrigin = (url) => {
191
- const origin = globalThis.location?.origin;
192
- return typeof origin === 'string' && url.origin === origin;
193
- };
194
- /**
195
- * The player for `value` (a stored or pasted link): the first provider of
196
- * `providers` that plays it, and its `https:` player URL. `null` when the
197
- * link is not a {@link safeWebUrl}, no provider plays it, or the player URL
198
- * a provider answers is not `https:` or is on the page's own origin. The frame's `src` is always this
199
- * answer, never the stored value.
200
- */
201
- export const embedSourceOf = (value, providers = EMBED_PROVIDERS) => {
202
- const href = safeWebUrl(value);
203
- if (!href)
204
- return null;
205
- const url = new URL(href);
206
- for (const provider of providers) {
207
- let src;
208
- try {
209
- src = provider.embed(new URL(url.href));
210
- }
211
- catch {
212
- continue;
213
- }
214
- if (src === null || src === undefined)
215
- continue;
216
- try {
217
- const player = new URL(src);
218
- if (player.protocol === 'https:' && safeWebUrl(src) === src && !sameOrigin(player))
219
- return { src, provider };
220
- }
221
- catch {
222
- // An unparsable player URL is refused like any other non-https one.
223
- }
224
- return null;
225
- }
226
- return null;
227
- };
228
- /** A file's display name from its URL's last path segment, decoded. */
229
- export const fileNameOf = (src) => {
230
- try {
231
- const last = new URL(src).pathname.split('/').filter(Boolean).at(-1);
232
- return last ? decodeURIComponent(last) : src;
233
- }
234
- catch {
235
- return src;
236
- }
237
- };
238
- /**
239
- * The element a media kind's HTML import reads: `element` itself when it
240
- * is a `tag` (not inside a `figure`, which claims it), or a `figure`'s own
241
- * `tag` child.
242
- */
243
- export const claimed = (element, tag) => {
244
- if (element.localName === 'figure')
245
- return [...element.children].find((child) => child.localName === tag);
246
- return element.localName === tag && element.parentElement?.localName !== 'figure'
247
- ? element
248
- : undefined;
249
- };
250
- /** An imported `video`'s or `audio`'s source: its `src`, else its first `source`'s. */
251
- export const mediaSourceOf = (element) => safeMediaSrc(element?.getAttribute('src') ?? element?.querySelector('source[src]')?.getAttribute('src'));
58
+ export * from './sources.js';
252
59
  export { escapeHtml };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The media kinds' pure source rules: which URL a media block may store or
3
+ * render, the embed providers and their players, a file's name, the element
4
+ * an import reads. No DOM state, no Svelte: the export entry reads them too.
5
+ */
6
+ import { safeMediaSrc, safeWebUrl } from '../../utils/sanitize.js';
7
+ export { safeMediaSrc, safeWebUrl };
8
+ /** One allowlisted embed provider: which links it plays, and its player. */
9
+ export type EmbedProvider = {
10
+ /** The provider's name: the frame's `title`. */
11
+ name: string;
12
+ /**
13
+ * The player's URL for a link of this provider, else `null`. It must be
14
+ * `https:` on another origin than the page's: any other answer is
15
+ * refused (the frame has `allow-scripts` and `allow-same-origin`, so a
16
+ * player on the page's origin, or on one that can script it, could lift
17
+ * its own sandbox). Match the host exactly (never a
18
+ * suffix or a substring) and check every id you copy into the player URL.
19
+ */
20
+ embed: (url: URL) => string | null;
21
+ /** The frame's CSS `aspect-ratio` (default `16 / 9`); ignored with `height`. */
22
+ aspectRatio?: string;
23
+ /** A fixed frame height in pixels (a music player). */
24
+ height?: number;
25
+ };
26
+ /** The frame's `sandbox`: scripts and the provider's own origin, popups that leave it; no top navigation, modals, downloads or forms. */
27
+ export declare const EMBED_SANDBOX = "allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-presentation";
28
+ /** The frame's permissions (`allow`): what a player needs, nothing that reads the viewer. */
29
+ export declare const EMBED_ALLOW = "fullscreen; picture-in-picture; encrypted-media; clipboard-write";
30
+ /**
31
+ * The default allowlist: YouTube (through `youtube-nocookie.com`), Vimeo,
32
+ * Loom, Figma, CodePen and Spotify. A link no provider plays renders no
33
+ * frame. Extend it with `createEmbedPlugin({ providers: [...EMBED_PROVIDERS, mine] })`.
34
+ */
35
+ export declare const EMBED_PROVIDERS: readonly EmbedProvider[];
36
+ /**
37
+ * The player for `value` (a stored or pasted link): the first provider of
38
+ * `providers` that plays it, and its `https:` player URL. `null` when the
39
+ * link is not a {@link safeWebUrl}, no provider plays it, or the player URL
40
+ * a provider answers is not `https:` or is on the page's own origin. The frame's `src` is always this
41
+ * answer, never the stored value.
42
+ */
43
+ export declare const embedSourceOf: (value: unknown, providers?: readonly EmbedProvider[]) => {
44
+ src: string;
45
+ provider: EmbedProvider;
46
+ } | null;
47
+ /** A file's display name from its URL's last path segment, decoded. */
48
+ export declare const fileNameOf: (src: string) => string;
49
+ /** A file block's name: its stored `name`, else its source's last segment (`''` without one). */
50
+ export declare const fileNameFor: (data: {
51
+ name?: unknown;
52
+ } | undefined, src: string | null) => string;
53
+ /**
54
+ * The element a media kind's HTML import reads: `element` itself when it
55
+ * is a `tag` (not inside a `figure`, which claims it), or a `figure`'s own
56
+ * `tag` child.
57
+ */
58
+ export declare const claimed: (element: HTMLElement, tag: string) => HTMLElement | undefined;
59
+ /** An imported `video`'s or `audio`'s source: its `src`, else its first `source`'s. */
60
+ export declare const mediaSourceOf: (element: HTMLElement | undefined) => string | null;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * The media kinds' pure source rules: which URL a media block may store or
3
+ * render, the embed providers and their players, a file's name, the element
4
+ * an import reads. No DOM state, no Svelte: the export entry reads them too.
5
+ */
6
+ import { safeMediaSrc, safeWebUrl } from '../../utils/sanitize.js';
7
+ export { safeMediaSrc, safeWebUrl };
8
+ /** The frame's `sandbox`: scripts and the provider's own origin, popups that leave it; no top navigation, modals, downloads or forms. */
9
+ export const EMBED_SANDBOX = 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-presentation';
10
+ /** The frame's permissions (`allow`): what a player needs, nothing that reads the viewer. */
11
+ export const EMBED_ALLOW = 'fullscreen; picture-in-picture; encrypted-media; clipboard-write';
12
+ const ID = /^[\w-]{1,128}$/;
13
+ const HASH = /^[\da-f]{1,32}$/i;
14
+ /** `url`'s path segments (empty ones dropped) when its host is exactly one `hosts` matches, else none. */
15
+ const on = (url, hosts) => hosts.test(url.hostname) ? url.pathname.split('/').filter(Boolean) : [];
16
+ const youtube = {
17
+ name: 'YouTube',
18
+ embed: (url) => {
19
+ const [first = '', second] = on(url, /^((www\.|m\.|music\.)?youtube\.com|youtu\.be|www\.youtube-nocookie\.com)$/);
20
+ const id = url.hostname === 'youtu.be'
21
+ ? first
22
+ : first === 'watch'
23
+ ? url.searchParams.get('v')
24
+ : /^(shorts|embed|live)$/.test(first) && second;
25
+ // A start time (`t=42`, `t=42s`, `start=42`) in seconds.
26
+ const t = url.searchParams.get('t') ?? url.searchParams.get('start');
27
+ return id && /^[\w-]{11}$/.test(id)
28
+ ? `https://www.youtube-nocookie.com/embed/${id}${t && /^\d{1,6}s?$/.test(t) ? `?start=${parseInt(t, 10)}` : ''}`
29
+ : null;
30
+ }
31
+ };
32
+ const vimeo = {
33
+ name: 'Vimeo',
34
+ embed: (url) => {
35
+ const [player, ...video] = on(url, /^player\.vimeo\.com$/);
36
+ const [id, hash] = player === 'video' ? video : on(url, /^(www\.)?vimeo\.com$/);
37
+ const h = hash && HASH.test(hash) ? hash : url.searchParams.get('h');
38
+ return id && /^\d{1,12}$/.test(id)
39
+ ? `https://player.vimeo.com/video/${id}${h && HASH.test(h) ? `?h=${h}` : ''}`
40
+ : null;
41
+ }
42
+ };
43
+ const loom = {
44
+ name: 'Loom',
45
+ embed: (url) => {
46
+ const [kind = '', id = ''] = on(url, /^(www\.)?loom\.com$/);
47
+ return /^(share|embed)$/.test(kind) && /^[\da-f]{32}$/i.test(id)
48
+ ? `https://www.loom.com/embed/${id}`
49
+ : null;
50
+ }
51
+ };
52
+ const figma = {
53
+ name: 'Figma',
54
+ embed: (url) => {
55
+ const [kind = '', key = ''] = on(url, /^(www\.)?figma\.com$/);
56
+ return ID.test(key) && /^(file|design|proto|board|slides|deck)$/.test(kind)
57
+ ? `https://www.figma.com/embed?embed_host=edytor&url=${encodeURIComponent(url.href)}`
58
+ : null;
59
+ }
60
+ };
61
+ const codepen = {
62
+ name: 'CodePen',
63
+ embed: (url) => {
64
+ const [user = '', kind = '', id = ''] = on(url, /^codepen\.io$/);
65
+ return ID.test(user) && /^(pen|embed)$/.test(kind) && ID.test(id)
66
+ ? `https://codepen.io/${user}/embed/${id}?default-tab=result`
67
+ : null;
68
+ },
69
+ height: 400
70
+ };
71
+ const spotify = {
72
+ name: 'Spotify',
73
+ embed: (url) => {
74
+ let parts = on(url, /^open\.spotify\.com$/);
75
+ if (/^(embed|intl-[a-z-]+)$/i.test(parts[0] ?? ''))
76
+ parts = parts.slice(1);
77
+ const [kind = '', id = ''] = parts;
78
+ return /^(track|album|playlist|episode|show|artist)$/.test(kind) &&
79
+ /^[A-Za-z0-9]{1,64}$/.test(id)
80
+ ? `https://open.spotify.com/embed/${kind}/${id}`
81
+ : null;
82
+ },
83
+ height: 352
84
+ };
85
+ /**
86
+ * The default allowlist: YouTube (through `youtube-nocookie.com`), Vimeo,
87
+ * Loom, Figma, CodePen and Spotify. A link no provider plays renders no
88
+ * frame. Extend it with `createEmbedPlugin({ providers: [...EMBED_PROVIDERS, mine] })`.
89
+ */
90
+ export const EMBED_PROVIDERS = Object.freeze([
91
+ youtube,
92
+ vimeo,
93
+ loom,
94
+ figma,
95
+ codepen,
96
+ spotify
97
+ ]);
98
+ /**
99
+ * `url` is on the page's own origin (in a browser): a frame there with
100
+ * `allow-scripts` and `allow-same-origin` could remove its own sandbox.
101
+ */
102
+ const sameOrigin = (url) => {
103
+ const origin = globalThis.location?.origin;
104
+ return typeof origin === 'string' && url.origin === origin;
105
+ };
106
+ /**
107
+ * The player for `value` (a stored or pasted link): the first provider of
108
+ * `providers` that plays it, and its `https:` player URL. `null` when the
109
+ * link is not a {@link safeWebUrl}, no provider plays it, or the player URL
110
+ * a provider answers is not `https:` or is on the page's own origin. The frame's `src` is always this
111
+ * answer, never the stored value.
112
+ */
113
+ export const embedSourceOf = (value, providers = EMBED_PROVIDERS) => {
114
+ const href = safeWebUrl(value);
115
+ if (!href)
116
+ return null;
117
+ const url = new URL(href);
118
+ for (const provider of providers) {
119
+ let src;
120
+ try {
121
+ src = provider.embed(new URL(url.href));
122
+ }
123
+ catch {
124
+ continue;
125
+ }
126
+ if (src === null || src === undefined)
127
+ continue;
128
+ try {
129
+ const player = new URL(src);
130
+ if (player.protocol === 'https:' && safeWebUrl(src) === src && !sameOrigin(player))
131
+ return { src, provider };
132
+ }
133
+ catch {
134
+ // An unparsable player URL is refused like any other non-https one.
135
+ }
136
+ return null;
137
+ }
138
+ return null;
139
+ };
140
+ /** A file's display name from its URL's last path segment, decoded. */
141
+ export const fileNameOf = (src) => {
142
+ try {
143
+ const last = new URL(src).pathname.split('/').filter(Boolean).at(-1);
144
+ return last ? decodeURIComponent(last) : src;
145
+ }
146
+ catch {
147
+ return src;
148
+ }
149
+ };
150
+ /** A file block's name: its stored `name`, else its source's last segment (`''` without one). */
151
+ export const fileNameFor = (data, src) => String(data?.name || (src && fileNameOf(src)) || '');
152
+ /**
153
+ * The element a media kind's HTML import reads: `element` itself when it
154
+ * is a `tag` (not inside a `figure`, which claims it), or a `figure`'s own
155
+ * `tag` child.
156
+ */
157
+ export const claimed = (element, tag) => {
158
+ if (element.localName === 'figure')
159
+ return [...element.children].find((child) => child.localName === tag);
160
+ return element.localName === tag && element.parentElement?.localName !== 'figure'
161
+ ? element
162
+ : undefined;
163
+ };
164
+ /** An imported `video`'s or `audio`'s source: its `src`, else its first `source`'s. */
165
+ export const mediaSourceOf = (element) => safeMediaSrc(element?.getAttribute('src') ?? element?.querySelector('source[src]')?.getAttribute('src'));
@@ -43,10 +43,11 @@ export declare class UrlPasteController extends ChromeList {
43
43
  } | null;
44
44
  constructor(edytor: Edytor);
45
45
  protected get count(): number;
46
- get readonly(): boolean;
47
46
  close: () => void;
48
47
  /** Pick a row: keep the link, or turn the line into the offer's kind. */
49
48
  pick: (option?: UrlPasteOption | undefined) => void;
49
+ /** Where the menu stands (`ChromeAnchor`): the pasted line, which your `menu` places itself under. */
50
+ readonly anchor: import("../chrome.js").ChromeAnchor;
50
51
  }
51
52
  /**
52
53
  * Register `offer` on `edytor`'s URL paste menu. The first plugin to offer
@@ -1,9 +1,7 @@
1
- import { placeNear } from '../../surface/overlay.js';
2
- import { onPress } from '../../events/onFocus.js';
3
1
  import { convertToKind, holdsNothing } from '../../kinds.js';
4
2
  import { pastedLink } from '../richtext/richTextOperations.js';
5
3
  import { safeWebUrl } from './media.js';
6
- import { mountChrome } from '../chrome.js';
4
+ import { mountChrome, onPressOutside, virtualAnchor } from '../chrome.js';
7
5
  import { ChromeList, inPage, listHotkeys } from '../list.svelte.js';
8
6
  /**
9
7
  * Pasting a bare URL on an empty line (Notion): the URL lands as a link at
@@ -27,9 +25,6 @@ export class UrlPasteController extends ChromeList {
27
25
  get count() {
28
26
  return this.open?.options.length ?? 0;
29
27
  }
30
- get readonly() {
31
- return this.edytor.readonly;
32
- }
33
28
  /** A custom menu (a media plugin's `menu`): the first one a plugin making an offer passed. */
34
29
  #menu;
35
30
  /** Take `menu` as the view's menu, unless a plugin listed before passed one. @internal */
@@ -70,7 +65,7 @@ export class UrlPasteController extends ChromeList {
70
65
  : {};
71
66
  edytor.dispatcher.run('insertFromPaste', () => {
72
67
  edytor.insertText(block.id, text.segStart, url, marks);
73
- edytor.dispatcher.caret(edytor.idToBlock.get(block.id)?.firstText, url.length);
68
+ edytor.dispatcher.caretIn(edytor.idToBlock.get(block.id)?.firstText, url.length);
74
69
  });
75
70
  if (edytor.dispatcher.last?.status !== 'applied')
76
71
  return;
@@ -122,12 +117,7 @@ export class UrlPasteController extends ChromeList {
122
117
  this.close();
123
118
  },
124
119
  onEdytorAttached: ({ node }) => {
125
- const outside = (event) => {
126
- const target = event.target;
127
- if (!target?.closest?.('[data-edytor-url-paste-host]'))
128
- this.close();
129
- };
130
- const offPress = onPress(this.edytor, node.ownerDocument, outside, true);
120
+ const offPress = onPressOutside(this.edytor, node.ownerDocument, '[data-edytor-url-paste-host]', this.close);
131
121
  const unmount = mountChrome(this.edytor, this.#menu, this, () => this.open, { name: 'edytor-url-paste-host', zIndex: 50, measure: this.measure }, this.close);
132
122
  return () => {
133
123
  offPress();
@@ -136,16 +126,17 @@ export class UrlPasteController extends ChromeList {
136
126
  };
137
127
  }
138
128
  });
139
- /** Under the pasted line, kept in the viewport; a gone line closes the menu. @internal */
140
- measure = (host) => {
129
+ /** A gone line closes the menu (measured in the overlay's frame). @internal */
130
+ measure = () => {
141
131
  const { open, edytor } = this;
142
- if (!open)
143
- return;
144
- const block = edytor.idToBlock.get(open.block);
145
- if (!block?.isInTree)
132
+ if (open && !edytor.idToBlock.get(open.block)?.isInTree)
146
133
  return () => this.close();
147
- const rect = (block.firstText?.node ?? block.node)?.getBoundingClientRect();
148
- return rect && placeNear(host, rect, [220, 120], { gap: 4 });
134
+ };
135
+ /** Where the menu stands (`ChromeAnchor`): the pasted line, which your `menu` places itself under. */
136
+ anchor = virtualAnchor(() => this.#line()?.getBoundingClientRect(), () => this.#line());
137
+ #line = () => {
138
+ const block = this.open && this.edytor.idToBlock.get(this.open.block);
139
+ return block ? (block.firstText?.node ?? block.node) : undefined;
149
140
  };
150
141
  }
151
142
  const controllers = new WeakMap();
@@ -1,6 +1,7 @@
1
1
  <svelte:options runes />
2
2
 
3
3
  <script module lang="ts">
4
+ import { mentionForms } from '../../export/forms.js';
4
5
  import './mention.css';
5
6
  import type { Snippet } from 'svelte';
6
7
  import type {
@@ -11,7 +12,7 @@
11
12
  TriggerContext
12
13
  } from '../../plugins.js';
13
14
  import type { TriggerMenuController } from '../triggers/TriggerController.svelte.js';
14
- import { withRulesAndTriggers } from '../triggers/triggers.js';
15
+ import { placeAtom, withRulesAndTriggers } from '../triggers/triggers.js';
15
16
 
16
17
  /** A person the mention menu offers: what your app's directory answers. */
17
18
  export type MentionItem = {
@@ -60,12 +61,6 @@
60
61
  (atom.handle?.edytor.inlineBlocks.get(atom.type) as Partial<MentionKind> | undefined)?.char ??
61
62
  '@';
62
63
 
63
- const escape = (value: string) =>
64
- value.replace(
65
- /[&<>"]/g,
66
- (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[c]!
67
- );
68
-
69
64
  /**
70
65
  * People mentions, as in Notion: `@` opens a menu of the people your app's
71
66
  * `items(query)` answers; picking one replaces `@query` with a `mention`
@@ -75,30 +70,10 @@
75
70
  export const createMentionPlugin = (options: MentionPluginOptions): Plugin => {
76
71
  const char = options.char ?? '@';
77
72
  const kind = options.kind ?? 'mention';
78
- const labelOf = (data: unknown) => {
79
- const label = (data as Partial<MentionData> | undefined)?.label;
80
- return typeof label === 'string' ? label : '';
81
- };
82
73
  const atom: MentionKind = {
83
74
  snippet: mention,
84
75
  char,
85
- plain: (data) => char + labelOf(data),
86
- html: (data) => {
87
- const id = (data as Partial<MentionData> | undefined)?.id;
88
- return (
89
- `<span data-edytor-mention="${escape(kind)}"` +
90
- (typeof id === 'string' ? ` data-mention-id="${escape(id)}"` : '') +
91
- `>${escape(char + labelOf(data))}</span>`
92
- );
93
- },
94
- parse: (element) => {
95
- // A bare `data-edytor-mention` (an older export) is a `mention`.
96
- const own = element.dataset.edytorMention;
97
- if (own === undefined || (own || 'mention') !== kind) return undefined;
98
- const text = element.textContent ?? '';
99
- const label = text.startsWith(char) ? text.slice(char.length) : text;
100
- return { id: element.dataset.mentionId ?? '', label };
101
- }
76
+ ...mentionForms(kind, char)
102
77
  };
103
78
  return (edytor) =>
104
79
  withRulesAndTriggers(
@@ -113,13 +88,11 @@
113
88
  label: (item: MentionItem) => item.label,
114
89
  key: (item: MentionItem) => item.id,
115
90
  menu: options.menu,
116
- onPick: (item: MentionItem, { edytor, block, from, caret }) => {
117
- const data: MentionData = { id: item.id, label: item.label };
118
- const written =
119
- edytor.insertInline(block.id, from, { type: kind, data }).status === 'applied';
120
- if (written) caret(from + 1);
121
- return written;
122
- }
91
+ onPick: (item: MentionItem, ctx) =>
92
+ placeAtom(ctx, {
93
+ type: kind,
94
+ data: { id: item.id, label: item.label } satisfies MentionData
95
+ })
123
96
  }
124
97
  ]
125
98
  }
@@ -1,4 +1,5 @@
1
1
  <script module lang="ts">
2
+ import { pageForms } from '../../export/forms.js';
2
3
  import type { Plugin, BlockSnippetPayload } from '../../plugins.js';
3
4
  import { pageKinds } from '../../crdt/semantics.js';
4
5
  import { convertToKind, type KindRow } from '../../kinds.js';
@@ -6,7 +7,6 @@
6
7
  import { getSelectedBlocksInDocumentOrder } from '../../selection/replaceSelection.js';
7
8
  import PageLink from './PageLink.svelte';
8
9
  import {
9
- pageHtml,
10
10
  pageIdOf,
11
11
  pageTitleOf,
12
12
  pageOptions as optionsOf,
@@ -63,15 +63,8 @@
63
63
  ...pageKinds.page,
64
64
  snippet: page,
65
65
  empty: { content: [], children: [] },
66
- html: (block) => pageHtml(block.data, own, labels.untitled),
67
- plain: (block) => pageTitleOf(block.data?.title) ?? labels.untitled,
68
66
  // Its own export: a `p[data-edytor-page]` naming the page.
69
- parse: (el) => {
70
- const pageId = pageIdOf(el.getAttribute('data-edytor-page'));
71
- if (el.localName !== 'p' || !pageId) return;
72
- const title = pageTitleOf(el.textContent);
73
- return { pageId, ...(title && { title }) };
74
- }
67
+ ...pageForms(own, labels.untitled).page
75
68
  }
76
69
  },
77
70
  commands: create
@@ -1,4 +1,4 @@
1
- import { sanitizeLinkHref } from '../richtext/richTextOperations.js';
1
+ import { sanitizeLinkHref } from '../../utils/sanitize.js';
2
2
  import { escapeHtml } from '../../clipboard/serializeClipboardFragment.js';
3
3
  /** Each view's page options (the first page plugin listed sets them). */
4
4
  export const pageOptions = new WeakMap();