@dxos/react-ui-editor 0.3.11-main.2c83f41 → 0.3.11-main.2cb95a4
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 +779 -760
- 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 +16 -13
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
- 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 +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/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 +7 -9
- 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 +7 -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/awareness.d.ts +2 -0
- 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/code.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +31 -18
- 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/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +2 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -5
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- 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/extensions/tasklist.d.ts.map +1 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +1 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge.d.ts +2 -1
- package/dist/types/src/hooks/automerge.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +28 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- 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/hooks/yjs.d.ts +2 -1
- package/dist/types/src/hooks/yjs.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- 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 +32 -31
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +77 -79
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +124 -92
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.ts +40 -46
- package/src/extensions/automerge/cursor.ts +2 -1
- package/src/extensions/automerge/defs.ts +10 -31
- package/src/extensions/automerge/index.ts +0 -1
- package/src/extensions/automerge/semaphore.ts +23 -20
- package/src/extensions/automerge/update-automerge.ts +2 -2
- package/src/extensions/awareness.ts +45 -34
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/code.ts +24 -18
- package/src/extensions/comments.ts +242 -234
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/hr.ts +49 -50
- package/src/extensions/image.ts +2 -2
- package/src/extensions/index.ts +2 -0
- package/src/extensions/link.ts +7 -7
- package/src/extensions/markdown/bundle.ts +18 -24
- package/src/extensions/markdown/highlight.ts +0 -8
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/extensions/table.ts +2 -2
- package/src/extensions/tasklist.ts +78 -86
- package/src/extensions/yjs/cursor.ts +2 -1
- package/src/extensions/yjs/yjs.test.ts +1 -1
- package/src/extensions/yjs/yjs.ts +2 -2
- package/src/hooks/automerge.ts +2 -1
- package/src/hooks/defs.ts +47 -0
- package/src/hooks/index.ts +3 -1
- package/src/hooks/useTextModel.ts +3 -49
- package/src/hooks/yjs.ts +2 -23
- package/src/index.ts +1 -0
- package/src/styles/markdown.ts +0 -2
- package/src/themes/default.ts +17 -50
- package/src/util.ts +41 -0
- 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/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
|
@@ -8,10 +8,10 @@ import { type EditorState, type StateField, type Text, type Transaction } from '
|
|
|
8
8
|
|
|
9
9
|
import { next as am, type Heads } from '@dxos/automerge/automerge';
|
|
10
10
|
|
|
11
|
-
import { type IDocHandle, type
|
|
11
|
+
import { type IDocHandle, type State } from './defs';
|
|
12
12
|
|
|
13
13
|
export const updateAutomerge = (
|
|
14
|
-
field: StateField<
|
|
14
|
+
field: StateField<State>,
|
|
15
15
|
handle: IDocHandle,
|
|
16
16
|
transactions: Transaction[],
|
|
17
17
|
state: EditorState,
|
|
@@ -12,11 +12,16 @@ import {
|
|
|
12
12
|
type ViewUpdate,
|
|
13
13
|
WidgetType,
|
|
14
14
|
} from '@codemirror/view';
|
|
15
|
+
import { useEffect } from 'react';
|
|
15
16
|
|
|
16
17
|
import { Event } from '@dxos/async';
|
|
17
18
|
import { Context } from '@dxos/context';
|
|
19
|
+
import { generateName } from '@dxos/display-name';
|
|
20
|
+
import { useThemeContext } from '@dxos/react-ui';
|
|
21
|
+
import { getColorForValue } from '@dxos/react-ui-theme';
|
|
18
22
|
|
|
19
|
-
import { CursorConverter } from '
|
|
23
|
+
import { Cursor, type CursorConverter } from './cursor';
|
|
24
|
+
import { type EditorModel } from '../hooks';
|
|
20
25
|
|
|
21
26
|
export interface AwarenessProvider {
|
|
22
27
|
remoteStateChange: Event<void>;
|
|
@@ -66,7 +71,6 @@ export type AwarenessState = {
|
|
|
66
71
|
/**
|
|
67
72
|
* Extension provides presence information about other peers.
|
|
68
73
|
*/
|
|
69
|
-
// TODO(burdon): Why provide default?
|
|
70
74
|
export const awareness = (provider = dummyProvider): Extension => {
|
|
71
75
|
return [
|
|
72
76
|
AwarenessProvider.of(provider),
|
|
@@ -77,6 +81,19 @@ export const awareness = (provider = dummyProvider): Extension => {
|
|
|
77
81
|
];
|
|
78
82
|
};
|
|
79
83
|
|
|
84
|
+
export const useAwareness = ({ awareness, peer }: EditorModel) => {
|
|
85
|
+
const { themeMode } = useThemeContext();
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (awareness && peer) {
|
|
88
|
+
awareness.setLocalStateField('user', {
|
|
89
|
+
name: peer.name ?? generateName(peer.id),
|
|
90
|
+
color: getColorForValue({ value: peer.id, type: 'color' }),
|
|
91
|
+
colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}, [awareness, peer, themeMode]);
|
|
95
|
+
};
|
|
96
|
+
|
|
80
97
|
/**
|
|
81
98
|
* Generates selection decorations from remote peers.
|
|
82
99
|
*/
|
|
@@ -91,7 +108,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
91
108
|
private _lastHead?: number = undefined;
|
|
92
109
|
|
|
93
110
|
constructor(view: EditorView) {
|
|
94
|
-
this._cursorConverter = view.state.facet(
|
|
111
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
95
112
|
this._provider = view.state.facet(AwarenessProvider);
|
|
96
113
|
this._provider.open();
|
|
97
114
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
@@ -156,7 +173,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
156
173
|
to: end,
|
|
157
174
|
value: Decoration.mark({
|
|
158
175
|
attributes: { style: `background-color: ${lightColor}` },
|
|
159
|
-
class: 'cm-
|
|
176
|
+
class: 'cm-collab-selection',
|
|
160
177
|
}),
|
|
161
178
|
});
|
|
162
179
|
} else {
|
|
@@ -166,7 +183,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
166
183
|
to: startLine.from + startLine.length,
|
|
167
184
|
value: Decoration.mark({
|
|
168
185
|
attributes: { style: `background-color: ${color}` },
|
|
169
|
-
class: 'cm-
|
|
186
|
+
class: 'cm-collab-selection',
|
|
170
187
|
}),
|
|
171
188
|
});
|
|
172
189
|
|
|
@@ -176,7 +193,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
176
193
|
to: end,
|
|
177
194
|
value: Decoration.mark({
|
|
178
195
|
attributes: { style: `background-color: ${color}` },
|
|
179
|
-
class: 'cm-
|
|
196
|
+
class: 'cm-collab-selection',
|
|
180
197
|
}),
|
|
181
198
|
});
|
|
182
199
|
|
|
@@ -186,7 +203,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
186
203
|
from: linePos,
|
|
187
204
|
to: linePos,
|
|
188
205
|
value: Decoration.line({
|
|
189
|
-
attributes: { style: `background-color: ${color}`, class: 'cm-
|
|
206
|
+
attributes: { style: `background-color: ${color}`, class: 'cm-collab-selectionLine' },
|
|
190
207
|
}),
|
|
191
208
|
});
|
|
192
209
|
}
|
|
@@ -208,24 +225,22 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
|
208
225
|
}
|
|
209
226
|
|
|
210
227
|
class RemoteCaretWidget extends WidgetType {
|
|
211
|
-
constructor(
|
|
228
|
+
constructor(private readonly _name: string, private readonly _color: string) {
|
|
212
229
|
super();
|
|
213
|
-
this.name = name;
|
|
214
|
-
this.color = color;
|
|
215
230
|
}
|
|
216
231
|
|
|
217
|
-
toDOM(): HTMLElement {
|
|
232
|
+
override toDOM(): HTMLElement {
|
|
218
233
|
const span = document.createElement('span');
|
|
219
|
-
span.className = 'cm-
|
|
220
|
-
span.style.backgroundColor = this.
|
|
221
|
-
span.style.borderColor = this.
|
|
234
|
+
span.className = 'cm-collab-selectionCaret';
|
|
235
|
+
span.style.backgroundColor = this._color;
|
|
236
|
+
span.style.borderColor = this._color;
|
|
222
237
|
|
|
223
238
|
const dot = document.createElement('div');
|
|
224
|
-
dot.className = 'cm-
|
|
239
|
+
dot.className = 'cm-collab-selectionCaretDot';
|
|
225
240
|
|
|
226
241
|
const info = document.createElement('div');
|
|
227
|
-
info.className = 'cm-
|
|
228
|
-
info.innerText = this.
|
|
242
|
+
info.className = 'cm-collab-selectionInfo';
|
|
243
|
+
info.innerText = this._name;
|
|
229
244
|
|
|
230
245
|
span.appendChild(document.createTextNode('\u2060'));
|
|
231
246
|
span.appendChild(dot);
|
|
@@ -236,18 +251,14 @@ class RemoteCaretWidget extends WidgetType {
|
|
|
236
251
|
return span;
|
|
237
252
|
}
|
|
238
253
|
|
|
239
|
-
override eq(widget: this) {
|
|
240
|
-
return widget.color === this.color;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
compare(widget: this) {
|
|
244
|
-
return widget.color === this.color;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
254
|
override updateDOM() {
|
|
248
255
|
return false;
|
|
249
256
|
}
|
|
250
257
|
|
|
258
|
+
override eq(widget: this) {
|
|
259
|
+
return widget._color === this._color;
|
|
260
|
+
}
|
|
261
|
+
|
|
251
262
|
override get estimatedHeight() {
|
|
252
263
|
return -1;
|
|
253
264
|
}
|
|
@@ -257,14 +268,14 @@ class RemoteCaretWidget extends WidgetType {
|
|
|
257
268
|
}
|
|
258
269
|
}
|
|
259
270
|
|
|
260
|
-
// TODO(burdon):
|
|
271
|
+
// TODO(burdon): Mixed case?
|
|
261
272
|
const styles = EditorView.baseTheme({
|
|
262
|
-
'.cm-
|
|
263
|
-
'.cm-
|
|
273
|
+
'.cm-collab-selection': {},
|
|
274
|
+
'.cm-collab-selectionLine': {
|
|
264
275
|
padding: 0,
|
|
265
276
|
margin: '0px 2px 0px 4px',
|
|
266
277
|
},
|
|
267
|
-
'.cm-
|
|
278
|
+
'.cm-collab-selectionCaret': {
|
|
268
279
|
position: 'relative',
|
|
269
280
|
borderLeft: '1px solid black',
|
|
270
281
|
borderRight: '1px solid black',
|
|
@@ -273,7 +284,7 @@ const styles = EditorView.baseTheme({
|
|
|
273
284
|
boxSizing: 'border-box',
|
|
274
285
|
display: 'inline',
|
|
275
286
|
},
|
|
276
|
-
'.cm-
|
|
287
|
+
'.cm-collab-selectionCaretDot': {
|
|
277
288
|
borderRadius: '50%',
|
|
278
289
|
position: 'absolute',
|
|
279
290
|
width: '.4em',
|
|
@@ -284,11 +295,11 @@ const styles = EditorView.baseTheme({
|
|
|
284
295
|
transition: 'transform .3s ease-in-out',
|
|
285
296
|
boxSizing: 'border-box',
|
|
286
297
|
},
|
|
287
|
-
'.cm-
|
|
298
|
+
'.cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot': {
|
|
288
299
|
transformOrigin: 'bottom center',
|
|
289
300
|
transform: 'scale(0)',
|
|
290
301
|
},
|
|
291
|
-
'.cm-
|
|
302
|
+
'.cm-collab-selectionInfo': {
|
|
292
303
|
position: 'absolute',
|
|
293
304
|
top: '-1.05em',
|
|
294
305
|
left: '-1px',
|
|
@@ -304,12 +315,12 @@ const styles = EditorView.baseTheme({
|
|
|
304
315
|
zIndex: 101,
|
|
305
316
|
transition: 'opacity .3s ease-in-out',
|
|
306
317
|
backgroundColor: 'inherit',
|
|
307
|
-
//
|
|
318
|
+
// These should be separate.
|
|
308
319
|
opacity: 0,
|
|
309
320
|
transitionDelay: '0s',
|
|
310
321
|
whiteSpace: 'nowrap',
|
|
311
322
|
},
|
|
312
|
-
'.cm-
|
|
323
|
+
'.cm-collab-selectionCaret:hover > .cm-collab-selectionInfo': {
|
|
313
324
|
opacity: 1,
|
|
314
325
|
transitionDelay: '0s',
|
|
315
326
|
},
|
package/src/extensions/basic.ts
CHANGED
|
@@ -3,30 +3,35 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { closeBrackets } from '@codemirror/autocomplete';
|
|
6
|
+
import { history } from '@codemirror/commands';
|
|
6
7
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
|
7
8
|
import { type Extension } from '@codemirror/state';
|
|
8
9
|
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
|
9
|
-
import { drawSelection, EditorView, placeholder } from '@codemirror/view';
|
|
10
|
+
import { drawSelection, EditorView, highlightActiveLine, placeholder } from '@codemirror/view';
|
|
10
11
|
|
|
11
|
-
import type
|
|
12
|
+
import { type ThemeMode } from '@dxos/react-ui';
|
|
13
|
+
|
|
14
|
+
import { type TextEditorProps } from '../components';
|
|
12
15
|
|
|
13
16
|
export type BasicBundleOptions = {
|
|
14
|
-
readonly?: boolean;
|
|
15
17
|
themeMode?: ThemeMode;
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
+
} & Pick<TextEditorProps, 'placeholder' | 'multiline'>;
|
|
18
19
|
|
|
19
|
-
export const basicBundle = ({
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
export const basicBundle = ({
|
|
21
|
+
themeMode,
|
|
22
|
+
placeholder: _placeholder,
|
|
23
|
+
multiline = true,
|
|
24
|
+
}: BasicBundleOptions): Extension[] => [
|
|
25
|
+
multiline ? EditorView.lineWrapping : [],
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
28
|
+
bracketMatching(),
|
|
29
|
+
closeBrackets(),
|
|
30
|
+
drawSelection(),
|
|
31
|
+
highlightActiveLine(),
|
|
32
|
+
history(),
|
|
33
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
// https://github.com/codemirror/theme-one-dark
|
|
36
|
+
themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
37
|
+
];
|
package/src/extensions/code.ts
CHANGED
|
@@ -53,22 +53,20 @@ const getLineRange = (lines: BlockInfo[], from: number, to: number) => {
|
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
export const code = () => {
|
|
56
|
-
const
|
|
56
|
+
const buildDecorations = (view: EditorView) => {
|
|
57
57
|
const decorations: Range<Decoration>[] = [];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
);
|
|
71
|
-
}
|
|
58
|
+
const text = view.state.doc.sliceString(0);
|
|
59
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
60
|
+
const blocks = view.viewportLineBlocks;
|
|
61
|
+
for (const match of matches) {
|
|
62
|
+
const range = getLineRange(blocks, match.index!, match.index! + match[0].length);
|
|
63
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
64
|
+
const block = blocks[i];
|
|
65
|
+
decorations.push(
|
|
66
|
+
Decoration.line({
|
|
67
|
+
class: mx('cm-codeblock', i === range[0] && 'cm-codeblock-first', i === range[1] && 'cm-codeblock-last'),
|
|
68
|
+
}).range(block.from),
|
|
69
|
+
);
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -78,14 +76,22 @@ export const code = () => {
|
|
|
78
76
|
return [
|
|
79
77
|
ViewPlugin.fromClass(
|
|
80
78
|
class {
|
|
79
|
+
hasFocus = false;
|
|
81
80
|
decorations: DecorationSet;
|
|
82
81
|
constructor(view: EditorView) {
|
|
83
|
-
this.decorations =
|
|
82
|
+
this.decorations = buildDecorations(view);
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
update(update: ViewUpdate) {
|
|
87
|
-
if (
|
|
88
|
-
|
|
86
|
+
if (
|
|
87
|
+
// TODO(burdon): Generalize for other extensions.
|
|
88
|
+
this.hasFocus !== update.view.hasFocus ||
|
|
89
|
+
update.startState.readOnly !== update.view.state.readOnly ||
|
|
90
|
+
update.docChanged ||
|
|
91
|
+
update.viewportChanged
|
|
92
|
+
) {
|
|
93
|
+
this.hasFocus = update.view.hasFocus;
|
|
94
|
+
this.decorations = buildDecorations(update.view);
|
|
89
95
|
}
|
|
90
96
|
}
|
|
91
97
|
},
|