@dxos/react-ui-editor 0.8.4-main.67995b8 → 0.8.4-main.a4bbb77

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 (261) hide show
  1. package/dist/lib/browser/index.mjs +3067 -1955
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +71 -1
  5. package/dist/lib/browser/testing/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/index.mjs +3067 -1955
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/testing/index.mjs +71 -1
  10. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  11. package/dist/types/src/components/{Popover → CommandMenu}/CommandMenu.d.ts +10 -6
  12. package/dist/types/src/components/CommandMenu/CommandMenu.d.ts.map +1 -0
  13. package/dist/types/src/components/CommandMenu/index.d.ts +2 -0
  14. package/dist/types/src/components/CommandMenu/index.d.ts.map +1 -0
  15. package/dist/types/src/components/Editor/Editor.d.ts +15 -9
  16. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  17. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  18. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  19. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  20. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  21. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  22. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  23. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  24. package/dist/types/src/components/EditorToolbar/util.d.ts +5 -5
  25. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  26. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -1
  27. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  28. package/dist/types/src/components/index.d.ts +1 -1
  29. package/dist/types/src/components/index.d.ts.map +1 -1
  30. package/dist/types/src/defaults.d.ts.map +1 -1
  31. package/dist/types/src/extensions/autocomplete.d.ts +20 -7
  32. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  33. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  34. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +10 -19
  35. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  36. package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
  37. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  38. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  39. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  40. package/dist/types/src/extensions/autoscroll.d.ts +10 -0
  41. package/dist/types/src/extensions/autoscroll.d.ts.map +1 -0
  42. package/dist/types/src/extensions/{command → command-dialog}/action.d.ts +1 -1
  43. package/dist/types/src/extensions/command-dialog/action.d.ts.map +1 -0
  44. package/dist/types/src/extensions/{command/command.d.ts → command-dialog/command-dialog.d.ts} +2 -2
  45. package/dist/types/src/extensions/command-dialog/command-dialog.d.ts.map +1 -0
  46. package/dist/types/src/extensions/{command → command-dialog}/hint.d.ts +2 -7
  47. package/dist/types/src/extensions/command-dialog/hint.d.ts.map +1 -0
  48. package/dist/types/src/extensions/command-dialog/index.d.ts +4 -0
  49. package/dist/types/src/extensions/command-dialog/index.d.ts.map +1 -0
  50. package/dist/types/src/extensions/{command → command-dialog}/state.d.ts +1 -1
  51. package/dist/types/src/extensions/command-dialog/state.d.ts.map +1 -0
  52. package/dist/types/src/extensions/command-dialog/typeahead.d.ts.map +1 -0
  53. package/dist/types/src/extensions/{command → command-menu}/command-menu.d.ts +3 -3
  54. package/dist/types/src/extensions/command-menu/command-menu.d.ts.map +1 -0
  55. package/dist/types/src/extensions/command-menu/index.d.ts +3 -0
  56. package/dist/types/src/extensions/command-menu/index.d.ts.map +1 -0
  57. package/dist/types/src/extensions/command-menu/placeholder.d.ts.map +1 -0
  58. package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts +24 -0
  59. package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts.map +1 -0
  60. package/dist/types/src/extensions/comments.d.ts +1 -1
  61. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  62. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  63. package/dist/types/src/extensions/factories.d.ts +3 -8
  64. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  65. package/dist/types/src/extensions/floating-menu.d.ts.map +1 -0
  66. package/dist/types/src/extensions/focus.d.ts.map +1 -1
  67. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  68. package/dist/types/src/extensions/index.d.ts +5 -1
  69. package/dist/types/src/extensions/index.d.ts.map +1 -1
  70. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  71. package/dist/types/src/extensions/markdown/bundle.d.ts +8 -2
  72. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  73. package/dist/types/src/extensions/markdown/changes.d.ts +1 -1
  74. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  75. package/dist/types/src/extensions/markdown/decorate.d.ts +9 -1
  76. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  77. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  78. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  79. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  80. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  81. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  82. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  83. package/dist/types/src/extensions/outliner/outliner.d.ts +1 -1
  84. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  85. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  86. package/dist/types/src/extensions/outliner/tree.d.ts +2 -2
  87. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  88. package/dist/types/src/extensions/preview/preview.d.ts +3 -6
  89. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  90. package/dist/types/src/extensions/tags/extended-markdown.d.ts +10 -0
  91. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -0
  92. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts +2 -0
  93. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +1 -0
  94. package/dist/types/src/extensions/tags/index.d.ts +4 -0
  95. package/dist/types/src/extensions/tags/index.d.ts.map +1 -0
  96. package/dist/types/src/extensions/tags/streamer.d.ts +12 -0
  97. package/dist/types/src/extensions/tags/streamer.d.ts.map +1 -0
  98. package/dist/types/src/extensions/tags/xml-tags.d.ts +72 -0
  99. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -0
  100. package/dist/types/src/extensions/tags/xml-util.d.ts +10 -0
  101. package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -0
  102. package/dist/types/src/hooks/useTextEditor.d.ts +2 -2
  103. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  104. package/dist/types/src/stories/CommandDialog.stories.d.ts +14 -0
  105. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -0
  106. package/dist/types/src/stories/CommandMenu.stories.d.ts +10 -4
  107. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +1 -1
  108. package/dist/types/src/stories/Comments.stories.d.ts +21 -10
  109. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  110. package/dist/types/src/stories/EditorToolbar.stories.d.ts +39 -3
  111. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  112. package/dist/types/src/stories/Experimental.stories.d.ts +22 -13
  113. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  114. package/dist/types/src/stories/Markdown.stories.d.ts +32 -43
  115. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  116. package/dist/types/src/stories/Outliner.stories.d.ts +15 -21
  117. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  118. package/dist/types/src/stories/Preview.stories.d.ts +21 -7
  119. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  120. package/dist/types/src/stories/Tags.stories.d.ts +16 -0
  121. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -0
  122. package/dist/types/src/stories/TextEditor.stories.d.ts +38 -52
  123. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  124. package/dist/types/src/stories/components/EditorStory.d.ts +5 -8
  125. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  126. package/dist/types/src/styles/theme.d.ts.map +1 -1
  127. package/dist/types/src/testing/PreviewPopover.d.ts +20 -0
  128. package/dist/types/src/testing/PreviewPopover.d.ts.map +1 -0
  129. package/dist/types/src/testing/index.d.ts +1 -0
  130. package/dist/types/src/testing/index.d.ts.map +1 -1
  131. package/dist/types/src/testing/util.d.ts +1 -0
  132. package/dist/types/src/testing/util.d.ts.map +1 -1
  133. package/dist/types/src/translations.d.ts +1 -1
  134. package/dist/types/src/types/types.d.ts +1 -1
  135. package/dist/types/src/util/cursor.d.ts.map +1 -1
  136. package/dist/types/src/util/debug.d.ts +1 -1
  137. package/dist/types/src/util/debug.d.ts.map +1 -1
  138. package/dist/types/src/util/decorations.d.ts +4 -0
  139. package/dist/types/src/util/decorations.d.ts.map +1 -0
  140. package/dist/types/src/util/dom.d.ts +2 -12
  141. package/dist/types/src/util/dom.d.ts.map +1 -1
  142. package/dist/types/src/util/index.d.ts +1 -0
  143. package/dist/types/src/util/index.d.ts.map +1 -1
  144. package/dist/types/src/util/react.d.ts +1 -1
  145. package/dist/types/src/util/react.d.ts.map +1 -1
  146. package/dist/types/tsconfig.tsbuildinfo +1 -1
  147. package/package.json +70 -66
  148. package/src/components/{Popover → CommandMenu}/CommandMenu.tsx +95 -26
  149. package/src/components/{Popover → CommandMenu}/index.ts +0 -2
  150. package/src/components/Editor/Editor.tsx +50 -15
  151. package/src/components/EditorToolbar/EditorToolbar.tsx +40 -30
  152. package/src/components/EditorToolbar/blocks.ts +21 -24
  153. package/src/components/EditorToolbar/formatting.ts +22 -25
  154. package/src/components/EditorToolbar/headings.ts +10 -5
  155. package/src/components/EditorToolbar/image.ts +8 -4
  156. package/src/components/EditorToolbar/lists.ts +16 -19
  157. package/src/components/EditorToolbar/search.ts +8 -4
  158. package/src/components/EditorToolbar/util.ts +16 -5
  159. package/src/components/EditorToolbar/view-mode.ts +11 -6
  160. package/src/components/index.ts +1 -1
  161. package/src/defaults.ts +5 -2
  162. package/src/extensions/autocomplete.ts +204 -54
  163. package/src/extensions/automerge/automerge.stories.tsx +31 -24
  164. package/src/extensions/automerge/automerge.ts +4 -3
  165. package/src/extensions/automerge/defs.ts +1 -1
  166. package/src/extensions/automerge/sync.ts +1 -1
  167. package/src/extensions/automerge/update-automerge.ts +1 -1
  168. package/src/extensions/autoscroll.ts +157 -0
  169. package/src/extensions/awareness/awareness.ts +2 -2
  170. package/src/extensions/{command → command-dialog}/action.ts +2 -3
  171. package/src/extensions/{command/command.ts → command-dialog/command-dialog.ts} +4 -4
  172. package/src/extensions/{command → command-dialog}/hint.ts +2 -1
  173. package/src/extensions/command-dialog/index.ts +7 -0
  174. package/src/extensions/{command → command-dialog}/state.ts +4 -3
  175. package/src/extensions/{command → command-dialog}/typeahead.ts +2 -2
  176. package/src/extensions/{command → command-menu}/command-menu.ts +9 -9
  177. package/src/extensions/command-menu/index.ts +6 -0
  178. package/src/extensions/{command → command-menu}/placeholder.ts +1 -1
  179. package/src/extensions/{command → command-menu}/useCommandMenu.ts +35 -19
  180. package/src/extensions/comments.ts +18 -13
  181. package/src/extensions/dnd.ts +1 -1
  182. package/src/extensions/factories.ts +37 -27
  183. package/src/extensions/{command/floating-menu.ts → floating-menu.ts} +12 -19
  184. package/src/extensions/focus.ts +5 -4
  185. package/src/extensions/folding.tsx +4 -6
  186. package/src/extensions/index.ts +5 -1
  187. package/src/extensions/markdown/action.ts +2 -1
  188. package/src/extensions/markdown/bundle.ts +27 -5
  189. package/src/extensions/markdown/changes.ts +1 -1
  190. package/src/extensions/markdown/decorate.ts +24 -14
  191. package/src/extensions/markdown/formatting.test.ts +6 -6
  192. package/src/extensions/markdown/formatting.ts +3 -3
  193. package/src/extensions/markdown/highlight.ts +1 -1
  194. package/src/extensions/markdown/image.ts +3 -4
  195. package/src/extensions/markdown/link.ts +3 -0
  196. package/src/extensions/markdown/table.ts +7 -1
  197. package/src/extensions/mention.ts +1 -1
  198. package/src/extensions/outliner/outliner.test.ts +3 -2
  199. package/src/extensions/outliner/outliner.ts +6 -5
  200. package/src/extensions/outliner/selection.ts +1 -1
  201. package/src/extensions/outliner/tree.test.ts +2 -1
  202. package/src/extensions/outliner/tree.ts +2 -2
  203. package/src/extensions/preview/preview.ts +59 -62
  204. package/src/extensions/selection.ts +2 -2
  205. package/src/extensions/tags/extended-markdown.test.ts +261 -0
  206. package/src/extensions/tags/extended-markdown.ts +78 -0
  207. package/src/extensions/tags/index.ts +7 -0
  208. package/src/extensions/tags/streamer.ts +243 -0
  209. package/src/extensions/tags/xml-tags.ts +393 -0
  210. package/src/extensions/tags/xml-util.ts +94 -0
  211. package/src/hooks/useTextEditor.ts +8 -20
  212. package/src/stories/CommandDialog.stories.tsx +89 -0
  213. package/src/stories/CommandMenu.stories.tsx +33 -34
  214. package/src/stories/Comments.stories.tsx +14 -10
  215. package/src/stories/EditorToolbar.stories.tsx +13 -12
  216. package/src/stories/Experimental.stories.tsx +17 -13
  217. package/src/stories/Markdown.stories.tsx +25 -21
  218. package/src/stories/Outliner.stories.tsx +46 -34
  219. package/src/stories/Preview.stories.tsx +34 -33
  220. package/src/stories/Tags.stories.tsx +81 -0
  221. package/src/stories/TextEditor.stories.tsx +45 -38
  222. package/src/stories/components/EditorStory.tsx +12 -13
  223. package/src/styles/theme.ts +15 -12
  224. package/src/testing/PreviewPopover.tsx +78 -0
  225. package/src/testing/index.ts +1 -0
  226. package/src/testing/util.ts +2 -0
  227. package/src/translations.ts +1 -1
  228. package/src/util/cursor.ts +2 -1
  229. package/src/util/debug.ts +2 -2
  230. package/src/util/decorations.ts +21 -0
  231. package/src/util/dom.ts +5 -27
  232. package/src/util/index.ts +1 -0
  233. package/src/util/react.tsx +1 -1
  234. package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
  235. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -21
  236. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
  237. package/dist/types/src/components/Popover/RefPopover.d.ts +0 -34
  238. package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
  239. package/dist/types/src/components/Popover/index.d.ts +0 -4
  240. package/dist/types/src/components/Popover/index.d.ts.map +0 -1
  241. package/dist/types/src/extensions/command/action.d.ts.map +0 -1
  242. package/dist/types/src/extensions/command/command-menu.d.ts.map +0 -1
  243. package/dist/types/src/extensions/command/command.d.ts.map +0 -1
  244. package/dist/types/src/extensions/command/floating-menu.d.ts.map +0 -1
  245. package/dist/types/src/extensions/command/hint.d.ts.map +0 -1
  246. package/dist/types/src/extensions/command/index.d.ts +0 -7
  247. package/dist/types/src/extensions/command/index.d.ts.map +0 -1
  248. package/dist/types/src/extensions/command/placeholder.d.ts.map +0 -1
  249. package/dist/types/src/extensions/command/state.d.ts.map +0 -1
  250. package/dist/types/src/extensions/command/typeahead.d.ts.map +0 -1
  251. package/dist/types/src/extensions/command/useCommandMenu.d.ts +0 -26
  252. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +0 -1
  253. package/dist/types/src/stories/Command.stories.d.ts +0 -7
  254. package/dist/types/src/stories/Command.stories.d.ts.map +0 -1
  255. package/src/components/Popover/RefDropdownMenu.tsx +0 -85
  256. package/src/components/Popover/RefPopover.tsx +0 -99
  257. package/src/extensions/command/index.ts +0 -10
  258. package/src/stories/Command.stories.tsx +0 -97
  259. /package/dist/types/src/extensions/{command → command-dialog}/typeahead.d.ts +0 -0
  260. /package/dist/types/src/extensions/{command → command-menu}/placeholder.d.ts +0 -0
  261. /package/dist/types/src/extensions/{command/floating-menu.d.ts → floating-menu.d.ts} +0 -0
