@dxos/react-ui-editor 0.4.4-main.2a45fa8 → 0.4.4-main.2c7ecda
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 +187 -139
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +3 -2
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +3 -3
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +2 -1
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +15 -7
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor.d.ts +1 -1
- package/dist/types/src/extensions/cursor.d.ts.map +1 -1
- package/dist/types/src/hooks/useEditorView.d.ts +6 -4
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +3 -0
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/styles/layout.d.ts +1 -1
- package/dist/types/src/styles/layout.d.ts.map +1 -1
- package/package.json +26 -26
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +9 -2
- package/src/components/TextEditor/TextEditor.tsx +21 -8
- package/src/components/TextEditor/automerge.stories.tsx +10 -7
- package/src/components/TextEditor/hooks.stories.tsx +44 -10
- package/src/components/Toolbar/Toolbar.stories.tsx +4 -4
- package/src/extensions/autocomplete.ts +1 -1
- package/src/extensions/automerge/cursor.ts +15 -4
- package/src/extensions/automerge/defs.ts +0 -1
- package/src/extensions/basic.ts +3 -1
- package/src/extensions/comments.ts +111 -82
- package/src/extensions/cursor.ts +4 -2
- package/src/extensions/markdown/image.ts +1 -1
- package/src/hooks/useEditorView.ts +13 -11
- package/src/hooks/useTextEditor.ts +6 -2
- package/src/hooks/useTextModel.ts +7 -7
- package/src/styles/layout.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-editor",
|
|
3
|
-
"version": "0.4.4-main.
|
|
3
|
+
"version": "0.4.4-main.2c7ecda",
|
|
4
4
|
"description": "Document editing experience within a DXOS shell.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -36,25 +36,25 @@
|
|
|
36
36
|
"lodash.pick": "^4.4.0",
|
|
37
37
|
"lodash.sortby": "^4.7.0",
|
|
38
38
|
"style-mod": "^4.1.0",
|
|
39
|
-
"@dxos/async": "0.4.4-main.
|
|
40
|
-
"@dxos/automerge": "0.4.4-main.
|
|
41
|
-
"@dxos/context": "0.4.4-main.
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/react-
|
|
50
|
-
"@dxos/react-ui-theme": "0.4.4-main.
|
|
51
|
-
"@dxos/text-model": "0.4.4-main.
|
|
52
|
-
"@dxos/util": "0.4.4-main.
|
|
39
|
+
"@dxos/async": "0.4.4-main.2c7ecda",
|
|
40
|
+
"@dxos/automerge": "0.4.4-main.2c7ecda",
|
|
41
|
+
"@dxos/context": "0.4.4-main.2c7ecda",
|
|
42
|
+
"@dxos/debug": "0.4.4-main.2c7ecda",
|
|
43
|
+
"@dxos/display-name": "0.4.4-main.2c7ecda",
|
|
44
|
+
"@dxos/echo-schema": "0.4.4-main.2c7ecda",
|
|
45
|
+
"@dxos/invariant": "0.4.4-main.2c7ecda",
|
|
46
|
+
"@dxos/react-async": "0.4.4-main.2c7ecda",
|
|
47
|
+
"@dxos/log": "0.4.4-main.2c7ecda",
|
|
48
|
+
"@dxos/protocols": "0.4.4-main.2c7ecda",
|
|
49
|
+
"@dxos/react-ui": "0.4.4-main.2c7ecda",
|
|
50
|
+
"@dxos/react-ui-theme": "0.4.4-main.2c7ecda",
|
|
51
|
+
"@dxos/text-model": "0.4.4-main.2c7ecda",
|
|
52
|
+
"@dxos/util": "0.4.4-main.2c7ecda"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@automerge/automerge-repo-network-broadcastchannel": "^1.1.1",
|
|
56
56
|
"@phosphor-icons/react": "^2.0.5",
|
|
57
|
-
"@preact/signals-react": "^1.3.
|
|
57
|
+
"@preact/signals-react": "^1.3.8",
|
|
58
58
|
"@testing-library/dom": "^8.17.1",
|
|
59
59
|
"@testing-library/react": "^13.4.0",
|
|
60
60
|
"@testing-library/user-event": "^14.4.3",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@types/react-dom": "^18.0.6",
|
|
67
67
|
"@types/react-test-renderer": "^17.0.2",
|
|
68
68
|
"@vitest/ui": "^1.2.1",
|
|
69
|
-
"deepsignal": "1.
|
|
69
|
+
"deepsignal": "^1.5.0",
|
|
70
70
|
"happy-dom": "^13.3.1",
|
|
71
71
|
"jsdom": "^20.0.1",
|
|
72
72
|
"react": "^18.2.0",
|
|
@@ -76,20 +76,20 @@
|
|
|
76
76
|
"vite-plugin-top-level-await": "^1.4.1",
|
|
77
77
|
"vite-plugin-wasm": "^3.3.0",
|
|
78
78
|
"vitest": "^1.2.1",
|
|
79
|
-
"@dxos/config": "0.4.4-main.
|
|
80
|
-
"@dxos/echo-signals": "0.4.4-main.
|
|
81
|
-
"@dxos/keyboard": "0.4.4-main.
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/
|
|
84
|
-
"@dxos/
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
79
|
+
"@dxos/config": "0.4.4-main.2c7ecda",
|
|
80
|
+
"@dxos/echo-signals": "0.4.4-main.2c7ecda",
|
|
81
|
+
"@dxos/keyboard": "0.4.4-main.2c7ecda",
|
|
82
|
+
"@dxos/random": "0.4.4-main.2c7ecda",
|
|
83
|
+
"@dxos/echo-typegen": "0.4.4-main.2c7ecda",
|
|
84
|
+
"@dxos/react-ui": "0.4.4-main.2c7ecda",
|
|
85
|
+
"@dxos/react-client": "0.4.4-main.2c7ecda",
|
|
86
|
+
"@dxos/storybook-utils": "0.4.4-main.2c7ecda"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@phosphor-icons/react": "^2.0.5",
|
|
90
90
|
"react": "^18.2.0",
|
|
91
91
|
"react-dom": "^18.2.0",
|
|
92
|
-
"@dxos/react-client": "0.4.4-main.
|
|
92
|
+
"@dxos/react-client": "0.4.4-main.2c7ecda"
|
|
93
93
|
},
|
|
94
94
|
"publishConfig": {
|
|
95
95
|
"access": "public"
|
|
@@ -131,6 +131,12 @@ const document = str(
|
|
|
131
131
|
'',
|
|
132
132
|
'> This is a block quote.',
|
|
133
133
|
'',
|
|
134
|
+
'> This is a long wrapping block quote. Neque reiciendis ullam quae error labore sit, at, et, nulla, aut at nostrum omnis quas nostrum, at consectetur vitae eos asperiores non omnis ullam in beatae at vitae deserunt asperiores sapiente.',
|
|
135
|
+
'',
|
|
136
|
+
'> This is',
|
|
137
|
+
'> a multi-line',
|
|
138
|
+
'> block quote.',
|
|
139
|
+
'',
|
|
134
140
|
'This is all about https://dxos.org and related technologies.',
|
|
135
141
|
'',
|
|
136
142
|
'This this is **bold**, ~~strikethrough~~, _italic_, and `f(INLINE)`.',
|
|
@@ -211,15 +217,16 @@ const onRenderLink: LinkOptions['onRender'] = (el, url) => {
|
|
|
211
217
|
};
|
|
212
218
|
|
|
213
219
|
type StoryProps = {
|
|
220
|
+
id?: string;
|
|
214
221
|
text?: string;
|
|
215
222
|
comments?: Comment[];
|
|
216
223
|
} & Pick<TextEditorProps, 'readonly' | 'placeholder' | 'extensions'>;
|
|
217
224
|
|
|
218
|
-
const Story = ({ text, comments, placeholder = 'New document.', ...props }: StoryProps) => {
|
|
225
|
+
const Story = ({ id = 'test', text, comments, placeholder = 'New document.', ...props }: StoryProps) => {
|
|
219
226
|
const [item] = useState({ text: new TextObject(text) });
|
|
220
227
|
const view = useRef<EditorView>(null);
|
|
221
228
|
const model = useTextModel({ text: item.text });
|
|
222
|
-
useComments(view.current, comments);
|
|
229
|
+
useComments(view.current, id, comments);
|
|
223
230
|
if (!model) {
|
|
224
231
|
return null;
|
|
225
232
|
}
|
|
@@ -15,6 +15,7 @@ import React, {
|
|
|
15
15
|
useImperativeHandle,
|
|
16
16
|
useRef,
|
|
17
17
|
useState,
|
|
18
|
+
useMemo,
|
|
18
19
|
} from 'react';
|
|
19
20
|
|
|
20
21
|
import { log } from '@dxos/log';
|
|
@@ -65,7 +66,7 @@ export type TextEditorProps = {
|
|
|
65
66
|
* Base text editor.
|
|
66
67
|
*/
|
|
67
68
|
// TODO(burdon): Replace with useTextEditor.
|
|
68
|
-
export const BaseTextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
69
|
+
export const BaseTextEditor = forwardRef<EditorView | null, TextEditorProps>(
|
|
69
70
|
(
|
|
70
71
|
{ model, readonly, autoFocus, scrollTo, selection, theme, slots = defaultSlots, extensions = [], debug },
|
|
71
72
|
forwardedRef,
|
|
@@ -172,7 +173,8 @@ export const BaseTextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
172
173
|
newView?.destroy();
|
|
173
174
|
setView(null);
|
|
174
175
|
};
|
|
175
|
-
|
|
176
|
+
// TODO(wittjosiah): Does `rootRef` ever change? Only `.current` changes?
|
|
177
|
+
}, [rootRef, extensions, model, readonly, themeMode]);
|
|
176
178
|
|
|
177
179
|
// Focus editor on Enter (e.g., when tabbing to this component).
|
|
178
180
|
const handleKeyUp = useCallback<KeyboardEventHandler<HTMLDivElement>>(
|
|
@@ -202,15 +204,22 @@ export const BaseTextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
202
204
|
},
|
|
203
205
|
);
|
|
204
206
|
|
|
205
|
-
export const TextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
206
|
-
(
|
|
207
|
+
export const TextEditor = forwardRef<EditorView | null, TextEditorProps>(
|
|
208
|
+
(
|
|
209
|
+
{ readonly, placeholder, lineWrapping, theme = textTheme, slots, extensions: _extensions, ...props },
|
|
210
|
+
forwardedRef,
|
|
211
|
+
) => {
|
|
207
212
|
const { themeMode } = useThemeContext();
|
|
208
213
|
const updatedSlots = defaultsDeep({}, slots, defaultTextSlots);
|
|
214
|
+
const extensions = useMemo(
|
|
215
|
+
() => [createBasicBundle({ themeMode, placeholder, lineWrapping }), ...(_extensions ?? [])],
|
|
216
|
+
[themeMode, placeholder, lineWrapping, _extensions],
|
|
217
|
+
);
|
|
209
218
|
return (
|
|
210
219
|
<BaseTextEditor
|
|
211
220
|
ref={forwardedRef}
|
|
212
221
|
readonly={readonly}
|
|
213
|
-
extensions={
|
|
222
|
+
extensions={extensions}
|
|
214
223
|
theme={theme}
|
|
215
224
|
slots={updatedSlots}
|
|
216
225
|
{...props}
|
|
@@ -219,15 +228,19 @@ export const TextEditor = forwardRef<EditorView, TextEditorProps>(
|
|
|
219
228
|
},
|
|
220
229
|
);
|
|
221
230
|
|
|
222
|
-
export const MarkdownEditor = forwardRef<EditorView, TextEditorProps>(
|
|
223
|
-
({ readonly, placeholder, theme = markdownTheme, slots, extensions
|
|
231
|
+
export const MarkdownEditor = forwardRef<EditorView | null, TextEditorProps>(
|
|
232
|
+
({ readonly, placeholder, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
|
|
224
233
|
const { themeMode } = useThemeContext();
|
|
225
234
|
const updatedSlots = defaultsDeep({}, slots, defaultMarkdownSlots);
|
|
235
|
+
const extensions = useMemo(
|
|
236
|
+
() => [createMarkdownExtensions({ themeMode, placeholder }), ...(_extensions ?? [])],
|
|
237
|
+
[themeMode, placeholder, _extensions],
|
|
238
|
+
);
|
|
226
239
|
return (
|
|
227
240
|
<BaseTextEditor
|
|
228
241
|
ref={forwardedRef}
|
|
229
242
|
readonly={readonly}
|
|
230
|
-
extensions={
|
|
243
|
+
extensions={extensions}
|
|
231
244
|
theme={theme}
|
|
232
245
|
slots={updatedSlots}
|
|
233
246
|
{...props}
|
|
@@ -8,7 +8,7 @@ import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-networ
|
|
|
8
8
|
import '@preact/signals-react';
|
|
9
9
|
import { EditorView } from '@codemirror/view'; // Register react integration.
|
|
10
10
|
import get from 'lodash.get';
|
|
11
|
-
import React, { useEffect, useState } from 'react';
|
|
11
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
12
12
|
|
|
13
13
|
import { type Prop } from '@dxos/automerge/automerge';
|
|
14
14
|
import { Repo, type DocHandle } from '@dxos/automerge/automerge-repo';
|
|
@@ -37,17 +37,20 @@ type EditorProps = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const Editor = ({ handle, path = ['text'] }: EditorProps) => {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
doc: get(handle.docSync()!, path),
|
|
43
|
-
extensions: [
|
|
44
|
-
//
|
|
40
|
+
const extensions = useMemo(
|
|
41
|
+
() => [
|
|
45
42
|
EditorView.baseTheme(defaultTheme),
|
|
46
43
|
EditorView.editorAttributes.of({ class: 'p-2 bg-white' }),
|
|
47
44
|
createBasicBundle({ placeholder: 'Type here...' }),
|
|
48
45
|
automerge({ handle, path }),
|
|
49
46
|
awareness(),
|
|
50
47
|
],
|
|
48
|
+
[handle, path],
|
|
49
|
+
);
|
|
50
|
+
const { parentRef } = useTextEditor({
|
|
51
|
+
autoFocus: true,
|
|
52
|
+
doc: get(handle.docSync()!, path),
|
|
53
|
+
extensions,
|
|
51
54
|
});
|
|
52
55
|
|
|
53
56
|
return <div ref={parentRef} />;
|
|
@@ -133,7 +136,7 @@ export const WithEcho = {
|
|
|
133
136
|
}),
|
|
134
137
|
);
|
|
135
138
|
}}
|
|
136
|
-
|
|
139
|
+
component={EchoStory}
|
|
137
140
|
/>
|
|
138
141
|
);
|
|
139
142
|
},
|
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxosTheme';
|
|
6
6
|
|
|
7
|
-
import React from 'react';
|
|
7
|
+
import React, { useMemo, useState } from 'react';
|
|
8
8
|
|
|
9
|
-
import { useThemeContext } from '@dxos/react-ui';
|
|
9
|
+
import { Toolbar as NaturalToolbar, Select, useThemeContext } from '@dxos/react-ui';
|
|
10
10
|
import { attentionSurface, mx, textBlockWidth } from '@dxos/react-ui-theme';
|
|
11
11
|
import { withTheme } from '@dxos/storybook-utils';
|
|
12
12
|
|
|
13
13
|
import { TextEditor } from './TextEditor';
|
|
14
14
|
import {
|
|
15
|
+
type EditorMode,
|
|
16
|
+
EditorModes,
|
|
15
17
|
code,
|
|
16
18
|
createMarkdownExtensions,
|
|
17
19
|
formatting,
|
|
@@ -45,11 +47,10 @@ type StoryProps = {
|
|
|
45
47
|
const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
|
|
46
48
|
const { themeMode } = useThemeContext();
|
|
47
49
|
const [formattingState, trackFormatting] = useFormattingState();
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
50
|
+
const [editorMode, setEditorMode] = useState<EditorMode>('default');
|
|
51
|
+
const extensions = useMemo(
|
|
52
|
+
() => [
|
|
53
|
+
editorMode ? EditorModes[editorMode] : [],
|
|
53
54
|
createDataExtensions({ readonly }),
|
|
54
55
|
createThemeExtensions({
|
|
55
56
|
themeMode,
|
|
@@ -71,16 +72,19 @@ const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
|
|
|
71
72
|
tasklist(),
|
|
72
73
|
trackFormatting,
|
|
73
74
|
],
|
|
74
|
-
|
|
75
|
+
[editorMode, themeMode, placeholder, trackFormatting, readonly],
|
|
76
|
+
);
|
|
77
|
+
const { parentRef, view } = useTextEditor({ autoFocus, doc, extensions });
|
|
75
78
|
|
|
76
79
|
const handleAction = useActionHandler(view);
|
|
77
80
|
|
|
78
|
-
//
|
|
79
|
-
// sure if view is even guaranteed to exist at this point.
|
|
81
|
+
// TODO(marijn) This doesn't update the state on view changes.
|
|
82
|
+
// Also not sure if view is even guaranteed to exist at this point.
|
|
80
83
|
return (
|
|
81
84
|
<div role='none' className={mx('fixed inset-0', editorWithToolbarLayout)}>
|
|
82
85
|
<Toolbar.Root onAction={handleAction} state={formattingState} classNames={textBlockWidth}>
|
|
83
86
|
<Toolbar.Markdown />
|
|
87
|
+
<EditorModeToolbar editorMode={editorMode} setEditorMode={setEditorMode} />
|
|
84
88
|
</Toolbar.Root>
|
|
85
89
|
<div role='none' className='overflow-y-auto'>
|
|
86
90
|
<div
|
|
@@ -93,6 +97,36 @@ const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
|
|
|
93
97
|
);
|
|
94
98
|
};
|
|
95
99
|
|
|
100
|
+
const EditorModeToolbar = ({
|
|
101
|
+
editorMode,
|
|
102
|
+
setEditorMode,
|
|
103
|
+
}: {
|
|
104
|
+
editorMode: EditorMode;
|
|
105
|
+
setEditorMode: (mode: EditorMode) => void;
|
|
106
|
+
}) => {
|
|
107
|
+
return (
|
|
108
|
+
<Select.Root value={editorMode} onValueChange={(value) => setEditorMode(value as EditorMode)}>
|
|
109
|
+
<NaturalToolbar.Button asChild>
|
|
110
|
+
<Select.TriggerButton variant='ghost'>{editorMode}</Select.TriggerButton>
|
|
111
|
+
</NaturalToolbar.Button>
|
|
112
|
+
<Select.Portal>
|
|
113
|
+
<Select.Content>
|
|
114
|
+
<Select.ScrollUpButton />
|
|
115
|
+
<Select.Viewport>
|
|
116
|
+
{['default', 'vim'].map((mode) => (
|
|
117
|
+
<Select.Option key={mode} value={mode}>
|
|
118
|
+
{mode}
|
|
119
|
+
</Select.Option>
|
|
120
|
+
))}
|
|
121
|
+
</Select.Viewport>
|
|
122
|
+
<Select.ScrollDownButton />
|
|
123
|
+
<Select.Arrow />
|
|
124
|
+
</Select.Content>
|
|
125
|
+
</Select.Portal>
|
|
126
|
+
</Select.Root>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
|
|
96
130
|
export default {
|
|
97
131
|
title: 'react-ui-editor/useTextEditor',
|
|
98
132
|
component: TextEditor,
|
|
@@ -31,10 +31,10 @@ import { MarkdownEditor } from '../TextEditor';
|
|
|
31
31
|
|
|
32
32
|
faker.seed(101);
|
|
33
33
|
|
|
34
|
-
const Story: FC<{ content: string }> = ({ content }) => {
|
|
34
|
+
const Story: FC<{ id?: string; content: string }> = ({ id = 'test', content }) => {
|
|
35
35
|
const [item] = useState({ text: new TextObject(content) });
|
|
36
36
|
const [_comments, setComments] = useState<Comment[]>([]);
|
|
37
|
-
const [editorRef,
|
|
37
|
+
const [editorRef, viewInvalidated] = useEditorView(id);
|
|
38
38
|
const model = useTextModel({ text: item.text });
|
|
39
39
|
const [formattingState, formattingObserver] = useFormattingState();
|
|
40
40
|
const extensions = useMemo(
|
|
@@ -57,8 +57,8 @@ const Story: FC<{ content: string }> = ({ content }) => {
|
|
|
57
57
|
[],
|
|
58
58
|
);
|
|
59
59
|
|
|
60
|
-
useComments(
|
|
61
|
-
const handleAction = useActionHandler(
|
|
60
|
+
useComments(viewInvalidated ? null : editorRef.current, id, _comments);
|
|
61
|
+
const handleAction = useActionHandler(editorRef.current);
|
|
62
62
|
|
|
63
63
|
if (!model) {
|
|
64
64
|
return null;
|
|
@@ -35,7 +35,7 @@ export const autocomplete = ({ onSearch }: AutocompleteOptions) => {
|
|
|
35
35
|
// https://codemirror.net/examples/autocompletion
|
|
36
36
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
37
37
|
autocompletion({
|
|
38
|
-
activateOnTyping:
|
|
38
|
+
activateOnTyping: false,
|
|
39
39
|
|
|
40
40
|
// closeOnBlur: false,
|
|
41
41
|
// defaultKeymap: false,
|
|
@@ -6,6 +6,7 @@ import get from 'lodash.get';
|
|
|
6
6
|
|
|
7
7
|
import type { Prop } from '@dxos/automerge/automerge';
|
|
8
8
|
import { next as A } from '@dxos/automerge/automerge';
|
|
9
|
+
import { log } from '@dxos/log';
|
|
9
10
|
|
|
10
11
|
import { type IDocHandle } from './defs';
|
|
11
12
|
import { type CursorConverter } from '../cursor';
|
|
@@ -23,8 +24,13 @@ export const cursorConverter = (handle: IDocHandle, path: Prop[]): CursorConvert
|
|
|
23
24
|
return 'end';
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
try {
|
|
28
|
+
// NOTE: Slice is needed because getCursor mutates the array.
|
|
29
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
log.catch(err);
|
|
32
|
+
return ''; // In case of invalid request (e.g., wrong document).
|
|
33
|
+
}
|
|
28
34
|
},
|
|
29
35
|
|
|
30
36
|
fromCursor: (cursor) => {
|
|
@@ -46,7 +52,12 @@ export const cursorConverter = (handle: IDocHandle, path: Prop[]): CursorConvert
|
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
try {
|
|
56
|
+
// NOTE: Slice is needed because getCursor mutates the array.
|
|
57
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
log.catch(err);
|
|
60
|
+
return 0; // In case of invalid request (e.g., wrong document).
|
|
61
|
+
}
|
|
51
62
|
},
|
|
52
63
|
});
|
|
@@ -35,7 +35,6 @@ export type IDocHandle<T = any> = {
|
|
|
35
35
|
docSync(): Doc<T> | undefined;
|
|
36
36
|
change(callback: ChangeFn<T>, options?: ChangeOptions<T>): void;
|
|
37
37
|
changeAt(heads: Heads, callback: ChangeFn<T>, options?: ChangeOptions<T>): string[] | undefined;
|
|
38
|
-
|
|
39
38
|
addListener(event: 'change', listener: () => void): void;
|
|
40
39
|
removeListener(event: 'change', listener: () => void): void;
|
|
41
40
|
};
|
package/src/extensions/basic.ts
CHANGED
|
@@ -16,18 +16,20 @@ import { type TextEditorProps } from '../components';
|
|
|
16
16
|
|
|
17
17
|
export type BasicBundleOptions = {
|
|
18
18
|
themeMode?: ThemeMode;
|
|
19
|
+
bracketMatching?: boolean;
|
|
19
20
|
} & Pick<TextEditorProps, 'placeholder' | 'lineWrapping'>;
|
|
20
21
|
|
|
21
22
|
export const createBasicBundle = ({
|
|
22
23
|
themeMode,
|
|
23
24
|
placeholder: _placeholder,
|
|
24
25
|
lineWrapping = true,
|
|
26
|
+
bracketMatching: _bracketMatching = true,
|
|
25
27
|
}: BasicBundleOptions = {}): Extension[] =>
|
|
26
28
|
[
|
|
27
29
|
lineWrapping && EditorView.lineWrapping,
|
|
28
30
|
|
|
29
31
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
30
|
-
bracketMatching(),
|
|
32
|
+
_bracketMatching && bracketMatching(),
|
|
31
33
|
closeBrackets(),
|
|
32
34
|
drawSelection(),
|
|
33
35
|
highlightActiveLine(),
|