@dxos/react-ui-editor 0.3.11-main.e0dc42b → 0.3.11-main.e19f39d
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.
- package/dist/lib/browser/index.mjs +1718 -1284
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -15
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +13 -10
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +4 -4
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/{yjs.stories.d.ts → hooks.stories.d.ts} +13 -2
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +23 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/index.d.ts +0 -1
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +8 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +36 -19
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/{util → extensions}/cursor.d.ts +10 -2
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +2 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts +13 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +8 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -32
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +48 -38
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +77 -87
- package/src/components/TextEditor/TextEditor.stories.tsx +10 -43
- package/src/components/TextEditor/TextEditor.tsx +116 -89
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/components/TextEditor/hooks.stories.tsx +106 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +90 -0
- package/src/components/Toolbar/Toolbar.tsx +166 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +55 -46
- package/src/extensions/automerge/cursor.ts +5 -4
- package/src/extensions/automerge/defs.ts +13 -34
- package/src/extensions/automerge/index.ts +0 -1
- package/src/extensions/automerge/semaphore.ts +33 -32
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +34 -39
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/comments.ts +318 -261
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -7
- package/src/extensions/markdown/bundle.ts +23 -28
- package/src/extensions/markdown/code.ts +150 -0
- package/src/extensions/markdown/formatting.ts +188 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -23
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +8 -5
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +62 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +49 -58
- package/src/styles/markdown.ts +9 -12
- package/src/themes/default.ts +19 -52
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/dist/types/src/util/cursor.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -3
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/util.d.ts +0 -5
- package/dist/types/src/util/util.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -106
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/tasklist.ts +0 -119
- package/src/extensions/yjs/cursor.ts +0 -21
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -178
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- package/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
- /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
- /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { EditorState, type Extension } from '@codemirror/state';
|
|
5
|
+
import { EditorState, type Extension, type StateEffect } from '@codemirror/state';
|
|
6
6
|
import { EditorView } from '@codemirror/view';
|
|
7
|
-
import { useFocusableGroup } from '@fluentui/react-tabster';
|
|
7
|
+
// import { useFocusableGroup } from '@fluentui/react-tabster';
|
|
8
8
|
import { vim } from '@replit/codemirror-vim';
|
|
9
9
|
import defaultsDeep from 'lodash.defaultsdeep';
|
|
10
10
|
import React, {
|
|
@@ -14,19 +14,22 @@ import React, {
|
|
|
14
14
|
useCallback,
|
|
15
15
|
useEffect,
|
|
16
16
|
useImperativeHandle,
|
|
17
|
-
useState,
|
|
18
17
|
useRef,
|
|
18
|
+
useState,
|
|
19
19
|
} from 'react';
|
|
20
20
|
|
|
21
|
-
import {
|
|
21
|
+
import { log } from '@dxos/log';
|
|
22
22
|
import { useThemeContext } from '@dxos/react-ui';
|
|
23
|
-
import {
|
|
23
|
+
import { attentionSurface, mx } from '@dxos/react-ui-theme';
|
|
24
|
+
import { isNotFalsy } from '@dxos/util';
|
|
24
25
|
|
|
25
|
-
import {
|
|
26
|
-
import { type
|
|
26
|
+
import { createBasicBundle, createMarkdownExtensions } from '../../extensions';
|
|
27
|
+
import { type EditorModel } from '../../hooks';
|
|
27
28
|
import { type ThemeStyles } from '../../styles';
|
|
28
29
|
import { defaultTheme, markdownTheme, textTheme } from '../../themes';
|
|
30
|
+
import { logChanges } from '../../util';
|
|
29
31
|
|
|
32
|
+
// TODO(burdon): Change to enum?
|
|
30
33
|
export const EditorModes = ['default', 'vim'] as const;
|
|
31
34
|
export type EditorMode = (typeof EditorModes)[number];
|
|
32
35
|
|
|
@@ -43,22 +46,26 @@ export type TextEditorSlots = {
|
|
|
43
46
|
root?: Omit<ComponentProps<'div'>, 'ref'>;
|
|
44
47
|
editor?: {
|
|
45
48
|
className?: string;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
theme?: ThemeStyles;
|
|
49
|
+
};
|
|
50
|
+
content?: {
|
|
51
|
+
className?: string;
|
|
50
52
|
};
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
// TODO(burdon): Spellcheck?
|
|
53
56
|
export type TextEditorProps = {
|
|
54
|
-
model: EditorModel;
|
|
55
|
-
focus?: boolean;
|
|
56
|
-
selection?: { anchor: number; head?: number };
|
|
57
|
+
model: EditorModel; // TODO(burdon): Optional (e.g., just provide content if readonly).
|
|
57
58
|
readonly?: boolean; // TODO(burdon): Move into model.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
autoFocus?: boolean;
|
|
60
|
+
lineWrapping?: boolean;
|
|
61
|
+
scrollTo?: StateEffect<any>; // TODO(burdon): Restore scroll position: scrollTo EditorView.scrollSnapshot().
|
|
62
|
+
selection?: { anchor: number; head?: number };
|
|
63
|
+
editorMode?: EditorMode; // TODO(burdon): Factor out.
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
theme?: ThemeStyles;
|
|
61
66
|
slots?: TextEditorSlots;
|
|
67
|
+
extensions?: Extension[];
|
|
68
|
+
debug?: boolean;
|
|
62
69
|
};
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -66,108 +73,134 @@ export type TextEditorProps = {
|
|
|
66
73
|
*/
|
|
67
74
|
export const BaseTextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
68
75
|
(
|
|
69
|
-
{
|
|
76
|
+
{
|
|
77
|
+
model,
|
|
78
|
+
readonly,
|
|
79
|
+
autoFocus,
|
|
80
|
+
scrollTo,
|
|
81
|
+
selection,
|
|
82
|
+
editorMode,
|
|
83
|
+
theme,
|
|
84
|
+
slots = defaultSlots,
|
|
85
|
+
extensions = [],
|
|
86
|
+
debug,
|
|
87
|
+
},
|
|
70
88
|
forwardedRef,
|
|
71
89
|
) => {
|
|
72
|
-
|
|
90
|
+
// TODO(burdon): Hook causes error even if properties are not spread into div.
|
|
91
|
+
// Uncaught TypeError: Cannot read properties of undefined (reading 'relatedTarget')
|
|
92
|
+
// Uses event.detail, which is deprecated (not event.details). At runtime the event has a property `details`.
|
|
93
|
+
// https://github.com/microsoft/tabster/blob/master/src/State/FocusedElement.ts#L348 (e.detail.relatedTarget)
|
|
94
|
+
// https://github.com/microsoft/keyborg/blob/49e49b2c3ba0a5f6cc518ac46825d7551def8109/src/FocusEvent.ts#L58
|
|
95
|
+
// const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
|
|
73
96
|
const { themeMode } = useThemeContext();
|
|
74
97
|
|
|
75
|
-
// The editor view ref should only be used as an escape hatch.
|
|
76
98
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
77
99
|
const [view, setView] = useState<EditorView | null>(null);
|
|
78
|
-
useImperativeHandle<EditorView | null, EditorView | null>(forwardedRef, () => view, [view]);
|
|
79
|
-
|
|
80
|
-
// Focus.
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
if (view && focus) {
|
|
83
|
-
view.focus();
|
|
84
|
-
}
|
|
85
|
-
}, [view, focus]);
|
|
86
100
|
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (awareness && peer) {
|
|
91
|
-
awareness.setLocalStateField('user', {
|
|
92
|
-
name: peer.name ?? generateName(peer.id),
|
|
93
|
-
color: getColorForValue({ value: peer.id, type: 'color' }),
|
|
94
|
-
colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}, [awareness, peer, themeMode]);
|
|
101
|
+
// The view ref can be used to focus the editor.
|
|
102
|
+
// NOTE: This does not cause the parent to re-render, so the ref is not available immediately.
|
|
103
|
+
useImperativeHandle<EditorView | null, EditorView | null>(forwardedRef, () => view, [view]);
|
|
98
104
|
|
|
99
|
-
//
|
|
105
|
+
// Set focus.
|
|
100
106
|
useEffect(() => {
|
|
101
|
-
if (
|
|
102
|
-
view.
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
if (autoFocus && !view?.hasFocus) {
|
|
108
|
+
if (view?.state.selection.main?.from === 0) {
|
|
109
|
+
// Start at end of line.
|
|
110
|
+
const { to } = view.state.doc.lineAt(0);
|
|
111
|
+
view?.dispatch({ selection: { anchor: to } });
|
|
112
|
+
}
|
|
113
|
+
view?.focus();
|
|
105
114
|
}
|
|
106
|
-
}, [view,
|
|
115
|
+
}, [view, autoFocus]);
|
|
107
116
|
|
|
117
|
+
// Create editor state and view.
|
|
118
|
+
// The view is recreated if the model or extensions are changed.
|
|
108
119
|
useEffect(() => {
|
|
109
120
|
if (!model || !rootRef.current) {
|
|
110
121
|
return;
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
//
|
|
124
|
+
//
|
|
125
|
+
// EditorState
|
|
114
126
|
// https://codemirror.net/docs/ref/#state.EditorStateConfig
|
|
127
|
+
//
|
|
115
128
|
const state = EditorState.create({
|
|
116
129
|
doc: model.text(),
|
|
117
130
|
selection,
|
|
118
131
|
extensions: [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
132
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
133
|
+
EditorView.exceptionSink.of((err) => {
|
|
134
|
+
log.catch(err);
|
|
135
|
+
}),
|
|
123
136
|
|
|
124
137
|
// Theme.
|
|
125
|
-
// TODO(burdon): Make
|
|
138
|
+
// TODO(burdon): Make configurable.
|
|
126
139
|
EditorView.baseTheme(defaultTheme),
|
|
127
|
-
EditorView.theme(
|
|
140
|
+
EditorView.theme(theme ?? {}),
|
|
128
141
|
EditorView.darkTheme.of(themeMode === 'dark'),
|
|
142
|
+
EditorView.editorAttributes.of({ class: slots.editor?.className ?? '' }),
|
|
143
|
+
EditorView.contentAttributes.of({ class: slots.content?.className ?? '' }),
|
|
144
|
+
|
|
145
|
+
// State.
|
|
146
|
+
EditorView.editable.of(!readonly),
|
|
147
|
+
EditorState.readOnly.of(!!readonly),
|
|
129
148
|
|
|
130
149
|
// Storage and replication.
|
|
150
|
+
// NOTE: This must come before user extensions.
|
|
131
151
|
model.extension,
|
|
132
152
|
|
|
153
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
154
|
+
editorMode === 'vim' && vim(),
|
|
155
|
+
|
|
133
156
|
// Custom.
|
|
134
157
|
...extensions,
|
|
135
|
-
].filter(
|
|
158
|
+
].filter(isNotFalsy),
|
|
136
159
|
});
|
|
137
160
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
|
|
161
|
+
//
|
|
162
|
+
// EditorView
|
|
163
|
+
// https://codemirror.net/docs/ref/#view.EditorViewConfig
|
|
164
|
+
//
|
|
142
165
|
const newView = new EditorView({
|
|
143
|
-
parent: rootRef.current,
|
|
144
166
|
state,
|
|
145
|
-
|
|
167
|
+
parent: rootRef.current,
|
|
168
|
+
scrollTo,
|
|
169
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
146
170
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
171
|
+
dispatchTransactions: (trs, view) => {
|
|
172
|
+
if (debug) {
|
|
173
|
+
logChanges(trs);
|
|
174
|
+
}
|
|
175
|
+
view.update(trs);
|
|
176
|
+
},
|
|
150
177
|
});
|
|
151
178
|
|
|
179
|
+
view?.destroy();
|
|
152
180
|
setView(newView);
|
|
181
|
+
|
|
153
182
|
return () => {
|
|
154
183
|
newView?.destroy();
|
|
155
184
|
setView(null);
|
|
156
185
|
};
|
|
157
186
|
}, [rootRef, model, readonly, editorMode, themeMode]);
|
|
158
187
|
|
|
188
|
+
// Handles tab/focus.
|
|
189
|
+
// Pressing Escape focuses the outer div (to support tab navigation); pressing Enter refocuses the editor.
|
|
190
|
+
// TODO(burdon): Convert to keymap?
|
|
159
191
|
const handleKeyUp = useCallback(
|
|
160
192
|
(event: KeyboardEvent) => {
|
|
161
193
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
162
194
|
switch (key) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
// }
|
|
195
|
+
case 'Enter': {
|
|
196
|
+
view?.focus();
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
168
199
|
|
|
169
200
|
case 'Escape': {
|
|
170
|
-
editorMode === 'vim' && (altKey || shiftKey || metaKey || ctrlKey)
|
|
201
|
+
if (editorMode === 'vim' && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
202
|
+
view?.focus();
|
|
203
|
+
}
|
|
171
204
|
break;
|
|
172
205
|
}
|
|
173
206
|
}
|
|
@@ -178,28 +211,27 @@ export const BaseTextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
178
211
|
return (
|
|
179
212
|
<div
|
|
180
213
|
key={model.id}
|
|
181
|
-
|
|
214
|
+
role='none'
|
|
182
215
|
tabIndex={0}
|
|
183
|
-
{...slots
|
|
184
|
-
{...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
216
|
+
{...slots.root}
|
|
217
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
185
218
|
onKeyUp={handleKeyUp}
|
|
219
|
+
ref={rootRef}
|
|
186
220
|
/>
|
|
187
221
|
);
|
|
188
222
|
},
|
|
189
223
|
);
|
|
190
224
|
|
|
191
225
|
export const TextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
192
|
-
({ readonly, extensions = [],
|
|
226
|
+
({ readonly, placeholder, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
193
227
|
const { themeMode } = useThemeContext();
|
|
194
228
|
const updatedSlots = defaultsDeep({}, slots, defaultTextSlots);
|
|
195
229
|
return (
|
|
196
230
|
<BaseTextEditor
|
|
197
231
|
ref={forwardedRef}
|
|
198
232
|
readonly={readonly}
|
|
199
|
-
extensions={[
|
|
200
|
-
|
|
201
|
-
...extensions,
|
|
202
|
-
]}
|
|
233
|
+
extensions={[createBasicBundle({ themeMode, placeholder, lineWrapping }), ...extensions]}
|
|
234
|
+
theme={theme}
|
|
203
235
|
slots={updatedSlots}
|
|
204
236
|
{...props}
|
|
205
237
|
/>
|
|
@@ -207,19 +239,16 @@ export const TextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
207
239
|
},
|
|
208
240
|
);
|
|
209
241
|
|
|
210
|
-
// TODO(burdon): Remove (Just provide bundle, slots).
|
|
211
242
|
export const MarkdownEditor = forwardRef<EditorView, TextEditorProps>(
|
|
212
|
-
({ readonly, extensions = [],
|
|
243
|
+
({ readonly, placeholder, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
213
244
|
const { themeMode } = useThemeContext();
|
|
214
245
|
const updatedSlots = defaultsDeep({}, slots, defaultMarkdownSlots);
|
|
215
246
|
return (
|
|
216
247
|
<BaseTextEditor
|
|
217
248
|
ref={forwardedRef}
|
|
218
249
|
readonly={readonly}
|
|
219
|
-
extensions={[
|
|
220
|
-
|
|
221
|
-
...extensions,
|
|
222
|
-
]}
|
|
250
|
+
extensions={[createMarkdownExtensions({ themeMode, placeholder }), ...extensions]}
|
|
251
|
+
theme={theme}
|
|
223
252
|
slots={updatedSlots}
|
|
224
253
|
{...props}
|
|
225
254
|
/>
|
|
@@ -229,20 +258,18 @@ export const MarkdownEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
229
258
|
|
|
230
259
|
export const defaultSlots: TextEditorSlots = {
|
|
231
260
|
root: {
|
|
232
|
-
|
|
261
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
262
|
+
className: mx('flex flex-col grow overflow-y-auto', attentionSurface),
|
|
263
|
+
},
|
|
264
|
+
editor: {
|
|
265
|
+
className: 'h-full p-2',
|
|
233
266
|
},
|
|
234
267
|
};
|
|
235
268
|
|
|
236
269
|
export const defaultTextSlots: TextEditorSlots = {
|
|
237
270
|
...defaultSlots,
|
|
238
|
-
editor: {
|
|
239
|
-
theme: textTheme,
|
|
240
|
-
},
|
|
241
271
|
};
|
|
242
272
|
|
|
243
273
|
export const defaultMarkdownSlots: TextEditorSlots = {
|
|
244
274
|
...defaultSlots,
|
|
245
|
-
editor: {
|
|
246
|
-
theme: markdownTheme,
|
|
247
|
-
},
|
|
248
275
|
};
|