@dxos/react-ui-editor 0.8.4-main.3a94e84 → 0.8.4-main.406dc2a

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 (310) hide show
  1. package/dist/lib/browser/{chunk-22UMM3QJ.mjs → chunk-HL3YF6WC.mjs} +2 -2
  2. package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +4239 -3098
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +71 -1
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/browser/types/index.mjs +1 -1
  9. package/dist/lib/node-esm/{chunk-YXYQPV6R.mjs → chunk-YJZGD3LY.mjs} +2 -2
  10. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +7 -0
  11. package/dist/lib/node-esm/index.mjs +4239 -3098
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +71 -1
  15. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  16. package/dist/lib/node-esm/types/index.mjs +1 -1
  17. package/dist/types/src/components/Editor/Editor.d.ts +24 -9
  18. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  19. package/dist/types/src/components/Editor/Editor.stories.d.ts +30 -0
  20. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -0
  21. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  22. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  23. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  24. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  25. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  26. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  27. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  28. package/dist/types/src/components/EditorToolbar/util.d.ts +3 -3
  29. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  30. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -1
  31. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  32. package/dist/types/src/components/index.d.ts +0 -1
  33. package/dist/types/src/components/index.d.ts.map +1 -1
  34. package/dist/types/src/defaults.d.ts.map +1 -1
  35. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts +26 -0
  36. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -0
  37. package/dist/types/src/extensions/autocomplete/index.d.ts +5 -0
  38. package/dist/types/src/extensions/autocomplete/index.d.ts.map +1 -0
  39. package/dist/types/src/extensions/autocomplete/match.d.ts +13 -0
  40. package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -0
  41. package/dist/types/src/extensions/autocomplete/placeholder.d.ts +20 -0
  42. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -0
  43. package/dist/types/src/extensions/autocomplete/typeahead.d.ts +10 -0
  44. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -0
  45. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  46. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  47. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +10 -19
  48. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  49. package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
  50. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  51. package/dist/types/src/extensions/automerge/sync.d.ts +2 -2
  52. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  53. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  54. package/dist/types/src/extensions/autoscroll.d.ts +10 -0
  55. package/dist/types/src/extensions/autoscroll.d.ts.map +1 -0
  56. package/dist/types/src/extensions/comments.d.ts +1 -1
  57. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  58. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  59. package/dist/types/src/extensions/factories.d.ts +8 -8
  60. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  61. package/dist/types/src/extensions/focus.d.ts.map +1 -1
  62. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  63. package/dist/types/src/extensions/index.d.ts +4 -1
  64. package/dist/types/src/extensions/index.d.ts.map +1 -1
  65. package/dist/types/src/extensions/json.d.ts +1 -1
  66. package/dist/types/src/extensions/json.d.ts.map +1 -1
  67. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  68. package/dist/types/src/extensions/markdown/bundle.d.ts +8 -2
  69. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  70. package/dist/types/src/extensions/markdown/changes.d.ts +1 -1
  71. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  72. package/dist/types/src/extensions/markdown/decorate.d.ts +9 -1
  73. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  74. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  75. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  76. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  77. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  78. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  79. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  80. package/dist/types/src/extensions/modes.d.ts +1 -1
  81. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  82. package/dist/types/src/extensions/outliner/menu.d.ts +8 -0
  83. package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -0
  84. package/dist/types/src/extensions/outliner/outliner.d.ts +1 -1
  85. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  86. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  87. package/dist/types/src/extensions/outliner/tree.d.ts +2 -2
  88. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  89. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts +36 -0
  90. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts.map +1 -0
  91. package/dist/types/src/extensions/popover/index.d.ts +8 -0
  92. package/dist/types/src/extensions/popover/index.d.ts.map +1 -0
  93. package/dist/types/src/extensions/popover/menu-presets.d.ts +4 -0
  94. package/dist/types/src/extensions/popover/menu-presets.d.ts.map +1 -0
  95. package/dist/types/src/extensions/popover/menu.d.ts +24 -0
  96. package/dist/types/src/extensions/popover/menu.d.ts.map +1 -0
  97. package/dist/types/src/extensions/popover/modal.d.ts +7 -0
  98. package/dist/types/src/extensions/popover/modal.d.ts.map +1 -0
  99. package/dist/types/src/extensions/popover/popover.d.ts +47 -0
  100. package/dist/types/src/extensions/popover/popover.d.ts.map +1 -0
  101. package/dist/types/src/extensions/popover/usePopoverMenu.d.ts +34 -0
  102. package/dist/types/src/extensions/popover/usePopoverMenu.d.ts.map +1 -0
  103. package/dist/types/src/extensions/popover/util.d.ts +8 -0
  104. package/dist/types/src/extensions/popover/util.d.ts.map +1 -0
  105. package/dist/types/src/extensions/preview/preview.d.ts +2 -6
  106. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  107. package/dist/types/src/extensions/state.d.ts +2 -0
  108. package/dist/types/src/extensions/state.d.ts.map +1 -0
  109. package/dist/types/src/extensions/tags/extended-markdown.d.ts +10 -0
  110. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -0
  111. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts +2 -0
  112. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +1 -0
  113. package/dist/types/src/extensions/tags/index.d.ts +4 -0
  114. package/dist/types/src/extensions/tags/index.d.ts.map +1 -0
  115. package/dist/types/src/extensions/tags/streamer.d.ts +12 -0
  116. package/dist/types/src/extensions/tags/streamer.d.ts.map +1 -0
  117. package/dist/types/src/extensions/tags/xml-tags.d.ts +72 -0
  118. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -0
  119. package/dist/types/src/extensions/tags/xml-util.d.ts +10 -0
  120. package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -0
  121. package/dist/types/src/hooks/useTextEditor.d.ts +4 -8
  122. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  123. package/dist/types/src/stories/CommandDialog.stories.d.ts +14 -0
  124. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -0
  125. package/dist/types/src/stories/Comments.stories.d.ts +21 -10
  126. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  127. package/dist/types/src/stories/EditorToolbar.stories.d.ts +39 -3
  128. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  129. package/dist/types/src/stories/Experimental.stories.d.ts +22 -13
  130. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  131. package/dist/types/src/stories/Markdown.stories.d.ts +32 -43
  132. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  133. package/dist/types/src/stories/Outliner.stories.d.ts +15 -21
  134. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  135. package/dist/types/src/stories/Popover.stories.d.ts +20 -0
  136. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
  137. package/dist/types/src/stories/Preview.stories.d.ts +21 -7
  138. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  139. package/dist/types/src/stories/Tags.stories.d.ts +16 -0
  140. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -0
  141. package/dist/types/src/stories/TextEditor.stories.d.ts +37 -52
  142. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  143. package/dist/types/src/stories/components/EditorStory.d.ts +6 -9
  144. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  145. package/dist/types/src/styles/theme.d.ts.map +1 -1
  146. package/dist/types/src/testing/PreviewPopover.d.ts +20 -0
  147. package/dist/types/src/testing/PreviewPopover.d.ts.map +1 -0
  148. package/dist/types/src/testing/index.d.ts +1 -0
  149. package/dist/types/src/testing/index.d.ts.map +1 -1
  150. package/dist/types/src/testing/util.d.ts +1 -0
  151. package/dist/types/src/testing/util.d.ts.map +1 -1
  152. package/dist/types/src/translations.d.ts +1 -1
  153. package/dist/types/src/types/types.d.ts +2 -2
  154. package/dist/types/src/types/types.d.ts.map +1 -1
  155. package/dist/types/src/util/cursor.d.ts.map +1 -1
  156. package/dist/types/src/util/debug.d.ts +1 -1
  157. package/dist/types/src/util/debug.d.ts.map +1 -1
  158. package/dist/types/src/util/decorations.d.ts +4 -0
  159. package/dist/types/src/util/decorations.d.ts.map +1 -0
  160. package/dist/types/src/util/dom.d.ts +2 -12
  161. package/dist/types/src/util/dom.d.ts.map +1 -1
  162. package/dist/types/src/util/index.d.ts +1 -0
  163. package/dist/types/src/util/index.d.ts.map +1 -1
  164. package/dist/types/src/util/react.d.ts +1 -1
  165. package/dist/types/src/util/react.d.ts.map +1 -1
  166. package/dist/types/tsconfig.tsbuildinfo +1 -1
  167. package/package.json +69 -61
  168. package/src/components/Editor/Editor.stories.tsx +72 -0
  169. package/src/components/Editor/Editor.tsx +58 -15
  170. package/src/components/EditorToolbar/EditorToolbar.tsx +41 -30
  171. package/src/components/EditorToolbar/blocks.ts +21 -24
  172. package/src/components/EditorToolbar/formatting.ts +22 -25
  173. package/src/components/EditorToolbar/headings.ts +10 -5
  174. package/src/components/EditorToolbar/image.ts +8 -4
  175. package/src/components/EditorToolbar/lists.ts +16 -19
  176. package/src/components/EditorToolbar/search.ts +8 -4
  177. package/src/components/EditorToolbar/util.ts +16 -5
  178. package/src/components/EditorToolbar/view-mode.ts +11 -6
  179. package/src/components/index.ts +0 -1
  180. package/src/defaults.ts +5 -2
  181. package/src/extensions/autocomplete/autocomplete.ts +220 -0
  182. package/src/extensions/autocomplete/index.ts +8 -0
  183. package/src/extensions/autocomplete/match.ts +46 -0
  184. package/src/extensions/{command → autocomplete}/placeholder.ts +22 -18
  185. package/src/extensions/{command → autocomplete}/typeahead.ts +8 -50
  186. package/src/extensions/automerge/automerge.stories.tsx +31 -24
  187. package/src/extensions/automerge/automerge.ts +31 -11
  188. package/src/extensions/automerge/defs.ts +1 -1
  189. package/src/extensions/automerge/sync.ts +8 -4
  190. package/src/extensions/automerge/update-automerge.ts +1 -1
  191. package/src/extensions/autoscroll.ts +157 -0
  192. package/src/extensions/awareness/awareness.ts +2 -2
  193. package/src/extensions/comments.ts +18 -13
  194. package/src/extensions/dnd.ts +1 -1
  195. package/src/extensions/factories.ts +48 -31
  196. package/src/extensions/focus.ts +5 -4
  197. package/src/extensions/folding.tsx +4 -6
  198. package/src/extensions/hashtag.tsx +2 -2
  199. package/src/extensions/index.ts +4 -1
  200. package/src/extensions/json.ts +1 -1
  201. package/src/extensions/markdown/action.ts +2 -1
  202. package/src/extensions/markdown/bundle.ts +29 -5
  203. package/src/extensions/markdown/changes.ts +1 -1
  204. package/src/extensions/markdown/decorate.ts +24 -14
  205. package/src/extensions/markdown/formatting.test.ts +6 -6
  206. package/src/extensions/markdown/formatting.ts +3 -3
  207. package/src/extensions/markdown/highlight.ts +1 -1
  208. package/src/extensions/markdown/image.ts +3 -4
  209. package/src/extensions/markdown/link.ts +3 -0
  210. package/src/extensions/markdown/table.ts +7 -1
  211. package/src/extensions/mention.ts +1 -1
  212. package/src/extensions/modes.ts +2 -2
  213. package/src/extensions/{command/floating-menu.ts → outliner/menu.ts} +16 -21
  214. package/src/extensions/outliner/outliner.test.ts +3 -2
  215. package/src/extensions/outliner/outliner.ts +7 -6
  216. package/src/extensions/outliner/selection.ts +1 -1
  217. package/src/extensions/outliner/tree.test.ts +2 -1
  218. package/src/extensions/outliner/tree.ts +2 -2
  219. package/src/extensions/popover/PopoverMenuProvider.tsx +221 -0
  220. package/src/extensions/popover/index.ts +12 -0
  221. package/src/extensions/popover/menu-presets.ts +124 -0
  222. package/src/extensions/popover/menu.ts +67 -0
  223. package/src/extensions/popover/modal.ts +24 -0
  224. package/src/extensions/popover/popover.ts +293 -0
  225. package/src/extensions/popover/usePopoverMenu.ts +173 -0
  226. package/src/extensions/popover/util.ts +29 -0
  227. package/src/extensions/preview/index.ts +1 -1
  228. package/src/extensions/preview/preview.ts +57 -62
  229. package/src/extensions/selection.ts +2 -2
  230. package/src/extensions/state.ts +7 -0
  231. package/src/extensions/tags/extended-markdown.test.ts +261 -0
  232. package/src/extensions/tags/extended-markdown.ts +78 -0
  233. package/src/extensions/tags/index.ts +7 -0
  234. package/src/extensions/tags/streamer.ts +243 -0
  235. package/src/extensions/tags/xml-tags.ts +393 -0
  236. package/src/extensions/tags/xml-util.ts +94 -0
  237. package/src/hooks/useTextEditor.ts +27 -39
  238. package/src/stories/CommandDialog.stories.tsx +78 -0
  239. package/src/stories/Comments.stories.tsx +14 -10
  240. package/src/stories/EditorToolbar.stories.tsx +13 -12
  241. package/src/stories/Experimental.stories.tsx +17 -13
  242. package/src/stories/Markdown.stories.tsx +25 -21
  243. package/src/stories/Outliner.stories.tsx +54 -35
  244. package/src/stories/Popover.stories.tsx +163 -0
  245. package/src/stories/Preview.stories.tsx +34 -33
  246. package/src/stories/Tags.stories.tsx +81 -0
  247. package/src/stories/TextEditor.stories.tsx +39 -58
  248. package/src/stories/components/EditorStory.tsx +16 -15
  249. package/src/styles/theme.ts +16 -12
  250. package/src/testing/PreviewPopover.tsx +80 -0
  251. package/src/testing/index.ts +1 -0
  252. package/src/testing/util.ts +2 -0
  253. package/src/translations.ts +1 -1
  254. package/src/types/types.ts +1 -1
  255. package/src/util/cursor.ts +2 -1
  256. package/src/util/debug.ts +2 -2
  257. package/src/util/decorations.ts +21 -0
  258. package/src/util/dom.ts +5 -27
  259. package/src/util/index.ts +1 -0
  260. package/src/util/react.tsx +1 -1
  261. package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +0 -7
  262. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +0 -7
  263. package/dist/types/src/components/Popover/CommandMenu.d.ts +0 -34
  264. package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
  265. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -21
  266. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
  267. package/dist/types/src/components/Popover/RefPopover.d.ts +0 -34
  268. package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
  269. package/dist/types/src/components/Popover/index.d.ts +0 -4
  270. package/dist/types/src/components/Popover/index.d.ts.map +0 -1
  271. package/dist/types/src/extensions/autocomplete.d.ts +0 -13
  272. package/dist/types/src/extensions/autocomplete.d.ts.map +0 -1
  273. package/dist/types/src/extensions/command/action.d.ts +0 -17
  274. package/dist/types/src/extensions/command/action.d.ts.map +0 -1
  275. package/dist/types/src/extensions/command/command-menu.d.ts +0 -20
  276. package/dist/types/src/extensions/command/command-menu.d.ts.map +0 -1
  277. package/dist/types/src/extensions/command/command.d.ts +0 -6
  278. package/dist/types/src/extensions/command/command.d.ts.map +0 -1
  279. package/dist/types/src/extensions/command/floating-menu.d.ts +0 -7
  280. package/dist/types/src/extensions/command/floating-menu.d.ts.map +0 -1
  281. package/dist/types/src/extensions/command/hint.d.ts +0 -24
  282. package/dist/types/src/extensions/command/hint.d.ts.map +0 -1
  283. package/dist/types/src/extensions/command/index.d.ts +0 -7
  284. package/dist/types/src/extensions/command/index.d.ts.map +0 -1
  285. package/dist/types/src/extensions/command/placeholder.d.ts +0 -10
  286. package/dist/types/src/extensions/command/placeholder.d.ts.map +0 -1
  287. package/dist/types/src/extensions/command/state.d.ts +0 -16
  288. package/dist/types/src/extensions/command/state.d.ts.map +0 -1
  289. package/dist/types/src/extensions/command/typeahead.d.ts +0 -22
  290. package/dist/types/src/extensions/command/typeahead.d.ts.map +0 -1
  291. package/dist/types/src/extensions/command/useCommandMenu.d.ts +0 -26
  292. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +0 -1
  293. package/dist/types/src/stories/Command.stories.d.ts +0 -7
  294. package/dist/types/src/stories/Command.stories.d.ts.map +0 -1
  295. package/dist/types/src/stories/CommandMenu.stories.d.ts +0 -13
  296. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
  297. package/src/components/Popover/CommandMenu.tsx +0 -279
  298. package/src/components/Popover/RefDropdownMenu.tsx +0 -85
  299. package/src/components/Popover/RefPopover.tsx +0 -99
  300. package/src/components/Popover/index.ts +0 -7
  301. package/src/extensions/autocomplete.ts +0 -69
  302. package/src/extensions/command/action.ts +0 -56
  303. package/src/extensions/command/command-menu.ts +0 -210
  304. package/src/extensions/command/command.ts +0 -34
  305. package/src/extensions/command/hint.ts +0 -102
  306. package/src/extensions/command/index.ts +0 -10
  307. package/src/extensions/command/state.ts +0 -89
  308. package/src/extensions/command/useCommandMenu.ts +0 -118
  309. package/src/stories/Command.stories.tsx +0 -97
  310. package/src/stories/CommandMenu.stories.tsx +0 -159
