@dxos/react-ui-editor 0.3.11-main.d7d4c52 → 0.3.11-main.da09c3c
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 +635 -508
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -14
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +13 -6
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/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 +29 -16
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor.d.ts +3 -3
- package/dist/types/src/extensions/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -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/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/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 -27
- 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/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +2 -0
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +32 -32
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +64 -69
- package/src/components/TextEditor/TextEditor.tsx +85 -68
- package/src/components/TextEditor/comments.stories.tsx +111 -69
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.ts +23 -48
- 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 +20 -2
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/code.ts +15 -17
- package/src/extensions/comments.ts +235 -132
- package/src/extensions/cursor.ts +7 -3
- package/src/extensions/hr.ts +49 -50
- package/src/extensions/index.ts +1 -0
- package/src/extensions/link.ts +3 -3
- package/src/extensions/markdown/bundle.ts +18 -24
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/extensions/tasklist.ts +76 -84
- package/src/extensions/yjs/yjs.test.ts +1 -1
- 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 +2 -45
- package/src/hooks/yjs.ts +2 -1
- package/src/themes/default.ts +0 -8
- package/src/util.ts +26 -3
|
@@ -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,
|
|
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,8 +53,8 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView } from "@codemirror/view";
|
|
56
58
|
import { next as A } from "@dxos/automerge/automerge";
|
|
57
59
|
|
|
58
60
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
@@ -94,12 +96,12 @@ var cursorConverter = (handle, path) => ({
|
|
|
94
96
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
97
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
98
|
var effectType = StateEffect.define({});
|
|
99
|
+
var reconcileAnnotationType = Annotation.define();
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
97
102
|
var updateHeads = (newHeads) => effectType.of({
|
|
98
103
|
newHeads
|
|
99
104
|
});
|
|
100
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
101
|
-
var getPath = (state, field) => state.field(field).path;
|
|
102
|
-
var reconcileAnnotationType = Annotation.define();
|
|
103
105
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
104
106
|
|
|
105
107
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
@@ -237,40 +239,42 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
239
|
|
|
238
240
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
239
241
|
var PatchSemaphore = class {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
+
// prettier-ignore
|
|
243
|
+
constructor(_handle, _state) {
|
|
244
|
+
this._handle = _handle;
|
|
245
|
+
this._state = _state;
|
|
242
246
|
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);
|
|
247
|
+
}
|
|
248
|
+
// NOTE: Cannot destruct view.state.
|
|
249
|
+
reconcile(view) {
|
|
250
|
+
if (this._inReconcile) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
this._inReconcile = true;
|
|
254
|
+
const path = getPath(view.state, this._state);
|
|
255
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
256
|
+
let selection = view.state.selection;
|
|
257
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
258
|
+
const toInvert = transactions.slice().reverse();
|
|
259
|
+
for (const tx of toInvert) {
|
|
260
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
261
|
+
selection = selection.map(inverted);
|
|
268
262
|
view.dispatch({
|
|
269
|
-
|
|
270
|
-
annotations: reconcileAnnotationType.of(
|
|
263
|
+
changes: inverted,
|
|
264
|
+
annotations: reconcileAnnotationType.of(true)
|
|
271
265
|
});
|
|
272
|
-
|
|
273
|
-
|
|
266
|
+
}
|
|
267
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
268
|
+
if (newHeads === null || newHeads === void 0) {
|
|
269
|
+
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
270
|
+
}
|
|
271
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
272
|
+
updateCodeMirror(view, selection, path, diff);
|
|
273
|
+
view.dispatch({
|
|
274
|
+
effects: updateHeads(newHeads),
|
|
275
|
+
annotations: reconcileAnnotationType.of({})
|
|
276
|
+
});
|
|
277
|
+
this._inReconcile = false;
|
|
274
278
|
}
|
|
275
279
|
};
|
|
276
280
|
|
|
@@ -280,14 +284,15 @@ var defaultCursorConverter = {
|
|
|
280
284
|
toCursor: (position) => position.toString(),
|
|
281
285
|
fromCursor: (cursor) => parseInt(cursor)
|
|
282
286
|
};
|
|
283
|
-
var Cursor = class {
|
|
287
|
+
var Cursor = class _Cursor {
|
|
284
288
|
static {
|
|
285
289
|
this.converter = Facet.define({
|
|
286
290
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
287
291
|
});
|
|
288
292
|
}
|
|
289
293
|
static {
|
|
290
|
-
this.getCursorFromRange = (
|
|
294
|
+
this.getCursorFromRange = (state, range) => {
|
|
295
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
291
296
|
const from = cursorConverter3.toCursor(range.from);
|
|
292
297
|
const to = cursorConverter3.toCursor(range.to, -1);
|
|
293
298
|
return [
|
|
@@ -297,7 +302,8 @@ var Cursor = class {
|
|
|
297
302
|
};
|
|
298
303
|
}
|
|
299
304
|
static {
|
|
300
|
-
this.getRangeFromCursor = (
|
|
305
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
306
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
301
307
|
const parts = cursor.split(":");
|
|
302
308
|
const from = cursorConverter3.fromCursor(parts[0]);
|
|
303
309
|
const to = cursorConverter3.fromCursor(parts[1]);
|
|
@@ -310,21 +316,18 @@ var Cursor = class {
|
|
|
310
316
|
};
|
|
311
317
|
|
|
312
318
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
313
|
-
var semaphoreFacet = Facet2.define({
|
|
314
|
-
combine: (values) => values.at(-1)
|
|
315
|
-
});
|
|
316
319
|
var automerge3 = ({ handle, path }) => {
|
|
317
|
-
const
|
|
320
|
+
const state = StateField.define({
|
|
318
321
|
create: () => ({
|
|
322
|
+
path: path.slice(),
|
|
319
323
|
lastHeads: A.getHeads(handle.docSync()),
|
|
320
|
-
unreconciledTransactions: []
|
|
321
|
-
path: path.slice()
|
|
324
|
+
unreconciledTransactions: []
|
|
322
325
|
}),
|
|
323
326
|
update: (value, tr) => {
|
|
324
327
|
const result = {
|
|
328
|
+
path: path.slice(),
|
|
325
329
|
lastHeads: value.lastHeads,
|
|
326
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
327
|
-
path: path.slice()
|
|
330
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
328
331
|
};
|
|
329
332
|
let clearUnreconciled = false;
|
|
330
333
|
for (const effect of tr.effects) {
|
|
@@ -343,41 +346,27 @@ var automerge3 = ({ handle, path }) => {
|
|
|
343
346
|
return result;
|
|
344
347
|
}
|
|
345
348
|
});
|
|
346
|
-
const semaphore = new PatchSemaphore(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
};
|
|
353
|
-
handle.addListener("change", this._handleChange);
|
|
354
|
-
}
|
|
355
|
-
update(update2) {
|
|
356
|
-
if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
357
|
-
queueMicrotask(() => {
|
|
358
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
359
|
-
});
|
|
349
|
+
const semaphore = new PatchSemaphore(handle, state);
|
|
350
|
+
return [
|
|
351
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
352
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
353
|
+
if (!changes.empty) {
|
|
354
|
+
semaphore.reconcile(view);
|
|
360
355
|
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
return {
|
|
367
|
-
extension: [
|
|
368
|
-
Cursor.converter.of(cursorConverter(handle, path)),
|
|
369
|
-
semaphoreFacet.of(semaphore),
|
|
370
|
-
stateField,
|
|
371
|
-
viewPlugin
|
|
372
|
-
]
|
|
373
|
-
};
|
|
356
|
+
}),
|
|
357
|
+
state
|
|
358
|
+
];
|
|
374
359
|
};
|
|
375
360
|
|
|
376
361
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
377
|
-
import { Annotation as Annotation2, Facet as
|
|
378
|
-
import { Decoration, EditorView
|
|
362
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
363
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin, WidgetType } from "@codemirror/view";
|
|
364
|
+
import { useEffect } from "react";
|
|
379
365
|
import { Event } from "@dxos/async";
|
|
380
366
|
import { Context } from "@dxos/context";
|
|
367
|
+
import { generateName } from "@dxos/display-name";
|
|
368
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
369
|
+
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
381
370
|
var dummyProvider = {
|
|
382
371
|
remoteStateChange: new Event(),
|
|
383
372
|
open: () => {
|
|
@@ -388,19 +377,42 @@ var dummyProvider = {
|
|
|
388
377
|
},
|
|
389
378
|
getRemoteStates: () => []
|
|
390
379
|
};
|
|
391
|
-
var AwarenessProvider =
|
|
380
|
+
var AwarenessProvider = Facet2.define({
|
|
392
381
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
393
382
|
});
|
|
394
383
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
395
384
|
var awareness = (provider = dummyProvider) => {
|
|
396
385
|
return [
|
|
397
386
|
AwarenessProvider.of(provider),
|
|
398
|
-
|
|
387
|
+
ViewPlugin.fromClass(RemoteSelectionsDecorator, {
|
|
399
388
|
decorations: (value) => value.decorations
|
|
400
389
|
}),
|
|
401
390
|
styles
|
|
402
391
|
];
|
|
403
392
|
};
|
|
393
|
+
var useAwareness = ({ awareness: awareness2, peer }) => {
|
|
394
|
+
const { themeMode } = useThemeContext();
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (awareness2 && peer) {
|
|
397
|
+
awareness2.setLocalStateField("user", {
|
|
398
|
+
name: peer.name ?? generateName(peer.id),
|
|
399
|
+
color: getColorForValue({
|
|
400
|
+
value: peer.id,
|
|
401
|
+
type: "color"
|
|
402
|
+
}),
|
|
403
|
+
colorLight: getColorForValue({
|
|
404
|
+
value: peer.id,
|
|
405
|
+
themeMode,
|
|
406
|
+
type: "highlight"
|
|
407
|
+
})
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}, [
|
|
411
|
+
awareness2,
|
|
412
|
+
peer,
|
|
413
|
+
themeMode
|
|
414
|
+
]);
|
|
415
|
+
};
|
|
404
416
|
var RemoteSelectionsDecorator = class {
|
|
405
417
|
constructor(view) {
|
|
406
418
|
this.decorations = RangeSet.of([]);
|
|
@@ -549,7 +561,7 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
549
561
|
return true;
|
|
550
562
|
}
|
|
551
563
|
};
|
|
552
|
-
var styles =
|
|
564
|
+
var styles = EditorView2.baseTheme({
|
|
553
565
|
".cm-collab-selection": {},
|
|
554
566
|
".cm-collab-selectionLine": {
|
|
555
567
|
padding: 0,
|
|
@@ -595,7 +607,7 @@ var styles = EditorView.baseTheme({
|
|
|
595
607
|
zIndex: 101,
|
|
596
608
|
transition: "opacity .3s ease-in-out",
|
|
597
609
|
backgroundColor: "inherit",
|
|
598
|
-
//
|
|
610
|
+
// These should be separate.
|
|
599
611
|
opacity: 0,
|
|
600
612
|
transitionDelay: "0s",
|
|
601
613
|
whiteSpace: "nowrap"
|
|
@@ -608,23 +620,25 @@ var styles = EditorView.baseTheme({
|
|
|
608
620
|
|
|
609
621
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
610
622
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
623
|
+
import { history } from "@codemirror/commands";
|
|
611
624
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
612
625
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
613
|
-
import { drawSelection, EditorView as
|
|
614
|
-
var basicBundle = ({
|
|
615
|
-
|
|
616
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
626
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, multiline = true }) => [
|
|
628
|
+
multiline ? EditorView3.lineWrapping : [],
|
|
617
629
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
618
630
|
bracketMatching(),
|
|
619
631
|
closeBrackets(),
|
|
620
632
|
drawSelection(),
|
|
621
|
-
|
|
622
|
-
|
|
633
|
+
highlightActiveLine(),
|
|
634
|
+
history(),
|
|
635
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
636
|
+
// https://github.com/codemirror/theme-one-dark
|
|
623
637
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
624
|
-
]
|
|
638
|
+
];
|
|
625
639
|
|
|
626
640
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
627
|
-
import { EditorView as
|
|
641
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
628
642
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
629
643
|
import { invariant } from "@dxos/invariant";
|
|
630
644
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
@@ -672,7 +686,7 @@ var blast = (options = defaultOptions) => {
|
|
|
672
686
|
};
|
|
673
687
|
return [
|
|
674
688
|
// Cursor moved.
|
|
675
|
-
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
676
690
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
677
691
|
if (blaster) {
|
|
678
692
|
blaster.destroy();
|
|
@@ -934,7 +948,7 @@ var random = (min, max) => {
|
|
|
934
948
|
};
|
|
935
949
|
|
|
936
950
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
937
|
-
import { ViewPlugin as
|
|
951
|
+
import { ViewPlugin as ViewPlugin2, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
|
|
938
952
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
939
953
|
|
|
940
954
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
@@ -1025,7 +1039,7 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
|
|
|
1025
1039
|
|
|
1026
1040
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1027
1041
|
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1028
|
-
var styles2 =
|
|
1042
|
+
var styles2 = EditorView5.baseTheme({
|
|
1029
1043
|
"& .cm-codeblock": {
|
|
1030
1044
|
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1031
1045
|
},
|
|
@@ -1059,29 +1073,27 @@ var getLineRange = (lines, from, to) => {
|
|
|
1059
1073
|
];
|
|
1060
1074
|
};
|
|
1061
1075
|
var code2 = () => {
|
|
1062
|
-
const
|
|
1076
|
+
const buildDecorations5 = (view) => {
|
|
1063
1077
|
const decorations = [];
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}).range(block.from));
|
|
1075
|
-
}
|
|
1078
|
+
const text = view.state.doc.sliceString(0);
|
|
1079
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1080
|
+
const blocks = view.viewportLineBlocks;
|
|
1081
|
+
for (const match of matches) {
|
|
1082
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1083
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1084
|
+
const block = blocks[i];
|
|
1085
|
+
decorations.push(Decoration2.line({
|
|
1086
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1087
|
+
}).range(block.from));
|
|
1076
1088
|
}
|
|
1077
1089
|
}
|
|
1078
1090
|
return Decoration2.set(decorations);
|
|
1079
1091
|
};
|
|
1080
1092
|
return [
|
|
1081
|
-
|
|
1093
|
+
ViewPlugin2.fromClass(class {
|
|
1082
1094
|
constructor(view) {
|
|
1083
1095
|
this.hasFocus = false;
|
|
1084
|
-
this.decorations =
|
|
1096
|
+
this.decorations = buildDecorations5(view);
|
|
1085
1097
|
}
|
|
1086
1098
|
update(update2) {
|
|
1087
1099
|
if (
|
|
@@ -1089,7 +1101,7 @@ var code2 = () => {
|
|
|
1089
1101
|
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1090
1102
|
) {
|
|
1091
1103
|
this.hasFocus = update2.view.hasFocus;
|
|
1092
|
-
this.decorations =
|
|
1104
|
+
this.decorations = buildDecorations5(update2.view);
|
|
1093
1105
|
}
|
|
1094
1106
|
}
|
|
1095
1107
|
}, {
|
|
@@ -1101,11 +1113,11 @@ var code2 = () => {
|
|
|
1101
1113
|
|
|
1102
1114
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1103
1115
|
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1104
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as
|
|
1116
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1105
1117
|
import sortBy from "lodash.sortby";
|
|
1118
|
+
import { useEffect as useEffect2 } from "react";
|
|
1106
1119
|
import { debounce } from "@dxos/async";
|
|
1107
1120
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1108
|
-
import { log as log2 } from "@dxos/log";
|
|
1109
1121
|
import { nonNullable } from "@dxos/util";
|
|
1110
1122
|
|
|
1111
1123
|
// packages/ui/react-ui-editor/src/util.ts
|
|
@@ -1114,19 +1126,38 @@ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src
|
|
|
1114
1126
|
var callbackWrapper = (fn) => (...args) => {
|
|
1115
1127
|
try {
|
|
1116
1128
|
return fn(...args);
|
|
1117
|
-
} catch (
|
|
1118
|
-
log.catch(
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
log.catch(err, void 0, {
|
|
1119
1131
|
F: __dxlog_file2,
|
|
1120
|
-
L:
|
|
1132
|
+
L: 18,
|
|
1121
1133
|
S: void 0,
|
|
1122
1134
|
C: (f, a) => f(...a)
|
|
1123
1135
|
});
|
|
1124
1136
|
}
|
|
1125
1137
|
};
|
|
1138
|
+
var logChanges = (trs) => {
|
|
1139
|
+
const changes = trs.flatMap((tr) => {
|
|
1140
|
+
if (tr.changes.empty) {
|
|
1141
|
+
return void 0;
|
|
1142
|
+
}
|
|
1143
|
+
const changes2 = [];
|
|
1144
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1145
|
+
fromA,
|
|
1146
|
+
toA,
|
|
1147
|
+
fromB,
|
|
1148
|
+
toB,
|
|
1149
|
+
inserted: inserted.toString()
|
|
1150
|
+
})));
|
|
1151
|
+
return changes2;
|
|
1152
|
+
}).filter(Boolean);
|
|
1153
|
+
if (changes.length) {
|
|
1154
|
+
console.log("changes", changes);
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1126
1157
|
|
|
1127
1158
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1128
1159
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1129
|
-
var styles3 =
|
|
1160
|
+
var styles3 = EditorView6.baseTheme({
|
|
1130
1161
|
"& .cm-comment": {
|
|
1131
1162
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1132
1163
|
},
|
|
@@ -1142,49 +1173,59 @@ var marks = {
|
|
|
1142
1173
|
class: "cm-comment-active"
|
|
1143
1174
|
})
|
|
1144
1175
|
};
|
|
1145
|
-
var setFocus = (view,
|
|
1146
|
-
const
|
|
1147
|
-
if (!
|
|
1176
|
+
var setFocus = (view, id, center = true) => {
|
|
1177
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1178
|
+
if (!comment?.comment.cursor) {
|
|
1148
1179
|
return;
|
|
1149
1180
|
}
|
|
1150
|
-
view.
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1181
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1182
|
+
if (range) {
|
|
1183
|
+
view.dispatch({
|
|
1184
|
+
selection: {
|
|
1185
|
+
anchor: range.from
|
|
1186
|
+
},
|
|
1187
|
+
effects: [
|
|
1188
|
+
//
|
|
1189
|
+
EditorView6.scrollIntoView(range.from, center ? {
|
|
1190
|
+
y: "center"
|
|
1191
|
+
} : void 0),
|
|
1192
|
+
setSelection.of({
|
|
1193
|
+
active: id
|
|
1194
|
+
})
|
|
1195
|
+
]
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1159
1198
|
};
|
|
1160
|
-
var
|
|
1199
|
+
var setComments = StateEffect2.define();
|
|
1161
1200
|
var setSelection = StateEffect2.define();
|
|
1162
1201
|
var setCommentState = StateEffect2.define();
|
|
1163
|
-
var
|
|
1202
|
+
var commentsState = StateField2.define({
|
|
1164
1203
|
create: () => ({
|
|
1165
|
-
|
|
1204
|
+
comments: [],
|
|
1205
|
+
selection: {}
|
|
1166
1206
|
}),
|
|
1167
1207
|
update: (value, tr) => {
|
|
1168
|
-
const cursorConverter3 = tr.state.facet(Cursor.converter);
|
|
1169
1208
|
for (const effect of tr.effects) {
|
|
1170
1209
|
if (effect.is(setSelection)) {
|
|
1171
1210
|
return {
|
|
1172
1211
|
...value,
|
|
1173
|
-
|
|
1212
|
+
selection: effect.value
|
|
1174
1213
|
};
|
|
1175
1214
|
}
|
|
1176
|
-
if (effect.is(
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1215
|
+
if (effect.is(setComments)) {
|
|
1216
|
+
const comments2 = effect.value.map((comment) => {
|
|
1217
|
+
if (!comment.cursor) {
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1180
1221
|
return range && {
|
|
1181
|
-
|
|
1182
|
-
|
|
1222
|
+
comment,
|
|
1223
|
+
range
|
|
1183
1224
|
};
|
|
1184
1225
|
}).filter(nonNullable);
|
|
1185
1226
|
return {
|
|
1186
1227
|
...value,
|
|
1187
|
-
|
|
1228
|
+
comments: comments2
|
|
1188
1229
|
};
|
|
1189
1230
|
}
|
|
1190
1231
|
if (effect.is(setCommentState)) {
|
|
@@ -1194,50 +1235,109 @@ var commentsStateField = StateField2.define({
|
|
|
1194
1235
|
return value;
|
|
1195
1236
|
}
|
|
1196
1237
|
});
|
|
1197
|
-
var highlightDecorations =
|
|
1198
|
-
|
|
1238
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1239
|
+
commentsState
|
|
1199
1240
|
], (state) => {
|
|
1200
|
-
const { active,
|
|
1201
|
-
const decorations = sortBy(
|
|
1202
|
-
|
|
1241
|
+
const { selection: { active }, comments: comments2 } = state.field(commentsState);
|
|
1242
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1243
|
+
const range = comment.range;
|
|
1244
|
+
if (!range || range.from === range.to) {
|
|
1245
|
+
console.warn("Invalid range:", range);
|
|
1203
1246
|
return void 0;
|
|
1204
1247
|
}
|
|
1205
|
-
|
|
1206
|
-
from: selection.from,
|
|
1207
|
-
to: selection.to
|
|
1208
|
-
};
|
|
1209
|
-
if (selection.id === active) {
|
|
1248
|
+
if (comment.comment.id === active) {
|
|
1210
1249
|
return marks.highlightActive.range(range.from, range.to);
|
|
1211
1250
|
} else {
|
|
1212
1251
|
return marks.highlight.range(range.from, range.to);
|
|
1213
1252
|
}
|
|
1214
|
-
}).filter(nonNullable)
|
|
1253
|
+
}).filter(nonNullable);
|
|
1215
1254
|
return Decoration3.set(decorations);
|
|
1216
1255
|
});
|
|
1256
|
+
var trackPastedComments = (onUpdate) => {
|
|
1257
|
+
let tracked = null;
|
|
1258
|
+
const handleTrack = (event, view) => {
|
|
1259
|
+
const comments2 = view.state.field(commentsState);
|
|
1260
|
+
const { main } = view.state.selection;
|
|
1261
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1262
|
+
if (!selectedRanges.length) {
|
|
1263
|
+
tracked = null;
|
|
1264
|
+
} else {
|
|
1265
|
+
tracked = {
|
|
1266
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1267
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1268
|
+
id: comment.id,
|
|
1269
|
+
from: range.from - main.from,
|
|
1270
|
+
to: range.to - main.from
|
|
1271
|
+
}))
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
return [
|
|
1276
|
+
EditorView6.domEventHandlers({
|
|
1277
|
+
cut: handleTrack,
|
|
1278
|
+
copy: handleTrack
|
|
1279
|
+
}),
|
|
1280
|
+
// Handle paste.
|
|
1281
|
+
EditorView6.updateListener.of(({ view, state, transactions }) => {
|
|
1282
|
+
if (tracked) {
|
|
1283
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1284
|
+
if (paste) {
|
|
1285
|
+
let found = -1;
|
|
1286
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1287
|
+
if (text.eq(tracked.text)) {
|
|
1288
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1289
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1290
|
+
}
|
|
1291
|
+
found = fromB;
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
if (found > -1) {
|
|
1295
|
+
for (const moved of tracked.comments) {
|
|
1296
|
+
const range = {
|
|
1297
|
+
from: found + moved.from,
|
|
1298
|
+
to: found + moved.to
|
|
1299
|
+
};
|
|
1300
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1301
|
+
onUpdate(moved.id, cursor);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
tracked = null;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
})
|
|
1308
|
+
];
|
|
1309
|
+
};
|
|
1217
1310
|
var comments = (options = {}) => {
|
|
1218
1311
|
const { key: shortcut = "meta-'" } = options;
|
|
1219
1312
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1220
1313
|
const createCommentThread = (view) => {
|
|
1221
|
-
const cursorConverter3 = view.state.facet(Cursor.converter);
|
|
1222
1314
|
invariant2(options.onCreate, void 0, {
|
|
1223
1315
|
F: __dxlog_file3,
|
|
1224
|
-
L:
|
|
1316
|
+
L: 259,
|
|
1225
1317
|
S: void 0,
|
|
1226
1318
|
A: [
|
|
1227
1319
|
"options.onCreate",
|
|
1228
1320
|
""
|
|
1229
1321
|
]
|
|
1230
1322
|
});
|
|
1231
|
-
const {
|
|
1323
|
+
const { from, to } = view.state.selection.main;
|
|
1232
1324
|
if (from === to) {
|
|
1233
1325
|
return false;
|
|
1234
1326
|
}
|
|
1235
|
-
|
|
1327
|
+
if (to === view.state.doc.length) {
|
|
1328
|
+
view.dispatch({
|
|
1329
|
+
changes: {
|
|
1330
|
+
from: to,
|
|
1331
|
+
insert: "\n"
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1236
1336
|
from,
|
|
1237
1337
|
to
|
|
1238
1338
|
});
|
|
1239
1339
|
if (cursor) {
|
|
1240
|
-
const id =
|
|
1340
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1241
1341
|
if (id) {
|
|
1242
1342
|
view.dispatch({
|
|
1243
1343
|
effects: setSelection.of({
|
|
@@ -1247,25 +1347,13 @@ var comments = (options = {}) => {
|
|
|
1247
1347
|
anchor: from
|
|
1248
1348
|
}
|
|
1249
1349
|
});
|
|
1250
|
-
if (options.footnote) {
|
|
1251
|
-
const tag = `[^${id}]`;
|
|
1252
|
-
view.dispatch({
|
|
1253
|
-
changes: {
|
|
1254
|
-
from: head,
|
|
1255
|
-
insert: tag
|
|
1256
|
-
},
|
|
1257
|
-
selection: {
|
|
1258
|
-
anchor: head + tag.length
|
|
1259
|
-
}
|
|
1260
|
-
});
|
|
1261
|
-
}
|
|
1262
1350
|
return true;
|
|
1263
1351
|
}
|
|
1264
1352
|
}
|
|
1265
1353
|
return false;
|
|
1266
1354
|
};
|
|
1267
1355
|
return [
|
|
1268
|
-
|
|
1356
|
+
commentsState,
|
|
1269
1357
|
highlightDecorations,
|
|
1270
1358
|
styles3,
|
|
1271
1359
|
//
|
|
@@ -1290,7 +1378,7 @@ var comments = (options = {}) => {
|
|
|
1290
1378
|
above: true,
|
|
1291
1379
|
create: () => {
|
|
1292
1380
|
const el = document.createElement("div");
|
|
1293
|
-
options.onHover
|
|
1381
|
+
options.onHover(el, shortcut);
|
|
1294
1382
|
return {
|
|
1295
1383
|
dom: el,
|
|
1296
1384
|
offset: {
|
|
@@ -1303,139 +1391,154 @@ var comments = (options = {}) => {
|
|
|
1303
1391
|
}
|
|
1304
1392
|
return null;
|
|
1305
1393
|
}, {
|
|
1306
|
-
|
|
1394
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1395
|
+
// hideOnChange: true,
|
|
1307
1396
|
hoverTime: 1e3
|
|
1308
1397
|
}) : [],
|
|
1309
1398
|
//
|
|
1310
|
-
//
|
|
1311
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1399
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1312
1400
|
//
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
{
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
if (
|
|
1321
|
-
|
|
1322
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1323
|
-
log2.info("deleted comment", {
|
|
1324
|
-
thread: range.id
|
|
1325
|
-
}, {
|
|
1326
|
-
F: __dxlog_file3,
|
|
1327
|
-
L: 274,
|
|
1328
|
-
S: void 0,
|
|
1329
|
-
C: (f, a) => f(...a)
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1401
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1402
|
+
let mod = false;
|
|
1403
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1404
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1405
|
+
comments2.forEach(({ comment, range }) => {
|
|
1406
|
+
if (from2 === to2) {
|
|
1407
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1408
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1409
|
+
options.onDelete?.(comment.id);
|
|
1332
1410
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
}
|
|
1411
|
+
}
|
|
1412
|
+
if (from <= range.to) {
|
|
1413
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1414
|
+
Object.assign(range, newRange);
|
|
1415
|
+
mod = true;
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1419
|
+
if (mod) {
|
|
1420
|
+
view.dispatch({
|
|
1421
|
+
effects: setCommentState.of({
|
|
1422
|
+
comments: comments2,
|
|
1423
|
+
...value
|
|
1424
|
+
})
|
|
1339
1425
|
});
|
|
1340
|
-
if (mod) {
|
|
1341
|
-
view.dispatch({
|
|
1342
|
-
effects: setCommentState.of({
|
|
1343
|
-
active,
|
|
1344
|
-
ranges
|
|
1345
|
-
})
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
1426
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1427
|
+
}),
|
|
1428
|
+
//
|
|
1429
|
+
// Track selection/proximity.
|
|
1430
|
+
//
|
|
1431
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1432
|
+
let min = Infinity;
|
|
1433
|
+
const { selection: { active, closest }, comments: comments2 } = state.field(commentsState);
|
|
1434
|
+
const { head } = state.selection.main;
|
|
1435
|
+
const selection = {};
|
|
1436
|
+
comments2.forEach(({ comment, range }) => {
|
|
1437
|
+
if (head >= range.from && head <= range.to) {
|
|
1438
|
+
selection.active = comment.id;
|
|
1439
|
+
selection.closest = void 0;
|
|
1440
|
+
}
|
|
1441
|
+
if (!selection.active) {
|
|
1442
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1362
1443
|
if (d < min) {
|
|
1363
|
-
|
|
1444
|
+
selection.closest = comment.id;
|
|
1364
1445
|
min = d;
|
|
1365
1446
|
}
|
|
1366
|
-
});
|
|
1367
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1368
|
-
view.dispatch({
|
|
1369
|
-
effects: setSelection.of(selected)
|
|
1370
|
-
});
|
|
1371
|
-
handleSelect({
|
|
1372
|
-
...selected,
|
|
1373
|
-
ranges: ranges.map((range) => ({
|
|
1374
|
-
...range,
|
|
1375
|
-
location: view.coordsAtPos(range.from)
|
|
1376
|
-
}))
|
|
1377
|
-
});
|
|
1378
1447
|
}
|
|
1448
|
+
});
|
|
1449
|
+
if (selection.active !== active || selection.closest !== closest) {
|
|
1450
|
+
view.dispatch({
|
|
1451
|
+
effects: setSelection.of(selection)
|
|
1452
|
+
});
|
|
1453
|
+
handleSelect({
|
|
1454
|
+
selection,
|
|
1455
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1456
|
+
comment,
|
|
1457
|
+
range,
|
|
1458
|
+
location: view.coordsAtPos(range.from)
|
|
1459
|
+
}))
|
|
1460
|
+
});
|
|
1379
1461
|
}
|
|
1380
|
-
})
|
|
1462
|
+
}),
|
|
1463
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1381
1464
|
];
|
|
1382
1465
|
};
|
|
1466
|
+
var useComments = (view, comments2) => {
|
|
1467
|
+
useEffect2(() => {
|
|
1468
|
+
if (view && comments2) {
|
|
1469
|
+
view.dispatch({
|
|
1470
|
+
effects: setComments.of(comments2)
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}, [
|
|
1474
|
+
view,
|
|
1475
|
+
comments2
|
|
1476
|
+
]);
|
|
1477
|
+
};
|
|
1383
1478
|
|
|
1384
1479
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1385
|
-
import {
|
|
1386
|
-
|
|
1480
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1481
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1482
|
+
import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1483
|
+
var styles4 = EditorView7.baseTheme({
|
|
1387
1484
|
"& .cm-hr": {
|
|
1388
|
-
// TODO(burdon): ???
|
|
1389
1485
|
// Note that block-level decorations should not have vertical margins,
|
|
1390
|
-
|
|
1486
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1391
1487
|
}
|
|
1392
1488
|
});
|
|
1393
1489
|
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1394
|
-
|
|
1395
|
-
super();
|
|
1396
|
-
this._pos = _pos;
|
|
1397
|
-
}
|
|
1398
|
-
eq(other) {
|
|
1399
|
-
return this._pos === other._pos;
|
|
1400
|
-
}
|
|
1401
|
-
toDOM(view) {
|
|
1490
|
+
toDOM() {
|
|
1402
1491
|
const el = document.createElement("div");
|
|
1403
1492
|
el.className = "cm-hr";
|
|
1404
1493
|
return el;
|
|
1405
1494
|
}
|
|
1406
1495
|
};
|
|
1407
|
-
var
|
|
1408
|
-
|
|
1409
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1410
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1411
|
-
})
|
|
1496
|
+
var decoration = Decoration4.replace({
|
|
1497
|
+
widget: new HorizontalRuleWidget()
|
|
1412
1498
|
});
|
|
1413
|
-
var
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1499
|
+
var buildDecorations = (view) => {
|
|
1500
|
+
const builder = new RangeSetBuilder();
|
|
1501
|
+
const { state } = view;
|
|
1502
|
+
const cursor = state.selection.main.head;
|
|
1503
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1504
|
+
syntaxTree(state).iterate({
|
|
1505
|
+
enter: (node) => {
|
|
1506
|
+
if (node.name === "HorizontalRule") {
|
|
1507
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1508
|
+
builder.add(node.from, node.to, decoration);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
from,
|
|
1513
|
+
to
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return builder.finish();
|
|
1517
|
+
};
|
|
1518
|
+
var hr = () => {
|
|
1519
|
+
return [
|
|
1520
|
+
styles4,
|
|
1521
|
+
ViewPlugin3.fromClass(class {
|
|
1522
|
+
constructor(view) {
|
|
1523
|
+
this.decorations = buildDecorations(view);
|
|
1524
|
+
}
|
|
1525
|
+
update(update2) {
|
|
1526
|
+
this.decorations = buildDecorations(update2.view);
|
|
1527
|
+
}
|
|
1528
|
+
}, {
|
|
1529
|
+
decorations: (v) => v.decorations
|
|
1427
1530
|
})
|
|
1428
|
-
|
|
1429
|
-
|
|
1531
|
+
];
|
|
1532
|
+
};
|
|
1430
1533
|
|
|
1431
1534
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1432
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1535
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1433
1536
|
import { StateField as StateField3 } from "@codemirror/state";
|
|
1434
|
-
import { Decoration as Decoration5, EditorView as
|
|
1537
|
+
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1435
1538
|
var image = (options = {}) => {
|
|
1436
1539
|
return StateField3.define({
|
|
1437
1540
|
create: (state) => {
|
|
1438
|
-
return Decoration5.set(
|
|
1541
|
+
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1439
1542
|
},
|
|
1440
1543
|
update: (value, tr) => {
|
|
1441
1544
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -1455,16 +1558,16 @@ var image = (options = {}) => {
|
|
|
1455
1558
|
filterFrom: from,
|
|
1456
1559
|
filterTo: to,
|
|
1457
1560
|
filter: () => false,
|
|
1458
|
-
add:
|
|
1561
|
+
add: buildDecorations2(from, to, tr.state)
|
|
1459
1562
|
});
|
|
1460
1563
|
},
|
|
1461
|
-
provide: (field) =>
|
|
1564
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1462
1565
|
});
|
|
1463
1566
|
};
|
|
1464
|
-
var
|
|
1567
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1465
1568
|
const decorations = [];
|
|
1466
1569
|
const cursor = state.selection.main.head;
|
|
1467
|
-
|
|
1570
|
+
syntaxTree2(state).iterate({
|
|
1468
1571
|
enter: (node) => {
|
|
1469
1572
|
if (node.name === "Image") {
|
|
1470
1573
|
const urlNode = node.node.getChild("URL");
|
|
@@ -1501,19 +1604,19 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1501
1604
|
};
|
|
1502
1605
|
|
|
1503
1606
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1504
|
-
import { syntaxTree as
|
|
1505
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1506
|
-
import {
|
|
1607
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1608
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1609
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin4, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1507
1610
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1508
1611
|
var link = (options = {}) => {
|
|
1509
1612
|
const extensions = [
|
|
1510
|
-
|
|
1613
|
+
ViewPlugin4.fromClass(class {
|
|
1511
1614
|
constructor(view) {
|
|
1512
|
-
this.decorations =
|
|
1615
|
+
this.decorations = buildDecorations3(view, options);
|
|
1513
1616
|
}
|
|
1514
1617
|
update(update2) {
|
|
1515
1618
|
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1516
|
-
this.decorations =
|
|
1619
|
+
this.decorations = buildDecorations3(update2.view, options);
|
|
1517
1620
|
}
|
|
1518
1621
|
}
|
|
1519
1622
|
}, {
|
|
@@ -1526,7 +1629,7 @@ var link = (options = {}) => {
|
|
|
1526
1629
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1527
1630
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1528
1631
|
hoverTooltip2((view, pos, side) => {
|
|
1529
|
-
const syntax =
|
|
1632
|
+
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1530
1633
|
let link2 = null;
|
|
1531
1634
|
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1532
1635
|
link2 = node.name === "Link" ? node : null;
|
|
@@ -1602,12 +1705,12 @@ var LinkText = class extends WidgetType4 {
|
|
|
1602
1705
|
return link2;
|
|
1603
1706
|
}
|
|
1604
1707
|
};
|
|
1605
|
-
var
|
|
1606
|
-
const builder = new
|
|
1708
|
+
var buildDecorations3 = (view, options) => {
|
|
1709
|
+
const builder = new RangeSetBuilder2();
|
|
1607
1710
|
const { state } = view;
|
|
1608
1711
|
const cursor = state.selection.main.head;
|
|
1609
1712
|
for (const { from, to } of view.visibleRanges) {
|
|
1610
|
-
|
|
1713
|
+
syntaxTree3(state).iterate({
|
|
1611
1714
|
enter: (node) => {
|
|
1612
1715
|
if (node.name === "Link") {
|
|
1613
1716
|
const marks2 = node.node.getChildren("LinkMark");
|
|
@@ -1638,14 +1741,14 @@ var buildDecorations2 = (view, options) => {
|
|
|
1638
1741
|
};
|
|
1639
1742
|
|
|
1640
1743
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1641
|
-
import { EditorView as
|
|
1744
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1642
1745
|
var listener = ({ onFocus, onChange }) => {
|
|
1643
1746
|
const extensions = [];
|
|
1644
|
-
onFocus && extensions.push(
|
|
1747
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1645
1748
|
onFocus(focused);
|
|
1646
1749
|
return null;
|
|
1647
1750
|
}));
|
|
1648
|
-
onChange && extensions.push(
|
|
1751
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1649
1752
|
onChange(update2.state.doc.toString());
|
|
1650
1753
|
}));
|
|
1651
1754
|
return extensions;
|
|
@@ -1653,14 +1756,14 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1653
1756
|
|
|
1654
1757
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1655
1758
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1656
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1759
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1657
1760
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1658
1761
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1659
1762
|
import { languages } from "@codemirror/language-data";
|
|
1660
1763
|
import { searchKeymap } from "@codemirror/search";
|
|
1661
1764
|
import { EditorState } from "@codemirror/state";
|
|
1662
1765
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1663
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1766
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1664
1767
|
|
|
1665
1768
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1666
1769
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1855,17 +1958,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1855
1958
|
return [
|
|
1856
1959
|
EditorState.allowMultipleSelections.of(true),
|
|
1857
1960
|
EditorState.tabSize.of(2),
|
|
1858
|
-
|
|
1859
|
-
|
|
1961
|
+
EditorView10.lineWrapping,
|
|
1962
|
+
// https://github.com/codemirror/basic-setup
|
|
1860
1963
|
bracketMatching2(),
|
|
1861
1964
|
closeBrackets2(),
|
|
1862
1965
|
crosshairCursor(),
|
|
1863
1966
|
dropCursor(),
|
|
1864
1967
|
drawSelection2(),
|
|
1865
|
-
|
|
1866
|
-
|
|
1968
|
+
highlightActiveLine2(),
|
|
1969
|
+
history2(),
|
|
1867
1970
|
indentOnInput(),
|
|
1868
|
-
_placeholder
|
|
1971
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1869
1972
|
// Main extension.
|
|
1870
1973
|
// https://github.com/codemirror/lang-markdown
|
|
1871
1974
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1887,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1887
1990
|
// https://github.com/codemirror/theme-one-dark
|
|
1888
1991
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1889
1992
|
// Custom styles.
|
|
1890
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1993
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly)),
|
|
1994
|
+
keymap4.of([
|
|
1995
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1996
|
+
indentWithTab,
|
|
1997
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1998
|
+
...closeBracketsKeymap,
|
|
1999
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2000
|
+
...historyKeymap,
|
|
2001
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2002
|
+
...searchKeymap,
|
|
2003
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2004
|
+
...standardKeymap
|
|
2005
|
+
])
|
|
2006
|
+
];
|
|
2007
|
+
};
|
|
1905
2008
|
|
|
1906
2009
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1907
2010
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1908
2011
|
var mention = ({ onSearch }) => {
|
|
1909
2012
|
return autocompletion2({
|
|
2013
|
+
// TODO(burdon): Not working.
|
|
2014
|
+
activateOnTyping: true,
|
|
2015
|
+
// activateOnTypingDelay: 100,
|
|
2016
|
+
// selectOnOpen: true,
|
|
1910
2017
|
closeOnBlur: false,
|
|
2018
|
+
// defaultKeymap: false,
|
|
2019
|
+
icons: false,
|
|
1911
2020
|
override: [
|
|
1912
2021
|
(context) => {
|
|
2022
|
+
console.log(context);
|
|
1913
2023
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1914
2024
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1915
2025
|
return null;
|
|
1916
2026
|
}
|
|
1917
|
-
console.log(match);
|
|
1918
2027
|
return {
|
|
1919
2028
|
from: match.from,
|
|
1920
2029
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1926,19 +2035,24 @@ var mention = ({ onSearch }) => {
|
|
|
1926
2035
|
});
|
|
1927
2036
|
};
|
|
1928
2037
|
|
|
2038
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2039
|
+
var outliner = (options = {}) => {
|
|
2040
|
+
return [];
|
|
2041
|
+
};
|
|
2042
|
+
|
|
1929
2043
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1930
|
-
import { syntaxTree as
|
|
1931
|
-
import { RangeSetBuilder as
|
|
1932
|
-
import { Decoration as Decoration7, EditorView as
|
|
2044
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2045
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
|
|
2046
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1933
2047
|
var table = (options = {}) => {
|
|
1934
2048
|
return StateField4.define({
|
|
1935
2049
|
create: (state) => update(state, options),
|
|
1936
2050
|
update: (_, tr) => update(tr.state, options),
|
|
1937
|
-
provide: (field) =>
|
|
2051
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1938
2052
|
});
|
|
1939
2053
|
};
|
|
1940
2054
|
var update = (state, options) => {
|
|
1941
|
-
const builder = new
|
|
2055
|
+
const builder = new RangeSetBuilder3();
|
|
1942
2056
|
const cursor = state.selection.main.head;
|
|
1943
2057
|
const tables = [];
|
|
1944
2058
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1946,7 +2060,7 @@ var update = (state, options) => {
|
|
|
1946
2060
|
const table2 = getTable();
|
|
1947
2061
|
return table2.rows?.[table2.rows.length - 1];
|
|
1948
2062
|
};
|
|
1949
|
-
|
|
2063
|
+
syntaxTree4(state).iterate({
|
|
1950
2064
|
enter: (node) => {
|
|
1951
2065
|
switch (node.name) {
|
|
1952
2066
|
case "Table": {
|
|
@@ -2025,85 +2139,98 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2025
2139
|
};
|
|
2026
2140
|
|
|
2027
2141
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2028
|
-
import {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2142
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2143
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2144
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
2145
|
+
var styles5 = EditorView12.baseTheme({
|
|
2146
|
+
"& .cm-task": {
|
|
2147
|
+
color: getToken("extend.colors.blue.500")
|
|
2148
|
+
},
|
|
2149
|
+
"& .cm-task-checkbox": {
|
|
2150
|
+
marginLeft: "4px",
|
|
2151
|
+
marginRight: "4px"
|
|
2033
2152
|
}
|
|
2034
2153
|
});
|
|
2035
2154
|
var CheckboxWidget = class extends WidgetType6 {
|
|
2036
|
-
constructor(_checked
|
|
2155
|
+
constructor(_checked) {
|
|
2037
2156
|
super();
|
|
2038
2157
|
this._checked = _checked;
|
|
2039
|
-
this._indent = _indent;
|
|
2040
|
-
this._onCheck = _onCheck;
|
|
2041
2158
|
}
|
|
2042
2159
|
eq(other) {
|
|
2043
|
-
return this._checked === other._checked
|
|
2160
|
+
return this._checked === other._checked;
|
|
2044
2161
|
}
|
|
2045
2162
|
toDOM(view) {
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2049
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2050
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2163
|
+
const input = document.createElement("input");
|
|
2164
|
+
input.className = "cm-task-checkbox";
|
|
2051
2165
|
input.type = "checkbox";
|
|
2052
2166
|
input.checked = this._checked;
|
|
2053
|
-
if (
|
|
2167
|
+
if (view.state.readOnly) {
|
|
2054
2168
|
input.setAttribute("disabled", "true");
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2169
|
+
} else {
|
|
2170
|
+
input.onmousedown = (event) => {
|
|
2171
|
+
const pos = view.posAtDOM(input);
|
|
2172
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2173
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2174
|
+
view.dispatch({
|
|
2175
|
+
changes: {
|
|
2176
|
+
from: pos + 1,
|
|
2177
|
+
to: pos + 2,
|
|
2178
|
+
insert: this._checked ? " " : "x"
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
event.preventDefault();
|
|
2182
|
+
}
|
|
2060
2183
|
};
|
|
2061
2184
|
}
|
|
2062
|
-
return
|
|
2185
|
+
return input;
|
|
2063
2186
|
}
|
|
2064
2187
|
ignoreEvent() {
|
|
2065
2188
|
return false;
|
|
2066
2189
|
}
|
|
2067
2190
|
};
|
|
2191
|
+
var checkedDecoration = Decoration8.replace({
|
|
2192
|
+
widget: new CheckboxWidget(true)
|
|
2193
|
+
});
|
|
2194
|
+
var uncheckedDecoration = Decoration8.replace({
|
|
2195
|
+
widget: new CheckboxWidget(false)
|
|
2196
|
+
});
|
|
2197
|
+
var buildDecorations4 = (view) => {
|
|
2198
|
+
const builder = new RangeSetBuilder4();
|
|
2199
|
+
const { state } = view;
|
|
2200
|
+
const cursor = state.selection.main.head;
|
|
2201
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2202
|
+
syntaxTree5(state).iterate({
|
|
2203
|
+
enter: (node) => {
|
|
2204
|
+
if (node.name === "TaskMarker") {
|
|
2205
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2206
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2207
|
+
builder.add(node.from - 2, node.from - 1, Decoration8.mark({
|
|
2208
|
+
class: "cm-task"
|
|
2209
|
+
}));
|
|
2210
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
from,
|
|
2215
|
+
to
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
return builder.finish();
|
|
2219
|
+
};
|
|
2068
2220
|
var tasklist = (options = {}) => {
|
|
2069
|
-
const taskMatcher = new MatchDecorator2({
|
|
2070
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2071
|
-
decoration: (match, view, pos) => {
|
|
2072
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2073
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2074
|
-
return Decoration8.replace({
|
|
2075
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2076
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2077
|
-
view.dispatch({
|
|
2078
|
-
changes: {
|
|
2079
|
-
from: idx,
|
|
2080
|
-
to: idx + 1,
|
|
2081
|
-
insert: checked2 ? "x" : " "
|
|
2082
|
-
},
|
|
2083
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2084
|
-
selection: {
|
|
2085
|
-
anchor: idx + 3
|
|
2086
|
-
}
|
|
2087
|
-
});
|
|
2088
|
-
})
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
|
-
});
|
|
2092
|
-
const tasks = ViewPlugin6.fromClass(class {
|
|
2093
|
-
constructor(view) {
|
|
2094
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2095
|
-
}
|
|
2096
|
-
update(update2) {
|
|
2097
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2098
|
-
}
|
|
2099
|
-
}, {
|
|
2100
|
-
decorations: (value) => value.tasks,
|
|
2101
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2102
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2103
|
-
})
|
|
2104
|
-
});
|
|
2105
2221
|
return [
|
|
2106
|
-
|
|
2222
|
+
ViewPlugin5.fromClass(class {
|
|
2223
|
+
constructor(view) {
|
|
2224
|
+
this.decorations = buildDecorations4(view);
|
|
2225
|
+
}
|
|
2226
|
+
update(update2) {
|
|
2227
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2228
|
+
this.decorations = buildDecorations4(update2.view);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}, {
|
|
2232
|
+
decorations: (v) => v.decorations
|
|
2233
|
+
}),
|
|
2107
2234
|
styles5
|
|
2108
2235
|
];
|
|
2109
2236
|
};
|
|
@@ -2315,13 +2442,6 @@ var defaultTheme = {
|
|
|
2315
2442
|
textDecoration: "none"
|
|
2316
2443
|
},
|
|
2317
2444
|
//
|
|
2318
|
-
// widgets
|
|
2319
|
-
//
|
|
2320
|
-
".cm-widgetBuffer": {
|
|
2321
|
-
display: "none",
|
|
2322
|
-
height: 0
|
|
2323
|
-
},
|
|
2324
|
-
//
|
|
2325
2445
|
// table
|
|
2326
2446
|
//
|
|
2327
2447
|
".cm-table *": {
|
|
@@ -2430,90 +2550,84 @@ var codeTheme = {
|
|
|
2430
2550
|
};
|
|
2431
2551
|
|
|
2432
2552
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2553
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2433
2554
|
var EditorModes = [
|
|
2434
2555
|
"default",
|
|
2435
2556
|
"vim"
|
|
2436
2557
|
];
|
|
2437
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2558
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [] }, forwardedRef) => {
|
|
2438
2559
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2439
2560
|
tabBehavior: "limited"
|
|
2440
2561
|
});
|
|
2441
|
-
const { themeMode } =
|
|
2562
|
+
const { themeMode } = useThemeContext2();
|
|
2442
2563
|
const rootRef = useRef(null);
|
|
2443
2564
|
const [view, setView] = useState(null);
|
|
2444
2565
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2445
2566
|
view
|
|
2446
2567
|
]);
|
|
2447
|
-
|
|
2448
|
-
if (
|
|
2449
|
-
view
|
|
2568
|
+
useEffect3(() => {
|
|
2569
|
+
if (autofocus) {
|
|
2570
|
+
view?.focus();
|
|
2450
2571
|
}
|
|
2451
2572
|
}, [
|
|
2452
2573
|
view,
|
|
2453
|
-
|
|
2574
|
+
autofocus
|
|
2454
2575
|
]);
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
if (awareness2 && peer) {
|
|
2458
|
-
awareness2.setLocalStateField("user", {
|
|
2459
|
-
name: peer.name ?? generateName(peer.id),
|
|
2460
|
-
color: getColorForValue({
|
|
2461
|
-
value: peer.id,
|
|
2462
|
-
type: "color"
|
|
2463
|
-
}),
|
|
2464
|
-
colorLight: getColorForValue({
|
|
2465
|
-
value: peer.id,
|
|
2466
|
-
themeMode,
|
|
2467
|
-
type: "highlight"
|
|
2468
|
-
})
|
|
2469
|
-
});
|
|
2470
|
-
}
|
|
2471
|
-
}, [
|
|
2472
|
-
awareness2,
|
|
2473
|
-
peer,
|
|
2474
|
-
themeMode
|
|
2475
|
-
]);
|
|
2476
|
-
useEffect(() => {
|
|
2477
|
-
if (view && comments2 !== void 0) {
|
|
2478
|
-
view.dispatch({
|
|
2479
|
-
effects: setCommentRange.of({
|
|
2480
|
-
model,
|
|
2481
|
-
comments: comments2
|
|
2482
|
-
})
|
|
2483
|
-
});
|
|
2484
|
-
}
|
|
2485
|
-
}, [
|
|
2486
|
-
view,
|
|
2487
|
-
comments2
|
|
2488
|
-
]);
|
|
2489
|
-
useEffect(() => {
|
|
2576
|
+
useAwareness(model);
|
|
2577
|
+
useEffect3(() => {
|
|
2490
2578
|
if (!model || !rootRef.current) {
|
|
2491
2579
|
return;
|
|
2492
2580
|
}
|
|
2493
2581
|
const state = EditorState2.create({
|
|
2494
2582
|
doc: model.text(),
|
|
2495
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2496
2583
|
selection,
|
|
2497
2584
|
extensions: [
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2585
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2586
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2587
|
+
log2.catch(err, void 0, {
|
|
2588
|
+
F: __dxlog_file4,
|
|
2589
|
+
L: 114,
|
|
2590
|
+
S: void 0,
|
|
2591
|
+
C: (f, a) => f(...a)
|
|
2592
|
+
});
|
|
2593
|
+
}),
|
|
2501
2594
|
// Theme.
|
|
2502
|
-
// TODO(burdon): Make
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2595
|
+
// TODO(burdon): Make configurable.
|
|
2596
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2597
|
+
EditorView13.theme(theme ?? {}),
|
|
2598
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2599
|
+
EditorView13.editorAttributes.of({
|
|
2600
|
+
class: slots.editor?.className ?? ""
|
|
2601
|
+
}),
|
|
2602
|
+
EditorView13.contentAttributes.of({
|
|
2603
|
+
class: slots.content?.className ?? ""
|
|
2604
|
+
}),
|
|
2605
|
+
// State.
|
|
2606
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2506
2607
|
// Storage and replication.
|
|
2608
|
+
// NOTE: This must come before user extensions.
|
|
2507
2609
|
model.extension,
|
|
2610
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2611
|
+
editorMode === "vim" && vim(),
|
|
2508
2612
|
// Custom.
|
|
2509
2613
|
...extensions
|
|
2510
2614
|
].filter(Boolean)
|
|
2511
2615
|
});
|
|
2512
|
-
|
|
2513
|
-
|
|
2616
|
+
const newView = new EditorView13({
|
|
2617
|
+
state,
|
|
2514
2618
|
parent: rootRef.current,
|
|
2515
|
-
|
|
2619
|
+
scrollTo,
|
|
2620
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2621
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2622
|
+
dispatchTransactions: (trs, view2) => {
|
|
2623
|
+
view2.update(trs);
|
|
2624
|
+
const debug = false;
|
|
2625
|
+
if (debug) {
|
|
2626
|
+
logChanges(trs);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2516
2629
|
});
|
|
2630
|
+
view?.destroy();
|
|
2517
2631
|
setView(newView);
|
|
2518
2632
|
return () => {
|
|
2519
2633
|
newView?.destroy();
|
|
@@ -2529,8 +2643,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2529
2643
|
const handleKeyUp = useCallback((event) => {
|
|
2530
2644
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2531
2645
|
switch (key) {
|
|
2646
|
+
case "Enter": {
|
|
2647
|
+
view?.focus();
|
|
2648
|
+
break;
|
|
2649
|
+
}
|
|
2532
2650
|
case "Escape": {
|
|
2533
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2651
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2652
|
+
rootRef.current?.focus();
|
|
2653
|
+
}
|
|
2534
2654
|
break;
|
|
2535
2655
|
}
|
|
2536
2656
|
}
|
|
@@ -2541,24 +2661,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2541
2661
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2542
2662
|
key: model.id,
|
|
2543
2663
|
role: "none",
|
|
2544
|
-
ref: rootRef,
|
|
2545
2664
|
tabIndex: 0,
|
|
2546
2665
|
onKeyUp: handleKeyUp,
|
|
2547
2666
|
...slots.root,
|
|
2548
|
-
...editorMode !== "vim" && tabsterDOMAttribute
|
|
2667
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2668
|
+
ref: rootRef
|
|
2549
2669
|
});
|
|
2550
2670
|
});
|
|
2551
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2552
|
-
const { themeMode } =
|
|
2671
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, multiline, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2672
|
+
const { themeMode } = useThemeContext2();
|
|
2553
2673
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2554
2674
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2555
2675
|
ref: forwardedRef,
|
|
2556
2676
|
readonly,
|
|
2557
2677
|
extensions: [
|
|
2558
2678
|
basicBundle({
|
|
2559
|
-
readonly,
|
|
2560
2679
|
themeMode,
|
|
2561
|
-
placeholder: placeholder3
|
|
2680
|
+
placeholder: placeholder3,
|
|
2681
|
+
multiline
|
|
2562
2682
|
}),
|
|
2563
2683
|
...extensions
|
|
2564
2684
|
],
|
|
@@ -2567,16 +2687,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2567
2687
|
...props
|
|
2568
2688
|
});
|
|
2569
2689
|
});
|
|
2570
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2571
|
-
const { themeMode } =
|
|
2690
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2691
|
+
const { themeMode } = useThemeContext2();
|
|
2572
2692
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2573
2693
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2574
2694
|
ref: forwardedRef,
|
|
2575
2695
|
readonly,
|
|
2576
2696
|
extensions: [
|
|
2577
2697
|
markdownBundle({
|
|
2578
|
-
readonly,
|
|
2579
2698
|
themeMode,
|
|
2699
|
+
readonly,
|
|
2580
2700
|
placeholder: placeholder3
|
|
2581
2701
|
}),
|
|
2582
2702
|
...extensions
|
|
@@ -2588,7 +2708,11 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2588
2708
|
});
|
|
2589
2709
|
var defaultSlots = {
|
|
2590
2710
|
root: {
|
|
2591
|
-
|
|
2711
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2712
|
+
className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
|
|
2713
|
+
},
|
|
2714
|
+
editor: {
|
|
2715
|
+
className: "h-full p-2"
|
|
2592
2716
|
}
|
|
2593
2717
|
};
|
|
2594
2718
|
var defaultTextSlots = {
|
|
@@ -2608,7 +2732,7 @@ import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
|
2608
2732
|
import { Context as Context2 } from "@dxos/context";
|
|
2609
2733
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2610
2734
|
import { log as log3 } from "@dxos/log";
|
|
2611
|
-
var
|
|
2735
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2612
2736
|
var DEBOUNCE_INTERVAL = 100;
|
|
2613
2737
|
var SpaceAwarenessProvider = class {
|
|
2614
2738
|
constructor(params) {
|
|
@@ -2649,7 +2773,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2649
2773
|
log3.debug("failed to query awareness", {
|
|
2650
2774
|
err
|
|
2651
2775
|
}, {
|
|
2652
|
-
F:
|
|
2776
|
+
F: __dxlog_file5,
|
|
2653
2777
|
L: 85,
|
|
2654
2778
|
S: this,
|
|
2655
2779
|
C: (f, a) => f(...a)
|
|
@@ -2663,7 +2787,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2663
2787
|
}
|
|
2664
2788
|
update(position) {
|
|
2665
2789
|
invariant3(this._postTask, void 0, {
|
|
2666
|
-
F:
|
|
2790
|
+
F: __dxlog_file5,
|
|
2667
2791
|
L: 96,
|
|
2668
2792
|
S: this,
|
|
2669
2793
|
A: [
|
|
@@ -2683,7 +2807,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2683
2807
|
}
|
|
2684
2808
|
_handleQueryMessage() {
|
|
2685
2809
|
invariant3(this._postTask, void 0, {
|
|
2686
|
-
F:
|
|
2810
|
+
F: __dxlog_file5,
|
|
2687
2811
|
L: 111,
|
|
2688
2812
|
S: this,
|
|
2689
2813
|
A: [
|
|
@@ -2695,7 +2819,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2695
2819
|
}
|
|
2696
2820
|
_handlePostMessage(message) {
|
|
2697
2821
|
invariant3(message.kind === "post", void 0, {
|
|
2698
|
-
F:
|
|
2822
|
+
F: __dxlog_file5,
|
|
2699
2823
|
L: 116,
|
|
2700
2824
|
S: this,
|
|
2701
2825
|
A: [
|
|
@@ -2708,10 +2832,50 @@ var SpaceAwarenessProvider = class {
|
|
|
2708
2832
|
}
|
|
2709
2833
|
};
|
|
2710
2834
|
|
|
2711
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2835
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2712
2836
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2713
|
-
|
|
2714
|
-
|
|
2837
|
+
var modelState = StateField5.define({
|
|
2838
|
+
create: () => void 0,
|
|
2839
|
+
update: (model) => model
|
|
2840
|
+
});
|
|
2841
|
+
|
|
2842
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2843
|
+
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2844
|
+
const obj = text;
|
|
2845
|
+
const doc = getRawDoc(obj, [
|
|
2846
|
+
obj.field
|
|
2847
|
+
]);
|
|
2848
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2849
|
+
space,
|
|
2850
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2851
|
+
info: {
|
|
2852
|
+
displayName: identity?.profile?.displayName ?? "",
|
|
2853
|
+
color: cursorColor.color,
|
|
2854
|
+
lightColor: cursorColor.light
|
|
2855
|
+
},
|
|
2856
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2857
|
+
});
|
|
2858
|
+
const model = {
|
|
2859
|
+
id: obj.id,
|
|
2860
|
+
content: doc,
|
|
2861
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2862
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2863
|
+
extension: [
|
|
2864
|
+
modelState.init(() => model),
|
|
2865
|
+
automerge3({
|
|
2866
|
+
handle: doc.handle,
|
|
2867
|
+
path: doc.path
|
|
2868
|
+
}),
|
|
2869
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2870
|
+
awareness()
|
|
2871
|
+
].filter(isNotNullOrUndefined),
|
|
2872
|
+
peer: identity ? {
|
|
2873
|
+
id: identity.identityKey.toHex(),
|
|
2874
|
+
name: identity.profile?.displayName
|
|
2875
|
+
} : void 0
|
|
2876
|
+
};
|
|
2877
|
+
return model;
|
|
2878
|
+
};
|
|
2715
2879
|
|
|
2716
2880
|
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2717
2881
|
import * as decoding from "lib0/decoding";
|
|
@@ -2720,11 +2884,11 @@ import { Observable } from "lib0/observable";
|
|
|
2720
2884
|
import * as YP from "y-protocols/awareness";
|
|
2721
2885
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2722
2886
|
import { log as log4 } from "@dxos/log";
|
|
2723
|
-
var
|
|
2887
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2724
2888
|
var createYjsModel = ({ identity, space, text }) => {
|
|
2725
2889
|
invariant4(text?.doc && text?.content, void 0, {
|
|
2726
|
-
F:
|
|
2727
|
-
L:
|
|
2890
|
+
F: __dxlog_file6,
|
|
2891
|
+
L: 22,
|
|
2728
2892
|
S: void 0,
|
|
2729
2893
|
A: [
|
|
2730
2894
|
"text?.doc && text?.content",
|
|
@@ -2788,8 +2952,8 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2788
2952
|
removed,
|
|
2789
2953
|
origin
|
|
2790
2954
|
}, {
|
|
2791
|
-
F:
|
|
2792
|
-
L:
|
|
2955
|
+
F: __dxlog_file6,
|
|
2956
|
+
L: 101,
|
|
2793
2957
|
S: this,
|
|
2794
2958
|
C: (f, a) => f(...a)
|
|
2795
2959
|
});
|
|
@@ -2801,8 +2965,8 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2801
2965
|
}
|
|
2802
2966
|
_handleSpaceMessage({ payload }) {
|
|
2803
2967
|
log4("space message", payload, {
|
|
2804
|
-
F:
|
|
2805
|
-
L:
|
|
2968
|
+
F: __dxlog_file6,
|
|
2969
|
+
L: 110,
|
|
2806
2970
|
S: this,
|
|
2807
2971
|
C: (f, a) => f(...a)
|
|
2808
2972
|
});
|
|
@@ -2846,14 +3010,12 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2846
3010
|
};
|
|
2847
3011
|
|
|
2848
3012
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
update: (model) => model
|
|
2852
|
-
});
|
|
3013
|
+
import { useEffect as useEffect4, useState as useState2 } from "react";
|
|
3014
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2853
3015
|
var useTextModel = (props) => {
|
|
2854
3016
|
const { identity, space, text } = props;
|
|
2855
3017
|
const [model, setModel] = useState2();
|
|
2856
|
-
|
|
3018
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2857
3019
|
identity,
|
|
2858
3020
|
space,
|
|
2859
3021
|
text
|
|
@@ -2870,44 +3032,6 @@ var createModel = (props) => {
|
|
|
2870
3032
|
return void 0;
|
|
2871
3033
|
}
|
|
2872
3034
|
};
|
|
2873
|
-
|
|
2874
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2875
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2876
|
-
const obj = text;
|
|
2877
|
-
const doc = getRawDoc(obj, [
|
|
2878
|
-
obj.field
|
|
2879
|
-
]);
|
|
2880
|
-
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2881
|
-
space,
|
|
2882
|
-
channel: `automerge.awareness.${obj.id}`,
|
|
2883
|
-
info: {
|
|
2884
|
-
displayName: identity?.profile?.displayName ?? "",
|
|
2885
|
-
color: cursorColor.color,
|
|
2886
|
-
lightColor: cursorColor.light
|
|
2887
|
-
},
|
|
2888
|
-
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2889
|
-
});
|
|
2890
|
-
const model = {
|
|
2891
|
-
id: obj.id,
|
|
2892
|
-
content: doc,
|
|
2893
|
-
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2894
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2895
|
-
extension: [
|
|
2896
|
-
modelState.init(() => model),
|
|
2897
|
-
automerge3({
|
|
2898
|
-
handle: doc.handle,
|
|
2899
|
-
path: doc.path
|
|
2900
|
-
}),
|
|
2901
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2902
|
-
awareness()
|
|
2903
|
-
].filter(isNotNullOrUndefined),
|
|
2904
|
-
peer: identity ? {
|
|
2905
|
-
id: identity.identityKey.toHex(),
|
|
2906
|
-
name: identity.profile?.displayName
|
|
2907
|
-
} : void 0
|
|
2908
|
-
};
|
|
2909
|
-
return model;
|
|
2910
|
-
};
|
|
2911
3035
|
export {
|
|
2912
3036
|
AwarenessProvider,
|
|
2913
3037
|
BaseTextEditor,
|
|
@@ -2933,7 +3057,6 @@ export {
|
|
|
2933
3057
|
comments,
|
|
2934
3058
|
createAutomergeModel,
|
|
2935
3059
|
createYjsModel,
|
|
2936
|
-
cursorConverter,
|
|
2937
3060
|
defaultMarkdownSlots,
|
|
2938
3061
|
defaultOptions,
|
|
2939
3062
|
defaultSlots,
|
|
@@ -2944,6 +3067,7 @@ export {
|
|
|
2944
3067
|
image,
|
|
2945
3068
|
link,
|
|
2946
3069
|
listener,
|
|
3070
|
+
logChanges,
|
|
2947
3071
|
markdownBundle,
|
|
2948
3072
|
markdownHighlightStyle,
|
|
2949
3073
|
markdownTags,
|
|
@@ -2951,7 +3075,8 @@ export {
|
|
|
2951
3075
|
markdownTheme,
|
|
2952
3076
|
mention,
|
|
2953
3077
|
modelState,
|
|
2954
|
-
|
|
3078
|
+
outliner,
|
|
3079
|
+
setComments,
|
|
2955
3080
|
setFocus,
|
|
2956
3081
|
setSelection,
|
|
2957
3082
|
table,
|
|
@@ -2959,6 +3084,8 @@ export {
|
|
|
2959
3084
|
tasklist,
|
|
2960
3085
|
textTheme,
|
|
2961
3086
|
typewriter,
|
|
3087
|
+
useAwareness,
|
|
3088
|
+
useComments,
|
|
2962
3089
|
useTextModel,
|
|
2963
3090
|
yjs
|
|
2964
3091
|
};
|