@dxos/react-ui-editor 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8

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 (416) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/index.mjs +1416 -7561
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/translations.mjs +39 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/lib/node-esm/index.mjs +1416 -7560
  9. package/dist/lib/node-esm/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/meta.json +1 -1
  11. package/dist/lib/node-esm/translations.mjs +41 -0
  12. package/dist/lib/node-esm/translations.mjs.map +7 -0
  13. package/dist/types/src/components/Editor/Editor.d.ts +54 -15
  14. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  15. package/dist/types/src/components/Editor/Editor.stories.d.ts +23 -0
  16. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -0
  17. package/dist/types/src/components/Editor/EditorView.d.ts +31 -0
  18. package/dist/types/src/components/Editor/EditorView.d.ts.map +1 -0
  19. package/dist/types/src/components/Editor/controller.d.ts +10 -0
  20. package/dist/types/src/components/Editor/controller.d.ts.map +1 -0
  21. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +34 -0
  22. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -0
  23. package/dist/types/src/components/EditorMenuProvider/index.d.ts +6 -0
  24. package/dist/types/src/components/EditorMenuProvider/index.d.ts.map +1 -0
  25. package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts +4 -0
  26. package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -0
  27. package/dist/types/src/components/EditorMenuProvider/menu.d.ts +28 -0
  28. package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -0
  29. package/dist/types/src/components/EditorMenuProvider/popover.d.ts +53 -0
  30. package/dist/types/src/components/EditorMenuProvider/popover.d.ts.map +1 -0
  31. package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts +34 -0
  32. package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -0
  33. package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts +16 -0
  34. package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -0
  35. package/dist/types/src/components/EditorPreviewProvider/index.d.ts +2 -0
  36. package/dist/types/src/components/EditorPreviewProvider/index.d.ts.map +1 -0
  37. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +28 -2
  38. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  39. package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -17
  40. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  41. package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -17
  42. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  43. package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -17
  44. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  45. package/dist/types/src/components/EditorToolbar/image.d.ts +3 -15
  46. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  47. package/dist/types/src/components/EditorToolbar/index.d.ts +1 -1
  48. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
  49. package/dist/types/src/components/EditorToolbar/lists.d.ts +4 -17
  50. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  51. package/dist/types/src/components/EditorToolbar/search.d.ts +3 -15
  52. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  53. package/dist/types/src/components/EditorToolbar/types.d.ts +6 -0
  54. package/dist/types/src/components/EditorToolbar/types.d.ts.map +1 -0
  55. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +5 -18
  56. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  57. package/dist/types/src/components/index.d.ts +2 -2
  58. package/dist/types/src/components/index.d.ts.map +1 -1
  59. package/dist/types/src/extensions/Assistant.stories.d.ts +10 -0
  60. package/dist/types/src/extensions/Assistant.stories.d.ts.map +1 -0
  61. package/dist/types/src/extensions/assistant-extension.d.ts +24 -0
  62. package/dist/types/src/extensions/assistant-extension.d.ts.map +1 -0
  63. package/dist/types/src/extensions/index.d.ts +1 -22
  64. package/dist/types/src/extensions/index.d.ts.map +1 -1
  65. package/dist/types/src/hooks/index.d.ts +1 -0
  66. package/dist/types/src/hooks/index.d.ts.map +1 -1
  67. package/dist/types/src/hooks/useBasicMarkdownExtensions.d.ts +25 -0
  68. package/dist/types/src/hooks/useBasicMarkdownExtensions.d.ts.map +1 -0
  69. package/dist/types/src/hooks/useTextEditor.d.ts +6 -10
  70. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  71. package/dist/types/src/index.d.ts +0 -9
  72. package/dist/types/src/index.d.ts.map +1 -1
  73. package/dist/types/src/stories/Automerge.stories.d.ts +44 -0
  74. package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -0
  75. package/dist/types/src/stories/Comments.stories.d.ts +22 -10
  76. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  77. package/dist/types/src/stories/EditorToolbar.stories.d.ts +42 -4
  78. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  79. package/dist/types/src/stories/Experimental.stories.d.ts +23 -13
  80. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  81. package/dist/types/src/stories/Markdown.stories.d.ts +33 -43
  82. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  83. package/dist/types/src/stories/Outliner.stories.d.ts +16 -22
  84. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  85. package/dist/types/src/stories/Popover.stories.d.ts +20 -0
  86. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
  87. package/dist/types/src/stories/Preview.stories.d.ts +23 -7
  88. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  89. package/dist/types/src/stories/Tags.stories.d.ts +16 -0
  90. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -0
  91. package/dist/types/src/stories/TextEditor.stories.d.ts +38 -52
  92. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  93. package/dist/types/src/stories/Theme.stories.d.ts +8 -0
  94. package/dist/types/src/stories/Theme.stories.d.ts.map +1 -0
  95. package/dist/types/src/stories/components/EditorStory.d.ts +11 -23
  96. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  97. package/dist/types/src/stories/components/util.d.ts +4 -3
  98. package/dist/types/src/stories/components/util.d.ts.map +1 -1
  99. package/dist/types/src/translations.d.ts +26 -26
  100. package/dist/types/src/translations.d.ts.map +1 -1
  101. package/dist/types/src/util/index.d.ts +0 -4
  102. package/dist/types/src/util/index.d.ts.map +1 -1
  103. package/dist/types/src/util/react.d.ts +7 -6
  104. package/dist/types/src/util/react.d.ts.map +1 -1
  105. package/dist/types/tsconfig.tsbuildinfo +1 -1
  106. package/package.json +101 -92
  107. package/src/components/Editor/Editor.stories.tsx +89 -0
  108. package/src/components/Editor/Editor.tsx +172 -24
  109. package/src/components/Editor/EditorView.tsx +99 -0
  110. package/src/components/Editor/controller.ts +59 -0
  111. package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +234 -0
  112. package/src/components/EditorMenuProvider/index.ts +10 -0
  113. package/src/components/EditorMenuProvider/menu-presets.ts +125 -0
  114. package/src/components/EditorMenuProvider/menu.ts +70 -0
  115. package/src/components/EditorMenuProvider/popover.ts +320 -0
  116. package/src/components/EditorMenuProvider/useEditorMenu.ts +189 -0
  117. package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +79 -0
  118. package/src/components/EditorPreviewProvider/index.ts +5 -0
  119. package/src/components/EditorToolbar/EditorToolbar.tsx +92 -103
  120. package/src/components/EditorToolbar/blocks.ts +52 -48
  121. package/src/components/EditorToolbar/formatting.ts +41 -46
  122. package/src/components/EditorToolbar/headings.ts +47 -46
  123. package/src/components/EditorToolbar/image.ts +16 -10
  124. package/src/components/EditorToolbar/index.ts +2 -7
  125. package/src/components/EditorToolbar/lists.ts +39 -41
  126. package/src/components/EditorToolbar/search.ts +16 -10
  127. package/src/components/EditorToolbar/types.ts +8 -0
  128. package/src/components/EditorToolbar/view-mode.ts +40 -41
  129. package/src/components/index.ts +3 -2
  130. package/src/extensions/Assistant.stories.tsx +112 -0
  131. package/src/extensions/assistant-extension.tsx +223 -0
  132. package/src/extensions/index.ts +2 -23
  133. package/src/hooks/index.ts +1 -0
  134. package/src/hooks/useBasicMarkdownExtensions.ts +55 -0
  135. package/src/hooks/useTextEditor.ts +39 -45
  136. package/src/index.ts +0 -13
  137. package/src/stories/Automerge.stories.tsx +177 -0
  138. package/src/stories/Comments.stories.tsx +59 -52
  139. package/src/stories/EditorToolbar.stories.tsx +49 -61
  140. package/src/stories/Experimental.stories.tsx +24 -23
  141. package/src/stories/Markdown.stories.tsx +37 -34
  142. package/src/stories/Outliner.stories.tsx +56 -46
  143. package/src/stories/Popover.stories.tsx +158 -0
  144. package/src/stories/Preview.stories.tsx +112 -92
  145. package/src/stories/Tags.stories.tsx +104 -0
  146. package/src/stories/TextEditor.stories.tsx +40 -66
  147. package/src/stories/Theme.stories.tsx +61 -0
  148. package/src/stories/components/EditorStory.tsx +48 -33
  149. package/src/stories/components/util.tsx +90 -59
  150. package/src/translations.ts +30 -25
  151. package/src/util/index.ts +1 -5
  152. package/src/util/react.tsx +9 -14
  153. package/dist/lib/browser/chunk-22UMM3QJ.mjs +0 -22
  154. package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +0 -7
  155. package/dist/lib/browser/testing/index.mjs +0 -6
  156. package/dist/lib/browser/testing/index.mjs.map +0 -7
  157. package/dist/lib/browser/types/index.mjs +0 -13
  158. package/dist/lib/browser/types/index.mjs.map +0 -7
  159. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs +0 -24
  160. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +0 -7
  161. package/dist/lib/node-esm/testing/index.mjs +0 -8
  162. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  163. package/dist/lib/node-esm/types/index.mjs +0 -14
  164. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  165. package/dist/types/src/components/EditorToolbar/util.d.ts +0 -51
  166. package/dist/types/src/components/EditorToolbar/util.d.ts.map +0 -1
  167. package/dist/types/src/components/Popover/CommandMenu.d.ts +0 -34
  168. package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
  169. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -21
  170. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
  171. package/dist/types/src/components/Popover/RefPopover.d.ts +0 -34
  172. package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
  173. package/dist/types/src/components/Popover/index.d.ts +0 -4
  174. package/dist/types/src/components/Popover/index.d.ts.map +0 -1
  175. package/dist/types/src/defaults.d.ts +0 -14
  176. package/dist/types/src/defaults.d.ts.map +0 -1
  177. package/dist/types/src/extensions/annotations.d.ts +0 -9
  178. package/dist/types/src/extensions/annotations.d.ts.map +0 -1
  179. package/dist/types/src/extensions/autocomplete.d.ts +0 -13
  180. package/dist/types/src/extensions/autocomplete.d.ts.map +0 -1
  181. package/dist/types/src/extensions/automerge/automerge.d.ts +0 -4
  182. package/dist/types/src/extensions/automerge/automerge.d.ts.map +0 -1
  183. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +0 -56
  184. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +0 -1
  185. package/dist/types/src/extensions/automerge/automerge.test.d.ts +0 -2
  186. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +0 -1
  187. package/dist/types/src/extensions/automerge/cursor.d.ts +0 -4
  188. package/dist/types/src/extensions/automerge/cursor.d.ts.map +0 -1
  189. package/dist/types/src/extensions/automerge/defs.d.ts +0 -17
  190. package/dist/types/src/extensions/automerge/defs.d.ts.map +0 -1
  191. package/dist/types/src/extensions/automerge/index.d.ts +0 -2
  192. package/dist/types/src/extensions/automerge/index.d.ts.map +0 -1
  193. package/dist/types/src/extensions/automerge/sync.d.ts +0 -17
  194. package/dist/types/src/extensions/automerge/sync.d.ts.map +0 -1
  195. package/dist/types/src/extensions/automerge/update-automerge.d.ts +0 -6
  196. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +0 -1
  197. package/dist/types/src/extensions/automerge/update-codemirror.d.ts +0 -5
  198. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +0 -1
  199. package/dist/types/src/extensions/awareness/awareness-provider.d.ts +0 -31
  200. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
  201. package/dist/types/src/extensions/awareness/awareness.d.ts +0 -46
  202. package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
  203. package/dist/types/src/extensions/awareness/index.d.ts +0 -3
  204. package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
  205. package/dist/types/src/extensions/blast.d.ts +0 -25
  206. package/dist/types/src/extensions/blast.d.ts.map +0 -1
  207. package/dist/types/src/extensions/command/action.d.ts +0 -17
  208. package/dist/types/src/extensions/command/action.d.ts.map +0 -1
  209. package/dist/types/src/extensions/command/command-menu.d.ts +0 -20
  210. package/dist/types/src/extensions/command/command-menu.d.ts.map +0 -1
  211. package/dist/types/src/extensions/command/command.d.ts +0 -6
  212. package/dist/types/src/extensions/command/command.d.ts.map +0 -1
  213. package/dist/types/src/extensions/command/floating-menu.d.ts +0 -7
  214. package/dist/types/src/extensions/command/floating-menu.d.ts.map +0 -1
  215. package/dist/types/src/extensions/command/hint.d.ts +0 -24
  216. package/dist/types/src/extensions/command/hint.d.ts.map +0 -1
  217. package/dist/types/src/extensions/command/index.d.ts +0 -7
  218. package/dist/types/src/extensions/command/index.d.ts.map +0 -1
  219. package/dist/types/src/extensions/command/placeholder.d.ts +0 -10
  220. package/dist/types/src/extensions/command/placeholder.d.ts.map +0 -1
  221. package/dist/types/src/extensions/command/state.d.ts +0 -16
  222. package/dist/types/src/extensions/command/state.d.ts.map +0 -1
  223. package/dist/types/src/extensions/command/typeahead.d.ts +0 -22
  224. package/dist/types/src/extensions/command/typeahead.d.ts.map +0 -1
  225. package/dist/types/src/extensions/command/useCommandMenu.d.ts +0 -26
  226. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +0 -1
  227. package/dist/types/src/extensions/comments.d.ts +0 -95
  228. package/dist/types/src/extensions/comments.d.ts.map +0 -1
  229. package/dist/types/src/extensions/debug.d.ts +0 -3
  230. package/dist/types/src/extensions/debug.d.ts.map +0 -1
  231. package/dist/types/src/extensions/dnd.d.ts +0 -9
  232. package/dist/types/src/extensions/dnd.d.ts.map +0 -1
  233. package/dist/types/src/extensions/factories.d.ts +0 -83
  234. package/dist/types/src/extensions/factories.d.ts.map +0 -1
  235. package/dist/types/src/extensions/focus.d.ts +0 -7
  236. package/dist/types/src/extensions/focus.d.ts.map +0 -1
  237. package/dist/types/src/extensions/folding.d.ts +0 -7
  238. package/dist/types/src/extensions/folding.d.ts.map +0 -1
  239. package/dist/types/src/extensions/hashtag.d.ts +0 -3
  240. package/dist/types/src/extensions/hashtag.d.ts.map +0 -1
  241. package/dist/types/src/extensions/json.d.ts +0 -7
  242. package/dist/types/src/extensions/json.d.ts.map +0 -1
  243. package/dist/types/src/extensions/listener.d.ts +0 -11
  244. package/dist/types/src/extensions/listener.d.ts.map +0 -1
  245. package/dist/types/src/extensions/markdown/action.d.ts +0 -12
  246. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  247. package/dist/types/src/extensions/markdown/bundle.d.ts +0 -16
  248. package/dist/types/src/extensions/markdown/bundle.d.ts.map +0 -1
  249. package/dist/types/src/extensions/markdown/changes.d.ts +0 -10
  250. package/dist/types/src/extensions/markdown/changes.d.ts.map +0 -1
  251. package/dist/types/src/extensions/markdown/changes.test.d.ts +0 -2
  252. package/dist/types/src/extensions/markdown/changes.test.d.ts.map +0 -1
  253. package/dist/types/src/extensions/markdown/debug.d.ts +0 -11
  254. package/dist/types/src/extensions/markdown/debug.d.ts.map +0 -1
  255. package/dist/types/src/extensions/markdown/decorate.d.ts +0 -17
  256. package/dist/types/src/extensions/markdown/decorate.d.ts.map +0 -1
  257. package/dist/types/src/extensions/markdown/formatting.d.ts +0 -63
  258. package/dist/types/src/extensions/markdown/formatting.d.ts.map +0 -1
  259. package/dist/types/src/extensions/markdown/formatting.test.d.ts +0 -3
  260. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +0 -1
  261. package/dist/types/src/extensions/markdown/highlight.d.ts +0 -37
  262. package/dist/types/src/extensions/markdown/highlight.d.ts.map +0 -1
  263. package/dist/types/src/extensions/markdown/image.d.ts +0 -7
  264. package/dist/types/src/extensions/markdown/image.d.ts.map +0 -1
  265. package/dist/types/src/extensions/markdown/index.d.ts +0 -10
  266. package/dist/types/src/extensions/markdown/index.d.ts.map +0 -1
  267. package/dist/types/src/extensions/markdown/link.d.ts +0 -7
  268. package/dist/types/src/extensions/markdown/link.d.ts.map +0 -1
  269. package/dist/types/src/extensions/markdown/parser.test.d.ts +0 -2
  270. package/dist/types/src/extensions/markdown/parser.test.d.ts.map +0 -1
  271. package/dist/types/src/extensions/markdown/styles.d.ts +0 -4
  272. package/dist/types/src/extensions/markdown/styles.d.ts.map +0 -1
  273. package/dist/types/src/extensions/markdown/table.d.ts +0 -8
  274. package/dist/types/src/extensions/markdown/table.d.ts.map +0 -1
  275. package/dist/types/src/extensions/mention.d.ts +0 -7
  276. package/dist/types/src/extensions/mention.d.ts.map +0 -1
  277. package/dist/types/src/extensions/modes.d.ts +0 -10
  278. package/dist/types/src/extensions/modes.d.ts.map +0 -1
  279. package/dist/types/src/extensions/outliner/commands.d.ts +0 -10
  280. package/dist/types/src/extensions/outliner/commands.d.ts.map +0 -1
  281. package/dist/types/src/extensions/outliner/editor.d.ts +0 -5
  282. package/dist/types/src/extensions/outliner/editor.d.ts.map +0 -1
  283. package/dist/types/src/extensions/outliner/editor.test.d.ts +0 -2
  284. package/dist/types/src/extensions/outliner/editor.test.d.ts.map +0 -1
  285. package/dist/types/src/extensions/outliner/index.d.ts +0 -4
  286. package/dist/types/src/extensions/outliner/index.d.ts.map +0 -1
  287. package/dist/types/src/extensions/outliner/outliner.d.ts +0 -11
  288. package/dist/types/src/extensions/outliner/outliner.d.ts.map +0 -1
  289. package/dist/types/src/extensions/outliner/outliner.test.d.ts +0 -2
  290. package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +0 -1
  291. package/dist/types/src/extensions/outliner/selection.d.ts +0 -12
  292. package/dist/types/src/extensions/outliner/selection.d.ts.map +0 -1
  293. package/dist/types/src/extensions/outliner/tree.d.ts +0 -79
  294. package/dist/types/src/extensions/outliner/tree.d.ts.map +0 -1
  295. package/dist/types/src/extensions/outliner/tree.test.d.ts +0 -2
  296. package/dist/types/src/extensions/outliner/tree.test.d.ts.map +0 -1
  297. package/dist/types/src/extensions/preview/index.d.ts +0 -2
  298. package/dist/types/src/extensions/preview/index.d.ts.map +0 -1
  299. package/dist/types/src/extensions/preview/preview.d.ts +0 -32
  300. package/dist/types/src/extensions/preview/preview.d.ts.map +0 -1
  301. package/dist/types/src/extensions/selection.d.ts +0 -24
  302. package/dist/types/src/extensions/selection.d.ts.map +0 -1
  303. package/dist/types/src/extensions/typewriter.d.ts +0 -10
  304. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  305. package/dist/types/src/stories/Command.stories.d.ts +0 -7
  306. package/dist/types/src/stories/Command.stories.d.ts.map +0 -1
  307. package/dist/types/src/stories/CommandMenu.stories.d.ts +0 -13
  308. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
  309. package/dist/types/src/styles/index.d.ts +0 -4
  310. package/dist/types/src/styles/index.d.ts.map +0 -1
  311. package/dist/types/src/styles/markdown.d.ts +0 -8
  312. package/dist/types/src/styles/markdown.d.ts.map +0 -1
  313. package/dist/types/src/styles/theme.d.ts +0 -38
  314. package/dist/types/src/styles/theme.d.ts.map +0 -1
  315. package/dist/types/src/styles/tokens.d.ts +0 -3
  316. package/dist/types/src/styles/tokens.d.ts.map +0 -1
  317. package/dist/types/src/testing/index.d.ts +0 -2
  318. package/dist/types/src/testing/index.d.ts.map +0 -1
  319. package/dist/types/src/testing/util.d.ts +0 -3
  320. package/dist/types/src/testing/util.d.ts.map +0 -1
  321. package/dist/types/src/types/index.d.ts +0 -2
  322. package/dist/types/src/types/index.d.ts.map +0 -1
  323. package/dist/types/src/types/types.d.ts +0 -21
  324. package/dist/types/src/types/types.d.ts.map +0 -1
  325. package/dist/types/src/util/cursor.d.ts +0 -31
  326. package/dist/types/src/util/cursor.d.ts.map +0 -1
  327. package/dist/types/src/util/debug.d.ts +0 -17
  328. package/dist/types/src/util/debug.d.ts.map +0 -1
  329. package/dist/types/src/util/dom.d.ts +0 -20
  330. package/dist/types/src/util/dom.d.ts.map +0 -1
  331. package/dist/types/src/util/facet.d.ts +0 -3
  332. package/dist/types/src/util/facet.d.ts.map +0 -1
  333. package/src/components/EditorToolbar/util.ts +0 -65
  334. package/src/components/Popover/CommandMenu.tsx +0 -279
  335. package/src/components/Popover/RefDropdownMenu.tsx +0 -85
  336. package/src/components/Popover/RefPopover.tsx +0 -99
  337. package/src/components/Popover/index.ts +0 -7
  338. package/src/defaults.ts +0 -49
  339. package/src/extensions/annotations.ts +0 -55
  340. package/src/extensions/autocomplete.ts +0 -69
  341. package/src/extensions/automerge/automerge.stories.tsx +0 -142
  342. package/src/extensions/automerge/automerge.test.tsx +0 -78
  343. package/src/extensions/automerge/automerge.ts +0 -86
  344. package/src/extensions/automerge/cursor.ts +0 -28
  345. package/src/extensions/automerge/defs.ts +0 -31
  346. package/src/extensions/automerge/index.ts +0 -5
  347. package/src/extensions/automerge/sync.ts +0 -75
  348. package/src/extensions/automerge/update-automerge.ts +0 -50
  349. package/src/extensions/automerge/update-codemirror.ts +0 -115
  350. package/src/extensions/awareness/awareness-provider.ts +0 -127
  351. package/src/extensions/awareness/awareness.ts +0 -315
  352. package/src/extensions/awareness/index.ts +0 -6
  353. package/src/extensions/blast.ts +0 -363
  354. package/src/extensions/command/action.ts +0 -56
  355. package/src/extensions/command/command-menu.ts +0 -211
  356. package/src/extensions/command/command.ts +0 -34
  357. package/src/extensions/command/floating-menu.ts +0 -133
  358. package/src/extensions/command/hint.ts +0 -103
  359. package/src/extensions/command/index.ts +0 -10
  360. package/src/extensions/command/placeholder.ts +0 -113
  361. package/src/extensions/command/state.ts +0 -90
  362. package/src/extensions/command/typeahead.ts +0 -129
  363. package/src/extensions/command/useCommandMenu.ts +0 -119
  364. package/src/extensions/comments.ts +0 -593
  365. package/src/extensions/debug.ts +0 -15
  366. package/src/extensions/dnd.ts +0 -37
  367. package/src/extensions/factories.ts +0 -260
  368. package/src/extensions/focus.ts +0 -35
  369. package/src/extensions/folding.tsx +0 -46
  370. package/src/extensions/hashtag.tsx +0 -68
  371. package/src/extensions/json.ts +0 -57
  372. package/src/extensions/listener.ts +0 -38
  373. package/src/extensions/markdown/action.ts +0 -117
  374. package/src/extensions/markdown/bundle.ts +0 -71
  375. package/src/extensions/markdown/changes.test.ts +0 -26
  376. package/src/extensions/markdown/changes.ts +0 -149
  377. package/src/extensions/markdown/debug.ts +0 -44
  378. package/src/extensions/markdown/decorate.ts +0 -592
  379. package/src/extensions/markdown/formatting.test.ts +0 -498
  380. package/src/extensions/markdown/formatting.ts +0 -1267
  381. package/src/extensions/markdown/highlight.ts +0 -183
  382. package/src/extensions/markdown/image.ts +0 -119
  383. package/src/extensions/markdown/index.ts +0 -13
  384. package/src/extensions/markdown/link.ts +0 -47
  385. package/src/extensions/markdown/parser.test.ts +0 -75
  386. package/src/extensions/markdown/styles.ts +0 -135
  387. package/src/extensions/markdown/table.ts +0 -144
  388. package/src/extensions/mention.ts +0 -41
  389. package/src/extensions/modes.ts +0 -41
  390. package/src/extensions/outliner/commands.ts +0 -270
  391. package/src/extensions/outliner/editor.test.ts +0 -33
  392. package/src/extensions/outliner/editor.ts +0 -184
  393. package/src/extensions/outliner/index.ts +0 -7
  394. package/src/extensions/outliner/outliner.test.ts +0 -100
  395. package/src/extensions/outliner/outliner.ts +0 -167
  396. package/src/extensions/outliner/selection.ts +0 -50
  397. package/src/extensions/outliner/tree.test.ts +0 -168
  398. package/src/extensions/outliner/tree.ts +0 -317
  399. package/src/extensions/preview/index.ts +0 -5
  400. package/src/extensions/preview/preview.ts +0 -193
  401. package/src/extensions/selection.ts +0 -100
  402. package/src/extensions/typewriter.ts +0 -68
  403. package/src/stories/Command.stories.tsx +0 -98
  404. package/src/stories/CommandMenu.stories.tsx +0 -160
  405. package/src/styles/index.ts +0 -7
  406. package/src/styles/markdown.ts +0 -26
  407. package/src/styles/theme.ts +0 -266
  408. package/src/styles/tokens.ts +0 -17
  409. package/src/testing/index.ts +0 -5
  410. package/src/testing/util.ts +0 -7
  411. package/src/types/index.ts +0 -5
  412. package/src/types/types.ts +0 -32
  413. package/src/util/cursor.ts +0 -56
  414. package/src/util/debug.ts +0 -64
  415. package/src/util/dom.ts +0 -56
  416. package/src/util/facet.ts +0 -13