@@ -2,20 +2,20 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import '@preact/signals-react';
8
6
 
9
7
  import { Repo } from '@automerge/automerge-repo';
10
8
  import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-network-broadcastchannel';
9
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
11
10
  import React, { useEffect, useState } from 'react';
12
11
 
13
12
  import { Obj, Ref, Type } from '@dxos/echo';
14
- import { DocAccessor, createDocAccessor, useQuery, useSpace, type Space, Query } from '@dxos/react-client/echo';
15
- import { useIdentity, type Identity } from '@dxos/react-client/halo';
16
- import { ClientRepeater, type ClientRepeatedComponentProps } from '@dxos/react-client/testing';
13
+ import { DocAccessor, Query, type Space, createDocAccessor, useQuery, useSpace } from '@dxos/react-client/echo';
14
+ import { type Identity, useIdentity } from '@dxos/react-client/halo';
15
+ import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
17
16
  import { useThemeContext } from '@dxos/react-ui';
18
- import { withLayout, withTheme } from '@dxos/storybook-utils';
17
+ import { withTheme } from '@dxos/react-ui/testing';
18
+ import { render } from '@dxos/storybook-utils';
19
19
 
20
20
  import { editorSlots } from '../../defaults';
21
21
  import { useTextEditor } from '../../hooks';
