@dxos/react-ui-editor 0.3.10-main.3cfd481 → 0.3.10-main.3edbcce

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 (64) hide show
  1. package/dist/lib/browser/index.mjs +351 -131
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +3 -0
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +1 -0
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts +3 -2
  9. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/extensions/comments.d.ts +18 -0
  11. package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -0
  12. package/dist/types/src/components/TextEditor/extensions/demo.d.ts +10 -0
  13. package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -0
  14. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -1
  15. package/dist/types/src/components/TextEditor/extensions/index.d.ts +2 -0
  16. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  17. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
  18. package/dist/types/src/components/TextEditor/extensions/listener.d.ts +4 -2
  19. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
  20. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  21. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
  22. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +1 -4
  23. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
  24. package/dist/types/src/components/TextEditor/themes/default.d.ts +3 -0
  25. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
  26. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts +3 -0
  27. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -1
  28. package/dist/types/src/hooks/automerge/index.d.ts +1 -1
  29. package/dist/types/src/hooks/automerge/index.d.ts.map +1 -1
  30. package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -1
  31. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
  32. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
  33. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
  34. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
  35. package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
  36. package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
  37. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  38. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  39. package/package.json +20 -19
  40. package/src/components/TextEditor/MarkdownEditor.stories.tsx +41 -8
  41. package/src/components/TextEditor/TextEditor.tsx +32 -11
  42. package/src/components/TextEditor/extensions/autocomplete.ts +5 -3
  43. package/src/components/TextEditor/extensions/comments.ts +190 -0
  44. package/src/components/TextEditor/extensions/demo.ts +66 -0
  45. package/src/components/TextEditor/extensions/experimental.tsx +1 -0
  46. package/src/components/TextEditor/extensions/index.ts +2 -0
  47. package/src/components/TextEditor/extensions/link.ts +10 -2
  48. package/src/components/TextEditor/extensions/listener.ts +3 -2
  49. package/src/components/TextEditor/extensions/markdown/bundle.ts +6 -14
  50. package/src/components/TextEditor/extensions/markdown/highlight.ts +2 -1
  51. package/src/components/TextEditor/extensions/tasklist.ts +73 -79
  52. package/src/components/TextEditor/themes/default.ts +15 -0
  53. package/src/hooks/automerge/PatchSemaphore.ts +12 -9
  54. package/src/hooks/automerge/index.ts +1 -1
  55. package/src/hooks/automerge/plugin.ts +1 -0
  56. package/src/hooks/automerge/{amToCodemirror.ts → translation/automerge-to-codemirror.ts} +10 -2
  57. package/src/hooks/automerge/{codeMirrorToAm.ts → translation/codemirror-to-automerge.ts} +7 -4
  58. package/src/hooks/automerge/translation/index.ts +6 -0
  59. package/src/hooks/useTextModel.ts +11 -8
  60. package/src/testing/replicator.ts +5 -5
  61. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts +0 -6
  62. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +0 -1
  63. package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts +0 -7
  64. package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts.map +0 -1
@@ -21,8 +21,8 @@ import { generateName } from '@dxos/display-name';
21
21
  import { useThemeContext } from '@dxos/react-ui';
22
22
  import { getColorForValue, inputSurface, mx } from '@dxos/react-ui-theme';
23
23
 
24
- import { basicBundle, markdownBundle } from './extensions';
25
- import { defaultTheme, textTheme } from './themes';
24
+ import { basicBundle, demo, markdownBundle } from './extensions';
25
+ import { defaultTheme, markdownTheme, textTheme } from './themes';
26
26
  import { type EditorModel } from '../../hooks';
27
27
  import { type ThemeStyles } from '../../styles';
28
28
 
@@ -70,6 +70,11 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
70
70
  const { themeMode } = useThemeContext();
71
71
  const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
72
72
 
73
+ const [root, setRoot] = useState<HTMLDivElement | null>(null);
74
+ const [state, setState] = useState<EditorState>();
75
+ const [view, setView] = useState<EditorView>();
76
+ useImperativeHandle(forwardedRef, () => ({ root, state, view }), [view, state, root]);
77
+
73
78
  // TODO(burdon): Factor out?
74
79
  const { awareness, peer } = model;
75
80
  useEffect(() => {
@@ -82,11 +87,6 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
82
87
  }
83
88
  }, [awareness, peer, themeMode]);
84
89
 