@@ -6,7 +6,7 @@ import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
6
6
  import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';
7
7
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
8
8
  import { searchKeymap } from '@codemirror/search';
9
- import { EditorState, type Extension } from '@codemirror/state';
9
+ import { type ChangeSpec, EditorState, type Extension, type TransactionSpec } from '@codemirror/state';
10
10
  import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
11
11
  import {
12
12
  EditorView,
@@ -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;
@@ -82,7 +106,7 @@ const defaultBasicOptions: BasicExtensionsOptions = {
82
106
  history: true,
83
107
  keymap: 'standard',
84
108
  lineWrapping: true,
85
- search: true,
109
+ search: false,
86
110
  } as const;
87
111
 
88
112
  const keymaps: { [key: string]: readonly KeyBinding[] } = {
@@ -137,9 +161,9 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
137
161
  preventDefault: true,
138
162
  run: () => true,
139
163
  },
140
- ].filter(isNotFalsy),
164
+ ].filter(isTruthy),
141
165
  ),
142
- ].filter(isNotFalsy);
166
+ ].filter(isTruthy);
143
167
  };
144
168
 
145
169
  //
@@ -157,9 +181,6 @@ export type ThemeExtensionsOptions = {
157
181
  scroll?: {
158
182
  className?: string;
159
183
  };
160
- scroller?: {
161
- className?: string;
162
- };
163
184
  content?: {
164
185
  className?: string;
165
186
  };
@@ -186,35 +207,25 @@ export const defaultThemeSlots = grow;
186
207
  export const createThemeExtensions = ({
187
208
  themeMode,
188
209
  styles,
189
- syntaxHighlighting: _syntaxHighlighting,
210
+ syntaxHighlighting: syntaxHighlightingProps,
190
211
  slots: _slots,
191
212
  }: ThemeExtensionsOptions = {}): Extension => {
192
213
  const slots = defaultsDeep({}, _slots, defaultThemeSlots);
193
214
  return [
194
215
  EditorView.darkTheme.of(themeMode === 'dark'),
195
216
  EditorView.baseTheme(styles ? merge({}, defaultTheme, styles) : defaultTheme),
196
- // https://github.com/codemirror/theme-one-dark
197
- _syntaxHighlighting &&
198
- (themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
217
+ syntaxHighlightingProps && syntaxHighlighting(themeMode === 'dark' ? oneDarkHighlightStyle : defaultHighlightStyle),
199
218
  slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
200
219
  slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
201
220
  slots.scroll?.className &&
202
221
  ViewPlugin.fromClass(
203
222
  class {
204
223
  constructor(view: EditorView) {
205
- view.scrollDOM.classList.add(slots.scroll.className);
224
+ view.scrollDOM.classList.add(...slots.scroll.className.split(/\s+/));
206
225
  }
207
226
  },
208
227
  ),
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(' '));
214
- }
215
- },
216
- ),
217
- ].filter(isNotFalsy);
228
+ ].filter(isTruthy);
218
229
  };