@@ -41,7 +41,7 @@ const Editor = ({ source, autoFocus, space, identity }: EditorProps) => {
41
41
  () => ({
42
42
  initialValue: DocAccessor.getValue(source),
43
43
  extensions: [
44
- createBasicExtensions({ placeholder: 'Type here...' }),
44
+ createBasicExtensions({ placeholder: 'Type here...', search: true }),
45
45
  createThemeExtensions({ themeMode, slots: editorSlots }),
46
46
  createDataExtensions({ id: 'test', text: source, space, identity }),
47
47
  ],
@@ -53,7 +53,7 @@ const Editor = ({ source, autoFocus, space, identity }: EditorProps) => {
53
53
  return <div ref={parentRef} className='flex w-full' />;
54
54
  };
55
55
 
56
- const Story = () => {
56
+ const DefaultStory = () => {
57
57
  const [object1, setObject1] = useState<DocAccessor<TestObject>>();
58
58
  const [object2, setObject2] = useState<DocAccessor<TestObject>>();
59
59
 
@@ -88,16 +88,6 @@ const Story = () => {
88
88
  );
89
89
  };
90
90
 
91
- export default {
92
- title: 'ui/react-ui-editor/Automerge',
93
- component: Editor,
94
- decorators: [withTheme, withLayout({ fullscreen: true })],
95
- render: () => <Story />,
96
- parameters: {
97
- translations,
98
- },
99
- };
100
-
101
91
  const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
102
92
  const identity = useIdentity();
103
93
  const space = useSpace(spaceKey);
@@ -105,8 +95,9 @@ const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
105
95
  const objects = useQuery(space, Query.type(Type.Expando, { type: 'test' }));
106
96
 
107
97
  useEffect(() => {
108
- if (!source && objects.length) {
109
- const source = createDocAccessor(objects[0].content, ['content']);
98
+ const content = objects[0]?.content.target;
99
+ if (!source && content) {
100
+ const source = createDocAccessor(content, ['content']);
110
101
  setSource(source);
111
102
  }
112
103
  }, [objects, source]);
@@ -118,17 +109,33 @@ const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
118
109
  return <Editor source={source} space={space} identity={identity ?? undefined} />;
119
110
  };
120
111
 
121
- export const Default = {};
122
-
123
- export const WithEcho = {
112
+ const meta = {
113
+ title: 'ui/react-ui-editor/Automerge',
114
+ component: Editor as any,
115
+ render: render(DefaultStory),
124
116
  decorators: [withTheme],
117
+ parameters: {
118
+ layout: 'fullscreen',
119
+ translations,
120
+ },
121
+ } satisfies Meta<typeof DefaultStory>;
122
+
123
+ export default meta;
124
+
125
+ type Story = StoryObj<typeof meta>;
126
+
127
+ export const Default: Story = {
128
+ args: {},
129
+ };
130
+
131
+ export const WithEcho: Story = {
125
132
  render: () => {
126
133
  return (
127
134
  <ClientRepeater
128
135
  count={2}
129
136
  component={EchoStory}
130
137
  createSpace
131
- onSpaceCreated={async ({ space }) => {
138
+ onCreateSpace={async ({ space }) => {
132
139
  space.db.add(
133
140
  Obj.make(Type.Expando, {
134
141
  type: 'test',
@@ -5,23 +5,27 @@
5
5
  //
6
6
 
7
7
  import { next as A } from '@automerge/automerge';
8
- import { StateField, type Extension } from '@codemirror/state';
8
+ import { type Extension, StateField, Transaction } from '@codemirror/state';
9
9
  import { EditorView, ViewPlugin } from '@codemirror/view';
10
10
 
11
- import { type DocAccessor } from '@dxos/react-client/echo';
11
+ import { DocAccessor } from '@dxos/react-client/echo';
12
+
13
+ import { Cursor } from '../../util';
14
+ import { initialSync } from '../state';
12
15
 
13
16
  import { cursorConverter } from './cursor';
14
- import { updateHeadsEffect, isReconcile, type State } from './defs';
17
+ import { type State, isReconcile, updateHeadsEffect } from './defs';
15
18
  import { Syncer } from './sync';
16
- import { Cursor } from '../../util';
17
19
 
18
20
  export const automerge = (accessor: DocAccessor): Extension => {
19
21
  const syncState = StateField.define<State>({
20
- create: () => ({
21
- path: accessor.path.slice(),
22
- lastHeads: A.getHeads(accessor.handle.doc()!),
23
- unreconciledTransactions: [],
24
- }),
22
+ create: () => {
23
+ return {
24
+ path: accessor.path.slice(),
25
+ lastHeads: A.getHeads(accessor.handle.doc()!),
26
+ unreconciledTransactions: [],
27
+ };
28
+ },
25
29
 
26
30
  update: (value, tr) => {
27
31
  const result: State = {
@@ -63,6 +67,18 @@ export const automerge = (accessor: DocAccessor): Extension => {
63
67
  class {
64
68
  constructor(private readonly _view: EditorView) {
65
69
  accessor.handle.addListener('change', this._handleChange);
70
+
71
+ requestAnimationFrame(() => {
72
+ const value = DocAccessor.getValue<string>(accessor);
73
+ const current = this._view.state.doc.toString();
74
+ if (value !== current) {
75
+ // TODO(burdon): This attempts to set the initial state, but creates problems.
76
+ // this._view.dispatch({
77
+ // changes: { from: 0, to: this._view.state.doc.length, insert: value },
78
+ // annotations: initialSync,
79
+ // });
80
+ }
81
+ });
66
82
  }
67
83
 
68
84
  destroy() {
@@ -76,9 +92,13 @@ export const automerge = (accessor: DocAccessor): Extension => {
76
92
  ),
77
93
 
78
94
  // Reconcile local updates.
79
- EditorView.updateListener.of(({ view, changes }) => {
95
+ EditorView.updateListener.of(({ view, changes, transactions }) => {
80
96
  if (!changes.empty) {
81
- syncer.reconcile(view, true);
97
+ // Only reconcile if it's not an initial sync (to avoid loops)
98
+ const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
99
+ if (!isInitialSync) {
100
+ syncer.reconcile(view, true);
101
+ }
82
102
  }
83
103
  }),
84
104
  ];
@@ -5,7 +5,7 @@
5
5
  //
6
6
 
7
7
  import { type Heads, type Prop } from '@automerge/automerge';
8
- import { Annotation, StateEffect, type StateField, type EditorState, type Transaction } from '@codemirror/state';
8
+ import { Annotation, type EditorState, StateEffect, type StateField, type Transaction } from '@codemirror/state';
9
9
 
10
10
  export type State = {
11
11
  path: Prop[];
@@ -8,9 +8,10 @@ import { next as A } from '@automerge/automerge';
8
8
  import { type StateField } from '@codemirror/state';
9
9
  import { type EditorView } from '@codemirror/view';
10
10
 
11
+ import { log } from '@dxos/log';
11
12
  import { type IDocHandle } from '@dxos/react-client/echo';
12
13
 
13
- import { getLastHeads, getPath, isReconcile, reconcileAnnotation, type State, updateHeads } from './defs';
14
+ import { type State, getLastHeads, getPath, isReconcile, reconcileAnnotation, updateHeads } from './defs';
14
15
  import { updateAutomerge } from './update-automerge';
15
16
  import { updateCodeMirror } from './update-codemirror';
16
17
 
@@ -27,7 +28,6 @@ export class Syncer {
27
28
  ) {}
28
29
 
29
30
  reconcile(view: EditorView, editor: boolean): void {
30
- // TODO(burdon): Better way to do mutex?
31
31
  if (this._pending) {
32
32
  return;
33
33
  }
@@ -41,7 +41,9 @@ export class Syncer {
41
41
  this._pending = false;
42
42
  }
43
43
 
44
- onEditorChange(view: EditorView): void {
44
+ private onEditorChange(view: EditorView): void {
45
+ log('onEditorChange');
46
+
45
47
  // Apply the unreconciled transactions to the document.
46
48
  const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
47
49
  const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
@@ -54,7 +56,9 @@ export class Syncer {
54
56
  }
55
57
  }
56
58
 
57
- onAutomergeChange(view: EditorView): void {
59
+ private onAutomergeChange(view: EditorView): void {
60
+ log('onAutomergeChange');
61
+
58
62
  // Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
59
63
  const oldHeads = getLastHeads(view.state, this._state);
60
64
  const newHeads = A.getHeads(this._handle.doc()!);
@@ -5,7 +5,7 @@
5
5
  //
6
6
 
7
7
  import { next as A, type Heads } from '@automerge/automerge';
8
- import { type EditorState, type StateField, type Transaction, type Text } from '@codemirror/state';
8
+ import { type EditorState, type StateField, type Text, type Transaction } from '@codemirror/state';
9
9
 
10
10
  import { type IDocHandle } from '@dxos/react-client/echo';
11
11
 
@@ -0,0 +1,157 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { StateEffect } from '@codemirror/state';
6
+ import { EditorView, ViewPlugin } from '@codemirror/view';
7
+
8
+ import { Domino } from '@dxos/react-ui';
9
+
10
+ const lineHeight = 24;
11
+
12
+ export const scrollToBottomEffect = StateEffect.define<any>();
13
+
14
+ export type AutoScrollOptions = {
15
+ overscroll?: number;
16
+ throttle?: number;
17
+ };
18
+
19
+ /**
20
+ * Extension that supports pinning the scroll position and automatically scrolls to the bottom when content is added.
21
+ */
22
+ // TODO(burdon): Reconcile with transcript-extension.
23
+ export const autoScroll = ({ overscroll = 4 * lineHeight, throttle = 2_000 }: Partial<AutoScrollOptions> = {}) => {
24
+ let isThrottled = false;
25
+ let isPinned = true;
26
+ let timeout: NodeJS.Timeout | undefined;
27
+ let buttonContainer: HTMLDivElement | undefined;
28
+ let lastScrollTop = 0;
29
+ let scrollCounter = 0;
30
+
31
+ const hideScrollbar = (view: EditorView) => {
32
+ view.scrollDOM.classList.add('cm-hide-scrollbar');
33
+ clearTimeout(timeout);
34
+ timeout = setTimeout(() => {
35
+ view.scrollDOM.classList.remove('cm-hide-scrollbar');
36
+ }, 1_000);
37
+ };
38
+
39
+ const scrollToBottom = (view: EditorView) => {
40
+ isPinned = true;
41
+ scrollCounter = 0;
42
+ buttonContainer?.classList.add('opacity-0');
43
+ requestAnimationFrame(() => {
44
+ hideScrollbar(view);
45
+ view.scrollDOM.scrollTo({
46
+ top: view.scrollDOM.scrollHeight,
47
+ behavior: 'smooth',
48
+ });
49
+ });
50
+ };
51
+
52
+ return [
53
+ // Update listener for logging when scrolling is needed.
54
+ EditorView.updateListener.of((update) => {
55
+ // Listen for effects.
56
+ update.transactions.forEach((transaction) => {
57
+ for (const effect of transaction.effects) {
58
+ if (effect.is(scrollToBottomEffect)) {
59
+ scrollToBottom(update.view);
60
+ }
61
+ }
62
+ });
63
+
64
+ // Maybe scroll if doc changed and pinned.
65
+ if (update.docChanged && isPinned && !isThrottled) {
66
+ const distanceFromBottom = calcDistance(update.view.scrollDOM);
67
+ if (distanceFromBottom >= overscroll) {
68
+ isThrottled = true;
69
+ requestAnimationFrame(() => {
70
+ scrollToBottom(update.view);
71
+ });
72
+
73
+ // Reset throttle.
74
+ setTimeout(() => {
75
+ isThrottled = false;
76
+ scrollToBottom(update.view);
77
+ }, throttle);
78
+ }
79
+ }
80
+ }),
81
+
82
+ // Detect user scroll.
83
+ // NOTE: Multiple scroll events are triggered during programmatic smooth scrolling.
84
+ EditorView.domEventHandlers({
85
+ scroll: (event, view) => {
86
+ const scroller = view.scrollDOM;
87
+ // Suspect delta goes positive when rendering widgets, so count positive deltas.
88
+ // TODO(burdon): Detect user scroll directly (wheel, touch, keys, etc.)
89
+ if (lastScrollTop > scroller.scrollTop) {
90
+ scrollCounter++;
91
+ }
92
+ lastScrollTop = scroller.scrollTop;
93
+ const distanceFromBottom = calcDistance(scroller);
94
+ if (distanceFromBottom === 0) {
95
+ // Pin to bottom.
96
+ isPinned = true;
97
+ buttonContainer?.classList.add('opacity-0');
98
+ scrollCounter = 0;
99
+ } else if (scrollCounter > 3) {
100
+ // Break pin if user scrolls up.
101
+ isPinned = false;
102
+ buttonContainer?.classList.remove('opacity-0');
103
+ }
104
+ },
105
+ }),
106
+
107
+ // Scroll button.
108
+ ViewPlugin.fromClass(
109
+ class {
110
+ constructor(view: EditorView) {
111
+ const scroller = view.scrollDOM.parentElement;
112
+ buttonContainer = Domino.of('div')
113
+ .classNames(true && 'cm-scroll-button transition-opacity duration-300 opacity-0')
114
+ .children(
115
+ Domino.of('button')
116
+ .classNames('dx-button bg-accentSurface')
117
+ .data('density', 'fine')
118
+ .children(Domino.of<any>('dx-icon').attributes({ icon: 'ph--arrow-down--regular' }))
119
+ .on('click', () => {
120
+ scrollToBottom(view);
121
+ }),
122
+ )
123
+ .build();
124
+ scroller?.appendChild(buttonContainer);
125
+ }
126
+ },
127
+ ),
128
+
129
+ // Styles.
130
+ EditorView.theme({
131
+ '.cm-scroller': {
132
+ paddingBottom: `${overscroll}px`,
133
+ scrollbarWidth: 'thin',
134
+ },
135
+ '.cm-scroller.cm-hide-scrollbar': {
136
+ scrollbarWidth: 'none',
137
+ },
138
+ '.cm-scroller.cm-hide-scrollbar::-webkit-scrollbar': {
139
+ display: 'none',
140
+ },
141
+
142
+ '.cm-scroll-button': {
143
+ position: 'absolute',
144
+ bottom: '0.5rem',
145
+ right: '1rem',
146
+ },
147
+ }),
148
+ ];
149
+ };
150
+
151
+ const calcDistance = (scroller: HTMLElement) => {
152
+ const scrollTop = scroller.scrollTop;
153
+ const scrollHeight = scroller.scrollHeight;
154
+ const clientHeight = scroller.clientHeight;
155
+ const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
156
+ return distanceFromBottom;
157
+ };
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Annotation, type Extension, RangeSet, type Range } from '@codemirror/state';
5
+ import { Annotation, type Extension, type Range, RangeSet } from '@codemirror/state';
6
6
  import {
7
7
  Decoration,
8
8
  type DecorationSet,
@@ -16,7 +16,7 @@ import {
16
16
  import { Event } from '@dxos/async';
17
17
  import { Context } from '@dxos/context';
18
18
 
19
- import { singleValueFacet, Cursor, type CursorConverter } from '../../util';
19
+ import { Cursor, type CursorConverter, singleValueFacet } from '../../util';
20
20
 
21
21
  export interface AwarenessProvider {
22
22
  remoteStateChange: Event<void>;
@@ -5,25 +5,26 @@
5
5
  import { invertedEffects } from '@codemirror/commands';
6
6
  import { type ChangeDesc, type Extension, StateEffect, StateField, type Text } from '@codemirror/state';
7
7
  import {
8
- hoverTooltip,
9
- keymap,
10
8
  type Command,
11
9
  Decoration,
12
10
  EditorView,
13
- type Rect,
14
11
  type PluginValue,
12
+ type Rect,
15
13
  ViewPlugin,
14
+ hoverTooltip,
15
+ keymap,
16
16
  } from '@codemirror/view';
17
17
  import sortBy from 'lodash.sortby';
18
18
  import { useEffect } from 'react';
19
19
 
20
- import { debounce, type CleanupFn } from '@dxos/async';
20
+ import { type CleanupFn, debounce } from '@dxos/async';
21
21
  import { log } from '@dxos/log';
22
22
  import { isNonNullable } from '@dxos/util';
23
23
 
24
+ import { type Comment, type Range, type RenderCallback } from '../types';
25
+ import { Cursor, callbackWrapper, singleValueFacet } from '../util';
26
+
24
27
  import { documentId } from './selection';
25
- import { type RenderCallback, type Comment, type Range } from '../types';
26
- import { Cursor, singleValueFacet, callbackWrapper } from '../util';
27
28
 
28
29
  //
29
30
  // State management.
@@ -57,7 +58,11 @@ const setCommentState = StateEffect.define<CommentsState>();
57
58
  * The ranges are tracked as Automerge cursors from which the absolute indexed ranges can be computed.
58
59
  */
59
60
  export const commentsState = StateField.define<CommentsState>({
60
- create: (state) => ({ id: state.facet(documentId), comments: [], selection: {} }),
61
+ create: (state) => ({
62
+ id: state.facet(documentId),
63
+ comments: [],
64
+ selection: {},
65
+ }),
61
66
  update: (value, tr) => {
62
67
  for (const effect of tr.effects) {
63
68
  // Update selection.
@@ -98,16 +103,16 @@ export const commentsState = StateField.define<CommentsState>({
98
103
  */
99
104
  const styles = EditorView.theme({
100
105
  '.cm-comment, .cm-comment-current': {
101
- margin: '0 -3px',
102
- padding: '3px',
103
- borderRadius: '3px',
106
+ padding: '3px 0',
107
+ backgroundColor: 'var(--dx-cmCommentSurface)',
108
+ },
109
+ '.cm-comment > span, .cm-comment-current > span': {
110
+ boxDecorationBreak: 'clone',
111
+ boxShadow: '0 0 1px 3px var(--dx-cmCommentSurface)',
104
112
  backgroundColor: 'var(--dx-cmCommentSurface)',
105
113
  color: 'var(--dx-cmComment)',
106
114
  cursor: 'pointer',
107
115
  },
108
- '.cm-comment:hover, .cm-comment-current': {
109
- textDecoration: 'underline',
110
- },
111
116
  });
112
117
 
113
118
  const createCommentMark = (id: string, isCurrent: boolean) =>
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import type { Extension } from '@codemirror/state';
6
- import { dropCursor, EditorView } from '@codemirror/view';
6
+ import { EditorView, dropCursor } from '@codemirror/view';
7
7
 
8
8
  export type DNDOptions = { onDrop?: (view: EditorView, event: { files: FileList }) => void };
9
9
 
@@ -4,10 +4,9 @@
4
4
 
5
5
  import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
6
6
  import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';
7
- import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
7
+ import { HighlightStyle, bracketMatching, syntaxHighlighting } from '@codemirror/language';
8
8
  import { searchKeymap } from '@codemirror/search';
9
- import { EditorState, type Extension } from '@codemirror/state';
10
- import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
9
+ import { type ChangeSpec, EditorState, type Extension, type TransactionSpec } from '@codemirror/state';
11
10
  import {
12
11
  EditorView,
13
12
  type KeyBinding,
@@ -20,6 +19,7 @@ import {
20
19
  placeholder,
21
20
  scrollPastEnd,
22
21
  } from '@codemirror/view';
22
+ import { vscodeDarkStyle, vscodeLightStyle } from '@uiw/codemirror-theme-vscode';
23
23
  import defaultsDeep from 'lodash.defaultsdeep';
24
24
  import merge from 'lodash.merge';
25
25
 
@@ -29,24 +29,48 @@ import { type DocAccessor, type Space } from '@dxos/react-client/echo';
29
29
  import { type Identity } from '@dxos/react-client/halo';
30
30
  import { type ThemeMode } from '@dxos/react-ui';
31
31
  import { type HuePalette } from '@dxos/react-ui-theme';
32
- import { hexToHue, isNotFalsy } from '@dxos/util';
32
+ import { hexToHue, isTruthy } from '@dxos/util';
33
+
34
+ import { editorGutter, editorMonospace } from '../defaults';
35
+ import { type ThemeStyles, defaultTheme } from '../styles';
33
36
 
34
37
  import { automerge } from './automerge';
35
38
  import { SpaceAwarenessProvider, awareness } from './awareness';
36
39
  import { focus } from './focus';
37
- import { editorGutter, editorMonospace } from '../defaults';
38
- import { type ThemeStyles, defaultTheme } from '../styles';
39
40
 
40
41
  //
41
42
  // Basic
42
43
  //
43
44
 
44
- export const preventNewline = EditorState.transactionFilter.of((tr) => (tr.newDoc.lines > 1 ? [] : tr));
45
+ export const filterChars = (chars: RegExp) => {
46
+ return EditorState.transactionFilter.of((transaction) => {
47
+ if (!transaction.docChanged) return transaction;
48
+
49
+ const changes: ChangeSpec[] = [];
50
+ transaction.changes.iterChanges((fromA, toA, fromB, toB, text) => {
51
+ const inserted = text.toString();
52
+ const filtered = inserted.replace(chars, '');
53
+ if (inserted !== filtered) {
54
+ changes.push({
55
+ from: fromB,
56
+ to: toB,
57
+ insert: filtered,
58
+ });
59
+ }
60
+ });
61
+
62
+ if (changes.length) {
63
+ return [transaction, { changes, sequential: true } as TransactionSpec];
64
+ }
65
+ return transaction;
66
+ });
67
+ };
45
68
 
46
69
  /**
47
70
  * https://codemirror.net/docs/extensions
48
71
  * https://github.com/codemirror/basic-setup
49
72
  * https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts
73
+ * https://github.com/codemirror/theme-one-dark
50
74
  */
51
75
  export type BasicExtensionsOptions = {
52
76
  allowMultipleSelections?: boolean;
@@ -68,6 +92,7 @@ export type BasicExtensionsOptions = {
68
92
  /** If true user cannot edit the text, but they can still select and copy it. */
69
93
  readOnly?: boolean;
70
94
  search?: boolean;
95
+ /** NOTE: Do not use with stack sections. */
71
96
  scrollPastEnd?: boolean;
72
97
  standardKeymap?: boolean;
73
98
  tabSize?: number;
@@ -82,7 +107,7 @@ const defaultBasicOptions: BasicExtensionsOptions = {
82
107
  history: true,
83
108
  keymap: 'standard',
84
109
  lineWrapping: true,
85
- search: true,
110
+ search: false,
86
111
  } as const;
87
112
 
88
113
  const keymaps: { [key: string]: readonly KeyBinding[] } = {
@@ -137,9 +162,9 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
137
162
  preventDefault: true,
138
163
  run: () => true,
139
164
  },
140
- ].filter(isNotFalsy),
165
+ ].filter(isTruthy),
141
166
  ),
142
- ].filter(isNotFalsy);
167
+ ].filter(isTruthy);
143
168
  };
144
169
 
145
170
  //
@@ -157,9 +182,6 @@ export type ThemeExtensionsOptions = {
157
182
  scroll?: {
158
183
  className?: string;
159
184
  };
160
- scroller?: {
161
- className?: string;
162
- };
163
185
  content?: {
164
186
  className?: string;
165
187
  };
@@ -180,41 +202,37 @@ export const fullWidth: ThemeExtensionsOptions['slots'] = {
180
202
 
181
203
  export const defaultThemeSlots = grow;
182
204
 
205
+ export const defaultStyles = {
206
+ dark: vscodeDarkStyle,
207
+ light: vscodeLightStyle,
208
+ };
209
+
183
210
  /**
184
211
  * https://codemirror.net/examples/styling
185
212
  */
186
213
  export const createThemeExtensions = ({
187
214
  themeMode,
188
215
  styles,
189
- syntaxHighlighting: _syntaxHighlighting,
190
- slots: _slots,
216
+ syntaxHighlighting: syntaxHighlightingProp,
217
+ slots: slotsParam,
191
218
  }: ThemeExtensionsOptions = {}): Extension => {
192
- const slots = defaultsDeep({}, _slots, defaultThemeSlots);
219
+ const slots = defaultsDeep({}, slotsParam, defaultThemeSlots);
193
220
  return [
194
221
  EditorView.darkTheme.of(themeMode === 'dark'),
195
222
  EditorView.baseTheme(styles ? merge({}, defaultTheme, styles) : defaultTheme),
196
- // https://github.com/codemirror/theme-one-dark
197
- _syntaxHighlighting &&
198
- (themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
223
+ syntaxHighlightingProp &&
224
+ syntaxHighlighting(HighlightStyle.define(themeMode === 'dark' ? defaultStyles.dark : defaultStyles.light)),
199
225
  slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
200
226
  slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
201
227
  slots.scroll?.className &&
202
228
  ViewPlugin.fromClass(
203
229
  class {
204
230
  constructor(view: EditorView) {
205
- view.scrollDOM.classList.add(slots.scroll.className);
206
- }
207
- },
208
- ),
209
- slots.scroller?.className &&
210
- ViewPlugin.fromClass(
211
- class {
212
- constructor(view: EditorView) {
213
- view.dom.querySelector('.cm-scroller')?.classList.add(...slots.scroller.className.split(' '));
231
+ view.scrollDOM.classList.add(...slots.scroll.className.split(/\s+/));
214
232
  }
215
233
  },
216
234
  ),
217
- ].filter(isNotFalsy);
235
+ ].filter(isTruthy);
218
236
  };
219
237
 
220
238
  //
@@ -238,7 +256,6 @@ export const createDataExtensions = <T>({ id, text, space, identity }: DataExten
238
256
  if (space && identity) {
239
257
  const peerId = identity?.identityKey.toHex();
240
258
  const hue = (identity?.profile?.data?.hue as HuePalette | undefined) ?? hexToHue(peerId ?? '0');
241
-
242
259
  extensions.push(
243
260
  awareness(
244
261
  new SpaceAwarenessProvider({
@@ -246,9 +263,9 @@ export const createDataExtensions = <T>({ id, text, space, identity }: DataExten
246
263
  channel: `awareness.${id}`,
247
264
  peerId: identity.identityKey.toHex(),
248
265
  info: {
249
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
250
266
  darkColor: `var(--dx-${hue}Cursor)`,
251
267
  lightColor: `var(--dx-${hue}Cursor)`,
268
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
252
269
  },
253
270
  }),
254
271
  ),