85
- const [root, setRoot] = useState<HTMLDivElement | null>(null);
86
- const [state, setState] = useState<EditorState>();
87
- const [view, setView] = useState<EditorView>();
88
- useImperativeHandle(forwardedRef, () => ({ root, state, view }), [view, state, root]);
89
-
90
90
  useEffect(() => {
91
91
  if (!root) {
92
92
  return;
@@ -157,7 +157,17 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
157
157
  },
158
158
  );
159
159
 
160
- // TODO(burdon): Set default text theme?
160
+ // TODO(burdon): Allow plugins to set extensions (factory).
161
+ const maybeDebug = (): Extension => {
162
+ // TODO(burdon): Parse JSON script format (with key bindings?)
163
+ const items = localStorage.getItem('dxos.composer.demo');
164
+ if (items) {
165
+ return demo({ items: items.split(',') });
166
+ }
167
+
168
+ return [];
169
+ };
170
+
161
171
  export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
162
172
  ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
163
173
  const { themeMode } = useThemeContext();
@@ -165,7 +175,7 @@ export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
165
175
  return (
166
176
  <BaseTextEditor
167
177
  ref={forwardedRef}
168
- extensions={[basicBundle({ themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
178
+ extensions={[basicBundle({ themeMode, placeholder: slots?.editor?.placeholder }), maybeDebug(), ...extensions]}
169
179
  slots={slots}
170
180
  {...props}
171
181
  />
@@ -176,11 +186,15 @@ export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
176
186
  export const MarkdownEditor = forwardRef<TextEditorRef, TextEditorProps>(
177
187
  ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
178
188
  const { themeMode } = useThemeContext();
179
- const slots = defaultsDeep({}, _slots, defaultSlots);
189
+ const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
180
190
  return (
181
191
  <BaseTextEditor
182
192
  ref={forwardedRef}
183
- extensions={[markdownBundle({ themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
193
+ extensions={[
194
+ markdownBundle({ themeMode, placeholder: slots?.editor?.placeholder }),
195
+ maybeDebug(),
196
+ ...extensions,
197
+ ]}
184
198
  slots={slots}
185
199
  {...props}
186
200
  />
@@ -200,3 +214,10 @@ export const defaultTextSlots: TextEditorSlots = {
200
214
  theme: textTheme,
201
215
  },
202
216
  };
217
+
218
+ export const defaultMarkdownSlots: TextEditorSlots = {
219
+ ...defaultSlots,
220
+ editor: {
221
+ theme: markdownTheme,
222
+ },
223
+ };
@@ -23,14 +23,16 @@ import {
23
23
  } from '@codemirror/autocomplete';
24
24
  import { keymap } from '@codemirror/view';
25
25
 
26
+ export type AutocompleteResult = Completion;
27
+
26
28
  export type AutocompleteOptions = {
27
- getOptions: (text: string) => Completion[];
29
+ onSearch: (text: string) => Completion[];
28
30
  };
29
31
 
30
32
  /**
31
33
  * Autocomplete extension.
32
34
  */
33
- export const autocomplete = ({ getOptions }: AutocompleteOptions) => {
35
+ export const autocomplete = ({ onSearch }: AutocompleteOptions) => {
34
36
  return [
35
37
  // https://codemirror.net/docs/ref/#view.keymap
36
38
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
@@ -57,7 +59,7 @@ export const autocomplete = ({ getOptions }: AutocompleteOptions) => {
57
59
  // TODO(burdon): Option to convert to links?
58
60
  return {
59
61
  from: word.from,
60
- options: getOptions(word.text.toLowerCase()),
62
+ options: onSearch(word.text.toLowerCase()),
61
63
  // options: [
62
64
  // { label: 'apple', type: 'keyword' },
63
65
  // { label: 'amazon', type: 'keyword' },
@@ -0,0 +1,190 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Extension } from '@codemirror/state';
6
+ import {
7
+ keymap,
8
+ type DecorationSet,
9
+ type Rect,
10
+ type ViewUpdate,
11
+ Decoration,
12
+ EditorView,
13
+ MatchDecorator,
14
+ ViewPlugin,
15
+ WidgetType,
16
+ } from '@codemirror/view';
17
+
18
+ import { debounce } from '@dxos/async';
19
+ import { invariant } from '@dxos/invariant';
20
+
21
+ // 1. TODO(burdon): Make atomic (for tasklist also).
22
+ // - https://discuss.codemirror.net/t/easily-track-remove-content-with-decorations/4606
23
+ // - https://discuss.codemirror.net/t/creating-atomic-replace-decorations/2961
24
+ // - https://codemirror.net/docs/ref/#state.EditorState%5EtransactionFilter (transaction filter: move, delete).
25
+ // 2. TODO(burdon): Create/track threads in composer (change global state). Select/follow. Scroll with page.
26
+ // - Separate from chat/search.
27
+ // 3. TODO(burdon): Support multiple threads in sidebar?
28
+ // 4. TODO(burdon): Anchor AI thread when creating section.
29
+ // 5. TODO(burdon): Button to resolve thread to close comments.
30
+
31
+ // 6. TODO(burdon): Perf: Update existing rangeset.
32
+ // https://discuss.codemirror.net/t/rangeset-with-metadata-and-different-decorations/3874
33
+
34
+ // TODO(burdon): Import note (performance):
35
+ // Easily track & remove content with decorations
36
+ // https://discuss.codemirror.net/t/easily-track-remove-content-with-decorations/4606
37
+
38
+ class BookmarkWidget extends WidgetType {
39
+ constructor(private readonly _pos: number, private readonly _id: string) {
40
+ super();
41
+ invariant(this._id);
42
+ }
43
+
44
+ override eq(other: BookmarkWidget) {
45
+ return this._id === other._id;
46
+ }
47
+
48
+ override toDOM() {
49
+ const span = document.createElement('span');
50
+ span.className = 'cm-bookmark';
51
+ // TODO(burdon): Call out to react?
52
+ // https://emojifinder.com/comment
53
+ span.textContent = '💬';
54
+ return span;
55
+ }
56
+ }
57
+
58
+ // TODO(burdon): Reconcile with theme.
59
+ const styles = EditorView.baseTheme({
60
+ '& .cm-bookmark': {
61
+ cursor: 'pointer',
62
+ margin: '4px',
63
+ padding: '4px',
64
+ backgroundColor: 'yellow',
65
+ },
66
+ '& .cm-bookmark-selected': {
67
+ backgroundColor: 'orange',
68
+ },
69
+ });
70
+
71
+ type CommentsInfo = {
72
+ active?: string;
73
+ items: { id: string; pos: number; location: Rect | null }[];
74
+ };
75
+
76
+ export type CommentsOptions = {
77
+ key?: string;
78
+ onCreate?: () => string | void;
79
+ onUpdate?: (info: CommentsInfo) => void;
80
+ };
81
+
82
+ // https://www.markdownguide.org/extended-syntax/#footnotes
83
+ // TODO(burdon): Record span in automerge model?
84
+ // TODO(burdon): Extended markdown: https://www.markdownguide.org/extended-syntax
85
+ export const comments = (options: CommentsOptions = {}): Extension => {
86
+ let active: string | undefined;
87
+
88
+ const bookmarkMatcher = new MatchDecorator({
89
+ regexp: /\[\^(\w+)\]/g,
90
+ decoration: (match, view, pos) => {
91
+ const id = match[1];
92
+ return Decoration.replace({
93
+ id,
94
+ widget: new BookmarkWidget(pos, id),
95
+ });
96
+ },
97
+ });
98
+
99
+ const bookmarks = ViewPlugin.fromClass(
100
+ class {
101
+ bookmarks: DecorationSet;
102
+ constructor(view: EditorView) {
103
+ this.bookmarks = bookmarkMatcher.createDeco(view);
104
+ }
105
+
106
+ update(update: ViewUpdate) {
107
+ this.bookmarks = bookmarkMatcher.updateDeco(update, this.bookmarks);
108
+ }
109
+ },
110
+ {
111
+ decorations: (instance) => instance.bookmarks,
112
+ provide: (plugin) =>
113
+ EditorView.atomicRanges.of((view) => {
114
+ return view.plugin(plugin)?.bookmarks || Decoration.none;
115
+ }),
116
+ },
117
+ );
118
+
119
+ const doUpdate = debounce((data: CommentsInfo) => {
120
+ options.onUpdate?.(data);
121
+ }, 200);
122
+
123
+ return [
124
+ keymap.of([
125
+ {
126
+ key: options?.key ?? 'shift-meta-c',
127
+ run: (view) => {
128
+ // Insert footnote.
129
+ const id = options.onCreate?.();
130
+ if (id) {
131
+ const pos = view.state.selection.main.head;
132
+ const tag = `[^${id}]`;
133
+ view.dispatch({
134
+ changes: { from: pos, insert: tag },
135
+ selection: { anchor: pos + tag.length },
136
+ });
137
+
138
+ return true;
139
+ }
140
+
141
+ return false;
142
+ },
143
+ },
144
+ ]),
145
+
146
+ bookmarks,
147
+
148
+ // Monitor cursor movement.
149
+ EditorView.updateListener.of((update) => {
150
+ active = undefined;
151
+ if (!options.onUpdate) {
152
+ return;
153
+ }
154
+
155
+ const view = update.view;
156
+ const pos = view.state.selection.main.head;
157
+
158
+ const decorations: { from: number; to: number; value: Decoration }[] = [];
159
+ const rangeSet = view.plugin(bookmarks)?.bookmarks;
160
+ let closest = Infinity;
161
+ // TODO(burdon): Always shows entire document?
162
+ const { from, to } = view.visibleRanges?.[0] ?? { from: 0, to: view.state.doc.length };
163
+ rangeSet?.between(from, to, (from, to, value) => {
164
+ decorations.push({ from, to, value });
165
+ const d = Math.min(Math.abs(pos - from), Math.abs(pos - to));
166
+ if (d < closest) {
167
+ // TODO(burdon): Update class of selected.
168
+ active = value.spec.id;
169
+ closest = d;
170
+ }
171
+ });
172
+
173
+ if (decorations.length) {
174
+ doUpdate({
175
+ active,
176
+ items: decorations.map(
177
+ ({
178
+ from,
179
+ value: {
180
+ spec: { id },
181
+ },
182
+ }) => ({ id: id as string, pos: from, location: view.coordsAtPos(from) }),
183
+ ),
184
+ });
185
+ }
186
+ }),
187
+
188
+ styles,
189
+ ];
190
+ };
@@ -0,0 +1,66 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { keymap } from '@codemirror/view';
6
+
7
+ export type DemoOptions = {
8
+ delay?: number;
9
+ items?: string[];
10
+ };
11
+
12
+ const defaultItems = ['hello world!', 'this is a test.', 'this is [DXOS](https://dxos.org)'];
13
+
14
+ /**
15
+ * Demo script.
16
+ * Configurable plugin that let's user cycle through pre-configured input script.
17
+ */
18
+ export const demo = ({ delay = 75, items = defaultItems }: DemoOptions = {}) => {
19
+ let t: any;
20
+ let idx = 0;
21
+
22
+ return [
23
+ keymap.of([
24
+ {
25
+ // Reset.
26
+ key: "alt-meta-'",
27
+ run: (view) => {
28
+ clearTimeout(t);
29
+ idx = 0;
30
+ return true;
31
+ },
32
+ },
33
+ {
34
+ // Next prompt.
35
+ // TODO(burdon): Press 1-9 to select prompt?
36
+ key: "shift-meta-'",
37
+ run: (view) => {
38
+ clearTimeout(t);
39
+ // TODO(burdon): Add space if needed.
40
+ const text = items[idx++];
41
+ if (idx === items?.length) {
42
+ idx = 0;
43
+ }
44
+
45
+ let i = 0;
46
+ const insert = (d = 0) => {
47
+ t = setTimeout(() => {
48
+ const pos = view.state.selection.main.head;
49
+ view.dispatch({
50
+ changes: { from: pos, insert: text[i++] },
51
+ selection: { anchor: pos + 1 },
52
+ });
53
+
54
+ if (i < text.length) {
55
+ insert(Math.random() * delay * (text[i] === ' ' ? 2 : 1));
56
+ }
57
+ }, d);
58
+ };
59
+
60
+ insert();
61
+ return true;
62
+ },
63
+ },
64
+ ]),
65
+ ];
66
+ };
@@ -19,6 +19,7 @@ import {
19
19
  // TODO(burdon): Add-on: dialog.
20
20
  // TODO(burdon): Comments: https://codemirror.net/5/doc/manual.html#setBookmark
21
21
  // TODO(burdon): Split view: https://codemirror.net/examples/split
22
+ // TODO(burdon): https://codemirror.net/5/demo/simplemode.html
22
23
 
23
24
  // https://codemirror.net/examples/autocompletion
24
25
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
@@ -4,6 +4,8 @@
4
4
 
5
5
  export * from './autocomplete';
6
6
  export * from './basic';
7
+ export * from './demo';
8
+ export * from './comments';
7
9
  export * from './link';
8
10
  export * from './listener';
9
11
  export * from './markdown';
@@ -77,6 +77,11 @@ class LinkText extends WidgetType {
77
77
  }
78
78
  }
79
79
 
80
+ /**
81
+ * Range sets provide a data structure that can hold a collection of tagged,
82
+ * possibly overlapping ranges in such a way that they can efficiently be mapped though document changes.
83
+ * https://codemirror.net/docs/ref/#state
84
+ */
80
85
  const update = (state: EditorState, options: LinkOptions) => {
81
86
  const builder = new RangeSetBuilder();
82
87
  const cursor = state.selection.main.head;
@@ -89,6 +94,9 @@ const update = (state: EditorState, options: LinkOptions) => {
89
94
 
90
95
  const urlNode = node.node.getChild('URL');
91
96
  const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : '';
97
+ if (!url) {
98
+ return false;
99
+ }
92
100
 
93
101
  if (cursor < node.from || cursor > node.to) {
94
102
  builder.add(
@@ -109,9 +117,9 @@ const update = (state: EditorState, options: LinkOptions) => {
109
117
  }),
110
118
  );
111
119
  }
112
- }
113
120
 
114
- return true;
121
+ return false;
122
+ }
115
123
  },
116
124
  });
117
125
 
@@ -4,12 +4,13 @@
4
4
 
5
5
  import { StateField } from '@codemirror/state';
6
6
 
7
- export type TextListener = (text: string) => void;
7
+ export type ListenerOptions = { onChange: (text: string) => void };
8
8
 
9
9
  /**
10
10
  * Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799
11
11
  */
12
- export const listener = (onChange: TextListener) =>
12
+ // TODO(burdon): Expose options.
13
+ export const listener = ({ onChange }: ListenerOptions) =>
13
14
  StateField.define({
14
15
  create: () => null,
15
16
  update: (_value, transaction) => {
@@ -3,17 +3,10 @@
3
3
  //
4
4
 
5
5
  import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
6
- import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';
6
+ import { defaultKeymap, history, indentWithTab } from '@codemirror/commands';
7
7
  import { markdownLanguage, markdown } from '@codemirror/lang-markdown';
8
- import {
9
- bracketMatching,
10
- defaultHighlightStyle,
11
- foldKeymap,
12
- indentOnInput,
13
- syntaxHighlighting,
14
- } from '@codemirror/language';
8
+ import { bracketMatching, defaultHighlightStyle, indentOnInput, syntaxHighlighting } from '@codemirror/language';
15
9
  import { languages } from '@codemirror/language-data';
16
- import { lintKeymap } from '@codemirror/lint';
17
10
  import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
18
11
  import { EditorState, type Extension } from '@codemirror/state';
19
12
  import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
@@ -50,7 +43,6 @@ export const markdownBundle = ({ themeMode, placeholder: _placeholder }: Markdow
50
43
  EditorState.allowMultipleSelections.of(true),
51
44
  EditorView.lineWrapping,
52
45
 
53
- // autocompletion(),
54
46
  crosshairCursor(),
55
47
  dropCursor(),
56
48
  drawSelection(),
@@ -62,13 +54,13 @@ export const markdownBundle = ({ themeMode, placeholder: _placeholder }: Markdow
62
54
  indentOnInput(),
63
55
  rectangularSelection(),
64
56
 
57
+ // TODO(burdon): Review.
65
58
  keymap.of([
66
59
  ...closeBracketsKeymap,
67
- // ...completionKeymap,
68
60
  ...defaultKeymap,
69
- ...foldKeymap,
70
- ...historyKeymap,
71
- ...lintKeymap,
61
+ // ...foldKeymap,
62
+ // ...historyKeymap,
63
+ // ...lintKeymap,
72
64
  ...searchKeymap,
73
65
  indentWithTab,
74
66
  ]),
@@ -134,10 +134,11 @@ export const markdownHighlightStyle = HighlightStyle.define(
134
134
  class: codeMark,
135
135
  },
136
136
 
137
- // The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
137
+ // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
138
138
  // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
139
139
  // when a language is specified. In this case, the syntax highlighting extensions will colorize
140
140
  // the code, but all other CSS properties will be inherited.
141
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font.
141
142
  {
142
143
  tag: [markdownTags.CodeText, markdownTags.InlineCode],
143
144
  class: code,