@@ -0,0 +1,320 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Extension, Prec, RangeSetBuilder, StateEffect, StateField } from '@codemirror/state';
6
+ import {
7
+ Decoration,
8
+ type DecorationSet,
9
+ EditorView,
10
+ type KeyBinding,
11
+ ViewPlugin,
12
+ type ViewUpdate,
13
+ keymap,
14
+ } from '@codemirror/view';
15
+
16
+ import { type PlaceholderOptions, modalStateField, placeholder } from '@dxos/ui-editor';
17
+ import { type Range } from '@dxos/ui-editor/types';
18
+ import { isNonNullable, isTruthy } from '@dxos/util';
19
+
20
+ const DELIMITERS = [' ', ':'];
21
+
22
+ export type PopoverOptions = {
23
+ trigger?: string | string[];
24
+ triggerKey?: string;
25
+ placeholder?: Partial<PlaceholderOptions>;
26
+ delimiters?: string[];
27
+
28
+ /**
29
+ * Open the popover automatically while typing a word (no trigger character required).
30
+ * The completion range covers the word under the cursor (delimited by {@link PopoverOptions.delimiters}).
31
+ */
32
+ activateOnTyping?: boolean;
33
+
34
+ // Trigger update.
35
+ onTextChange?: (event: { view: EditorView; pos: number; text: string; trigger?: string }) => void;
36
+ onClose?: (event: { view: EditorView }) => void;
37
+
38
+ // Menu specific.
39
+ /** Returns true when the menu consumed the key (an item was selected); false falls through. */
40
+ onEnter?: (event: { view: EditorView }) => boolean | void;
41
+ onArrowUp?: (event: { view: EditorView }) => void;
42
+ onArrowDown?: (event: { view: EditorView }) => void;
43
+ };
44
+
45
+ /**
46
+ * Creates a popover that appears when the trigger character is inserted.
47
+ * This can be used for context menus or autocompletion.
48
+ */
49
+ export const popover = (options: PopoverOptions = {}): Extension => {
50
+ return [
51
+ Prec.highest(popoverKeymap(options)),
52
+ popoverStateField,
53
+ popoverTriggerListener(options),
54
+ options.activateOnTyping && popoverAutoActivate(options),
55
+ popoverAnchorDecoration(options),
56
+ modalStateField,
57
+ options.trigger &&
58
+ placeholder({
59
+ // TODO(burdon): Translations.
60
+ content: `Press '${Array.isArray(options.trigger) ? options.trigger[0] : options.trigger}' for commands`,
61
+ focusOnly: true,
62
+ ...options.placeholder,
63
+ }),
64
+ ].filter(isTruthy);
65
+ };
66
+
67
+ /**
68
+ * Listen for selection and document changes.
69
+ */
70
+ const popoverTriggerListener = (options: PopoverOptions) =>
71
+ EditorView.updateListener.of(({ view, docChanged }) => {
72
+ const { range: activeRange, trigger } = view.state.field(popoverStateField) ?? {};
73
+ if (!activeRange) {
74
+ return;
75
+ }
76
+
77
+ const text = view.state.doc.sliceString(activeRange.from, activeRange.to);
78
+ const selection = view.state.selection.main;
79
+ const shouldClose =
80
+ // Trigger deleted.
81
+ (trigger ? trigger !== text[0] : false) ||
82
+ // Whitespace in text.
83
+ /\s/.test(trigger ? text.slice(1) : text) ||
84
+ // Cursor moved before the range.
85
+ selection.head < activeRange.from ||
86
+ // Cursor moved after the range (+1 to handle selection changing before doc).
87
+ selection.head > activeRange.to + 1;
88
+
89
+ const nextRange = shouldClose ? null : docChanged ? { from: activeRange.from, to: selection.head } : activeRange;
90
+ if (nextRange !== activeRange) {
91
+ view.dispatch({
92
+ effects: popoverRangeEffect.of(nextRange ? { range: nextRange, trigger } : null),
93
+ });
94
+ }
95
+
96
+ if (shouldClose) {
97
+ options.onClose?.({ view });
98
+ }
99
+ });
100
+
101
+ /**
102
+ * Open the popover while typing a word, without requiring a trigger character. Once a range is
103
+ * active, {@link popoverTriggerListener} keeps it in sync and closes it (whitespace, cursor moves).
104
+ */
105
+ const popoverAutoActivate = (options: PopoverOptions) =>
106
+ EditorView.updateListener.of(({ view, docChanged, transactions }) => {
107
+ // Only user input opens the popover — programmatic syncs (e.g. a controlled `value` update on
108
+ // mount) must not pop the menu.
109
+ if (!docChanged || !transactions.some((tr) => tr.isUserEvent('input')) || view.state.field(popoverStateField)) {
110
+ return;
111
+ }
112
+ const selection = view.state.selection.main;
113
+ if (!selection.empty) {
114
+ return;
115
+ }
116
+ const line = view.state.doc.lineAt(selection.head);
117
+ const before = line.text.slice(0, selection.head - line.from);
118
+ const idx = getLastIndexOf(before, options.delimiters ?? DELIMITERS);
119
+ const token = before.slice(idx + 1);
120
+ if (token.length === 0) {
121
+ return;
122
+ }
123
+ view.dispatch({
124
+ effects: popoverRangeEffect.of({ range: { from: line.from + idx + 1, to: selection.head } }),
125
+ });
126
+ });
127
+
128
+ /**
129
+ * Popover navigation.
130
+ */
131
+ const popoverKeymap = (options: PopoverOptions) => {
132
+ const triggers = Array.isArray(options.trigger) ? options.trigger : [options.trigger];
133
+ return keymap.of(
134
+ [
135
+ // Prefix triggers.
136
+ ...triggers.filter(isNonNullable).map((trigger) => ({
137
+ key: trigger,
138
+ run: (view: EditorView) => {
139
+ // Determine if we should trigger the popover:
140
+ // 1. Empty lines or at the beginning of a line.
141
+ // 2. When there's a preceding space.
142
+ const selection = view.state.selection.main;
143
+ const line = view.state.doc.lineAt(selection.head);
144
+ if (
145
+ line.text.trim() === '' ||
146
+ selection.head === line.from ||
147
+ (selection.head > line.from && line.text[selection.head - line.from - 1] === ' ')
148
+ ) {
149
+ // Insert and select the trigger.
150
+ view.dispatch({
151
+ changes: { from: selection.head, insert: trigger },
152
+ selection: { anchor: selection.head + 1, head: selection.head + 1 },
153
+ effects: popoverRangeEffect.of({ trigger, range: { from: selection.head, to: selection.head + 1 } }),
154
+ });
155
+
156
+ return true;
157
+ }
158
+
159
+ return false;
160
+ },
161
+ })),
162
+
163
+ //
164
+ // Custom trigger.
165
+ //
166
+ options.triggerKey &&
167
+ ({
168
+ key: options.triggerKey,
169
+ run: (view: EditorView) => {
170
+ const selection = view.state.selection.main;
171
+ const line = view.state.doc.lineAt(selection.head);
172
+
173
+ // Get last word.
174
+ let str = line.text.slice(0, selection.head - line.from);
175
+ const idx = getLastIndexOf(str, options.delimiters ?? DELIMITERS);
176
+ if (idx !== -1) {
177
+ str = str.slice(idx + 1);
178
+ }
179
+
180
+ // Create anchor even if zero length (append space).
181
+ const from = line.from + idx;
182
+ view.dispatch({
183
+ effects: popoverRangeEffect.of({ range: { from: from + 1, to: selection.head } }),
184
+ changes:
185
+ selection.head === view.state.doc.length
186
+ ? { from: from + 1, to: selection.head, insert: ' ' }
187
+ : undefined,
188
+ });
189
+ return true;
190
+ },
191
+ } satisfies KeyBinding),
192
+
193
+ //
194
+ // Nav keys.
195
+ //
196
+ {
197
+ key: 'ArrowUp',
198
+ run: (view: EditorView) => {
199
+ const range = view.state.field(popoverStateField)?.range;
200
+ if (range) {
201
+ options.onArrowUp?.({ view });
202
+ return true;
203
+ }
204
+
205
+ return false;
206
+ },
207
+ },
208
+ {
209
+ key: 'ArrowDown',
210
+ run: (view: EditorView) => {
211
+ const range = view.state.field(popoverStateField)?.range;
212
+ if (range) {
213
+ options.onArrowDown?.({ view });
214
+ return true;
215
+ }
216
+
217
+ return false;
218
+ },
219
+ },
220
+ {
221
+ key: 'Enter',
222
+ run: (view: EditorView) => {
223
+ const range = view.state.field(popoverStateField)?.range;
224
+ if (range) {
225
+ // The consumer deletes the range when it selects an item; when nothing is selectable
226
+ // (empty menu over an `activateOnTyping` range) the key must fall through so the
227
+ // typed text is preserved.
228
+ return options.onEnter?.({ view }) ?? false;
229
+ }
230
+
231
+ return false;
232
+ },
233
+ },
234
+ ].filter(isTruthy),
235
+ );
236
+ };
237
+
238
+ /**
239
+ * Creates a <dx-anchor> tag, which is used to anchor the Popver.
240
+ */
241
+ const popoverAnchorDecoration = (options: PopoverOptions) => {
242
+ return ViewPlugin.fromClass(
243
+ class {
244
+ _decorations: DecorationSet = Decoration.none;
245
+
246
+ constructor(readonly view: EditorView) {}
247
+
248
+ // TODO(wittjosiah): The decorations are repainted on every update, this occasionally causes menu to flicker.
249
+ update({ view, transactions }: ViewUpdate) {
250
+ const builder = new RangeSetBuilder<Decoration>();
251
+ const { range, trigger } = view.state.field(popoverStateField) ?? {};
252
+ if (range) {
253
+ // Check if we should show the widget (only if cursor is within the active command range).
254
+ const selection = view.state.selection.main;
255
+ const showWidget = selection.head >= range.from && selection.head <= range.to;
256
+ if (showWidget) {
257
+ builder.add(
258
+ range.from,
259
+ range.to + 1,
260
+ Decoration.mark({
261
+ tagName: 'dx-anchor',
262
+ class: 'cm-popover-trigger',
263
+ attributes: {
264
+ 'data-visible-focus': 'false',
265
+ 'data-auto-trigger': 'true',
266
+ 'data-trigger': trigger ?? options.triggerKey ?? '',
267
+ },
268
+ }),
269
+ );
270
+ }
271
+
272
+ const rangeChanged = transactions.some((tr) => tr.effects.some((effect) => effect.is(popoverRangeEffect)));
273
+ if (rangeChanged) {
274
+ // NOTE: Content skips the trigger character.
275
+ const content = view.state.sliceDoc(range.from + (trigger ? trigger.length : 0), range.to);
276
+ options.onTextChange?.({ view, pos: selection.head, text: content, trigger });
277
+ }
278
+ }
279
+
280
+ this._decorations = builder.finish();
281
+ }
282
+ },
283
+ {
284
+ decorations: (v) => v._decorations,
285
+ },
286
+ );
287
+ };
288
+
289
+ type PopoverState = {
290
+ /**
291
+ * Trigger prefix (in document).
292
+ */
293
+ trigger?: string;
294
+
295
+ /**
296
+ * Current document completion range.
297
+ */
298
+ range: Range;
299
+ };
300
+
301
+ // State effects for managing popover state.
302
+ export const popoverRangeEffect = StateEffect.define<PopoverState | null>();
303
+
304
+ // State field to track the active popover trigger range.
305
+ export const popoverStateField = StateField.define<PopoverState | null>({
306
+ create: () => null,
307
+ update: (value, tr) => {
308
+ let newValue = value;
309
+ for (const effect of tr.effects) {
310
+ if (effect.is(popoverRangeEffect)) {
311
+ newValue = effect.value;
312
+ }
313
+ }
314
+
315
+ return newValue;
316
+ },
317
+ });
318
+
319
+ const getLastIndexOf = (str: string, delimiters: string[]) =>
320
+ Math.max(...delimiters.map((delim) => str.lastIndexOf(delim)));
@@ -0,0 +1,189 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Extension } from '@codemirror/state';
6
+ import { type EditorState } from '@codemirror/state';
7
+ import { type RefObject, useCallback, useMemo, useRef, useState } from 'react';
8
+
9
+ import { invariant } from '@dxos/invariant';
10
+ import { modalStateEffect } from '@dxos/ui-editor';
11
+ import { type MaybePromise } from '@dxos/util';
12
+
13
+ import { type EditorMenuProviderProps } from './EditorMenuProvider';
14
+ import { type EditorMenuGroup, type EditorMenuItem } from './menu';
15
+ import { filterMenuGroups, getMenuItem, getNextMenuItem, getPreviousMenuItem } from './menu';
16
+ import { type PopoverOptions, popover, popoverRangeEffect, popoverStateField } from './popover';
17
+
18
+ export type GetMenuContext = {
19
+ state: EditorState;
20
+ pos: number;
21
+ text: string;
22
+ trigger?: string;
23
+ };
24
+
25
+ export type UseEditorMenuProps = {
26
+ filter?: boolean;
27
+ getMenu?: (context: GetMenuContext) => MaybePromise<EditorMenuGroup[]>;
28
+ } & Pick<PopoverOptions, 'trigger' | 'triggerKey' | 'placeholder' | 'activateOnTyping'>;
29
+
30
+ export type UseEditorMenu = {
31
+ groupsRef: RefObject<EditorMenuGroup[]>;
32
+ extension: Extension;
33
+ } & Pick<EditorMenuProviderProps, 'currentItem' | 'open' | 'onOpenChange' | 'onActivate' | 'onSelect' | 'onCancel'>;
34
+
35
+ /**
36
+ * ```tsx
37
+ * const { groupsRef, extension, ...menuProps } = useEditorMenu();
38
+ * const { parentRef, viewRef } = useTextEditor({ extensions: [extension] });
39
+ * return (
40
+ * <EditorMenuProvider getView={() => viewRef.current} groups={groupsRef.current} {...menuProps}>
41
+ * <div ref={parentRef} />
42
+ * </EditorMenuProvider>
43
+ * );
44
+ * ```
45
+ */
46
+ export const useEditorMenu = ({
47
+ trigger,
48
+ triggerKey,
49
+ placeholder,
50
+ activateOnTyping,
51
+ filter = true,
52
+ getMenu,
53
+ }: UseEditorMenuProps): UseEditorMenu => {
54
+ const groupsRef = useRef<EditorMenuGroup[]>([]);
55
+ const currentRef = useRef<EditorMenuItem | null>(null);
56
+ const [currentItem, setCurrentItem] = useState<string>();
57
+ const [open, setOpen] = useState(false);
58
+ const [_, refresh] = useState({});
59
+
60
+ /**
61
+ * Get filtered options.
62
+ */
63
+ const getMenuOptions = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(
64
+ async ({ text, trigger, ...props }) => {
65
+ const groups = (await getMenu?.({ text, trigger, ...props })) ?? [];
66
+ // The "@" menu can use "@@" as syntax for block embeds, so it owns its own query filtering.
67
+ return filter && trigger !== '@'
68
+ ? filterMenuGroups(groups, (item) =>
69
+ text ? (item.label as string).toLowerCase().startsWith(text.toLowerCase()) : true,
70
+ )
71
+ : groups;
72
+ },
73
+ [getMenu, filter],
74
+ );
75
+
76
+ const handleOpenChange = useCallback<NonNullable<UseEditorMenu['onOpenChange']>>(
77
+ async ({ view, open }) => {
78
+ invariant(view);
79
+ setOpen(open);
80
+ if (!open) {
81
+ setCurrentItem(undefined);
82
+ view.dispatch({
83
+ effects: [popoverRangeEffect.of(null)],
84
+ });
85
+ }
86
+
87
+ // TODO(burdon): Possible race condition.
88
+ // useTextEditor.handleKeyDown will get called after this handler completes.
89
+ requestAnimationFrame(() => {
90
+ view.dispatch({
91
+ effects: [modalStateEffect.of(open)],
92
+ });
93
+ });
94
+ },
95
+ [getMenuOptions],
96
+ );
97
+
98
+ const handleActivate = useCallback<NonNullable<UseEditorMenu['onActivate']>>(
99
+ async ({ view, trigger }) => {
100
+ const item = getMenuItem(groupsRef.current, currentItem);
101
+ if (item) {
102
+ currentRef.current = item;
103
+ }
104
+
105
+ if (!open) {
106
+ handleOpenChange({ view, open: true, trigger });
107
+ }
108
+ },
109
+ [open, handleOpenChange],
110
+ );
111
+
112
+ const handleSelect = useCallback<NonNullable<UseEditorMenu['onSelect']>>(({ view, item }) => {
113
+ // Delete trigger range (e.g., "/" and any typed filter text).
114
+ const { range } = view.state.field(popoverStateField) ?? {};
115
+ if (range) {
116
+ view.dispatch({ changes: { from: range.from, to: range.to, insert: '' } });
117
+ }
118
+ void item.onSelect?.({ view, head: view.state.selection.main.head });
119
+ view.focus();
120
+ }, []);
121
+
122
+ const handleCancel = useCallback<NonNullable<UseEditorMenu['onCancel']>>(({ view }) => {
123
+ // Delete trigger.
124
+ const { range, trigger } = view.state.field(popoverStateField) ?? {};
125
+ if (range && trigger) {
126
+ view.dispatch({
127
+ changes: { ...range, insert: '' },
128
+ });
129
+ }
130
+ }, []);
131
+
132
+ const serializedTrigger = Array.isArray(trigger) ? trigger.join(',') : trigger;
133
+ const extension = useMemo<Extension>(() => {
134
+ return popover({
135
+ trigger,
136
+ triggerKey,
137
+ placeholder,
138
+ activateOnTyping,
139
+ onClose: ({ view }) => handleOpenChange({ view, open: false }),
140
+ onEnter: ({ view }) => {
141
+ if (currentRef.current) {
142
+ handleSelect({ view, item: currentRef.current });
143
+ return true;
144
+ }
145
+ return false;
146
+ },
147
+ onArrowUp: () => {
148
+ setCurrentItem((currentItem) => {
149
+ const previous = getPreviousMenuItem(groupsRef.current, currentItem);
150
+ currentRef.current = previous;
151
+ return previous.id;
152
+ });
153
+ },
154
+ onArrowDown: () => {
155
+ setCurrentItem((currentItem) => {
156
+ const next = getNextMenuItem(groupsRef.current, currentItem);
157
+ currentRef.current = next;
158
+ return next.id;
159
+ });
160
+ },
161
+ onTextChange: async ({ view, pos, text, trigger }) => {
162
+ groupsRef.current = (await getMenuOptions({ state: view.state, pos, text, trigger })) ?? [];
163
+ const firstItem = groupsRef.current.filter((group) => group.items.length > 0)[0]?.items[0];
164
+ if (firstItem) {
165
+ setCurrentItem(firstItem.id);
166
+ currentRef.current = firstItem;
167
+ } else {
168
+ // No matches: clear the selection so Enter falls through instead of
169
+ // selecting a stale item from a previous query.
170
+ setCurrentItem(undefined);
171
+ currentRef.current = null;
172
+ }
173
+
174
+ refresh({});
175
+ },
176
+ });
177
+ }, [handleOpenChange, getMenuOptions, serializedTrigger, placeholder, activateOnTyping]);
178
+
179
+ return {
180
+ groupsRef,
181
+ extension,
182
+ currentItem,
183
+ open,
184
+ onOpenChange: handleOpenChange,
185
+ onActivate: handleActivate,
186
+ onSelect: handleSelect,
187
+ onCancel: handleCancel,
188
+ };
189
+ };
@@ -0,0 +1,79 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createContext } from '@radix-ui/react-context';
6
+ import React, { type PropsWithChildren, type RefObject, useCallback, useEffect, useRef, useState } from 'react';
7
+
8
+ import { addEventListener } from '@dxos/async';
9
+ import { DX_ANCHOR_ACTIVATE, type DxAnchorActivate, Popover } from '@dxos/react-ui';
10
+ import { type PreviewLinkRef, type PreviewLinkTarget } from '@dxos/ui-editor';
11
+
12
+ type EditorPreviewPopoverValue = Partial<{
13
+ link: PreviewLinkRef;
14
+ target: PreviewLinkTarget;
15
+ pending: boolean;
16
+ }>;
17
+
18
+ const [EditorPreviewContextProvider, useEditorPreview] = createContext<EditorPreviewPopoverValue>('PreviewPopover', {});
19
+
20
+ export type EditorPreviewProviderProps = PropsWithChildren<{
21
+ onLookup?: (link: PreviewLinkRef) => Promise<PreviewLinkTarget | null | undefined>;
22
+ }>;
23
+
24
+ /**
25
+ * NOTE: In Composer, the DeckPlugin provides the Popover.Root as part of the DeckLayout.
26
+ */
27
+ // TOOD(burdon): Reconcile with PreviewPlugin.
28
+ export const EditorPreviewProvider = ({ children, onLookup }: EditorPreviewProviderProps) => {
29
+ const triggerRef = useRef<HTMLElement | null>(null);
30
+ const [value, setValue] = useState<EditorPreviewPopoverValue>({});
31
+ const [open, setOpen] = useState(false);
32
+
33
+ const handleActivate = useCallback(
34
+ (event: DxAnchorActivate) => {
35
+ const { dxn, label, trigger } = event;
36
+ setValue((value) => ({
37
+ ...value,
38
+ link: { label, dxn },
39
+ pending: true,
40
+ }));
41
+
42
+ triggerRef.current = trigger;
43
+ queueMicrotask(() => setOpen(true));
44
+ void onLookup?.({ label, dxn }).then((target) =>
45
+ setValue((value) => ({
46
+ ...value,
47
+ target: target ?? undefined,
48
+ pending: false,
49
+ })),
50
+ );
51
+ },
52
+ [onLookup],
53
+ );
54
+
55
+ const [root, setRoot] = useState<HTMLDivElement | null>(null);
56
+ useEffect(() => {
57
+ if (!root || !handleActivate) {
58
+ return;
59
+ }
60
+
61
+ return addEventListener(root, DX_ANCHOR_ACTIVATE as any, handleActivate, {
62
+ capture: true,
63
+ passive: false,
64
+ });
65
+ }, [root, handleActivate]);
66
+
67
+ return (
68
+ <EditorPreviewContextProvider pending={value.pending} link={value.link} target={value.target}>
69
+ <Popover.Root open={open} onOpenChange={setOpen}>
70
+ <Popover.VirtualTrigger virtualRef={triggerRef as unknown as RefObject<HTMLButtonElement>} />
71
+ <div className='contents' ref={setRoot}>
72
+ {children}
73
+ </div>
74
+ </Popover.Root>
75
+ </EditorPreviewContextProvider>
76
+ );
77
+ };
78
+
79
+ export { useEditorPreview };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './EditorPreviewProvider';