219
230
 
220
231
  //
@@ -238,7 +249,6 @@ export const createDataExtensions = <T>({ id, text, space, identity }: DataExten
238
249
  if (space && identity) {
239
250
  const peerId = identity?.identityKey.toHex();
240
251
  const hue = (identity?.profile?.data?.hue as HuePalette | undefined) ?? hexToHue(peerId ?? '0');
241
-
242
252
  extensions.push(
243
253
  awareness(
244
254
  new SpaceAwarenessProvider({
@@ -246,9 +256,9 @@ export const createDataExtensions = <T>({ id, text, space, identity }: DataExten
246
256
  channel: `awareness.${id}`,
247
257
  peerId: identity.identityKey.toHex(),
248
258
  info: {
249
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
250
259
  darkColor: `var(--dx-${hue}Cursor)`,
251
260
  lightColor: `var(--dx-${hue}Cursor)`,
261
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
252
262
  },
253
263
  }),
254
264
  ),
@@ -6,8 +6,6 @@ import { EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
6
6
 
7
7
  import { type CleanupFn, addEventListener } from '@dxos/async';
8
8
 
9
- import { closeEffect, openEffect } from './action';
10
-
11
9
  export type FloatingMenuOptions = {
12
10
  icon?: string;
13
11
  height?: number;
@@ -34,12 +32,10 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
34
32
  {
35
33
  const icon = document.createElement('dx-icon');
36
34
  icon.setAttribute('icon', options.icon ?? 'ph--dots-three-vertical--regular');
37
- const button = document.createElement('button');
38
- button.appendChild(icon);
39
35
 
40
- this.tag = document.createElement('dx-ref-tag');
41
- this.tag.classList.add('cm-ref-tag');
42
- this.tag.appendChild(button);
36
+ this.tag = document.createElement('dx-anchor');
37
+ this.tag.classList.add('cm-floating-menu-trigger');
38
+ this.tag.appendChild(icon);
43
39
  }
44
40
 
45
41
  container.appendChild(this.tag);
@@ -65,12 +61,12 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
65
61
  }
66
62
 
67
63
  // TODO(burdon): Timer to fade in/out.
68
- if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
64
+ /*if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
69
65
  this.tag.style.display = 'none';
70
66
  this.tag.classList.add('opacity-10');
71
67
  } else if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
72
- this.tag.style.display = 'block';
73
- } else if (
68
+ this.tag.style.display = '';
69
+ } else */ if (
74
70
  update.docChanged ||
75
71
  update.focusChanged ||
76
72
  update.geometryChanged ||
@@ -99,7 +95,7 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
99
95
 
100
96
  this.tag.style.top = `${offsetTop}px`;
101
97
  this.tag.style.left = `${offsetLeft}px`;
102
- this.tag.style.display = 'block';
98
+ this.tag.style.display = '';
103
99
  }
104
100
 
105
101
  scheduleUpdate() {
@@ -113,21 +109,18 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
113
109
  ),
114
110
 
115
111
  EditorView.theme({
116
- '.cm-ref-tag': {
112
+ '.cm-floating-menu-trigger': {
117
113
  position: 'fixed',
118
114
  padding: '0',
119
115
  border: 'none',
120
116
  opacity: '0',
121
- },
122
- '[data-has-focus] & .cm-ref-tag': {
123
- opacity: '1',
124
- },
125
- '.cm-ref-tag button': {
126
117
  display: 'grid',
127
- alignItems: 'center',
128
- justifyContent: 'center',
118
+ placeContent: 'center',
129
119
  width: '2rem',
130
120
  height: '2rem',
131
121
  },
122
+ '&:focus-within .cm-floating-menu-trigger': {
123
+ opacity: '1',
124
+ },
132
125
  }),
133
126
  ];
@@ -15,6 +15,7 @@ export const focusField = StateField.define<boolean>({
15
15
  return effect.value;
16
16
  }
17
17
  }
18
+
18
19
  return value;
19
20
  },
20
21
  });
@@ -25,11 +26,11 @@ export const focusField = StateField.define<boolean>({
25
26
  export const focus = [
26
27
  focusField,
27
28
  EditorView.domEventHandlers({
28
- focus: (event, view) => {
29
- setTimeout(() => view.dispatch({ effects: focusEffect.of(true) }));
29
+ focus: (_event, view) => {
30
+ requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(true) }));
30
31
  },
31
- blur: (event, view) => {
32
- setTimeout(() => view.dispatch({ effects: focusEffect.of(false) }));
32
+ blur: (_event, view) => {
33
+ requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(false) }));
33
34
  },
34
35
  }),
35
36
  ];
