@dxos/react-ui-editor 0.3.11-main.7e75884 → 0.3.11-main.7ff9773
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 +770 -769
- 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 +19 -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/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 +2 -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 +113 -92
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/extensions/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.ts +24 -49
- package/src/extensions/automerge/cursor.ts +2 -1
- package/src/extensions/automerge/defs.ts +10 -31
- 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 +6 -3
- 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 +2 -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
|
@@ -7,51 +7,54 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
7
7
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
9
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
11
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
15
|
-
import {
|
|
16
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
|
+
import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
|
|
17
|
+
import { inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
18
|
|
|
19
19
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
21
22
|
import { keymap } from "@codemirror/view";
|
|
22
23
|
var autocomplete = ({ onSearch }) => {
|
|
23
24
|
return [
|
|
24
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
25
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
26
28
|
keymap.of(completionKeymap),
|
|
27
29
|
// https://codemirror.net/examples/autocompletion
|
|
28
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
29
31
|
autocompletion({
|
|
30
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
31
34
|
// defaultKeymap: false,
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
from: match.from,
|
|
44
|
-
options: onSearch(match.text.toLowerCase())
|
|
45
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
46
45
|
}
|
|
47
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
48
51
|
})
|
|
49
52
|
];
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView } from "@codemirror/view";
|
|
55
58
|
import { next as A } from "@dxos/automerge/automerge";
|
|
56
59
|
|
|
57
60
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
@@ -93,12 +96,12 @@ var cursorConverter = (handle, path) => ({
|
|
|
93
96
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
94
97
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
95
98
|
var effectType = StateEffect.define({});
|
|
99
|
+
var reconcileAnnotationType = Annotation.define();
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
96
102
|
var updateHeads = (newHeads) => effectType.of({
|
|
97
103
|
newHeads
|
|
98
104
|
});
|
|
99
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
100
|
-
var getPath = (state, field) => state.field(field).path;
|
|
101
|
-
var reconcileAnnotationType = Annotation.define();
|
|
102
105
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
103
106
|
|
|
104
107
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
@@ -236,85 +239,95 @@ var charPath = (textPath, candidatePath) => {
|
|
|
236
239
|
|
|
237
240
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
238
241
|
var PatchSemaphore = class {
|
|
239
|
-
|
|
240
|
-
|
|
242
|
+
// prettier-ignore
|
|
243
|
+
constructor(_handle, _state) {
|
|
244
|
+
this._handle = _handle;
|
|
245
|
+
this._state = _state;
|
|
241
246
|
this._inReconcile = false;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
changes: inverted,
|
|
258
|
-
annotations: reconcileAnnotationType.of(true)
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
262
|
-
if (newHeads === null || newHeads === void 0) {
|
|
263
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
264
|
-
}
|
|
265
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
266
|
-
updateCodeMirror(view, selection, path, diff);
|
|
247
|
+
}
|
|
248
|
+
// NOTE: Cannot destruct view.state.
|
|
249
|
+
reconcile(view) {
|
|
250
|
+
if (this._inReconcile) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
this._inReconcile = true;
|
|
254
|
+
const path = getPath(view.state, this._state);
|
|
255
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
256
|
+
let selection = view.state.selection;
|
|
257
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
258
|
+
const toInvert = transactions.slice().reverse();
|
|
259
|
+
for (const tx of toInvert) {
|
|
260
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
261
|
+
selection = selection.map(inverted);
|
|
267
262
|
view.dispatch({
|
|
268
|
-
|
|
269
|
-
annotations: reconcileAnnotationType.of(
|
|
263
|
+
changes: inverted,
|
|
264
|
+
annotations: reconcileAnnotationType.of(true)
|
|
270
265
|
});
|
|
271
|
-
|
|
272
|
-
|
|
266
|
+
}
|
|
267
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
268
|
+
if (newHeads === null || newHeads === void 0) {
|
|
269
|
+
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
270
|
+
}
|
|
271
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
272
|
+
updateCodeMirror(view, selection, path, diff);
|
|
273
|
+
view.dispatch({
|
|
274
|
+
effects: updateHeads(newHeads),
|
|
275
|
+
annotations: reconcileAnnotationType.of({})
|
|
276
|
+
});
|
|
277
|
+
this._inReconcile = false;
|
|
273
278
|
}
|
|
274
279
|
};
|
|
275
280
|
|
|
276
|
-
// packages/ui/react-ui-editor/src/
|
|
281
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
277
282
|
import { Facet } from "@codemirror/state";
|
|
278
|
-
var
|
|
283
|
+
var defaultCursorConverter = {
|
|
279
284
|
toCursor: (position) => position.toString(),
|
|
280
285
|
fromCursor: (cursor) => parseInt(cursor)
|
|
281
286
|
};
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
// packages/ui/react-ui-editor/src/util/util.ts
|
|
287
|
-
import { log } from "@dxos/log";
|
|
288
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
289
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
290
|
-
try {
|
|
291
|
-
return fn(...args);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
log.catch(error, void 0, {
|
|
294
|
-
F: __dxlog_file,
|
|
295
|
-
L: 16,
|
|
296
|
-
S: void 0,
|
|
297
|
-
C: (f, a) => f(...a)
|
|
287
|
+
var Cursor = class _Cursor {
|
|
288
|
+
static {
|
|
289
|
+
this.converter = Facet.define({
|
|
290
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
298
291
|
});
|
|
299
292
|
}
|
|
293
|
+
static {
|
|
294
|
+
this.getCursorFromRange = (state, range) => {
|
|
295
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
296
|
+
const from = cursorConverter3.toCursor(range.from);
|
|
297
|
+
const to = cursorConverter3.toCursor(range.to, -1);
|
|
298
|
+
return [
|
|
299
|
+
from,
|
|
300
|
+
to
|
|
301
|
+
].join(":");
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
static {
|
|
305
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
306
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
307
|
+
const parts = cursor.split(":");
|
|
308
|
+
const from = cursorConverter3.fromCursor(parts[0]);
|
|
309
|
+
const to = cursorConverter3.fromCursor(parts[1]);
|
|
310
|
+
return from !== void 0 && to !== void 0 ? {
|
|
311
|
+
from,
|
|
312
|
+
to
|
|
313
|
+
} : void 0;
|
|
314
|
+
};
|
|
315
|
+
}
|
|
300
316
|
};
|
|
301
317
|
|
|
302
318
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
303
|
-
var semaphoreFacet = Facet2.define({
|
|
304
|
-
combine: (values) => values.at(-1)
|
|
305
|
-
});
|
|
306
319
|
var automerge3 = ({ handle, path }) => {
|
|
307
|
-
const
|
|
320
|
+
const state = StateField.define({
|
|
308
321
|
create: () => ({
|
|
322
|
+
path: path.slice(),
|
|
309
323
|
lastHeads: A.getHeads(handle.docSync()),
|
|
310
|
-
unreconciledTransactions: []
|
|
311
|
-
path: path.slice()
|
|
324
|
+
unreconciledTransactions: []
|
|
312
325
|
}),
|
|
313
326
|
update: (value, tr) => {
|
|
314
327
|
const result = {
|
|
328
|
+
path: path.slice(),
|
|
315
329
|
lastHeads: value.lastHeads,
|
|
316
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
317
|
-
path: path.slice()
|
|
330
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
318
331
|
};
|
|
319
332
|
let clearUnreconciled = false;
|
|
320
333
|
for (const effect of tr.effects) {
|
|
@@ -333,41 +346,27 @@ var automerge3 = ({ handle, path }) => {
|
|
|
333
346
|
return result;
|
|
334
347
|
}
|
|
335
348
|
});
|
|
336
|
-
const semaphore = new PatchSemaphore(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
};
|
|
343
|
-
handle.addListener("change", this._handleChange);
|
|
344
|
-
}
|
|
345
|
-
update(update2) {
|
|
346
|
-
if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
347
|
-
queueMicrotask(() => {
|
|
348
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
349
|
-
});
|
|
349
|
+
const semaphore = new PatchSemaphore(handle, state);
|
|
350
|
+
return [
|
|
351
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
352
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
353
|
+
if (!changes.empty) {
|
|
354
|
+
semaphore.reconcile(view);
|
|
350
355
|
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
return {
|
|
357
|
-
extension: [
|
|
358
|
-
CursorConverter.of(cursorConverter(handle, path)),
|
|
359
|
-
semaphoreFacet.of(semaphore),
|
|
360
|
-
stateField,
|
|
361
|
-
viewPlugin
|
|
362
|
-
]
|
|
363
|
-
};
|
|
356
|
+
}),
|
|
357
|
+
state
|
|
358
|
+
];
|
|
364
359
|
};
|
|
365
360
|
|
|
366
361
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
367
|
-
import { Annotation as Annotation2, Facet as
|
|
368
|
-
import { Decoration, EditorView
|
|
362
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
363
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin, WidgetType } from "@codemirror/view";
|
|
364
|
+
import { useEffect } from "react";
|
|
369
365
|
import { Event } from "@dxos/async";
|
|
370
366
|
import { Context } from "@dxos/context";
|
|
367
|
+
import { generateName } from "@dxos/display-name";
|
|
368
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
369
|
+
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
371
370
|
var dummyProvider = {
|
|
372
371
|
remoteStateChange: new Event(),
|
|
373
372
|
open: () => {
|
|
@@ -378,26 +377,49 @@ var dummyProvider = {
|
|
|
378
377
|
},
|
|
379
378
|
getRemoteStates: () => []
|
|
380
379
|
};
|
|
381
|
-
var AwarenessProvider =
|
|
380
|
+
var AwarenessProvider = Facet2.define({
|
|
382
381
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
383
382
|
});
|
|
384
383
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
385
384
|
var awareness = (provider = dummyProvider) => {
|
|
386
385
|
return [
|
|
387
386
|
AwarenessProvider.of(provider),
|
|
388
|
-
|
|
387
|
+
ViewPlugin.fromClass(RemoteSelectionsDecorator, {
|
|
389
388
|
decorations: (value) => value.decorations
|
|
390
389
|
}),
|
|
391
390
|
styles
|
|
392
391
|
];
|
|
393
392
|
};
|
|
393
|
+
var useAwareness = ({ awareness: awareness2, peer }) => {
|
|
394
|
+
const { themeMode } = useThemeContext();
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (awareness2 && peer) {
|
|
397
|
+
awareness2.setLocalStateField("user", {
|
|
398
|
+
name: peer.name ?? generateName(peer.id),
|
|
399
|
+
color: getColorForValue({
|
|
400
|
+
value: peer.id,
|
|
401
|
+
type: "color"
|
|
402
|
+
}),
|
|
403
|
+
colorLight: getColorForValue({
|
|
404
|
+
value: peer.id,
|
|
405
|
+
themeMode,
|
|
406
|
+
type: "highlight"
|
|
407
|
+
})
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}, [
|
|
411
|
+
awareness2,
|
|
412
|
+
peer,
|
|
413
|
+
themeMode
|
|
414
|
+
]);
|
|
415
|
+
};
|
|
394
416
|
var RemoteSelectionsDecorator = class {
|
|
395
417
|
constructor(view) {
|
|
396
418
|
this.decorations = RangeSet.of([]);
|
|
397
419
|
this._ctx = new Context();
|
|
398
420
|
this._lastAnchor = void 0;
|
|
399
421
|
this._lastHead = void 0;
|
|
400
|
-
this._cursorConverter = view.state.facet(
|
|
422
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
401
423
|
this._provider = view.state.facet(AwarenessProvider);
|
|
402
424
|
this._provider.open();
|
|
403
425
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
@@ -452,7 +474,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
452
474
|
attributes: {
|
|
453
475
|
style: `background-color: ${lightColor}`
|
|
454
476
|
},
|
|
455
|
-
class: "cm-
|
|
477
|
+
class: "cm-collab-selection"
|
|
456
478
|
})
|
|
457
479
|
});
|
|
458
480
|
} else {
|
|
@@ -463,7 +485,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
463
485
|
attributes: {
|
|
464
486
|
style: `background-color: ${color}`
|
|
465
487
|
},
|
|
466
|
-
class: "cm-
|
|
488
|
+
class: "cm-collab-selection"
|
|
467
489
|
})
|
|
468
490
|
});
|
|
469
491
|
decorations.push({
|
|
@@ -473,7 +495,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
473
495
|
attributes: {
|
|
474
496
|
style: `background-color: ${color}`
|
|
475
497
|
},
|
|
476
|
-
class: "cm-
|
|
498
|
+
class: "cm-collab-selection"
|
|
477
499
|
})
|
|
478
500
|
});
|
|
479
501
|
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
@@ -484,7 +506,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
484
506
|
value: Decoration.line({
|
|
485
507
|
attributes: {
|
|
486
508
|
style: `background-color: ${color}`,
|
|
487
|
-
class: "cm-
|
|
509
|
+
class: "cm-collab-selectionLine"
|
|
488
510
|
}
|
|
489
511
|
})
|
|
490
512
|
});
|
|
@@ -504,23 +526,21 @@ var RemoteSelectionsDecorator = class {
|
|
|
504
526
|
}
|
|
505
527
|
};
|
|
506
528
|
var RemoteCaretWidget = class extends WidgetType {
|
|
507
|
-
constructor(
|
|
529
|
+
constructor(_name, _color) {
|
|
508
530
|
super();
|
|
509
|
-
this.
|
|
510
|
-
this.
|
|
511
|
-
this.name = name;
|
|
512
|
-
this.color = color;
|
|
531
|
+
this._name = _name;
|
|
532
|
+
this._color = _color;
|
|
513
533
|
}
|
|
514
534
|
toDOM() {
|
|
515
535
|
const span = document.createElement("span");
|
|
516
|
-
span.className = "cm-
|
|
517
|
-
span.style.backgroundColor = this.
|
|
518
|
-
span.style.borderColor = this.
|
|
536
|
+
span.className = "cm-collab-selectionCaret";
|
|
537
|
+
span.style.backgroundColor = this._color;
|
|
538
|
+
span.style.borderColor = this._color;
|
|
519
539
|
const dot = document.createElement("div");
|
|
520
|
-
dot.className = "cm-
|
|
540
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
521
541
|
const info = document.createElement("div");
|
|
522
|
-
info.className = "cm-
|
|
523
|
-
info.innerText = this.
|
|
542
|
+
info.className = "cm-collab-selectionInfo";
|
|
543
|
+
info.innerText = this._name;
|
|
524
544
|
span.appendChild(document.createTextNode("\u2060"));
|
|
525
545
|
span.appendChild(dot);
|
|
526
546
|
span.appendChild(document.createTextNode("\u2060"));
|
|
@@ -528,15 +548,12 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
528
548
|
span.appendChild(document.createTextNode("\u2060"));
|
|
529
549
|
return span;
|
|
530
550
|
}
|
|
531
|
-
eq(widget) {
|
|
532
|
-
return widget.color === this.color;
|
|
533
|
-
}
|
|
534
|
-
compare(widget) {
|
|
535
|
-
return widget.color === this.color;
|
|
536
|
-
}
|
|
537
551
|
updateDOM() {
|
|
538
552
|
return false;
|
|
539
553
|
}
|
|
554
|
+
eq(widget) {
|
|
555
|
+
return widget._color === this._color;
|
|
556
|
+
}
|
|
540
557
|
get estimatedHeight() {
|
|
541
558
|
return -1;
|
|
542
559
|
}
|
|
@@ -544,13 +561,13 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
544
561
|
return true;
|
|
545
562
|
}
|
|
546
563
|
};
|
|
547
|
-
var styles =
|
|
548
|
-
".cm-
|
|
549
|
-
".cm-
|
|
564
|
+
var styles = EditorView2.baseTheme({
|
|
565
|
+
".cm-collab-selection": {},
|
|
566
|
+
".cm-collab-selectionLine": {
|
|
550
567
|
padding: 0,
|
|
551
568
|
margin: "0px 2px 0px 4px"
|
|
552
569
|
},
|
|
553
|
-
".cm-
|
|
570
|
+
".cm-collab-selectionCaret": {
|
|
554
571
|
position: "relative",
|
|
555
572
|
borderLeft: "1px solid black",
|
|
556
573
|
borderRight: "1px solid black",
|
|
@@ -559,7 +576,7 @@ var styles = EditorView.baseTheme({
|
|
|
559
576
|
boxSizing: "border-box",
|
|
560
577
|
display: "inline"
|
|
561
578
|
},
|
|
562
|
-
".cm-
|
|
579
|
+
".cm-collab-selectionCaretDot": {
|
|
563
580
|
borderRadius: "50%",
|
|
564
581
|
position: "absolute",
|
|
565
582
|
width: ".4em",
|
|
@@ -570,11 +587,11 @@ var styles = EditorView.baseTheme({
|
|
|
570
587
|
transition: "transform .3s ease-in-out",
|
|
571
588
|
boxSizing: "border-box"
|
|
572
589
|
},
|
|
573
|
-
".cm-
|
|
590
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
574
591
|
transformOrigin: "bottom center",
|
|
575
592
|
transform: "scale(0)"
|
|
576
593
|
},
|
|
577
|
-
".cm-
|
|
594
|
+
".cm-collab-selectionInfo": {
|
|
578
595
|
position: "absolute",
|
|
579
596
|
top: "-1.05em",
|
|
580
597
|
left: "-1px",
|
|
@@ -590,12 +607,12 @@ var styles = EditorView.baseTheme({
|
|
|
590
607
|
zIndex: 101,
|
|
591
608
|
transition: "opacity .3s ease-in-out",
|
|
592
609
|
backgroundColor: "inherit",
|
|
593
|
-
//
|
|
610
|
+
// These should be separate.
|
|
594
611
|
opacity: 0,
|
|
595
612
|
transitionDelay: "0s",
|
|
596
613
|
whiteSpace: "nowrap"
|
|
597
614
|
},
|
|
598
|
-
".cm-
|
|
615
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
599
616
|
opacity: 1,
|
|
600
617
|
transitionDelay: "0s"
|
|
601
618
|
}
|
|
@@ -603,26 +620,28 @@ var styles = EditorView.baseTheme({
|
|
|
603
620
|
|
|
604
621
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
605
622
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
623
|
+
import { history } from "@codemirror/commands";
|
|
606
624
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
607
625
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
608
|
-
import { drawSelection, EditorView as
|
|
609
|
-
var basicBundle = ({
|
|
610
|
-
|
|
611
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
626
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, multiline = true }) => [
|
|
628
|
+
multiline ? EditorView3.lineWrapping : [],
|
|
612
629
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
613
630
|
bracketMatching(),
|
|
614
631
|
closeBrackets(),
|
|
615
632
|
drawSelection(),
|
|
616
|
-
|
|
617
|
-
|
|
633
|
+
highlightActiveLine(),
|
|
634
|
+
history(),
|
|
635
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
636
|
+
// https://github.com/codemirror/theme-one-dark
|
|
618
637
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
619
|
-
]
|
|
638
|
+
];
|
|
620
639
|
|
|
621
640
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
622
|
-
import { EditorView as
|
|
641
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
623
642
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
624
643
|
import { invariant } from "@dxos/invariant";
|
|
625
|
-
var
|
|
644
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
626
645
|
var defaultOptions = {
|
|
627
646
|
effect: 2,
|
|
628
647
|
maxParticles: 200,
|
|
@@ -667,7 +686,7 @@ var blast = (options = defaultOptions) => {
|
|
|
667
686
|
};
|
|
668
687
|
return [
|
|
669
688
|
// Cursor moved.
|
|
670
|
-
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
671
690
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
691
|
if (blaster) {
|
|
673
692
|
blaster.destroy();
|
|
@@ -749,7 +768,7 @@ var Blaster = class {
|
|
|
749
768
|
}
|
|
750
769
|
initialize() {
|
|
751
770
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
752
|
-
F:
|
|
771
|
+
F: __dxlog_file,
|
|
753
772
|
L: 138,
|
|
754
773
|
S: this,
|
|
755
774
|
A: [
|
|
@@ -786,7 +805,7 @@ var Blaster = class {
|
|
|
786
805
|
}
|
|
787
806
|
start() {
|
|
788
807
|
invariant(this._canvas && this._ctx, void 0, {
|
|
789
|
-
F:
|
|
808
|
+
F: __dxlog_file,
|
|
790
809
|
L: 177,
|
|
791
810
|
S: this,
|
|
792
811
|
A: [
|
|
@@ -929,7 +948,7 @@ var random = (min, max) => {
|
|
|
929
948
|
};
|
|
930
949
|
|
|
931
950
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
932
|
-
import { ViewPlugin as
|
|
951
|
+
import { ViewPlugin as ViewPlugin2, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
|
|
933
952
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
934
953
|
|
|
935
954
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
@@ -1020,7 +1039,7 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
|
|
|
1020
1039
|
|
|
1021
1040
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1022
1041
|
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1023
|
-
var styles2 =
|
|
1042
|
+
var styles2 = EditorView5.baseTheme({
|
|
1024
1043
|
"& .cm-codeblock": {
|
|
1025
1044
|
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1026
1045
|
},
|
|
@@ -1054,32 +1073,35 @@ var getLineRange = (lines, from, to) => {
|
|
|
1054
1073
|
];
|
|
1055
1074
|
};
|
|
1056
1075
|
var code2 = () => {
|
|
1057
|
-
const
|
|
1076
|
+
const buildDecorations5 = (view) => {
|
|
1058
1077
|
const decorations = [];
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}).range(block.from));
|
|
1070
|
-
}
|
|
1078
|
+
const text = view.state.doc.sliceString(0);
|
|
1079
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1080
|
+
const blocks = view.viewportLineBlocks;
|
|
1081
|
+
for (const match of matches) {
|
|
1082
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1083
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1084
|
+
const block = blocks[i];
|
|
1085
|
+
decorations.push(Decoration2.line({
|
|
1086
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1087
|
+
}).range(block.from));
|
|
1071
1088
|
}
|
|
1072
1089
|
}
|
|
1073
1090
|
return Decoration2.set(decorations);
|
|
1074
1091
|
};
|
|
1075
1092
|
return [
|
|
1076
|
-
|
|
1093
|
+
ViewPlugin2.fromClass(class {
|
|
1077
1094
|
constructor(view) {
|
|
1078
|
-
this.
|
|
1095
|
+
this.hasFocus = false;
|
|
1096
|
+
this.decorations = buildDecorations5(view);
|
|
1079
1097
|
}
|
|
1080
1098
|
update(update2) {
|
|
1081
|
-
if (
|
|
1082
|
-
|
|
1099
|
+
if (
|
|
1100
|
+
// TODO(burdon): Generalize for other extensions.
|
|
1101
|
+
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1102
|
+
) {
|
|
1103
|
+
this.hasFocus = update2.view.hasFocus;
|
|
1104
|
+
this.decorations = buildDecorations5(update2.view);
|
|
1083
1105
|
}
|
|
1084
1106
|
}
|
|
1085
1107
|
}, {
|
|
@@ -1091,23 +1113,51 @@ var code2 = () => {
|
|
|
1091
1113
|
|
|
1092
1114
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1093
1115
|
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1094
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as
|
|
1116
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1095
1117
|
import sortBy from "lodash.sortby";
|
|
1118
|
+
import { useEffect as useEffect2 } from "react";
|
|
1096
1119
|
import { debounce } from "@dxos/async";
|
|
1097
1120
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1098
|
-
import { log as log2 } from "@dxos/log";
|
|
1099
1121
|
import { nonNullable } from "@dxos/util";
|
|
1122
|
+
|
|
1123
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1124
|
+
import { log } from "@dxos/log";
|
|
1125
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1126
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1127
|
+
try {
|
|
1128
|
+
return fn(...args);
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
log.catch(err, void 0, {
|
|
1131
|
+
F: __dxlog_file2,
|
|
1132
|
+
L: 18,
|
|
1133
|
+
S: void 0,
|
|
1134
|
+
C: (f, a) => f(...a)
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
var logChanges = (trs) => {
|
|
1139
|
+
const changes = trs.flatMap((tr) => {
|
|
1140
|
+
if (tr.changes.empty) {
|
|
1141
|
+
return void 0;
|
|
1142
|
+
}
|
|
1143
|
+
const changes2 = [];
|
|
1144
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1145
|
+
fromA,
|
|
1146
|
+
toA,
|
|
1147
|
+
fromB,
|
|
1148
|
+
toB,
|
|
1149
|
+
inserted: inserted.toString()
|
|
1150
|
+
})));
|
|
1151
|
+
return changes2;
|
|
1152
|
+
}).filter(Boolean);
|
|
1153
|
+
if (changes.length) {
|
|
1154
|
+
console.log("changes", changes);
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1100
1159
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1101
|
-
var styles3 =
|
|
1102
|
-
"& .cm-bookmark": {
|
|
1103
|
-
cursor: "pointer",
|
|
1104
|
-
margin: "4px",
|
|
1105
|
-
padding: "4px",
|
|
1106
|
-
backgroundColor: "yellow"
|
|
1107
|
-
},
|
|
1108
|
-
"& .cm-bookmark-selected": {
|
|
1109
|
-
backgroundColor: "orange"
|
|
1110
|
-
},
|
|
1160
|
+
var styles3 = EditorView6.baseTheme({
|
|
1111
1161
|
"& .cm-comment": {
|
|
1112
1162
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1163
|
},
|
|
@@ -1123,49 +1173,59 @@ var marks = {
|
|
|
1123
1173
|
class: "cm-comment-active"
|
|
1124
1174
|
})
|
|
1125
1175
|
};
|
|
1126
|
-
var setFocus = (view,
|
|
1127
|
-
const
|
|
1128
|
-
if (!
|
|
1176
|
+
var setFocus = (view, id, center = true) => {
|
|
1177
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1178
|
+
if (!comment?.comment.cursor) {
|
|
1129
1179
|
return;
|
|
1130
1180
|
}
|
|
1131
|
-
view.
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1181
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1182
|
+
if (range) {
|
|
1183
|
+
view.dispatch({
|
|
1184
|
+
selection: {
|
|
1185
|
+
anchor: range.from
|
|
1186
|
+
},
|
|
1187
|
+
effects: [
|
|
1188
|
+
//
|
|
1189
|
+
EditorView6.scrollIntoView(range.from, center ? {
|
|
1190
|
+
y: "center"
|
|
1191
|
+
} : void 0),
|
|
1192
|
+
setSelection.of({
|
|
1193
|
+
active: id
|
|
1194
|
+
})
|
|
1195
|
+
]
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1140
1198
|
};
|
|
1141
|
-
var
|
|
1199
|
+
var setComments = StateEffect2.define();
|
|
1142
1200
|
var setSelection = StateEffect2.define();
|
|
1143
1201
|
var setCommentState = StateEffect2.define();
|
|
1144
|
-
var
|
|
1202
|
+
var commentsState = StateField2.define({
|
|
1145
1203
|
create: () => ({
|
|
1146
|
-
|
|
1204
|
+
comments: [],
|
|
1205
|
+
selection: {}
|
|
1147
1206
|
}),
|
|
1148
1207
|
update: (value, tr) => {
|
|
1149
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1150
1208
|
for (const effect of tr.effects) {
|
|
1151
1209
|
if (effect.is(setSelection)) {
|
|
1152
1210
|
return {
|
|
1153
1211
|
...value,
|
|
1154
|
-
|
|
1212
|
+
selection: effect.value
|
|
1155
1213
|
};
|
|
1156
1214
|
}
|
|
1157
|
-
if (effect.is(
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1215
|
+
if (effect.is(setComments)) {
|
|
1216
|
+
const comments2 = effect.value.map((comment) => {
|
|
1217
|
+
if (!comment.cursor) {
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1161
1221
|
return range && {
|
|
1162
|
-
|
|
1163
|
-
|
|
1222
|
+
comment,
|
|
1223
|
+
range
|
|
1164
1224
|
};
|
|
1165
1225
|
}).filter(nonNullable);
|
|
1166
1226
|
return {
|
|
1167
1227
|
...value,
|
|
1168
|
-
|
|
1228
|
+
comments: comments2
|
|
1169
1229
|
};
|
|
1170
1230
|
}
|
|
1171
1231
|
if (effect.is(setCommentState)) {
|
|
@@ -1175,78 +1235,109 @@ var commentsStateField = StateField2.define({
|
|
|
1175
1235
|
return value;
|
|
1176
1236
|
}
|
|
1177
1237
|
});
|
|
1178
|
-
var highlightDecorations =
|
|
1179
|
-
|
|
1238
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1239
|
+
commentsState
|
|
1180
1240
|
], (state) => {
|
|
1181
|
-
const { active,
|
|
1182
|
-
const decorations = sortBy(
|
|
1183
|
-
|
|
1241
|
+
const { selection: { active }, comments: comments2 } = state.field(commentsState);
|
|
1242
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1243
|
+
const range = comment.range;
|
|
1244
|
+
if (!range || range.from === range.to) {
|
|
1245
|
+
console.warn("Invalid range:", range);
|
|
1184
1246
|
return void 0;
|
|
1185
1247
|
}
|
|
1186
|
-
|
|
1187
|
-
from: selection.from,
|
|
1188
|
-
to: selection.to
|
|
1189
|
-
};
|
|
1190
|
-
if (selection.id === active) {
|
|
1248
|
+
if (comment.comment.id === active) {
|
|
1191
1249
|
return marks.highlightActive.range(range.from, range.to);
|
|
1192
1250
|
} else {
|
|
1193
1251
|
return marks.highlight.range(range.from, range.to);
|
|
1194
1252
|
}
|
|
1195
|
-
}).filter(nonNullable)
|
|
1253
|
+
}).filter(nonNullable);
|
|
1196
1254
|
return Decoration3.set(decorations);
|
|
1197
1255
|
});
|
|
1198
|
-
var
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1216
|
-
}
|
|
1217
|
-
toDOM() {
|
|
1218
|
-
const span = document.createElement("span");
|
|
1219
|
-
span.className = "cm-bookmark";
|
|
1220
|
-
span.textContent = "\u203B";
|
|
1221
|
-
if (this._handleClick) {
|
|
1222
|
-
span.onclick = () => this._handleClick();
|
|
1256
|
+
var trackPastedComments = (onUpdate) => {
|
|
1257
|
+
let tracked = null;
|
|
1258
|
+
const handleTrack = (event, view) => {
|
|
1259
|
+
const comments2 = view.state.field(commentsState);
|
|
1260
|
+
const { main } = view.state.selection;
|
|
1261
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1262
|
+
if (!selectedRanges.length) {
|
|
1263
|
+
tracked = null;
|
|
1264
|
+
} else {
|
|
1265
|
+
tracked = {
|
|
1266
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1267
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1268
|
+
id: comment.id,
|
|
1269
|
+
from: range.from - main.from,
|
|
1270
|
+
to: range.to - main.from
|
|
1271
|
+
}))
|
|
1272
|
+
};
|
|
1223
1273
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1274
|
+
};
|
|
1275
|
+
return [
|
|
1276
|
+
EditorView6.domEventHandlers({
|
|
1277
|
+
cut: handleTrack,
|
|
1278
|
+
copy: handleTrack
|
|
1279
|
+
}),
|
|
1280
|
+
// Handle paste.
|
|
1281
|
+
EditorView6.updateListener.of(({ view, state, transactions }) => {
|
|
1282
|
+
if (tracked) {
|
|
1283
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1284
|
+
if (paste) {
|
|
1285
|
+
let found = -1;
|
|
1286
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1287
|
+
if (text.eq(tracked.text)) {
|
|
1288
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1289
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1290
|
+
}
|
|
1291
|
+
found = fromB;
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
if (found > -1) {
|
|
1295
|
+
for (const moved of tracked.comments) {
|
|
1296
|
+
const range = {
|
|
1297
|
+
from: found + moved.from,
|
|
1298
|
+
to: found + moved.to
|
|
1299
|
+
};
|
|
1300
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1301
|
+
onUpdate(moved.id, cursor);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
tracked = null;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
})
|
|
1308
|
+
];
|
|
1226
1309
|
};
|
|
1227
1310
|
var comments = (options = {}) => {
|
|
1311
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1228
1312
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1229
1313
|
const createCommentThread = (view) => {
|
|
1230
|
-
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1231
1314
|
invariant2(options.onCreate, void 0, {
|
|
1232
1315
|
F: __dxlog_file3,
|
|
1233
|
-
L:
|
|
1316
|
+
L: 259,
|
|
1234
1317
|
S: void 0,
|
|
1235
1318
|
A: [
|
|
1236
1319
|
"options.onCreate",
|
|
1237
1320
|
""
|
|
1238
1321
|
]
|
|
1239
1322
|
});
|
|
1240
|
-
const {
|
|
1323
|
+
const { from, to } = view.state.selection.main;
|
|
1241
1324
|
if (from === to) {
|
|
1242
1325
|
return false;
|
|
1243
1326
|
}
|
|
1244
|
-
|
|
1327
|
+
if (to === view.state.doc.length) {
|
|
1328
|
+
view.dispatch({
|
|
1329
|
+
changes: {
|
|
1330
|
+
from: to,
|
|
1331
|
+
insert: "\n"
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1245
1336
|
from,
|
|
1246
1337
|
to
|
|
1247
1338
|
});
|
|
1248
|
-
if (
|
|
1249
|
-
const id =
|
|
1339
|
+
if (cursor) {
|
|
1340
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1250
1341
|
if (id) {
|
|
1251
1342
|
view.dispatch({
|
|
1252
1343
|
effects: setSelection.of({
|
|
@@ -1256,53 +1347,13 @@ var comments = (options = {}) => {
|
|
|
1256
1347
|
anchor: from
|
|
1257
1348
|
}
|
|
1258
1349
|
});
|
|
1259
|
-
if (options.footnote) {
|
|
1260
|
-
const tag = `[^${id}]`;
|
|
1261
|
-
view.dispatch({
|
|
1262
|
-
changes: {
|
|
1263
|
-
from: head,
|
|
1264
|
-
insert: tag
|
|
1265
|
-
},
|
|
1266
|
-
selection: {
|
|
1267
|
-
anchor: head + tag.length
|
|
1268
|
-
}
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
1350
|
return true;
|
|
1272
1351
|
}
|
|
1273
1352
|
}
|
|
1274
1353
|
return false;
|
|
1275
1354
|
};
|
|
1276
|
-
const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
|
|
1277
|
-
static {
|
|
1278
|
-
// Match markdown footnotes (option).
|
|
1279
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1280
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1281
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1282
|
-
decoration: (match, view, pos) => {
|
|
1283
|
-
const id = match[1];
|
|
1284
|
-
return Decoration3.replace({
|
|
1285
|
-
id,
|
|
1286
|
-
widget: new BookmarkWidget(pos, id)
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
constructor(view) {
|
|
1292
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1293
|
-
}
|
|
1294
|
-
update(update2) {
|
|
1295
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update2, this.bookmarks);
|
|
1296
|
-
}
|
|
1297
|
-
}, {
|
|
1298
|
-
decorations: (instance) => instance.bookmarks,
|
|
1299
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1300
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1301
|
-
})
|
|
1302
|
-
});
|
|
1303
1355
|
return [
|
|
1304
|
-
|
|
1305
|
-
commentsStateField,
|
|
1356
|
+
commentsState,
|
|
1306
1357
|
highlightDecorations,
|
|
1307
1358
|
styles3,
|
|
1308
1359
|
//
|
|
@@ -1310,7 +1361,7 @@ var comments = (options = {}) => {
|
|
|
1310
1361
|
//
|
|
1311
1362
|
options.onCreate ? keymap3.of([
|
|
1312
1363
|
{
|
|
1313
|
-
key:
|
|
1364
|
+
key: shortcut,
|
|
1314
1365
|
run: callbackWrapper(createCommentThread)
|
|
1315
1366
|
}
|
|
1316
1367
|
]) : [],
|
|
@@ -1327,7 +1378,7 @@ var comments = (options = {}) => {
|
|
|
1327
1378
|
above: true,
|
|
1328
1379
|
create: () => {
|
|
1329
1380
|
const el = document.createElement("div");
|
|
1330
|
-
options.onHover
|
|
1381
|
+
options.onHover(el, shortcut);
|
|
1331
1382
|
return {
|
|
1332
1383
|
dom: el,
|
|
1333
1384
|
offset: {
|
|
@@ -1340,156 +1391,154 @@ var comments = (options = {}) => {
|
|
|
1340
1391
|
}
|
|
1341
1392
|
return null;
|
|
1342
1393
|
}, {
|
|
1343
|
-
|
|
1394
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1395
|
+
// hideOnChange: true,
|
|
1344
1396
|
hoverTime: 1e3
|
|
1345
1397
|
}) : [],
|
|
1346
1398
|
//
|
|
1347
|
-
//
|
|
1348
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1399
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1349
1400
|
//
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
{
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1360
|
-
log2.info("deleted comment", {
|
|
1361
|
-
thread: range.id
|
|
1362
|
-
}, {
|
|
1363
|
-
F: __dxlog_file3,
|
|
1364
|
-
L: 358,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1401
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1402
|
+
let mod = false;
|
|
1403
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1404
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1405
|
+
comments2.forEach(({ comment, range }) => {
|
|
1406
|
+
if (from2 === to2) {
|
|
1407
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1408
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1409
|
+
options.onDelete?.(comment.id);
|
|
1369
1410
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1411
|
+
}
|
|
1412
|
+
if (from <= range.to) {
|
|
1413
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1414
|
+
Object.assign(range, newRange);
|
|
1415
|
+
mod = true;
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1419
|
+
if (mod) {
|
|
1420
|
+
view.dispatch({
|
|
1421
|
+
effects: setCommentState.of({
|
|
1422
|
+
comments: comments2,
|
|
1423
|
+
...value
|
|
1424
|
+
})
|
|
1376
1425
|
});
|
|
1377
|
-
if (mod) {
|
|
1378
|
-
view.dispatch({
|
|
1379
|
-
effects: setCommentState.of({
|
|
1380
|
-
active,
|
|
1381
|
-
ranges
|
|
1382
|
-
})
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
1426
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1427
|
+
}),
|
|
1428
|
+
//
|
|
1429
|
+
// Track selection/proximity.
|
|
1430
|
+
//
|
|
1431
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1432
|
+
let min = Infinity;
|
|
1433
|
+
const { selection: { active, closest }, comments: comments2 } = state.field(commentsState);
|
|
1434
|
+
const { head } = state.selection.main;
|
|
1435
|
+
const selection = {};
|
|
1436
|
+
comments2.forEach(({ comment, range }) => {
|
|
1437
|
+
if (head >= range.from && head <= range.to) {
|
|
1438
|
+
selection.active = comment.id;
|
|
1439
|
+
selection.closest = void 0;
|
|
1440
|
+
}
|
|
1441
|
+
if (!selection.active) {
|
|
1442
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1399
1443
|
if (d < min) {
|
|
1400
|
-
|
|
1444
|
+
selection.closest = comment.id;
|
|
1401
1445
|
min = d;
|
|
1402
1446
|
}
|
|
1403
|
-
});
|
|
1404
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1405
|
-
view.dispatch({
|
|
1406
|
-
effects: setSelection.of(selected)
|
|
1407
|
-
});
|
|
1408
|
-
handleSelect({
|
|
1409
|
-
...selected,
|
|
1410
|
-
ranges: ranges.map((range) => ({
|
|
1411
|
-
...range,
|
|
1412
|
-
location: view.coordsAtPos(range.from)
|
|
1413
|
-
}))
|
|
1414
|
-
});
|
|
1415
1447
|
}
|
|
1448
|
+
});
|
|
1449
|
+
if (selection.active !== active || selection.closest !== closest) {
|
|
1450
|
+
view.dispatch({
|
|
1451
|
+
effects: setSelection.of(selection)
|
|
1452
|
+
});
|
|
1453
|
+
handleSelect({
|
|
1454
|
+
selection,
|
|
1455
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1456
|
+
comment,
|
|
1457
|
+
range,
|
|
1458
|
+
location: view.coordsAtPos(range.from)
|
|
1459
|
+
}))
|
|
1460
|
+
});
|
|
1416
1461
|
}
|
|
1417
|
-
})
|
|
1462
|
+
}),
|
|
1463
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1418
1464
|
];
|
|
1419
1465
|
};
|
|
1420
|
-
var
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1432
|
-
return from !== void 0 && to !== void 0 ? {
|
|
1433
|
-
from,
|
|
1434
|
-
to
|
|
1435
|
-
} : void 0;
|
|
1466
|
+
var useComments = (view, comments2) => {
|
|
1467
|
+
useEffect2(() => {
|
|
1468
|
+
if (view && comments2) {
|
|
1469
|
+
view.dispatch({
|
|
1470
|
+
effects: setComments.of(comments2)
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}, [
|
|
1474
|
+
view,
|
|
1475
|
+
comments2
|
|
1476
|
+
]);
|
|
1436
1477
|
};
|
|
1437
1478
|
|
|
1438
1479
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1439
|
-
import {
|
|
1440
|
-
|
|
1480
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1481
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1482
|
+
import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1483
|
+
var styles4 = EditorView7.baseTheme({
|
|
1441
1484
|
"& .cm-hr": {
|
|
1442
|
-
// TODO(burdon): ???
|
|
1443
1485
|
// Note that block-level decorations should not have vertical margins,
|
|
1444
|
-
|
|
1486
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1445
1487
|
}
|
|
1446
1488
|
});
|
|
1447
|
-
var HorizontalRuleWidget = class extends
|
|
1448
|
-
|
|
1449
|
-
super();
|
|
1450
|
-
this._pos = _pos;
|
|
1451
|
-
}
|
|
1452
|
-
eq(other) {
|
|
1453
|
-
return this._pos === other._pos;
|
|
1454
|
-
}
|
|
1455
|
-
toDOM(view) {
|
|
1489
|
+
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1490
|
+
toDOM() {
|
|
1456
1491
|
const el = document.createElement("div");
|
|
1457
1492
|
el.className = "cm-hr";
|
|
1458
1493
|
return el;
|
|
1459
1494
|
}
|
|
1460
1495
|
};
|
|
1461
|
-
var
|
|
1462
|
-
|
|
1463
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1464
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1465
|
-
})
|
|
1496
|
+
var decoration = Decoration4.replace({
|
|
1497
|
+
widget: new HorizontalRuleWidget()
|
|
1466
1498
|
});
|
|
1467
|
-
var
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1499
|
+
var buildDecorations = (view) => {
|
|
1500
|
+
const builder = new RangeSetBuilder();
|
|
1501
|
+
const { state } = view;
|
|
1502
|
+
const cursor = state.selection.main.head;
|
|
1503
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1504
|
+
syntaxTree(state).iterate({
|
|
1505
|
+
enter: (node) => {
|
|
1506
|
+
if (node.name === "HorizontalRule") {
|
|
1507
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1508
|
+
builder.add(node.from, node.to, decoration);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
from,
|
|
1513
|
+
to
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return builder.finish();
|
|
1517
|
+
};
|
|
1518
|
+
var hr = () => {
|
|
1519
|
+
return [
|
|
1520
|
+
styles4,
|
|
1521
|
+
ViewPlugin3.fromClass(class {
|
|
1522
|
+
constructor(view) {
|
|
1523
|
+
this.decorations = buildDecorations(view);
|
|
1524
|
+
}
|
|
1525
|
+
update(update2) {
|
|
1526
|
+
this.decorations = buildDecorations(update2.view);
|
|
1527
|
+
}
|
|
1528
|
+
}, {
|
|
1529
|
+
decorations: (v) => v.decorations
|
|
1481
1530
|
})
|
|
1482
|
-
|
|
1483
|
-
|
|
1531
|
+
];
|
|
1532
|
+
};
|
|
1484
1533
|
|
|
1485
1534
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1486
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1535
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1487
1536
|
import { StateField as StateField3 } from "@codemirror/state";
|
|
1488
|
-
import { Decoration as Decoration5, EditorView as
|
|
1537
|
+
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1489
1538
|
var image = (options = {}) => {
|
|
1490
1539
|
return StateField3.define({
|
|
1491
1540
|
create: (state) => {
|
|
1492
|
-
return Decoration5.set(
|
|
1541
|
+
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1493
1542
|
},
|
|
1494
1543
|
update: (value, tr) => {
|
|
1495
1544
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -1509,16 +1558,16 @@ var image = (options = {}) => {
|
|
|
1509
1558
|
filterFrom: from,
|
|
1510
1559
|
filterTo: to,
|
|
1511
1560
|
filter: () => false,
|
|
1512
|
-
add:
|
|
1561
|
+
add: buildDecorations2(from, to, tr.state)
|
|
1513
1562
|
});
|
|
1514
1563
|
},
|
|
1515
|
-
provide: (field) =>
|
|
1564
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1516
1565
|
});
|
|
1517
1566
|
};
|
|
1518
|
-
var
|
|
1567
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1519
1568
|
const decorations = [];
|
|
1520
1569
|
const cursor = state.selection.main.head;
|
|
1521
|
-
|
|
1570
|
+
syntaxTree2(state).iterate({
|
|
1522
1571
|
enter: (node) => {
|
|
1523
1572
|
if (node.name === "Image") {
|
|
1524
1573
|
const urlNode = node.node.getChild("URL");
|
|
@@ -1537,7 +1586,7 @@ var buildDecorations = (from, to, state) => {
|
|
|
1537
1586
|
});
|
|
1538
1587
|
return decorations;
|
|
1539
1588
|
};
|
|
1540
|
-
var ImageWidget = class extends
|
|
1589
|
+
var ImageWidget = class extends WidgetType3 {
|
|
1541
1590
|
constructor(_url) {
|
|
1542
1591
|
super();
|
|
1543
1592
|
this._url = _url;
|
|
@@ -1555,19 +1604,19 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
1555
1604
|
};
|
|
1556
1605
|
|
|
1557
1606
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1558
|
-
import { syntaxTree as
|
|
1559
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1560
|
-
import {
|
|
1607
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1608
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1609
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin4, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1561
1610
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1562
1611
|
var link = (options = {}) => {
|
|
1563
1612
|
const extensions = [
|
|
1564
|
-
|
|
1613
|
+
ViewPlugin4.fromClass(class {
|
|
1565
1614
|
constructor(view) {
|
|
1566
|
-
this.decorations =
|
|
1615
|
+
this.decorations = buildDecorations3(view, options);
|
|
1567
1616
|
}
|
|
1568
1617
|
update(update2) {
|
|
1569
1618
|
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1570
|
-
this.decorations =
|
|
1619
|
+
this.decorations = buildDecorations3(update2.view, options);
|
|
1571
1620
|
}
|
|
1572
1621
|
}
|
|
1573
1622
|
}, {
|
|
@@ -1580,7 +1629,7 @@ var link = (options = {}) => {
|
|
|
1580
1629
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1581
1630
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1582
1631
|
hoverTooltip2((view, pos, side) => {
|
|
1583
|
-
const syntax =
|
|
1632
|
+
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1584
1633
|
let link2 = null;
|
|
1585
1634
|
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1586
1635
|
link2 = node.name === "Link" ? node : null;
|
|
@@ -1612,7 +1661,7 @@ var link = (options = {}) => {
|
|
|
1612
1661
|
}
|
|
1613
1662
|
return extensions;
|
|
1614
1663
|
};
|
|
1615
|
-
var LinkButton = class extends
|
|
1664
|
+
var LinkButton = class extends WidgetType4 {
|
|
1616
1665
|
constructor(_url, _onAttach) {
|
|
1617
1666
|
super();
|
|
1618
1667
|
this._url = _url;
|
|
@@ -1627,7 +1676,7 @@ var LinkButton = class extends WidgetType5 {
|
|
|
1627
1676
|
return el;
|
|
1628
1677
|
}
|
|
1629
1678
|
};
|
|
1630
|
-
var LinkText = class extends
|
|
1679
|
+
var LinkText = class extends WidgetType4 {
|
|
1631
1680
|
constructor(_text, _url) {
|
|
1632
1681
|
super();
|
|
1633
1682
|
this._text = _text;
|
|
@@ -1656,12 +1705,12 @@ var LinkText = class extends WidgetType5 {
|
|
|
1656
1705
|
return link2;
|
|
1657
1706
|
}
|
|
1658
1707
|
};
|
|
1659
|
-
var
|
|
1660
|
-
const builder = new
|
|
1708
|
+
var buildDecorations3 = (view, options) => {
|
|
1709
|
+
const builder = new RangeSetBuilder2();
|
|
1661
1710
|
const { state } = view;
|
|
1662
1711
|
const cursor = state.selection.main.head;
|
|
1663
1712
|
for (const { from, to } of view.visibleRanges) {
|
|
1664
|
-
|
|
1713
|
+
syntaxTree3(state).iterate({
|
|
1665
1714
|
enter: (node) => {
|
|
1666
1715
|
if (node.name === "Link") {
|
|
1667
1716
|
const marks2 = node.node.getChildren("LinkMark");
|
|
@@ -1692,14 +1741,14 @@ var buildDecorations2 = (view, options) => {
|
|
|
1692
1741
|
};
|
|
1693
1742
|
|
|
1694
1743
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1695
|
-
import { EditorView as
|
|
1744
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1696
1745
|
var listener = ({ onFocus, onChange }) => {
|
|
1697
1746
|
const extensions = [];
|
|
1698
|
-
onFocus && extensions.push(
|
|
1747
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1699
1748
|
onFocus(focused);
|
|
1700
1749
|
return null;
|
|
1701
1750
|
}));
|
|
1702
|
-
onChange && extensions.push(
|
|
1751
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1703
1752
|
onChange(update2.state.doc.toString());
|
|
1704
1753
|
}));
|
|
1705
1754
|
return extensions;
|
|
@@ -1707,17 +1756,17 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1707
1756
|
|
|
1708
1757
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1709
1758
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1710
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1711
|
-
import { markdownLanguage as
|
|
1759
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1760
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1712
1761
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1713
1762
|
import { languages } from "@codemirror/language-data";
|
|
1714
1763
|
import { searchKeymap } from "@codemirror/search";
|
|
1715
1764
|
import { EditorState } from "@codemirror/state";
|
|
1716
1765
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1717
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1766
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1718
1767
|
|
|
1719
1768
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1720
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1769
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1721
1770
|
import { HighlightStyle } from "@codemirror/language";
|
|
1722
1771
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1723
1772
|
import { Table } from "@lezer/markdown";
|
|
@@ -1727,7 +1776,6 @@ var markdownTags = {
|
|
|
1727
1776
|
CodeText: Tag.define(),
|
|
1728
1777
|
EmphasisMark: Tag.define(),
|
|
1729
1778
|
HeaderMark: Tag.define(),
|
|
1730
|
-
// HorizontalRule: Tag.define(),
|
|
1731
1779
|
InlineCode: Tag.define(),
|
|
1732
1780
|
LinkLabel: Tag.define(),
|
|
1733
1781
|
LinkReference: Tag.define(),
|
|
@@ -1891,12 +1939,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1891
1939
|
],
|
|
1892
1940
|
class: blockquote
|
|
1893
1941
|
},
|
|
1894
|
-
// TODO(burdon): Replace with extension.
|
|
1895
|
-
// {
|
|
1896
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1897
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1898
|
-
// },
|
|
1899
|
-
// TODO(burdon): Only if being edited.
|
|
1900
1942
|
{
|
|
1901
1943
|
tag: [
|
|
1902
1944
|
markdownTags.TableCell
|
|
@@ -1904,7 +1946,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1904
1946
|
class: "font-mono"
|
|
1905
1947
|
}
|
|
1906
1948
|
], {
|
|
1907
|
-
scope:
|
|
1949
|
+
scope: markdownLanguage2,
|
|
1908
1950
|
all: {
|
|
1909
1951
|
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1910
1952
|
}
|
|
@@ -1916,17 +1958,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1916
1958
|
return [
|
|
1917
1959
|
EditorState.allowMultipleSelections.of(true),
|
|
1918
1960
|
EditorState.tabSize.of(2),
|
|
1919
|
-
|
|
1920
|
-
|
|
1961
|
+
EditorView10.lineWrapping,
|
|
1962
|
+
// https://github.com/codemirror/basic-setup
|
|
1921
1963
|
bracketMatching2(),
|
|
1922
1964
|
closeBrackets2(),
|
|
1923
1965
|
crosshairCursor(),
|
|
1924
1966
|
dropCursor(),
|
|
1925
1967
|
drawSelection2(),
|
|
1926
|
-
|
|
1927
|
-
|
|
1968
|
+
highlightActiveLine2(),
|
|
1969
|
+
history2(),
|
|
1928
1970
|
indentOnInput(),
|
|
1929
|
-
_placeholder
|
|
1971
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1930
1972
|
// Main extension.
|
|
1931
1973
|
// https://github.com/codemirror/lang-markdown
|
|
1932
1974
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1936,7 +1978,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1936
1978
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1937
1979
|
// https://github.github.com/gfm
|
|
1938
1980
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1939
|
-
base:
|
|
1981
|
+
base: markdownLanguage3,
|
|
1940
1982
|
// Languages for syntax highlighting fenced code blocks.
|
|
1941
1983
|
codeLanguages: languages,
|
|
1942
1984
|
// Parser extensions.
|
|
@@ -1948,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1948
1990
|
// https://github.com/codemirror/theme-one-dark
|
|
1949
1991
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1950
1992
|
// Custom styles.
|
|
1951
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1993
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly)),
|
|
1994
|
+
keymap4.of([
|
|
1995
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1996
|
+
indentWithTab,
|
|
1997
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1998
|
+
...closeBracketsKeymap,
|
|
1999
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2000
|
+
...historyKeymap,
|
|
2001
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2002
|
+
...searchKeymap,
|
|
2003
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2004
|
+
...standardKeymap
|
|
2005
|
+
])
|
|
2006
|
+
];
|
|
2007
|
+
};
|
|
1966
2008
|
|
|
1967
2009
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1968
2010
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1969
2011
|
var mention = ({ onSearch }) => {
|
|
1970
2012
|
return autocompletion2({
|
|
2013
|
+
// TODO(burdon): Not working.
|
|
2014
|
+
activateOnTyping: true,
|
|
2015
|
+
// activateOnTypingDelay: 100,
|
|
2016
|
+
// selectOnOpen: true,
|
|
1971
2017
|
closeOnBlur: false,
|
|
2018
|
+
// defaultKeymap: false,
|
|
2019
|
+
icons: false,
|
|
1972
2020
|
override: [
|
|
1973
2021
|
(context) => {
|
|
2022
|
+
console.log(context);
|
|
1974
2023
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1975
2024
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1976
2025
|
return null;
|
|
1977
2026
|
}
|
|
1978
|
-
console.log(match);
|
|
1979
2027
|
return {
|
|
1980
2028
|
from: match.from,
|
|
1981
2029
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1987,19 +2035,24 @@ var mention = ({ onSearch }) => {
|
|
|
1987
2035
|
});
|
|
1988
2036
|
};
|
|
1989
2037
|
|
|
2038
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2039
|
+
var outliner = (options = {}) => {
|
|
2040
|
+
return [];
|
|
2041
|
+
};
|
|
2042
|
+
|
|
1990
2043
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1991
|
-
import { syntaxTree as
|
|
1992
|
-
import { RangeSetBuilder as
|
|
1993
|
-
import { Decoration as Decoration7, EditorView as
|
|
2044
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2045
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
|
|
2046
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1994
2047
|
var table = (options = {}) => {
|
|
1995
2048
|
return StateField4.define({
|
|
1996
2049
|
create: (state) => update(state, options),
|
|
1997
2050
|
update: (_, tr) => update(tr.state, options),
|
|
1998
|
-
provide: (field) =>
|
|
2051
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1999
2052
|
});
|
|
2000
2053
|
};
|
|
2001
2054
|
var update = (state, options) => {
|
|
2002
|
-
const builder = new
|
|
2055
|
+
const builder = new RangeSetBuilder3();
|
|
2003
2056
|
const cursor = state.selection.main.head;
|
|
2004
2057
|
const tables = [];
|
|
2005
2058
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2007,7 +2060,7 @@ var update = (state, options) => {
|
|
|
2007
2060
|
const table2 = getTable();
|
|
2008
2061
|
return table2.rows?.[table2.rows.length - 1];
|
|
2009
2062
|
};
|
|
2010
|
-
|
|
2063
|
+
syntaxTree4(state).iterate({
|
|
2011
2064
|
enter: (node) => {
|
|
2012
2065
|
switch (node.name) {
|
|
2013
2066
|
case "Table": {
|
|
@@ -2040,7 +2093,6 @@ var update = (state, options) => {
|
|
|
2040
2093
|
tables.forEach((table2) => {
|
|
2041
2094
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2042
2095
|
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
2043
|
-
block: true,
|
|
2044
2096
|
widget: new TableWidget(table2)
|
|
2045
2097
|
}));
|
|
2046
2098
|
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
@@ -2049,7 +2101,7 @@ var update = (state, options) => {
|
|
|
2049
2101
|
});
|
|
2050
2102
|
return builder.finish();
|
|
2051
2103
|
};
|
|
2052
|
-
var TableWidget = class extends
|
|
2104
|
+
var TableWidget = class extends WidgetType5 {
|
|
2053
2105
|
constructor(_table) {
|
|
2054
2106
|
super();
|
|
2055
2107
|
this._table = _table;
|
|
@@ -2081,88 +2133,104 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2081
2133
|
}
|
|
2082
2134
|
return table2;
|
|
2083
2135
|
}
|
|
2136
|
+
ignoreEvent(e) {
|
|
2137
|
+
return !/^mouse/.test(e.type);
|
|
2138
|
+
}
|
|
2084
2139
|
};
|
|
2085
2140
|
|
|
2086
2141
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2087
|
-
import {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2142
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2143
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2144
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
2145
|
+
var styles5 = EditorView12.baseTheme({
|
|
2146
|
+
"& .cm-task": {
|
|
2147
|
+
color: getToken("extend.colors.blue.500")
|
|
2148
|
+
},
|
|
2149
|
+
"& .cm-task-checkbox": {
|
|
2150
|
+
marginLeft: "4px",
|
|
2151
|
+
marginRight: "4px"
|
|
2092
2152
|
}
|
|
2093
2153
|
});
|
|
2094
|
-
var CheckboxWidget = class extends
|
|
2095
|
-
constructor(_checked
|
|
2154
|
+
var CheckboxWidget = class extends WidgetType6 {
|
|
2155
|
+
constructor(_checked) {
|
|
2096
2156
|
super();
|
|
2097
2157
|
this._checked = _checked;
|
|
2098
|
-
this._indent = _indent;
|
|
2099
|
-
this._onCheck = _onCheck;
|
|
2100
2158
|
}
|
|
2101
2159
|
eq(other) {
|
|
2102
|
-
return this._checked === other._checked
|
|
2160
|
+
return this._checked === other._checked;
|
|
2103
2161
|
}
|
|
2104
2162
|
toDOM(view) {
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2108
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2109
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2163
|
+
const input = document.createElement("input");
|
|
2164
|
+
input.className = "cm-task-checkbox";
|
|
2110
2165
|
input.type = "checkbox";
|
|
2111
2166
|
input.checked = this._checked;
|
|
2112
|
-
if (
|
|
2167
|
+
if (view.state.readOnly) {
|
|
2113
2168
|
input.setAttribute("disabled", "true");
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2169
|
+
} else {
|
|
2170
|
+
input.onmousedown = (event) => {
|
|
2171
|
+
const pos = view.posAtDOM(input);
|
|
2172
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2173
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2174
|
+
view.dispatch({
|
|
2175
|
+
changes: {
|
|
2176
|
+
from: pos + 1,
|
|
2177
|
+
to: pos + 2,
|
|
2178
|
+
insert: this._checked ? " " : "x"
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
event.preventDefault();
|
|
2182
|
+
}
|
|
2119
2183
|
};
|
|
2120
2184
|
}
|
|
2121
|
-
return
|
|
2185
|
+
return input;
|
|
2122
2186
|
}
|
|
2123
2187
|
ignoreEvent() {
|
|
2124
2188
|
return false;
|
|
2125
2189
|
}
|
|
2126
2190
|
};
|
|
2191
|
+
var checkedDecoration = Decoration8.replace({
|
|
2192
|
+
widget: new CheckboxWidget(true)
|
|
2193
|
+
});
|
|
2194
|
+
var uncheckedDecoration = Decoration8.replace({
|
|
2195
|
+
widget: new CheckboxWidget(false)
|
|
2196
|
+
});
|
|
2197
|
+
var buildDecorations4 = (view) => {
|
|
2198
|
+
const builder = new RangeSetBuilder4();
|
|
2199
|
+
const { state } = view;
|
|
2200
|
+
const cursor = state.selection.main.head;
|
|
2201
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2202
|
+
syntaxTree5(state).iterate({
|
|
2203
|
+
enter: (node) => {
|
|
2204
|
+
if (node.name === "TaskMarker") {
|
|
2205
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2206
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2207
|
+
builder.add(node.from - 2, node.from - 1, Decoration8.mark({
|
|
2208
|
+
class: "cm-task"
|
|
2209
|
+
}));
|
|
2210
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
from,
|
|
2215
|
+
to
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
return builder.finish();
|
|
2219
|
+
};
|
|
2127
2220
|
var tasklist = (options = {}) => {
|
|
2128
|
-
const taskMatcher = new MatchDecorator3({
|
|
2129
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2130
|
-
decoration: (match, view, pos) => {
|
|
2131
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2132
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2133
|
-
return Decoration8.replace({
|
|
2134
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2135
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2136
|
-
view.dispatch({
|
|
2137
|
-
changes: {
|
|
2138
|
-
from: idx,
|
|
2139
|
-
to: idx + 1,
|
|
2140
|
-
insert: checked2 ? "x" : " "
|
|
2141
|
-
},
|
|
2142
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2143
|
-
selection: {
|
|
2144
|
-
anchor: idx + 3
|
|
2145
|
-
}
|
|
2146
|
-
});
|
|
2147
|
-
})
|
|
2148
|
-
});
|
|
2149
|
-
}
|
|
2150
|
-
});
|
|
2151
|
-
const tasks = ViewPlugin7.fromClass(class {
|
|
2152
|
-
constructor(view) {
|
|
2153
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2154
|
-
}
|
|
2155
|
-
update(update2) {
|
|
2156
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2157
|
-
}
|
|
2158
|
-
}, {
|
|
2159
|
-
decorations: (value) => value.tasks,
|
|
2160
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2161
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2162
|
-
})
|
|
2163
|
-
});
|
|
2164
2221
|
return [
|
|
2165
|
-
|
|
2222
|
+
ViewPlugin5.fromClass(class {
|
|
2223
|
+
constructor(view) {
|
|
2224
|
+
this.decorations = buildDecorations4(view);
|
|
2225
|
+
}
|
|
2226
|
+
update(update2) {
|
|
2227
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2228
|
+
this.decorations = buildDecorations4(update2.view);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}, {
|
|
2232
|
+
decorations: (v) => v.decorations
|
|
2233
|
+
}),
|
|
2166
2234
|
styles5
|
|
2167
2235
|
];
|
|
2168
2236
|
};
|
|
@@ -2241,7 +2309,7 @@ var cursorConverter2 = (text) => ({
|
|
|
2241
2309
|
|
|
2242
2310
|
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2243
2311
|
var yjs = (content, awareness2) => [
|
|
2244
|
-
|
|
2312
|
+
Cursor.converter.of(cursorConverter2(content)),
|
|
2245
2313
|
yCollab(content, awareness2)
|
|
2246
2314
|
];
|
|
2247
2315
|
|
|
@@ -2338,33 +2406,6 @@ var defaultTheme = {
|
|
|
2338
2406
|
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2339
2407
|
},
|
|
2340
2408
|
//
|
|
2341
|
-
// collaboration
|
|
2342
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2343
|
-
//
|
|
2344
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2345
|
-
mixBlendMode: "multiply"
|
|
2346
|
-
},
|
|
2347
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2348
|
-
mixBlendMode: "screen"
|
|
2349
|
-
},
|
|
2350
|
-
".cm-ySelectionInfo": {
|
|
2351
|
-
padding: "2px 4px",
|
|
2352
|
-
marginBlockStart: "-4px"
|
|
2353
|
-
},
|
|
2354
|
-
".cm-ySelection, & .cm-selectionMatch": {
|
|
2355
|
-
paddingBlockStart: ".15em",
|
|
2356
|
-
paddingBlockEnd: ".15em"
|
|
2357
|
-
},
|
|
2358
|
-
".cm-ySelectionCaret": {
|
|
2359
|
-
display: "inline-block",
|
|
2360
|
-
insetBlockStart: ".1em",
|
|
2361
|
-
blockSize: "1.4em",
|
|
2362
|
-
verticalAlign: "top"
|
|
2363
|
-
},
|
|
2364
|
-
".cm-yLineSelection": {
|
|
2365
|
-
margin: 0
|
|
2366
|
-
},
|
|
2367
|
-
//
|
|
2368
2409
|
// link
|
|
2369
2410
|
//
|
|
2370
2411
|
".cm-link": {
|
|
@@ -2401,13 +2442,6 @@ var defaultTheme = {
|
|
|
2401
2442
|
textDecoration: "none"
|
|
2402
2443
|
},
|
|
2403
2444
|
//
|
|
2404
|
-
// widgets
|
|
2405
|
-
//
|
|
2406
|
-
".cm-widgetBuffer": {
|
|
2407
|
-
display: "none",
|
|
2408
|
-
height: 0
|
|
2409
|
-
},
|
|
2410
|
-
//
|
|
2411
2445
|
// table
|
|
2412
2446
|
//
|
|
2413
2447
|
".cm-table *": {
|
|
@@ -2438,27 +2472,17 @@ var defaultTheme = {
|
|
|
2438
2472
|
},
|
|
2439
2473
|
//
|
|
2440
2474
|
// font size
|
|
2441
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2475
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2476
|
+
// but it's far more verbose than it needs to be.
|
|
2442
2477
|
//
|
|
2443
|
-
...Object.keys(
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2452
|
-
height
|
|
2453
|
-
};
|
|
2454
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2455
|
-
height
|
|
2456
|
-
};
|
|
2457
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2458
|
-
height
|
|
2459
|
-
};
|
|
2460
|
-
return acc;
|
|
2461
|
-
}, {}),
|
|
2478
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2479
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2480
|
+
//
|
|
2481
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2482
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2483
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2484
|
+
// return acc;
|
|
2485
|
+
// }, {}),
|
|
2462
2486
|
/**
|
|
2463
2487
|
* Panels
|
|
2464
2488
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2509,7 +2533,9 @@ var textTheme = {
|
|
|
2509
2533
|
}
|
|
2510
2534
|
};
|
|
2511
2535
|
var markdownTheme = {
|
|
2512
|
-
|
|
2536
|
+
".cm-scroller": {
|
|
2537
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2538
|
+
},
|
|
2513
2539
|
".cm-placeholder": {
|
|
2514
2540
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2515
2541
|
}
|
|
@@ -2524,95 +2550,91 @@ var codeTheme = {
|
|
|
2524
2550
|
};
|
|
2525
2551
|
|
|
2526
2552
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2553
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2527
2554
|
var EditorModes = [
|
|
2528
2555
|
"default",
|
|
2529
2556
|
"vim"
|
|
2530
2557
|
];
|
|
2531
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2532
|
-
const { themeMode } = useThemeContext();
|
|
2558
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [] }, forwardedRef) => {
|
|
2533
2559
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2534
2560
|
tabBehavior: "limited"
|
|
2535
2561
|
});
|
|
2536
|
-
const
|
|
2537
|
-
const
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
state,
|
|
2562
|
+
const { themeMode } = useThemeContext2();
|
|
2563
|
+
const rootRef = useRef(null);
|
|
2564
|
+
const [view, setView] = useState(null);
|
|
2565
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2541
2566
|
view
|
|
2542
|
-
}), [
|
|
2543
|
-
view,
|
|
2544
|
-
state,
|
|
2545
|
-
root
|
|
2546
2567
|
]);
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
awareness2.setLocalStateField("user", {
|
|
2551
|
-
name: peer.name ?? generateName(peer.id),
|
|
2552
|
-
color: getColorForValue({
|
|
2553
|
-
value: peer.id,
|
|
2554
|
-
type: "color"
|
|
2555
|
-
}),
|
|
2556
|
-
colorLight: getColorForValue({
|
|
2557
|
-
value: peer.id,
|
|
2558
|
-
themeMode,
|
|
2559
|
-
type: "highlight"
|
|
2560
|
-
})
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
}, [
|
|
2564
|
-
awareness2,
|
|
2565
|
-
peer,
|
|
2566
|
-
themeMode
|
|
2567
|
-
]);
|
|
2568
|
-
useEffect(() => {
|
|
2569
|
-
if (view && comments2?.length) {
|
|
2570
|
-
view.dispatch({
|
|
2571
|
-
effects: setCommentRange.of({
|
|
2572
|
-
model,
|
|
2573
|
-
comments: comments2
|
|
2574
|
-
})
|
|
2575
|
-
});
|
|
2568
|
+
useEffect3(() => {
|
|
2569
|
+
if (autofocus) {
|
|
2570
|
+
view?.focus();
|
|
2576
2571
|
}
|
|
2577
2572
|
}, [
|
|
2578
2573
|
view,
|
|
2579
|
-
|
|
2574
|
+
autofocus
|
|
2580
2575
|
]);
|
|
2581
|
-
|
|
2582
|
-
|
|
2576
|
+
useAwareness(model);
|
|
2577
|
+
useEffect3(() => {
|
|
2578
|
+
if (!model || !rootRef.current) {
|
|
2583
2579
|
return;
|
|
2584
2580
|
}
|
|
2585
|
-
const
|
|
2581
|
+
const state = EditorState2.create({
|
|
2586
2582
|
doc: model.text(),
|
|
2583
|
+
selection,
|
|
2587
2584
|
extensions: [
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2585
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2586
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2587
|
+
log2.catch(err, void 0, {
|
|
2588
|
+
F: __dxlog_file4,
|
|
2589
|
+
L: 114,
|
|
2590
|
+
S: void 0,
|
|
2591
|
+
C: (f, a) => f(...a)
|
|
2592
|
+
});
|
|
2593
|
+
}),
|
|
2591
2594
|
// Theme.
|
|
2592
|
-
// TODO(burdon): Make
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2595
|
+
// TODO(burdon): Make configurable.
|
|
2596
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2597
|
+
EditorView13.theme(theme ?? {}),
|
|
2598
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2599
|
+
EditorView13.editorAttributes.of({
|
|
2600
|
+
class: slots.editor?.className ?? ""
|
|
2601
|
+
}),
|
|
2602
|
+
EditorView13.contentAttributes.of({
|
|
2603
|
+
class: slots.content?.className ?? ""
|
|
2604
|
+
}),
|
|
2605
|
+
// State.
|
|
2606
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2596
2607
|
// Storage and replication.
|
|
2608
|
+
// NOTE: This must come before user extensions.
|
|
2597
2609
|
model.extension,
|
|
2610
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2611
|
+
editorMode === "vim" && vim(),
|
|
2598
2612
|
// Custom.
|
|
2599
2613
|
...extensions
|
|
2600
2614
|
].filter(Boolean)
|
|
2601
2615
|
});
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2616
|
+
const newView = new EditorView13({
|
|
2617
|
+
state,
|
|
2618
|
+
parent: rootRef.current,
|
|
2619
|
+
scrollTo,
|
|
2620
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2621
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2622
|
+
dispatchTransactions: (trs, view2) => {
|
|
2623
|
+
view2.update(trs);
|
|
2624
|
+
const debug = false;
|
|
2625
|
+
if (debug) {
|
|
2626
|
+
logChanges(trs);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2609
2629
|
});
|
|
2630
|
+
view?.destroy();
|
|
2631
|
+
setView(newView);
|
|
2610
2632
|
return () => {
|
|
2611
|
-
|
|
2612
|
-
|
|
2633
|
+
newView?.destroy();
|
|
2634
|
+
setView(null);
|
|
2613
2635
|
};
|
|
2614
2636
|
}, [
|
|
2615
|
-
|
|
2637
|
+
rootRef,
|
|
2616
2638
|
model,
|
|
2617
2639
|
readonly,
|
|
2618
2640
|
editorMode,
|
|
@@ -2622,11 +2644,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2622
2644
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2623
2645
|
switch (key) {
|
|
2624
2646
|
case "Enter": {
|
|
2625
|
-
view?.
|
|
2647
|
+
view?.focus();
|
|
2626
2648
|
break;
|
|
2627
2649
|
}
|
|
2628
2650
|
case "Escape": {
|
|
2629
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2651
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2652
|
+
rootRef.current?.focus();
|
|
2653
|
+
}
|
|
2630
2654
|
break;
|
|
2631
2655
|
}
|
|
2632
2656
|
}
|
|
@@ -2636,65 +2660,66 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2636
2660
|
]);
|
|
2637
2661
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2638
2662
|
key: model.id,
|
|
2639
|
-
|
|
2663
|
+
role: "none",
|
|
2640
2664
|
tabIndex: 0,
|
|
2641
|
-
|
|
2665
|
+
onKeyUp: handleKeyUp,
|
|
2666
|
+
...slots.root,
|
|
2642
2667
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2643
|
-
|
|
2668
|
+
ref: rootRef
|
|
2644
2669
|
});
|
|
2645
2670
|
});
|
|
2646
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2647
|
-
const { themeMode } =
|
|
2648
|
-
const
|
|
2671
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, multiline, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2672
|
+
const { themeMode } = useThemeContext2();
|
|
2673
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2649
2674
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2650
2675
|
ref: forwardedRef,
|
|
2651
2676
|
readonly,
|
|
2652
2677
|
extensions: [
|
|
2653
2678
|
basicBundle({
|
|
2654
|
-
readonly,
|
|
2655
2679
|
themeMode,
|
|
2656
|
-
placeholder:
|
|
2680
|
+
placeholder: placeholder3,
|
|
2681
|
+
multiline
|
|
2657
2682
|
}),
|
|
2658
2683
|
...extensions
|
|
2659
2684
|
],
|
|
2660
|
-
|
|
2685
|
+
theme,
|
|
2686
|
+
slots: updatedSlots,
|
|
2661
2687
|
...props
|
|
2662
2688
|
});
|
|
2663
2689
|
});
|
|
2664
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2665
|
-
const { themeMode } =
|
|
2666
|
-
const
|
|
2690
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2691
|
+
const { themeMode } = useThemeContext2();
|
|
2692
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2667
2693
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2668
2694
|
ref: forwardedRef,
|
|
2669
2695
|
readonly,
|
|
2670
2696
|
extensions: [
|
|
2671
2697
|
markdownBundle({
|
|
2672
|
-
readonly,
|
|
2673
2698
|
themeMode,
|
|
2674
|
-
|
|
2699
|
+
readonly,
|
|
2700
|
+
placeholder: placeholder3
|
|
2675
2701
|
}),
|
|
2676
2702
|
...extensions
|
|
2677
2703
|
],
|
|
2678
|
-
|
|
2704
|
+
theme,
|
|
2705
|
+
slots: updatedSlots,
|
|
2679
2706
|
...props
|
|
2680
2707
|
});
|
|
2681
2708
|
});
|
|
2682
2709
|
var defaultSlots = {
|
|
2683
2710
|
root: {
|
|
2684
|
-
|
|
2711
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2712
|
+
className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
|
|
2713
|
+
},
|
|
2714
|
+
editor: {
|
|
2715
|
+
className: "h-full p-2"
|
|
2685
2716
|
}
|
|
2686
2717
|
};
|
|
2687
2718
|
var defaultTextSlots = {
|
|
2688
|
-
...defaultSlots
|
|
2689
|
-
editor: {
|
|
2690
|
-
theme: textTheme
|
|
2691
|
-
}
|
|
2719
|
+
...defaultSlots
|
|
2692
2720
|
};
|
|
2693
2721
|
var defaultMarkdownSlots = {
|
|
2694
|
-
...defaultSlots
|
|
2695
|
-
editor: {
|
|
2696
|
-
theme: markdownTheme
|
|
2697
|
-
}
|
|
2722
|
+
...defaultSlots
|
|
2698
2723
|
};
|
|
2699
2724
|
|
|
2700
2725
|
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
@@ -2707,7 +2732,7 @@ import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
|
2707
2732
|
import { Context as Context2 } from "@dxos/context";
|
|
2708
2733
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2709
2734
|
import { log as log3 } from "@dxos/log";
|
|
2710
|
-
var
|
|
2735
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2711
2736
|
var DEBOUNCE_INTERVAL = 100;
|
|
2712
2737
|
var SpaceAwarenessProvider = class {
|
|
2713
2738
|
constructor(params) {
|
|
@@ -2748,7 +2773,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2748
2773
|
log3.debug("failed to query awareness", {
|
|
2749
2774
|
err
|
|
2750
2775
|
}, {
|
|
2751
|
-
F:
|
|
2776
|
+
F: __dxlog_file5,
|
|
2752
2777
|
L: 85,
|
|
2753
2778
|
S: this,
|
|
2754
2779
|
C: (f, a) => f(...a)
|
|
@@ -2762,7 +2787,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2762
2787
|
}
|
|
2763
2788
|
update(position) {
|
|
2764
2789
|
invariant3(this._postTask, void 0, {
|
|
2765
|
-
F:
|
|
2790
|
+
F: __dxlog_file5,
|
|
2766
2791
|
L: 96,
|
|
2767
2792
|
S: this,
|
|
2768
2793
|
A: [
|
|
@@ -2782,7 +2807,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2782
2807
|
}
|
|
2783
2808
|
_handleQueryMessage() {
|
|
2784
2809
|
invariant3(this._postTask, void 0, {
|
|
2785
|
-
F:
|
|
2810
|
+
F: __dxlog_file5,
|
|
2786
2811
|
L: 111,
|
|
2787
2812
|
S: this,
|
|
2788
2813
|
A: [
|
|
@@ -2794,7 +2819,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2794
2819
|
}
|
|
2795
2820
|
_handlePostMessage(message) {
|
|
2796
2821
|
invariant3(message.kind === "post", void 0, {
|
|
2797
|
-
F:
|
|
2822
|
+
F: __dxlog_file5,
|
|
2798
2823
|
L: 116,
|
|
2799
2824
|
S: this,
|
|
2800
2825
|
A: [
|
|
@@ -2807,25 +2832,63 @@ var SpaceAwarenessProvider = class {
|
|
|
2807
2832
|
}
|
|
2808
2833
|
};
|
|
2809
2834
|
|
|
2810
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2835
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2811
2836
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2812
|
-
|
|
2813
|
-
|
|
2837
|
+
var modelState = StateField5.define({
|
|
2838
|
+
create: () => void 0,
|
|
2839
|
+
update: (model) => model
|
|
2840
|
+
});
|
|
2841
|
+
|
|
2842
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2843
|
+
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2844
|
+
const obj = text;
|
|
2845
|
+
const doc = getRawDoc(obj, [
|
|
2846
|
+
obj.field
|
|
2847
|
+
]);
|
|
2848
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2849
|
+
space,
|
|
2850
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2851
|
+
info: {
|
|
2852
|
+
displayName: identity?.profile?.displayName ?? "",
|
|
2853
|
+
color: cursorColor.color,
|
|
2854
|
+
lightColor: cursorColor.light
|
|
2855
|
+
},
|
|
2856
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2857
|
+
});
|
|
2858
|
+
const model = {
|
|
2859
|
+
id: obj.id,
|
|
2860
|
+
content: doc,
|
|
2861
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2862
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2863
|
+
extension: [
|
|
2864
|
+
modelState.init(() => model),
|
|
2865
|
+
automerge3({
|
|
2866
|
+
handle: doc.handle,
|
|
2867
|
+
path: doc.path
|
|
2868
|
+
}),
|
|
2869
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2870
|
+
awareness()
|
|
2871
|
+
].filter(isNotNullOrUndefined),
|
|
2872
|
+
peer: identity ? {
|
|
2873
|
+
id: identity.identityKey.toHex(),
|
|
2874
|
+
name: identity.profile?.displayName
|
|
2875
|
+
} : void 0
|
|
2876
|
+
};
|
|
2877
|
+
return model;
|
|
2878
|
+
};
|
|
2814
2879
|
|
|
2815
2880
|
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2816
2881
|
import * as decoding from "lib0/decoding";
|
|
2817
2882
|
import * as encoding from "lib0/encoding";
|
|
2818
2883
|
import { Observable } from "lib0/observable";
|
|
2819
2884
|
import * as YP from "y-protocols/awareness";
|
|
2820
|
-
import * as Y2 from "yjs";
|
|
2821
2885
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2822
2886
|
import { log as log4 } from "@dxos/log";
|
|
2823
|
-
|
|
2824
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2887
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2825
2888
|
var createYjsModel = ({ identity, space, text }) => {
|
|
2826
2889
|
invariant4(text?.doc && text?.content, void 0, {
|
|
2827
|
-
F:
|
|
2828
|
-
L:
|
|
2890
|
+
F: __dxlog_file6,
|
|
2891
|
+
L: 22,
|
|
2829
2892
|
S: void 0,
|
|
2830
2893
|
A: [
|
|
2831
2894
|
"text?.doc && text?.content",
|
|
@@ -2841,34 +2904,6 @@ var createYjsModel = ({ identity, space, text }) => {
|
|
|
2841
2904
|
id: text.doc.guid,
|
|
2842
2905
|
content: text.content,
|
|
2843
2906
|
text: () => text.content.toString(),
|
|
2844
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2845
|
-
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2846
|
-
getCursorFromRange: (range) => {
|
|
2847
|
-
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2848
|
-
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2849
|
-
return [
|
|
2850
|
-
arrayToString2(from),
|
|
2851
|
-
arrayToString2(to)
|
|
2852
|
-
].join(":");
|
|
2853
|
-
},
|
|
2854
|
-
getRangeFromCursor: (cursor) => {
|
|
2855
|
-
invariant4(text.doc, void 0, {
|
|
2856
|
-
F: __dxlog_file5,
|
|
2857
|
-
L: 40,
|
|
2858
|
-
S: void 0,
|
|
2859
|
-
A: [
|
|
2860
|
-
"text.doc",
|
|
2861
|
-
""
|
|
2862
|
-
]
|
|
2863
|
-
});
|
|
2864
|
-
const parts = cursor.split(":");
|
|
2865
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2866
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2867
|
-
return from && to ? {
|
|
2868
|
-
from: from.index,
|
|
2869
|
-
to: to.index
|
|
2870
|
-
} : void 0;
|
|
2871
|
-
},
|
|
2872
2907
|
extension: [
|
|
2873
2908
|
modelState.init(() => model),
|
|
2874
2909
|
yjs(text.content, provider?.awareness)
|
|
@@ -2917,8 +2952,8 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2917
2952
|
removed,
|
|
2918
2953
|
origin
|
|
2919
2954
|
}, {
|
|
2920
|
-
F:
|
|
2921
|
-
L:
|
|
2955
|
+
F: __dxlog_file6,
|
|
2956
|
+
L: 101,
|
|
2922
2957
|
S: this,
|
|
2923
2958
|
C: (f, a) => f(...a)
|
|
2924
2959
|
});
|
|
@@ -2930,8 +2965,8 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2930
2965
|
}
|
|
2931
2966
|
_handleSpaceMessage({ payload }) {
|
|
2932
2967
|
log4("space message", payload, {
|
|
2933
|
-
F:
|
|
2934
|
-
L:
|
|
2968
|
+
F: __dxlog_file6,
|
|
2969
|
+
L: 110,
|
|
2935
2970
|
S: this,
|
|
2936
2971
|
C: (f, a) => f(...a)
|
|
2937
2972
|
});
|
|
@@ -2975,14 +3010,12 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2975
3010
|
};
|
|
2976
3011
|
|
|
2977
3012
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
update: (model) => model
|
|
2981
|
-
});
|
|
3013
|
+
import { useEffect as useEffect4, useState as useState2 } from "react";
|
|
3014
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2982
3015
|
var useTextModel = (props) => {
|
|
2983
3016
|
const { identity, space, text } = props;
|
|
2984
|
-
const [model, setModel] = useState2(
|
|
2985
|
-
|
|
3017
|
+
const [model, setModel] = useState2();
|
|
3018
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2986
3019
|
identity,
|
|
2987
3020
|
space,
|
|
2988
3021
|
text
|
|
@@ -2999,47 +3032,10 @@ var createModel = (props) => {
|
|
|
2999
3032
|
return void 0;
|
|
3000
3033
|
}
|
|
3001
3034
|
};
|
|
3002
|
-
|
|
3003
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
3004
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
3005
|
-
const obj = text;
|
|
3006
|
-
const doc = getRawDoc(obj, [
|
|
3007
|
-
obj.field
|
|
3008
|
-
]);
|
|
3009
|
-
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
3010
|
-
space,
|
|
3011
|
-
channel: `automerge.awareness.${obj.id}`,
|
|
3012
|
-
info: {
|
|
3013
|
-
displayName: identity?.profile?.displayName ?? "",
|
|
3014
|
-
color: cursorColor.color,
|
|
3015
|
-
lightColor: cursorColor.light
|
|
3016
|
-
},
|
|
3017
|
-
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3018
|
-
});
|
|
3019
|
-
const model = {
|
|
3020
|
-
id: obj.id,
|
|
3021
|
-
content: doc,
|
|
3022
|
-
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3023
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
3024
|
-
extension: [
|
|
3025
|
-
modelState.init(() => model),
|
|
3026
|
-
automerge3({
|
|
3027
|
-
handle: doc.handle,
|
|
3028
|
-
path: doc.path
|
|
3029
|
-
}),
|
|
3030
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3031
|
-
awareness()
|
|
3032
|
-
].filter(isNotNullOrUndefined),
|
|
3033
|
-
peer: identity ? {
|
|
3034
|
-
id: identity.identityKey.toHex(),
|
|
3035
|
-
name: identity.profile?.displayName
|
|
3036
|
-
} : void 0
|
|
3037
|
-
};
|
|
3038
|
-
return model;
|
|
3039
|
-
};
|
|
3040
3035
|
export {
|
|
3041
3036
|
AwarenessProvider,
|
|
3042
3037
|
BaseTextEditor,
|
|
3038
|
+
Cursor,
|
|
3043
3039
|
Doc,
|
|
3044
3040
|
EditorModes,
|
|
3045
3041
|
MarkdownEditor,
|
|
@@ -3055,6 +3051,7 @@ export {
|
|
|
3055
3051
|
awareness,
|
|
3056
3052
|
basicBundle,
|
|
3057
3053
|
blast,
|
|
3054
|
+
callbackWrapper,
|
|
3058
3055
|
code2 as code,
|
|
3059
3056
|
codeTheme,
|
|
3060
3057
|
comments,
|
|
@@ -3070,6 +3067,7 @@ export {
|
|
|
3070
3067
|
image,
|
|
3071
3068
|
link,
|
|
3072
3069
|
listener,
|
|
3070
|
+
logChanges,
|
|
3073
3071
|
markdownBundle,
|
|
3074
3072
|
markdownHighlightStyle,
|
|
3075
3073
|
markdownTags,
|
|
@@ -3077,7 +3075,8 @@ export {
|
|
|
3077
3075
|
markdownTheme,
|
|
3078
3076
|
mention,
|
|
3079
3077
|
modelState,
|
|
3080
|
-
|
|
3078
|
+
outliner,
|
|
3079
|
+
setComments,
|
|
3081
3080
|
setFocus,
|
|
3082
3081
|
setSelection,
|
|
3083
3082
|
table,
|
|
@@ -3085,6 +3084,8 @@ export {
|
|
|
3085
3084
|
tasklist,
|
|
3086
3085
|
textTheme,
|
|
3087
3086
|
typewriter,
|
|
3087
|
+
useAwareness,
|
|
3088
|
+
useComments,
|
|
3088
3089
|
useTextModel,
|
|
3089
3090
|
yjs
|
|
3090
3091
|
};
|