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