@@ -7,16 +7,15 @@ import { type Extension } from '@codemirror/state';
7
7
  import { EditorView } from '@codemirror/view';
8
8
  import React from 'react';
9
9
 
10
- import { Icon } from '@dxos/react-ui';
10
+ import { Domino, Icon } from '@dxos/react-ui';
11
11
 
12
- import { createElement, renderRoot } from '../util';
12
+ import { renderRoot } from '../util';
13
13
 
14
14
  export type FoldingOptions = {};
15
15
 
16
16
  /**
17
17
  * https://codemirror.net/examples/gutter
18
18
  */
19
- // TODO(burdon): Remember folding state (to state).
20
19
  export const folding = (_props: FoldingOptions = {}): Extension => [
21
20
  codeFolding({
22
21
  placeholderDOM: () => {
@@ -25,10 +24,9 @@ export const folding = (_props: FoldingOptions = {}): Extension => [
25
24
  }),
26
25
  foldGutter({
27
26
  markerDOM: (open) => {
28
- // TODO(burdon): Use sprite directly.
29
- const el = createElement('div', { className: 'flex h-full items-center' });
30
27
  return renderRoot(
31
- el,
28
+ Domino.of('div').classNames('flex h-full items-center').build(),
29
+ // TODO(burdon): Use sprite directly.
32
30
  <Icon icon='ph--caret-right--bold' size={3} classNames={['mx-3 cursor-pointer', open && 'rotate-90']} />,
33
31
  );
34
32
  },
@@ -4,14 +4,17 @@
4
4
 
5
5
  export * from './annotations';
6
6
  export * from './autocomplete';
7
+ export * from './autoscroll';
7
8
  export * from './automerge';
8
9
  export * from './awareness';
9
10
  export * from './blast';
10
- export * from './command';
11
+ export * from './command-dialog';
12
+ export * from './command-menu';
11
13
  export * from './comments';
12
14
  export * from './debug';
13
15
  export * from './dnd';
14
16
  export * from './factories';
17
+ export * from './floating-menu';
15
18
  export * from './focus';
16
19
  export * from './folding';
17
20
  export * from './hashtag';
@@ -23,4 +26,5 @@ export * from './modes';
23
26
  export * from './outliner';
24
27
  export * from './preview';
25
28
  export * from './selection';
29
+ export * from './tags';
26
30
  export * from './typewriter';
@@ -7,6 +7,8 @@ import { type EditorView } from '@codemirror/view';
7
7
  import { type Action } from '@dxos/app-graph';
8
8
  import { type MenuActionProperties } from '@dxos/react-ui-menu';
9
9
 
10
+ import { createComment } from '../comments';
11
+
10
12
  import {
11
13
  Inline,
12
14
  List,
@@ -25,7 +27,6 @@ import {
25
27
  toggleList,
26
28
  toggleStyle,
27
29
  } from './formatting';
28
- import { createComment } from '../comments';
29
30
 
30
31
  export type PayloadType =
31
32
  | 'view-mode'
@@ -4,20 +4,21 @@
4
4
 
5
5
  import { completionKeymap } from '@codemirror/autocomplete';
6
6
  import { defaultKeymap, indentWithTab } from '@codemirror/commands';
7
- import { markdownLanguage, markdown } from '@codemirror/lang-markdown';
7
+ import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
8
8
  import { syntaxHighlighting } from '@codemirror/language';
9
9
  import { languages } from '@codemirror/language-data';
10
10
  import { type Extension } from '@codemirror/state';
11
11
  import { keymap } from '@codemirror/view';
12
+ import { type MarkdownConfig } from '@lezer/markdown';
12
13
 
13
- import { type ThemeMode } from '@dxos/react-ui';
14
- import { isNotFalsy } from '@dxos/util';
14
+ import { isTruthy } from '@dxos/util';
15
15
 
16
16
  import { markdownHighlightStyle, markdownTagsExtensions } from './highlight';
17
17
 
18
18
  export type MarkdownBundleOptions = {
19
- themeMode?: ThemeMode;
19
+ extensions?: MarkdownConfig[];
20
20
  indentWithTab?: boolean;
21
+ setextHeading?: boolean;
21
22
  };
22
23
 
23
24
  /**
@@ -51,6 +52,7 @@ export const createMarkdownExtensions = (options: MarkdownBundleOptions = {}): E
51
52
  extensions: [
52
53
  // GFM provided by default.
53
54
  markdownTagsExtensions,
55
+ ...(options.extensions ?? defaultExtensions()),
54
56
  ],
55
57
  }),
56
58
 
@@ -65,7 +67,27 @@ export const createMarkdownExtensions = (options: MarkdownBundleOptions = {}): E
65
67
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
66
68
  ...defaultKeymap,
67
69
  ...completionKeymap,
68
- ].filter(isNotFalsy),
70
+ ].filter(isTruthy),
69
71
  ),
70
72
  ];
71
73
  };
74
+
75
+ /**
76
+ * Default customizations.
77
+ * https://github.com/lezer-parser/markdown/blob/main/src/markdown.ts
78
+ */
79
+ export const defaultExtensions = (): MarkdownConfig[] => [noSetExtHeading, noHtml];
80
+
81
+ /**
82
+ * Remove SetextHeading (e.g., headings created from "---").
83
+ */
84
+ const noSetExtHeading: MarkdownConfig = {
85
+ remove: ['SetextHeading'],
86
+ };
87
+
88
+ /**
89
+ * Remove HTML and XML parsing.
90
+ */
91
+ const noHtml: MarkdownConfig = {
92
+ remove: ['HTMLBlock', 'HTMLTag'],
93
+ };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { syntaxTree } from '@codemirror/language';
6
6
  import { type ChangeSpec, Transaction } from '@codemirror/state';
7
- import { ViewPlugin, type ViewUpdate, type PluginValue } from '@codemirror/view';
7
+ import { type PluginValue, ViewPlugin, type ViewUpdate } from '@codemirror/view';
8
8
 
9
9
  /**
10
10
  * Monitors and augments changes.
@@ -3,20 +3,21 @@
3
3
  //
4
4
 
5
5
  import { syntaxTree } from '@codemirror/language';
6
- import { RangeSetBuilder, type EditorState, StateEffect } from '@codemirror/state';
7
- import { EditorView, Decoration, type DecorationSet, WidgetType, ViewPlugin, type ViewUpdate } from '@codemirror/view';
6
+ import { type EditorState, Prec, RangeSetBuilder, StateEffect } from '@codemirror/state';
7
+ import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';
8
8
  import { type SyntaxNodeRef } from '@lezer/common';
9
9
 
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { mx } from '@dxos/react-ui-theme';
12
12
 
13
+ import { type HeadingLevel, theme } from '../../styles';
14
+ import { type RenderCallback } from '../../types';
15
+ import { wrapWithCatch } from '../../util';
16
+
13
17
  import { adjustChanges } from './changes';
14
18
  import { image } from './image';
15
- import { formattingStyles, bulletListIndentationWidth, orderedListIndentationWidth } from './styles';
19
+ import { bulletListIndentationWidth, formattingStyles, orderedListIndentationWidth } from './styles';
16
20
  import { table } from './table';
17
- import { theme, type HeadingLevel } from '../../styles';
18
- import { type RenderCallback } from '../../types';
19
- import { wrapWithCatch } from '../../util';
20
21
 
21
22
  /**
22
23
  * Unicode characters.
@@ -233,7 +234,7 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
233
234
  const mark = node.node.firstChild!;
234
235
  if (mark?.name === 'HeaderMark') {
235
236
  const { from, to = 6 } = options.numberedHeadings ?? {};
236
- const text = view.state.sliceDoc(node.from, node.to);
237
+ const text = state.sliceDoc(node.from, node.to);
237
238
  const len = text.match(/[#\s]+/)![0].length;
238
239
  if (!from || level < from || level > to) {
239
240
  atomicDeco.add(mark.from, mark.from + len, hide);
@@ -426,6 +427,9 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
426
427
  const editing = editingRange(state, node, focus);
427
428
  if (urlNode && marks.length >= 2) {
428
429
  const url = state.sliceDoc(urlNode.from, urlNode.to);
430
+ if (options.skip?.({ name: 'Link', url })) {
431
+ break;
432
+ }
429
433
  if (!editing) {
430
434
  atomicDeco.add(node.from, marks[0].to, hide);
431
435
  }
@@ -443,6 +447,7 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
443
447
  },
444
448
  }),
445
449
  );
450
+
446
451
  if (!editing) {
447
452
  atomicDeco.add(
448
453
  marks[1].from,
@@ -493,15 +498,15 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
493
498
  tree.iterate({
494
499
  from,
495
500
  to,
496
- enter: wrapWithCatch(enterNode),
497
- leave: wrapWithCatch(leaveNode),
501
+ enter: wrapWithCatch(enterNode, 'decorate.enter'),
502
+ leave: wrapWithCatch(leaveNode, 'decorate.leave'),
498
503
  });
499
504
  }
500
505
  } else {
501
506
  // NOTE: If line numbering then we must iterate from the start of document.
502
507
  tree.iterate({
503
- enter: wrapWithCatch(enterNode),
504
- leave: wrapWithCatch(leaveNode),
508
+ enter: wrapWithCatch(enterNode, 'decorate.enter'),
509
+ leave: wrapWithCatch(leaveNode, 'decorate.leave'),
505
510
  });
506
511
  }
507
512
 
@@ -513,15 +518,20 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
513
518
 
514
519
  const forceUpdate = StateEffect.define<null>();
515
520
 
521
+ export type NodeData = { name: 'Link'; url: string } | { name: 'Image'; url: string };
522
+
516
523
  export interface DecorateOptions {
517
524
  /**
518
525
  * Prevents triggering decorations as the cursor moves through the document.
519
526
  */
520
527
  selectionChangeDelay?: number;
521
528
  numberedHeadings?: { from: number; to?: number };
522
- renderLinkButton?: RenderCallback<{ url: string }>;
523
529
  // TODO(burdon): Additional padding for each line.
524
530
  listPaddingLeft?: number;
531
+ // TODO(burdon): Use consistently.
532
+ skip?: (node: NodeData) => boolean;
533
+ // TODO(burdon): Remove.
534
+ renderLinkButton?: RenderCallback<{ url: string }>;
525
535
  }
526
536
 
527
537
  export const decorateMarkdown = (options: DecorateOptions = {}) => {
@@ -577,9 +587,9 @@ export const decorateMarkdown = (options: DecorateOptions = {}) => {
577
587
  },
578
588
  {
579
589
  provide: (plugin) => [
580
- EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration.none),
590
+ Prec.low(EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration.none)),
581
591
  EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration.none),
582
- EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration.none),
592
+ EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration.none),
583
593
  ],
584
594
  },
585
595
  ),
@@ -7,21 +7,21 @@ import { EditorState, type StateCommand } from '@codemirror/state';
7
7
  import { describe, expect, test } from 'vitest';
8
8
 
9
9
  import {
10
+ type Formatting,
11
+ Inline,
12
+ List,
10
13
  addBlockquote,
11
14
  addCodeblock,
12
15
  addLink,
13
16
  addList,
14
17
  addStyle,
15
18
  getFormatting,
16
- removeStyle,
17
- removeLink,
18
- removeList,
19
19
  removeBlockquote,
20
20
  removeCodeblock,
21
+ removeLink,
22
+ removeList,
23
+ removeStyle,
21
24
  setHeading,
22
- Inline,
23
- List,
24
- type Formatting,
25
25
  } from './formatting';
26
26
 
27
27
  export const emptyFormatting: Formatting = {
@@ -7,14 +7,14 @@ import { syntaxTree } from '@codemirror/language';
7
7
  import {
8
8
  type ChangeSpec,
9
9
  EditorSelection,
10
- type Extension,
11
10
  type EditorState,
11
+ type Extension,
12
12
  type Line,
13
13
  type StateCommand,
14
14
  type Text,
15
15
  } from '@codemirror/state';
16
- import { EditorView, keymap, type ViewUpdate } from '@codemirror/view';
17
- import { type SyntaxNodeRef, type SyntaxNode } from '@lezer/common';
16
+ import { EditorView, type ViewUpdate, keymap } from '@codemirror/view';
17
+ import { type SyntaxNode, type SyntaxNodeRef } from '@lezer/common';
18
18
  import { useCallback, useMemo } from 'react';
19
19
 
20
20
  import { debounceAndThrottle } from '@dxos/async';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { markdownLanguage } from '@codemirror/lang-markdown';
6
6
  import { HighlightStyle } from '@codemirror/language';
7
- import { tags, styleTags, Tag } from '@lezer/highlight';
7
+ import { Tag, styleTags, tags } from '@lezer/highlight';
8
8
  import { type MarkdownConfig, Table } from '@lezer/markdown';
9
9
 
10
10
  import { fontBody, theme } from '../../styles';
@@ -17,8 +17,7 @@ export const image = (_options: ImageOptions = {}): Extension => {
17
17
  return [
18
18
  StateField.define<DecorationSet>({
19
19
  create: (state) => {
20
- // Process all images.
21
- return Decoration.set(buildDecorations(0, state.doc.length, state));
20
+ return Decoration.set(buildDecorations(state, 0, state.doc.length));
22
21
  },
23
22
  update: (value: DecorationSet, tr: Transaction) => {
24
23
  if (!tr.docChanged && !tr.selection) {
@@ -43,7 +42,7 @@ export const image = (_options: ImageOptions = {}): Extension => {
43
42
  filterFrom: from,
44
43
  filterTo: to,
45
44
  filter: () => false,
46
- add: buildDecorations(from, to, tr.state),
45
+ add: buildDecorations(tr.state, from, to),
47
46
  });
48
47
  },
49
48
  provide: (field) => EditorView.decorations.from(field),
@@ -51,7 +50,7 @@ export const image = (_options: ImageOptions = {}): Extension => {
51
50
  ];
52
51
  };
53
52
 
54
- const buildDecorations = (from: number, to: number, state: EditorState) => {
53
+ const buildDecorations = (state: EditorState, from: number, to: number) => {
55
54
  const decorations: Range<Decoration>[] = [];
56
55
  const cursor = state.selection.main.head;
57
56
  syntaxTree(state).iterate({
@@ -26,6 +26,9 @@ export const linkTooltip = (renderTooltip: RenderCallback<{ url: string }>) => {
26
26
  }
27
27
 
28
28
  const urlText = view.state.sliceDoc(url.from, url.to);
29
+ if (urlText.startsWith('dxn')) {
30
+ return null;
31
+ }
29
32
  return {
30
33
  pos: link.from,
31
34
  end: link.to,
@@ -94,7 +94,13 @@ const update = (state: EditorState, _options: TableOptions) => {
94
94
  } else {
95
95
  // Add class for styling.
96
96
  // TODO(burdon): Apply to each line?
97
- builder.add(table.from, table.to, Decoration.mark({ class: 'cm-table' }));
97
+ builder.add(
98
+ table.from,
99
+ table.to,
100
+ Decoration.mark({
101
+ class: 'cm-table',
102
+ }),
103
+ );
98
104
  }
99
105
  });
100
106
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { autocompletion, type CompletionContext, type CompletionResult } from '@codemirror/autocomplete';
5
+ import { type CompletionContext, type CompletionResult, autocompletion } from '@codemirror/autocomplete';
6
6
  import type { Extension } from '@codemirror/state';
7
7
 
8
8
  import { log } from '@dxos/log';
@@ -6,11 +6,12 @@ import { EditorSelection, EditorState } from '@codemirror/state';
6
6
  import { EditorView } from '@codemirror/view';
7
7
  import { describe, test } from 'vitest';
8
8
 
9
- import { indentItemLess, indentItemMore, moveItemDown, moveItemUp } from './commands';
10
- import { listItemToString, outlinerTree, treeFacet } from './tree';
11
9
  import { str } from '../../testing';
12
10
  import { createMarkdownExtensions } from '../markdown';
13
11
 
12
+ import { indentItemLess, indentItemMore, moveItemDown, moveItemUp } from './commands';
13
+ import { listItemToString, outlinerTree, treeFacet } from './tree';
14
+
14
15
  const lines = [
15
16
  '- [ ] 1',
16
17
  '- [ ] 2',