@dxos/react-ui-editor 0.3.11-main.8a2cfe6 → 0.3.11-main.8b0e08e
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 +1157 -1258
- 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/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +7 -9
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +7 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts +1 -1
- 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/comments.d.ts +32 -19
- 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/index.d.ts +2 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +7 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- 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/hooks/awareness-provider.d.ts +7 -4
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- 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/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- 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 +33 -35
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +82 -82
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +122 -93
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/extensions/autocomplete.ts +23 -19
- 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/semaphore.ts +23 -20
- package/src/extensions/automerge/update-automerge.ts +2 -2
- package/src/extensions/awareness.ts +40 -46
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/comments.ts +246 -238
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -7
- package/src/extensions/markdown/bundle.ts +20 -30
- package/src/extensions/markdown/code.ts +127 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -23
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/{image.ts → markdown/image.ts} +2 -2
- package/src/extensions/markdown/index.ts +7 -0
- package/src/extensions/{link.ts → markdown/link.ts} +8 -9
- package/src/extensions/{table.ts → markdown/table.ts} +6 -3
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +3 -2
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +48 -60
- package/src/index.ts +2 -0
- package/src/styles/markdown.ts +9 -12
- package/src/themes/default.ts +15 -50
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- 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/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -98
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/tasklist.ts +0 -119
- package/src/extensions/yjs/cursor.ts +0 -21
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -178
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- package/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
|
@@ -7,52 +7,56 @@ 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 {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
18
|
|
|
19
19
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
21
22
|
import { keymap } from "@codemirror/view";
|
|
22
23
|
var autocomplete = ({ onSearch }) => {
|
|
23
24
|
return [
|
|
24
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
25
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
26
28
|
keymap.of(completionKeymap),
|
|
27
29
|
// https://codemirror.net/examples/autocompletion
|
|
28
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
29
31
|
autocompletion({
|
|
30
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
31
34
|
// defaultKeymap: false,
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
from: match.from,
|
|
44
|
-
options: onSearch(match.text.toLowerCase())
|
|
45
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
46
45
|
}
|
|
47
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
48
51
|
})
|
|
49
52
|
];
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
53
|
-
import {
|
|
54
|
-
import { ViewPlugin } from "@codemirror/view";
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
55
58
|
import { next as A } from "@dxos/automerge/automerge";
|
|
59
|
+
import { invariant } from "@dxos/invariant";
|
|
56
60
|
|
|
57
61
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
58
62
|
import get from "lodash.get";
|
|
@@ -93,12 +97,12 @@ var cursorConverter = (handle, path) => ({
|
|
|
93
97
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
94
98
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
95
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;
|
|
96
103
|
var updateHeads = (newHeads) => effectType.of({
|
|
97
104
|
newHeads
|
|
98
105
|
});
|
|
99
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
100
|
-
var getPath = (state, field) => state.field(field).path;
|
|
101
|
-
var reconcileAnnotationType = Annotation.define();
|
|
102
106
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
103
107
|
|
|
104
108
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
@@ -236,85 +240,96 @@ var charPath = (textPath, candidatePath) => {
|
|
|
236
240
|
|
|
237
241
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
238
242
|
var PatchSemaphore = class {
|
|
239
|
-
|
|
240
|
-
|
|
243
|
+
// prettier-ignore
|
|
244
|
+
constructor(_handle, _state) {
|
|
245
|
+
this._handle = _handle;
|
|
246
|
+
this._state = _state;
|
|
241
247
|
this._inReconcile = false;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
changes: inverted,
|
|
258
|
-
annotations: reconcileAnnotationType.of(true)
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
262
|
-
if (newHeads === null || newHeads === void 0) {
|
|
263
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
264
|
-
}
|
|
265
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
266
|
-
updateCodeMirror(view, selection, path, diff);
|
|
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);
|
|
267
263
|
view.dispatch({
|
|
268
|
-
|
|
269
|
-
annotations: reconcileAnnotationType.of(
|
|
264
|
+
changes: inverted,
|
|
265
|
+
annotations: reconcileAnnotationType.of(true)
|
|
270
266
|
});
|
|
271
|
-
|
|
272
|
-
|
|
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;
|
|
273
279
|
}
|
|
274
280
|
};
|
|
275
281
|
|
|
276
|
-
// packages/ui/react-ui-editor/src/
|
|
282
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
277
283
|
import { Facet } from "@codemirror/state";
|
|
278
|
-
var
|
|
284
|
+
var defaultCursorConverter = {
|
|
279
285
|
toCursor: (position) => position.toString(),
|
|
280
286
|
fromCursor: (cursor) => parseInt(cursor)
|
|
281
287
|
};
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
// packages/ui/react-ui-editor/src/util/util.ts
|
|
287
|
-
import { log } from "@dxos/log";
|
|
288
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
289
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
290
|
-
try {
|
|
291
|
-
return fn(...args);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
log.catch(error, void 0, {
|
|
294
|
-
F: __dxlog_file,
|
|
295
|
-
L: 16,
|
|
296
|
-
S: void 0,
|
|
297
|
-
C: (f, a) => f(...a)
|
|
288
|
+
var Cursor = class _Cursor {
|
|
289
|
+
static {
|
|
290
|
+
this.converter = Facet.define({
|
|
291
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
298
292
|
});
|
|
299
293
|
}
|
|
294
|
+
static {
|
|
295
|
+
this.getCursorFromRange = (state, range) => {
|
|
296
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
297
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
298
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
299
|
+
return [
|
|
300
|
+
from,
|
|
301
|
+
to
|
|
302
|
+
].join(":");
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
static {
|
|
306
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
|
+
const parts = cursor.split(":");
|
|
309
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
310
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
311
|
+
return from !== void 0 && to !== void 0 ? {
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
} : void 0;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
300
317
|
};
|
|
301
318
|
|
|
302
319
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
303
|
-
var
|
|
304
|
-
combine: (values) => values.at(-1)
|
|
305
|
-
});
|
|
320
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
|
|
306
321
|
var automerge3 = ({ handle, path }) => {
|
|
307
|
-
const
|
|
322
|
+
const state = StateField.define({
|
|
308
323
|
create: () => ({
|
|
324
|
+
path: path.slice(),
|
|
309
325
|
lastHeads: A.getHeads(handle.docSync()),
|
|
310
|
-
unreconciledTransactions: []
|
|
311
|
-
path: path.slice()
|
|
326
|
+
unreconciledTransactions: []
|
|
312
327
|
}),
|
|
313
328
|
update: (value, tr) => {
|
|
314
329
|
const result = {
|
|
330
|
+
path: path.slice(),
|
|
315
331
|
lastHeads: value.lastHeads,
|
|
316
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
317
|
-
path: path.slice()
|
|
332
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
318
333
|
};
|
|
319
334
|
let clearUnreconciled = false;
|
|
320
335
|
for (const effect of tr.effects) {
|
|
@@ -333,39 +348,44 @@ var automerge3 = ({ handle, path }) => {
|
|
|
333
348
|
return result;
|
|
334
349
|
}
|
|
335
350
|
});
|
|
336
|
-
const semaphore = new PatchSemaphore(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
+
]
|
|
349
366
|
});
|
|
367
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
350
368
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
+
];
|
|
364
384
|
};
|
|
365
385
|
|
|
366
386
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
367
|
-
import { Annotation as Annotation2, Facet as
|
|
368
|
-
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";
|
|
369
389
|
import { Event } from "@dxos/async";
|
|
370
390
|
import { Context } from "@dxos/context";
|
|
371
391
|
var dummyProvider = {
|
|
@@ -374,11 +394,11 @@ var dummyProvider = {
|
|
|
374
394
|
},
|
|
375
395
|
close: () => {
|
|
376
396
|
},
|
|
397
|
+
getRemoteStates: () => [],
|
|
377
398
|
update: () => {
|
|
378
|
-
}
|
|
379
|
-
getRemoteStates: () => []
|
|
399
|
+
}
|
|
380
400
|
};
|
|
381
|
-
var AwarenessProvider =
|
|
401
|
+
var AwarenessProvider = Facet2.define({
|
|
382
402
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
383
403
|
});
|
|
384
404
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
@@ -397,7 +417,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
397
417
|
this._ctx = new Context();
|
|
398
418
|
this._lastAnchor = void 0;
|
|
399
419
|
this._lastHead = void 0;
|
|
400
|
-
this._cursorConverter = view.state.facet(
|
|
420
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
401
421
|
this._provider = view.state.facet(AwarenessProvider);
|
|
402
422
|
this._provider.open();
|
|
403
423
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
@@ -452,7 +472,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
452
472
|
attributes: {
|
|
453
473
|
style: `background-color: ${lightColor}`
|
|
454
474
|
},
|
|
455
|
-
class: "cm-
|
|
475
|
+
class: "cm-collab-selection"
|
|
456
476
|
})
|
|
457
477
|
});
|
|
458
478
|
} else {
|
|
@@ -463,7 +483,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
463
483
|
attributes: {
|
|
464
484
|
style: `background-color: ${color}`
|
|
465
485
|
},
|
|
466
|
-
class: "cm-
|
|
486
|
+
class: "cm-collab-selection"
|
|
467
487
|
})
|
|
468
488
|
});
|
|
469
489
|
decorations.push({
|
|
@@ -473,7 +493,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
473
493
|
attributes: {
|
|
474
494
|
style: `background-color: ${color}`
|
|
475
495
|
},
|
|
476
|
-
class: "cm-
|
|
496
|
+
class: "cm-collab-selection"
|
|
477
497
|
})
|
|
478
498
|
});
|
|
479
499
|
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
@@ -484,7 +504,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
484
504
|
value: Decoration.line({
|
|
485
505
|
attributes: {
|
|
486
506
|
style: `background-color: ${color}`,
|
|
487
|
-
class: "cm-
|
|
507
|
+
class: "cm-collab-selectionLine"
|
|
488
508
|
}
|
|
489
509
|
})
|
|
490
510
|
});
|
|
@@ -504,23 +524,21 @@ var RemoteSelectionsDecorator = class {
|
|
|
504
524
|
}
|
|
505
525
|
};
|
|
506
526
|
var RemoteCaretWidget = class extends WidgetType {
|
|
507
|
-
constructor(
|
|
527
|
+
constructor(_name, _color) {
|
|
508
528
|
super();
|
|
509
|
-
this.
|
|
510
|
-
this.
|
|
511
|
-
this.name = name;
|
|
512
|
-
this.color = color;
|
|
529
|
+
this._name = _name;
|
|
530
|
+
this._color = _color;
|
|
513
531
|
}
|
|
514
532
|
toDOM() {
|
|
515
533
|
const span = document.createElement("span");
|
|
516
|
-
span.className = "cm-
|
|
517
|
-
span.style.backgroundColor = this.
|
|
518
|
-
span.style.borderColor = this.
|
|
534
|
+
span.className = "cm-collab-selectionCaret";
|
|
535
|
+
span.style.backgroundColor = this._color;
|
|
536
|
+
span.style.borderColor = this._color;
|
|
519
537
|
const dot = document.createElement("div");
|
|
520
|
-
dot.className = "cm-
|
|
538
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
521
539
|
const info = document.createElement("div");
|
|
522
|
-
info.className = "cm-
|
|
523
|
-
info.innerText = this.
|
|
540
|
+
info.className = "cm-collab-selectionInfo";
|
|
541
|
+
info.innerText = this._name;
|
|
524
542
|
span.appendChild(document.createTextNode("\u2060"));
|
|
525
543
|
span.appendChild(dot);
|
|
526
544
|
span.appendChild(document.createTextNode("\u2060"));
|
|
@@ -528,15 +546,12 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
528
546
|
span.appendChild(document.createTextNode("\u2060"));
|
|
529
547
|
return span;
|
|
530
548
|
}
|
|
531
|
-
eq(widget) {
|
|
532
|
-
return widget.color === this.color;
|
|
533
|
-
}
|
|
534
|
-
compare(widget) {
|
|
535
|
-
return widget.color === this.color;
|
|
536
|
-
}
|
|
537
549
|
updateDOM() {
|
|
538
550
|
return false;
|
|
539
551
|
}
|
|
552
|
+
eq(widget) {
|
|
553
|
+
return widget._color === this._color;
|
|
554
|
+
}
|
|
540
555
|
get estimatedHeight() {
|
|
541
556
|
return -1;
|
|
542
557
|
}
|
|
@@ -544,58 +559,60 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
544
559
|
return true;
|
|
545
560
|
}
|
|
546
561
|
};
|
|
547
|
-
var styles =
|
|
548
|
-
".cm-
|
|
549
|
-
".cm-
|
|
562
|
+
var styles = EditorView2.baseTheme({
|
|
563
|
+
".cm-collab-selection": {},
|
|
564
|
+
".cm-collab-selectionLine": {
|
|
550
565
|
padding: 0,
|
|
551
566
|
margin: "0px 2px 0px 4px"
|
|
552
567
|
},
|
|
553
|
-
".cm-
|
|
568
|
+
".cm-collab-selectionCaret": {
|
|
554
569
|
position: "relative",
|
|
555
570
|
borderLeft: "1px solid black",
|
|
556
571
|
borderRight: "1px solid black",
|
|
557
572
|
marginLeft: "-1px",
|
|
558
573
|
marginRight: "-1px",
|
|
559
574
|
boxSizing: "border-box",
|
|
560
|
-
display: "inline"
|
|
575
|
+
display: "inline",
|
|
576
|
+
cursor: "pointer"
|
|
561
577
|
},
|
|
562
|
-
".cm-
|
|
578
|
+
".cm-collab-selectionCaretDot": {
|
|
563
579
|
borderRadius: "50%",
|
|
564
580
|
position: "absolute",
|
|
565
|
-
width: ".
|
|
566
|
-
height: ".
|
|
567
|
-
top: "-.
|
|
568
|
-
left: "-.
|
|
581
|
+
width: ".5em",
|
|
582
|
+
height: ".5em",
|
|
583
|
+
top: "-.25em",
|
|
584
|
+
left: "-.25em",
|
|
569
585
|
backgroundColor: "inherit",
|
|
570
586
|
transition: "transform .3s ease-in-out",
|
|
571
587
|
boxSizing: "border-box"
|
|
572
588
|
},
|
|
573
|
-
".cm-
|
|
574
|
-
|
|
575
|
-
|
|
589
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
590
|
+
transform: "scale(0)",
|
|
591
|
+
transformOrigin: "center"
|
|
576
592
|
},
|
|
577
|
-
".cm-
|
|
593
|
+
".cm-collab-selectionInfo": {
|
|
578
594
|
position: "absolute",
|
|
579
|
-
|
|
580
|
-
|
|
595
|
+
transform: "translate(-50%, 0)",
|
|
596
|
+
top: "-20px",
|
|
597
|
+
left: 0,
|
|
581
598
|
fontSize: ".75em",
|
|
582
|
-
fontFamily: "serif",
|
|
599
|
+
fontFamily: "sans-serif",
|
|
583
600
|
fontStyle: "normal",
|
|
584
601
|
fontWeight: "normal",
|
|
585
602
|
lineHeight: "normal",
|
|
586
603
|
userSelect: "none",
|
|
587
604
|
color: "white",
|
|
588
|
-
|
|
589
|
-
paddingRight: "2px",
|
|
605
|
+
padding: "2px",
|
|
590
606
|
zIndex: 101,
|
|
591
607
|
transition: "opacity .3s ease-in-out",
|
|
592
608
|
backgroundColor: "inherit",
|
|
593
|
-
|
|
609
|
+
borderRadius: "2px",
|
|
610
|
+
// These should be separate.
|
|
594
611
|
opacity: 0,
|
|
595
612
|
transitionDelay: "0s",
|
|
596
613
|
whiteSpace: "nowrap"
|
|
597
614
|
},
|
|
598
|
-
".cm-
|
|
615
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
599
616
|
opacity: 1,
|
|
600
617
|
transitionDelay: "0s"
|
|
601
618
|
}
|
|
@@ -603,25 +620,27 @@ var styles = EditorView.baseTheme({
|
|
|
603
620
|
|
|
604
621
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
605
622
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
623
|
+
import { history } from "@codemirror/commands";
|
|
606
624
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
607
625
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
608
|
-
import { drawSelection, EditorView as
|
|
609
|
-
var basicBundle = ({
|
|
610
|
-
|
|
611
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
626
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
628
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
612
629
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
613
630
|
bracketMatching(),
|
|
614
631
|
closeBrackets(),
|
|
615
632
|
drawSelection(),
|
|
616
|
-
|
|
617
|
-
|
|
633
|
+
highlightActiveLine(),
|
|
634
|
+
history(),
|
|
635
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
636
|
+
// https://github.com/codemirror/theme-one-dark
|
|
618
637
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
619
|
-
]
|
|
638
|
+
];
|
|
620
639
|
|
|
621
640
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
622
|
-
import { EditorView as
|
|
641
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
623
642
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
624
|
-
import { invariant } from "@dxos/invariant";
|
|
643
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
625
644
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
626
645
|
var defaultOptions = {
|
|
627
646
|
effect: 2,
|
|
@@ -655,10 +674,10 @@ var blast = (options = defaultOptions) => {
|
|
|
655
674
|
const getPoint = (view, pos) => {
|
|
656
675
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
657
676
|
const element = document.elementFromPoint(x, y);
|
|
658
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
677
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
659
678
|
const point = {
|
|
660
679
|
x: x - left,
|
|
661
|
-
y: y -
|
|
680
|
+
y: y - top2
|
|
662
681
|
};
|
|
663
682
|
return {
|
|
664
683
|
element,
|
|
@@ -667,7 +686,7 @@ var blast = (options = defaultOptions) => {
|
|
|
667
686
|
};
|
|
668
687
|
return [
|
|
669
688
|
// Cursor moved.
|
|
670
|
-
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
671
690
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
691
|
if (blaster) {
|
|
673
692
|
blaster.destroy();
|
|
@@ -748,7 +767,7 @@ var Blaster = class {
|
|
|
748
767
|
return this._node;
|
|
749
768
|
}
|
|
750
769
|
initialize() {
|
|
751
|
-
|
|
770
|
+
invariant2(!this._canvas && !this._ctx, void 0, {
|
|
752
771
|
F: __dxlog_file2,
|
|
753
772
|
L: 138,
|
|
754
773
|
S: this,
|
|
@@ -785,7 +804,7 @@ var Blaster = class {
|
|
|
785
804
|
}
|
|
786
805
|
}
|
|
787
806
|
start() {
|
|
788
|
-
|
|
807
|
+
invariant2(this._canvas && this._ctx, void 0, {
|
|
789
808
|
F: __dxlog_file2,
|
|
790
809
|
L: 177,
|
|
791
810
|
S: this,
|
|
@@ -928,9 +947,14 @@ var random = (min, max) => {
|
|
|
928
947
|
return min + ~~(Math.random() * (max - min + 1));
|
|
929
948
|
};
|
|
930
949
|
|
|
931
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
932
|
-
import {
|
|
933
|
-
import {
|
|
950
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
951
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
952
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
953
|
+
import sortBy from "lodash.sortby";
|
|
954
|
+
import { useEffect } from "react";
|
|
955
|
+
import { debounce } from "@dxos/async";
|
|
956
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
957
|
+
import { nonNullable } from "@dxos/util";
|
|
934
958
|
|
|
935
959
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
936
960
|
import * as random2 from "lib0/random";
|
|
@@ -973,34 +997,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
973
997
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
974
998
|
import { mx } from "@dxos/react-ui-theme";
|
|
975
999
|
var headings = {
|
|
976
|
-
1:
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
986
|
-
"-ml-[7px]"
|
|
987
|
-
],
|
|
988
|
-
4: [
|
|
989
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
990
|
-
"-ml-[6px]"
|
|
991
|
-
],
|
|
992
|
-
5: [
|
|
993
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
994
|
-
"-ml-[5px]"
|
|
995
|
-
],
|
|
996
|
-
6: [
|
|
997
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
998
|
-
"-ml-[4px]"
|
|
999
|
-
]
|
|
1000
|
-
};
|
|
1001
|
-
var heading = (level, readonly) => {
|
|
1002
|
-
const [style, offset] = headings[level];
|
|
1003
|
-
return mx(style, readonly && offset);
|
|
1000
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1001
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1002
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1003
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1004
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1005
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1006
|
+
};
|
|
1007
|
+
var heading = (level) => {
|
|
1008
|
+
return headings[level];
|
|
1004
1009
|
};
|
|
1005
1010
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1006
1011
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1018,154 +1023,112 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1018
1023
|
var tokens = tailwindConfig({}).theme;
|
|
1019
1024
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1020
1025
|
|
|
1021
|
-
// packages/ui/react-ui-editor/src/
|
|
1022
|
-
|
|
1023
|
-
var
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
display: "block",
|
|
1035
|
-
paddingInline: "4px !important"
|
|
1036
|
-
},
|
|
1037
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1038
|
-
paddingTop: "4px !important",
|
|
1039
|
-
borderTopLeftRadius: "4px",
|
|
1040
|
-
borderTopRightRadius: "4px"
|
|
1041
|
-
},
|
|
1042
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1043
|
-
paddingBottom: "4px !important",
|
|
1044
|
-
borderBottomLeftRadius: "4px",
|
|
1045
|
-
borderBottomRightRadius: "4px"
|
|
1026
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1027
|
+
import { log } from "@dxos/log";
|
|
1028
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1029
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1030
|
+
try {
|
|
1031
|
+
return fn(...args);
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
log.catch(err, void 0, {
|
|
1034
|
+
F: __dxlog_file3,
|
|
1035
|
+
L: 18,
|
|
1036
|
+
S: void 0,
|
|
1037
|
+
C: (f, a) => f(...a)
|
|
1038
|
+
});
|
|
1046
1039
|
}
|
|
1047
|
-
});
|
|
1048
|
-
var getLineRange = (lines, from, to) => {
|
|
1049
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1050
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1051
|
-
return [
|
|
1052
|
-
start,
|
|
1053
|
-
end
|
|
1054
|
-
];
|
|
1055
1040
|
};
|
|
1056
|
-
var
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
const text = view.state.doc.sliceString(0);
|
|
1061
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1062
|
-
const blocks = view.viewportLineBlocks;
|
|
1063
|
-
for (const match of matches) {
|
|
1064
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1065
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1066
|
-
const block = blocks[i];
|
|
1067
|
-
decorations.push(Decoration2.line({
|
|
1068
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1069
|
-
}).range(block.from));
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1041
|
+
var logChanges = (trs) => {
|
|
1042
|
+
const changes = trs.flatMap((tr) => {
|
|
1043
|
+
if (tr.changes.empty) {
|
|
1044
|
+
return void 0;
|
|
1072
1045
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
decorations: (value) => value.decorations
|
|
1087
|
-
}),
|
|
1088
|
-
styles2
|
|
1089
|
-
];
|
|
1046
|
+
const changes2 = [];
|
|
1047
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1048
|
+
fromA,
|
|
1049
|
+
toA,
|
|
1050
|
+
fromB,
|
|
1051
|
+
toB,
|
|
1052
|
+
inserted: inserted.toString()
|
|
1053
|
+
})));
|
|
1054
|
+
return changes2;
|
|
1055
|
+
}).filter(Boolean);
|
|
1056
|
+
if (changes.length) {
|
|
1057
|
+
console.log("changes", changes);
|
|
1058
|
+
}
|
|
1090
1059
|
};
|
|
1091
1060
|
|
|
1092
1061
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
import sortBy from "lodash.sortby";
|
|
1096
|
-
import { debounce } from "@dxos/async";
|
|
1097
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1098
|
-
import { log as log2 } from "@dxos/log";
|
|
1099
|
-
import { nonNullable } from "@dxos/util";
|
|
1100
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1101
|
-
var styles3 = EditorView5.baseTheme({
|
|
1102
|
-
"& .cm-bookmark": {
|
|
1103
|
-
cursor: "pointer",
|
|
1104
|
-
margin: "4px",
|
|
1105
|
-
padding: "4px",
|
|
1106
|
-
backgroundColor: "yellow"
|
|
1107
|
-
},
|
|
1108
|
-
"& .cm-bookmark-selected": {
|
|
1109
|
-
backgroundColor: "orange"
|
|
1110
|
-
},
|
|
1062
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1063
|
+
var styles2 = EditorView5.baseTheme({
|
|
1111
1064
|
"& .cm-comment": {
|
|
1112
1065
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1066
|
},
|
|
1114
|
-
"& .cm-comment-
|
|
1067
|
+
"& .cm-comment-current": {
|
|
1115
1068
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1116
1069
|
}
|
|
1117
1070
|
});
|
|
1118
1071
|
var marks = {
|
|
1119
|
-
highlight:
|
|
1072
|
+
highlight: Decoration2.mark({
|
|
1120
1073
|
class: "cm-comment"
|
|
1121
1074
|
}),
|
|
1122
|
-
highlightActive:
|
|
1123
|
-
class: "cm-comment-
|
|
1075
|
+
highlightActive: Decoration2.mark({
|
|
1076
|
+
class: "cm-comment-current"
|
|
1124
1077
|
})
|
|
1125
1078
|
};
|
|
1126
|
-
var setFocus = (view,
|
|
1127
|
-
const
|
|
1128
|
-
if (!
|
|
1079
|
+
var setFocus = (view, id, center = true) => {
|
|
1080
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1081
|
+
if (!comment?.comment.cursor) {
|
|
1129
1082
|
return;
|
|
1130
1083
|
}
|
|
1131
|
-
view.
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1084
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1085
|
+
if (range) {
|
|
1086
|
+
view.dispatch({
|
|
1087
|
+
selection: {
|
|
1088
|
+
anchor: range.from
|
|
1089
|
+
},
|
|
1090
|
+
effects: [
|
|
1091
|
+
//
|
|
1092
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1093
|
+
y: "center"
|
|
1094
|
+
} : void 0),
|
|
1095
|
+
setSelection.of({
|
|
1096
|
+
current: id
|
|
1097
|
+
})
|
|
1098
|
+
]
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1140
1101
|
};
|
|
1141
|
-
var
|
|
1102
|
+
var setComments = StateEffect2.define();
|
|
1142
1103
|
var setSelection = StateEffect2.define();
|
|
1143
1104
|
var setCommentState = StateEffect2.define();
|
|
1144
|
-
var
|
|
1105
|
+
var commentsState = StateField2.define({
|
|
1145
1106
|
create: () => ({
|
|
1146
|
-
|
|
1107
|
+
comments: [],
|
|
1108
|
+
selection: {}
|
|
1147
1109
|
}),
|
|
1148
1110
|
update: (value, tr) => {
|
|
1149
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1150
1111
|
for (const effect of tr.effects) {
|
|
1151
1112
|
if (effect.is(setSelection)) {
|
|
1152
1113
|
return {
|
|
1153
1114
|
...value,
|
|
1154
|
-
|
|
1115
|
+
selection: effect.value
|
|
1155
1116
|
};
|
|
1156
1117
|
}
|
|
1157
|
-
if (effect.is(
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1118
|
+
if (effect.is(setComments)) {
|
|
1119
|
+
const comments2 = effect.value.map((comment) => {
|
|
1120
|
+
if (!comment.cursor) {
|
|
1121
|
+
return void 0;
|
|
1122
|
+
}
|
|
1123
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1161
1124
|
return range && {
|
|
1162
|
-
|
|
1163
|
-
|
|
1125
|
+
comment,
|
|
1126
|
+
range
|
|
1164
1127
|
};
|
|
1165
1128
|
}).filter(nonNullable);
|
|
1166
1129
|
return {
|
|
1167
1130
|
...value,
|
|
1168
|
-
|
|
1131
|
+
comments: comments2
|
|
1169
1132
|
};
|
|
1170
1133
|
}
|
|
1171
1134
|
if (effect.is(setCommentState)) {
|
|
@@ -1176,141 +1139,132 @@ var commentsStateField = StateField2.define({
|
|
|
1176
1139
|
}
|
|
1177
1140
|
});
|
|
1178
1141
|
var highlightDecorations = EditorView5.decorations.compute([
|
|
1179
|
-
|
|
1142
|
+
commentsState
|
|
1180
1143
|
], (state) => {
|
|
1181
|
-
const {
|
|
1182
|
-
const decorations = sortBy(
|
|
1183
|
-
|
|
1144
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1145
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1146
|
+
const range = comment.range;
|
|
1147
|
+
if (!range || range.from === range.to) {
|
|
1148
|
+
console.warn("Invalid range:", range);
|
|
1184
1149
|
return void 0;
|
|
1185
1150
|
}
|
|
1186
|
-
|
|
1187
|
-
from: selection.from,
|
|
1188
|
-
to: selection.to
|
|
1189
|
-
};
|
|
1190
|
-
if (selection.id === active) {
|
|
1151
|
+
if (comment.comment.id === current) {
|
|
1191
1152
|
return marks.highlightActive.range(range.from, range.to);
|
|
1192
1153
|
} else {
|
|
1193
1154
|
return marks.highlight.range(range.from, range.to);
|
|
1194
1155
|
}
|
|
1195
|
-
}).filter(nonNullable)
|
|
1196
|
-
return
|
|
1156
|
+
}).filter(nonNullable);
|
|
1157
|
+
return Decoration2.set(decorations);
|
|
1197
1158
|
});
|
|
1198
|
-
var
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1216
|
-
}
|
|
1217
|
-
toDOM() {
|
|
1218
|
-
const span = document.createElement("span");
|
|
1219
|
-
span.className = "cm-bookmark";
|
|
1220
|
-
span.textContent = "\u203B";
|
|
1221
|
-
if (this._handleClick) {
|
|
1222
|
-
span.onclick = () => this._handleClick();
|
|
1159
|
+
var trackPastedComments = (onUpdate) => {
|
|
1160
|
+
let tracked = null;
|
|
1161
|
+
const handleTrack = (event, view) => {
|
|
1162
|
+
const comments2 = view.state.field(commentsState);
|
|
1163
|
+
const { main } = view.state.selection;
|
|
1164
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1165
|
+
if (!selectedRanges.length) {
|
|
1166
|
+
tracked = null;
|
|
1167
|
+
} else {
|
|
1168
|
+
tracked = {
|
|
1169
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1170
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1171
|
+
id: comment.id,
|
|
1172
|
+
from: range.from - main.from,
|
|
1173
|
+
to: range.to - main.from
|
|
1174
|
+
}))
|
|
1175
|
+
};
|
|
1223
1176
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1177
|
+
};
|
|
1178
|
+
return [
|
|
1179
|
+
EditorView5.domEventHandlers({
|
|
1180
|
+
cut: handleTrack,
|
|
1181
|
+
copy: handleTrack
|
|
1182
|
+
}),
|
|
1183
|
+
// Handle paste.
|
|
1184
|
+
EditorView5.updateListener.of(({ view, state, transactions }) => {
|
|
1185
|
+
if (tracked) {
|
|
1186
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1187
|
+
if (paste) {
|
|
1188
|
+
let found = -1;
|
|
1189
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1190
|
+
if (text.eq(tracked.text)) {
|
|
1191
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1192
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1193
|
+
}
|
|
1194
|
+
found = fromB;
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
if (found > -1) {
|
|
1198
|
+
for (const moved of tracked.comments) {
|
|
1199
|
+
const range = {
|
|
1200
|
+
from: found + moved.from,
|
|
1201
|
+
to: found + moved.to
|
|
1202
|
+
};
|
|
1203
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1204
|
+
onUpdate(moved.id, cursor);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
tracked = null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
})
|
|
1211
|
+
];
|
|
1226
1212
|
};
|
|
1227
1213
|
var comments = (options = {}) => {
|
|
1214
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1228
1215
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1229
1216
|
const createCommentThread = (view) => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
L: 224,
|
|
1217
|
+
invariant3(options.onCreate, void 0, {
|
|
1218
|
+
F: __dxlog_file4,
|
|
1219
|
+
L: 259,
|
|
1234
1220
|
S: void 0,
|
|
1235
1221
|
A: [
|
|
1236
1222
|
"options.onCreate",
|
|
1237
1223
|
""
|
|
1238
1224
|
]
|
|
1239
1225
|
});
|
|
1240
|
-
const {
|
|
1226
|
+
const { from, to } = view.state.selection.main;
|
|
1241
1227
|
if (from === to) {
|
|
1242
1228
|
return false;
|
|
1243
1229
|
}
|
|
1244
|
-
|
|
1230
|
+
if (to === view.state.doc.length) {
|
|
1231
|
+
view.dispatch({
|
|
1232
|
+
changes: {
|
|
1233
|
+
from: to,
|
|
1234
|
+
insert: "\n"
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1245
1239
|
from,
|
|
1246
1240
|
to
|
|
1247
1241
|
});
|
|
1248
|
-
if (
|
|
1249
|
-
const id =
|
|
1242
|
+
if (cursor) {
|
|
1243
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1250
1244
|
if (id) {
|
|
1251
1245
|
view.dispatch({
|
|
1252
1246
|
effects: setSelection.of({
|
|
1253
|
-
|
|
1247
|
+
current: id
|
|
1254
1248
|
}),
|
|
1255
1249
|
selection: {
|
|
1256
1250
|
anchor: from
|
|
1257
1251
|
}
|
|
1258
1252
|
});
|
|
1259
|
-
if (options.footnote) {
|
|
1260
|
-
const tag = `[^${id}]`;
|
|
1261
|
-
view.dispatch({
|
|
1262
|
-
changes: {
|
|
1263
|
-
from: head,
|
|
1264
|
-
insert: tag
|
|
1265
|
-
},
|
|
1266
|
-
selection: {
|
|
1267
|
-
anchor: head + tag.length
|
|
1268
|
-
}
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
1253
|
return true;
|
|
1272
1254
|
}
|
|
1273
1255
|
}
|
|
1274
1256
|
return false;
|
|
1275
1257
|
};
|
|
1276
|
-
const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
|
|
1277
|
-
static {
|
|
1278
|
-
// Match markdown footnotes (option).
|
|
1279
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1280
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1281
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1282
|
-
decoration: (match, view, pos) => {
|
|
1283
|
-
const id = match[1];
|
|
1284
|
-
return Decoration3.replace({
|
|
1285
|
-
id,
|
|
1286
|
-
widget: new BookmarkWidget(pos, id)
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
constructor(view) {
|
|
1292
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1293
|
-
}
|
|
1294
|
-
update(update2) {
|
|
1295
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update2, this.bookmarks);
|
|
1296
|
-
}
|
|
1297
|
-
}, {
|
|
1298
|
-
decorations: (instance) => instance.bookmarks,
|
|
1299
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1300
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1301
|
-
})
|
|
1302
|
-
});
|
|
1303
1258
|
return [
|
|
1304
|
-
|
|
1305
|
-
commentsStateField,
|
|
1259
|
+
commentsState,
|
|
1306
1260
|
highlightDecorations,
|
|
1307
|
-
|
|
1261
|
+
styles2,
|
|
1308
1262
|
//
|
|
1309
1263
|
// Keymap.
|
|
1310
1264
|
//
|
|
1311
1265
|
options.onCreate ? keymap3.of([
|
|
1312
1266
|
{
|
|
1313
|
-
key:
|
|
1267
|
+
key: shortcut,
|
|
1314
1268
|
run: callbackWrapper(createCommentThread)
|
|
1315
1269
|
}
|
|
1316
1270
|
]) : [],
|
|
@@ -1327,7 +1281,7 @@ var comments = (options = {}) => {
|
|
|
1327
1281
|
above: true,
|
|
1328
1282
|
create: () => {
|
|
1329
1283
|
const el = document.createElement("div");
|
|
1330
|
-
options.onHover
|
|
1284
|
+
options.onHover(el, shortcut);
|
|
1331
1285
|
return {
|
|
1332
1286
|
dom: el,
|
|
1333
1287
|
offset: {
|
|
@@ -1340,384 +1294,118 @@ var comments = (options = {}) => {
|
|
|
1340
1294
|
}
|
|
1341
1295
|
return null;
|
|
1342
1296
|
}, {
|
|
1343
|
-
|
|
1297
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1298
|
+
// hideOnChange: true,
|
|
1344
1299
|
hoverTime: 1e3
|
|
1345
1300
|
}) : [],
|
|
1346
1301
|
//
|
|
1347
|
-
//
|
|
1348
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1302
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1349
1303
|
//
|
|
1350
1304
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1351
|
-
|
|
1352
|
-
{
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1360
|
-
log2.info("deleted comment", {
|
|
1361
|
-
thread: range.id
|
|
1362
|
-
}, {
|
|
1363
|
-
F: __dxlog_file3,
|
|
1364
|
-
L: 358,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1305
|
+
let mod = false;
|
|
1306
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1307
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1308
|
+
comments2.forEach(({ comment, range }) => {
|
|
1309
|
+
if (from2 === to2) {
|
|
1310
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1311
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1312
|
+
options.onDelete?.(comment.id);
|
|
1369
1313
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1314
|
+
}
|
|
1315
|
+
if (from <= range.to) {
|
|
1316
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1317
|
+
Object.assign(range, newRange);
|
|
1318
|
+
mod = true;
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
});
|
|
1322
|
+
if (mod) {
|
|
1323
|
+
view.dispatch({
|
|
1324
|
+
effects: setCommentState.of({
|
|
1325
|
+
comments: comments2,
|
|
1326
|
+
...value
|
|
1327
|
+
})
|
|
1376
1328
|
});
|
|
1377
|
-
if (mod) {
|
|
1378
|
-
view.dispatch({
|
|
1379
|
-
effects: setCommentState.of({
|
|
1380
|
-
active,
|
|
1381
|
-
ranges
|
|
1382
|
-
})
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
1329
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1330
|
+
}),
|
|
1331
|
+
//
|
|
1332
|
+
// Track selection/proximity.
|
|
1333
|
+
//
|
|
1334
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1335
|
+
let min = Infinity;
|
|
1336
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1337
|
+
const { head } = state.selection.main;
|
|
1338
|
+
const selection = {};
|
|
1339
|
+
comments2.forEach(({ comment, range }) => {
|
|
1340
|
+
if (head >= range.from && head <= range.to) {
|
|
1341
|
+
selection.current = comment.id;
|
|
1342
|
+
selection.closest = void 0;
|
|
1343
|
+
}
|
|
1344
|
+
if (!selection.current) {
|
|
1345
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1399
1346
|
if (d < min) {
|
|
1400
|
-
|
|
1347
|
+
selection.closest = comment.id;
|
|
1401
1348
|
min = d;
|
|
1402
1349
|
}
|
|
1403
|
-
});
|
|
1404
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1405
|
-
view.dispatch({
|
|
1406
|
-
effects: setSelection.of(selected)
|
|
1407
|
-
});
|
|
1408
|
-
handleSelect({
|
|
1409
|
-
...selected,
|
|
1410
|
-
ranges: ranges.map((range) => ({
|
|
1411
|
-
...range,
|
|
1412
|
-
location: view.coordsAtPos(range.from)
|
|
1413
|
-
}))
|
|
1414
|
-
});
|
|
1415
1350
|
}
|
|
1351
|
+
});
|
|
1352
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1353
|
+
view.dispatch({
|
|
1354
|
+
effects: setSelection.of(selection)
|
|
1355
|
+
});
|
|
1356
|
+
handleSelect({
|
|
1357
|
+
selection,
|
|
1358
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1359
|
+
comment,
|
|
1360
|
+
range,
|
|
1361
|
+
location: view.coordsAtPos(range.from)
|
|
1362
|
+
}))
|
|
1363
|
+
});
|
|
1416
1364
|
}
|
|
1417
|
-
})
|
|
1365
|
+
}),
|
|
1366
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1418
1367
|
];
|
|
1419
1368
|
};
|
|
1420
|
-
var
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1369
|
+
var useComments = (view, comments2 = []) => {
|
|
1370
|
+
useEffect(() => {
|
|
1371
|
+
if (view) {
|
|
1372
|
+
view.dispatch({
|
|
1373
|
+
effects: setComments.of(comments2)
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
}, [
|
|
1377
|
+
view,
|
|
1378
|
+
comments2
|
|
1379
|
+
]);
|
|
1427
1380
|
};
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
};
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
"& .cm-hr": {
|
|
1442
|
-
// TODO(burdon): ???
|
|
1443
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1444
|
-
borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1445
|
-
}
|
|
1446
|
-
});
|
|
1447
|
-
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1448
|
-
constructor(_pos) {
|
|
1449
|
-
super();
|
|
1450
|
-
this._pos = _pos;
|
|
1451
|
-
}
|
|
1452
|
-
eq(other) {
|
|
1453
|
-
return this._pos === other._pos;
|
|
1454
|
-
}
|
|
1455
|
-
toDOM(view) {
|
|
1456
|
-
const el = document.createElement("div");
|
|
1457
|
-
el.className = "cm-hr";
|
|
1458
|
-
return el;
|
|
1459
|
-
}
|
|
1460
|
-
};
|
|
1461
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1462
|
-
regexp: /^---$/g,
|
|
1463
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1464
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1465
|
-
})
|
|
1466
|
-
});
|
|
1467
|
-
var hr = () => [
|
|
1468
|
-
styles4,
|
|
1469
|
-
ViewPlugin5.fromClass(class {
|
|
1470
|
-
constructor(view) {
|
|
1471
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1472
|
-
}
|
|
1473
|
-
update(update2) {
|
|
1474
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1475
|
-
}
|
|
1476
|
-
}, {
|
|
1477
|
-
decorations: (instance) => instance.rules,
|
|
1478
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1479
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1480
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1481
|
-
})
|
|
1482
|
-
})
|
|
1483
|
-
];
|
|
1484
|
-
|
|
1485
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1486
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1487
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1488
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1489
|
-
var image = (options = {}) => {
|
|
1490
|
-
return StateField3.define({
|
|
1491
|
-
create: (state) => {
|
|
1492
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1493
|
-
},
|
|
1494
|
-
update: (value, tr) => {
|
|
1495
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1496
|
-
return value;
|
|
1497
|
-
}
|
|
1498
|
-
const cursor = tr.state.selection.main.head;
|
|
1499
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1500
|
-
let from = Math.min(cursor, oldCursor);
|
|
1501
|
-
let to = Math.max(cursor, oldCursor);
|
|
1502
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1503
|
-
from = Math.min(from, fromB);
|
|
1504
|
-
to = Math.max(to, toB);
|
|
1505
|
-
});
|
|
1506
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1507
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1508
|
-
return value.map(tr.changes).update({
|
|
1509
|
-
filterFrom: from,
|
|
1510
|
-
filterTo: to,
|
|
1511
|
-
filter: () => false,
|
|
1512
|
-
add: buildDecorations(from, to, tr.state)
|
|
1513
|
-
});
|
|
1514
|
-
},
|
|
1515
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1516
|
-
});
|
|
1517
|
-
};
|
|
1518
|
-
var buildDecorations = (from, to, state) => {
|
|
1519
|
-
const decorations = [];
|
|
1520
|
-
const cursor = state.selection.main.head;
|
|
1521
|
-
syntaxTree(state).iterate({
|
|
1522
|
-
enter: (node) => {
|
|
1523
|
-
if (node.name === "Image") {
|
|
1524
|
-
const urlNode = node.node.getChild("URL");
|
|
1525
|
-
if (urlNode) {
|
|
1526
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1527
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1528
|
-
decorations.push(Decoration5.replace({
|
|
1529
|
-
block: true,
|
|
1530
|
-
widget: new ImageWidget(url)
|
|
1531
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
},
|
|
1535
|
-
from,
|
|
1536
|
-
to
|
|
1537
|
-
});
|
|
1538
|
-
return decorations;
|
|
1539
|
-
};
|
|
1540
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1541
|
-
constructor(_url) {
|
|
1542
|
-
super();
|
|
1543
|
-
this._url = _url;
|
|
1544
|
-
}
|
|
1545
|
-
eq(other) {
|
|
1546
|
-
return this._url === other._url;
|
|
1547
|
-
}
|
|
1548
|
-
toDOM(view) {
|
|
1549
|
-
const img = document.createElement("img");
|
|
1550
|
-
img.setAttribute("src", this._url);
|
|
1551
|
-
img.setAttribute("class", "cm-image");
|
|
1552
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1553
|
-
return img;
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
|
|
1557
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1558
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1559
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1560
|
-
import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
1561
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1562
|
-
var link = (options = {}) => {
|
|
1563
|
-
const extensions = [
|
|
1564
|
-
ViewPlugin6.fromClass(class {
|
|
1565
|
-
constructor(view) {
|
|
1566
|
-
this.decorations = buildDecorations2(view, options);
|
|
1567
|
-
}
|
|
1568
|
-
update(update2) {
|
|
1569
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1570
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
}, {
|
|
1574
|
-
decorations: (v) => v.decorations
|
|
1575
|
-
})
|
|
1576
|
-
];
|
|
1577
|
-
if (options.onHover) {
|
|
1578
|
-
extensions.push(
|
|
1579
|
-
// https://codemirror.net/examples/tooltip
|
|
1580
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1581
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1582
|
-
hoverTooltip2((view, pos, side) => {
|
|
1583
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1584
|
-
let link2 = null;
|
|
1585
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1586
|
-
link2 = node.name === "Link" ? node : null;
|
|
1587
|
-
}
|
|
1588
|
-
const url = link2 && link2.getChild("URL");
|
|
1589
|
-
if (!url || !link2) {
|
|
1590
|
-
return null;
|
|
1591
|
-
}
|
|
1592
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1593
|
-
return {
|
|
1594
|
-
pos: link2.from,
|
|
1595
|
-
end: link2.to,
|
|
1596
|
-
above: true,
|
|
1597
|
-
create: () => {
|
|
1598
|
-
const el = document.createElement("div");
|
|
1599
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1600
|
-
options.onHover(el, urlText);
|
|
1601
|
-
return {
|
|
1602
|
-
dom: el,
|
|
1603
|
-
offset: {
|
|
1604
|
-
x: 0,
|
|
1605
|
-
y: 4
|
|
1606
|
-
}
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
};
|
|
1610
|
-
})
|
|
1611
|
-
);
|
|
1612
|
-
}
|
|
1613
|
-
return extensions;
|
|
1614
|
-
};
|
|
1615
|
-
var LinkButton = class extends WidgetType5 {
|
|
1616
|
-
constructor(_url, _onAttach) {
|
|
1617
|
-
super();
|
|
1618
|
-
this._url = _url;
|
|
1619
|
-
this._onAttach = _onAttach;
|
|
1620
|
-
}
|
|
1621
|
-
eq(other) {
|
|
1622
|
-
return this._url === other._url;
|
|
1623
|
-
}
|
|
1624
|
-
toDOM(view) {
|
|
1625
|
-
const el = document.createElement("span");
|
|
1626
|
-
this._onAttach(el, this._url);
|
|
1627
|
-
return el;
|
|
1628
|
-
}
|
|
1629
|
-
};
|
|
1630
|
-
var LinkText = class extends WidgetType5 {
|
|
1631
|
-
constructor(_text, _url) {
|
|
1632
|
-
super();
|
|
1633
|
-
this._text = _text;
|
|
1634
|
-
this._url = _url;
|
|
1635
|
-
}
|
|
1636
|
-
eq(other) {
|
|
1637
|
-
return this._url === other._url;
|
|
1638
|
-
}
|
|
1639
|
-
toDOM(view) {
|
|
1640
|
-
const link2 = document.createElement("a");
|
|
1641
|
-
link2.setAttribute("class", "cm-link");
|
|
1642
|
-
link2.textContent = this._text;
|
|
1643
|
-
if (this._url) {
|
|
1644
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1645
|
-
link2.setAttribute("target", "_blank");
|
|
1646
|
-
link2.href = this._url;
|
|
1647
|
-
} else {
|
|
1648
|
-
link2.onclick = () => {
|
|
1649
|
-
view.dispatch({
|
|
1650
|
-
selection: {
|
|
1651
|
-
anchor: view.posAtDOM(link2)
|
|
1652
|
-
}
|
|
1653
|
-
});
|
|
1654
|
-
};
|
|
1655
|
-
}
|
|
1656
|
-
return link2;
|
|
1657
|
-
}
|
|
1658
|
-
};
|
|
1659
|
-
var buildDecorations2 = (view, options) => {
|
|
1660
|
-
const builder = new RangeSetBuilder();
|
|
1661
|
-
const { state } = view;
|
|
1662
|
-
const cursor = state.selection.main.head;
|
|
1663
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1664
|
-
syntaxTree2(state).iterate({
|
|
1665
|
-
enter: (node) => {
|
|
1666
|
-
if (node.name === "Link") {
|
|
1667
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1668
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1669
|
-
const urlNode = node.node.getChild("URL");
|
|
1670
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1671
|
-
if (!url) {
|
|
1672
|
-
return false;
|
|
1673
|
-
}
|
|
1674
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1675
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1676
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1677
|
-
}));
|
|
1678
|
-
}
|
|
1679
|
-
if (options.onRender) {
|
|
1680
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1681
|
-
widget: new LinkButton(url, options.onRender)
|
|
1682
|
-
}));
|
|
1683
|
-
}
|
|
1684
|
-
return false;
|
|
1685
|
-
}
|
|
1686
|
-
},
|
|
1687
|
-
from,
|
|
1688
|
-
to
|
|
1689
|
-
});
|
|
1690
|
-
}
|
|
1691
|
-
return builder.finish();
|
|
1692
|
-
};
|
|
1693
|
-
|
|
1694
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1695
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1696
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1697
|
-
const extensions = [];
|
|
1698
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1699
|
-
onFocus(focused);
|
|
1700
|
-
return null;
|
|
1701
|
-
}));
|
|
1702
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1703
|
-
onChange(update2.state.doc.toString());
|
|
1704
|
-
}));
|
|
1705
|
-
return extensions;
|
|
1381
|
+
|
|
1382
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1383
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1384
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1385
|
+
const extensions = [];
|
|
1386
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1387
|
+
onFocus(focused);
|
|
1388
|
+
return null;
|
|
1389
|
+
}));
|
|
1390
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1391
|
+
onChange(update2.state.doc.toString());
|
|
1392
|
+
}));
|
|
1393
|
+
return extensions;
|
|
1706
1394
|
};
|
|
1707
1395
|
|
|
1708
1396
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1709
1397
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1710
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1711
|
-
import { markdownLanguage as
|
|
1398
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1399
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1712
1400
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1713
1401
|
import { languages } from "@codemirror/language-data";
|
|
1714
1402
|
import { searchKeymap } from "@codemirror/search";
|
|
1715
1403
|
import { EditorState } from "@codemirror/state";
|
|
1716
1404
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1717
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1405
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1718
1406
|
|
|
1719
1407
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1720
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1408
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1721
1409
|
import { HighlightStyle } from "@codemirror/language";
|
|
1722
1410
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1723
1411
|
import { Table } from "@lezer/markdown";
|
|
@@ -1727,7 +1415,6 @@ var markdownTags = {
|
|
|
1727
1415
|
CodeText: Tag.define(),
|
|
1728
1416
|
EmphasisMark: Tag.define(),
|
|
1729
1417
|
HeaderMark: Tag.define(),
|
|
1730
|
-
// HorizontalRule: Tag.define(),
|
|
1731
1418
|
InlineCode: Tag.define(),
|
|
1732
1419
|
LinkLabel: Tag.define(),
|
|
1733
1420
|
LinkReference: Tag.define(),
|
|
@@ -1812,7 +1499,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1812
1499
|
markdownTags.QuoteMark,
|
|
1813
1500
|
markdownTags.EmphasisMark
|
|
1814
1501
|
],
|
|
1815
|
-
class:
|
|
1502
|
+
class: mark
|
|
1816
1503
|
},
|
|
1817
1504
|
// E.g., code block language (after ```).
|
|
1818
1505
|
{
|
|
@@ -1820,7 +1507,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1820
1507
|
tags.function(tags.variableName),
|
|
1821
1508
|
tags.labelName
|
|
1822
1509
|
],
|
|
1823
|
-
class:
|
|
1510
|
+
class: codeMark
|
|
1824
1511
|
},
|
|
1825
1512
|
{
|
|
1826
1513
|
tag: [
|
|
@@ -1831,27 +1518,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1831
1518
|
// Headings.
|
|
1832
1519
|
{
|
|
1833
1520
|
tag: tags.heading1,
|
|
1834
|
-
class: heading(1
|
|
1521
|
+
class: heading(1)
|
|
1835
1522
|
},
|
|
1836
1523
|
{
|
|
1837
1524
|
tag: tags.heading2,
|
|
1838
|
-
class: heading(2
|
|
1525
|
+
class: heading(2)
|
|
1839
1526
|
},
|
|
1840
1527
|
{
|
|
1841
1528
|
tag: tags.heading3,
|
|
1842
|
-
class: heading(3
|
|
1529
|
+
class: heading(3)
|
|
1843
1530
|
},
|
|
1844
1531
|
{
|
|
1845
1532
|
tag: tags.heading4,
|
|
1846
|
-
class: heading(4
|
|
1533
|
+
class: heading(4)
|
|
1847
1534
|
},
|
|
1848
1535
|
{
|
|
1849
1536
|
tag: tags.heading5,
|
|
1850
|
-
class: heading(5
|
|
1537
|
+
class: heading(5)
|
|
1851
1538
|
},
|
|
1852
1539
|
{
|
|
1853
1540
|
tag: tags.heading6,
|
|
1854
|
-
class: heading(6
|
|
1541
|
+
class: heading(6)
|
|
1855
1542
|
},
|
|
1856
1543
|
// Emphasis.
|
|
1857
1544
|
{
|
|
@@ -1877,7 +1564,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1877
1564
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1878
1565
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1879
1566
|
// the code, but all other CSS properties will be inherited.
|
|
1880
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1567
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1881
1568
|
{
|
|
1882
1569
|
tag: [
|
|
1883
1570
|
markdownTags.CodeText,
|
|
@@ -1891,12 +1578,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1891
1578
|
],
|
|
1892
1579
|
class: blockquote
|
|
1893
1580
|
},
|
|
1894
|
-
// TODO(burdon): Replace with extension.
|
|
1895
|
-
// {
|
|
1896
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1897
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1898
|
-
// },
|
|
1899
|
-
// TODO(burdon): Only if being edited.
|
|
1900
1581
|
{
|
|
1901
1582
|
tag: [
|
|
1902
1583
|
markdownTags.TableCell
|
|
@@ -1904,7 +1585,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1904
1585
|
class: "font-mono"
|
|
1905
1586
|
}
|
|
1906
1587
|
], {
|
|
1907
|
-
scope:
|
|
1588
|
+
scope: markdownLanguage2,
|
|
1908
1589
|
all: {
|
|
1909
1590
|
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1910
1591
|
}
|
|
@@ -1912,21 +1593,21 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1912
1593
|
};
|
|
1913
1594
|
|
|
1914
1595
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1915
|
-
var markdownBundle = ({
|
|
1596
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1916
1597
|
return [
|
|
1917
1598
|
EditorState.allowMultipleSelections.of(true),
|
|
1918
1599
|
EditorState.tabSize.of(2),
|
|
1919
|
-
|
|
1920
|
-
|
|
1600
|
+
EditorView7.lineWrapping,
|
|
1601
|
+
// https://github.com/codemirror/basic-setup
|
|
1921
1602
|
bracketMatching2(),
|
|
1922
1603
|
closeBrackets2(),
|
|
1923
1604
|
crosshairCursor(),
|
|
1924
1605
|
dropCursor(),
|
|
1925
1606
|
drawSelection2(),
|
|
1926
|
-
|
|
1927
|
-
|
|
1607
|
+
highlightActiveLine2(),
|
|
1608
|
+
history2(),
|
|
1928
1609
|
indentOnInput(),
|
|
1929
|
-
_placeholder
|
|
1610
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1930
1611
|
// Main extension.
|
|
1931
1612
|
// https://github.com/codemirror/lang-markdown
|
|
1932
1613
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1936,7 +1617,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1936
1617
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1937
1618
|
// https://github.github.com/gfm
|
|
1938
1619
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1939
|
-
base:
|
|
1620
|
+
base: markdownLanguage3,
|
|
1940
1621
|
// Languages for syntax highlighting fenced code blocks.
|
|
1941
1622
|
codeLanguages: languages,
|
|
1942
1623
|
// Parser extensions.
|
|
@@ -1948,58 +1629,445 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1948
1629
|
// https://github.com/codemirror/theme-one-dark
|
|
1949
1630
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1950
1631
|
// Custom styles.
|
|
1951
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1632
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1633
|
+
keymap4.of([
|
|
1634
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1635
|
+
indentWithTab,
|
|
1636
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1637
|
+
...closeBracketsKeymap,
|
|
1638
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1639
|
+
...historyKeymap,
|
|
1640
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1641
|
+
...searchKeymap,
|
|
1642
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1643
|
+
...standardKeymap
|
|
1644
|
+
])
|
|
1645
|
+
];
|
|
1646
|
+
};
|
|
1966
1647
|
|
|
1967
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1968
|
-
import {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1648
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1649
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1650
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1651
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1652
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1653
|
+
var styles3 = EditorView8.baseTheme({
|
|
1654
|
+
"& .cm-code": {
|
|
1655
|
+
paddingInline: "1rem !important",
|
|
1656
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1657
|
+
},
|
|
1658
|
+
"& .cm-codeblock": {
|
|
1659
|
+
display: "inline-block",
|
|
1660
|
+
width: "100%"
|
|
1661
|
+
},
|
|
1662
|
+
"&light .cm-codeblock, &light .cm-codeblock.cm-activeLine": {
|
|
1663
|
+
background: getToken("extend.colors.neutral.25")
|
|
1664
|
+
},
|
|
1665
|
+
"&dark .cm-codeblock, &dark .cm-codeblock.cm-activeLine": {
|
|
1666
|
+
background: getToken("extend.colors.neutral.850")
|
|
1667
|
+
},
|
|
1668
|
+
"& .cm-codeblock-first": {
|
|
1669
|
+
borderTopLeftRadius: ".5rem",
|
|
1670
|
+
borderTopRightRadius: ".5rem"
|
|
1671
|
+
},
|
|
1672
|
+
"& .cm-codeblock-last": {
|
|
1673
|
+
borderBottomLeftRadius: ".5rem",
|
|
1674
|
+
borderBottomRightRadius: ".5rem"
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
var getLineRange = (lines, from, to) => {
|
|
1678
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1679
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1680
|
+
return [
|
|
1681
|
+
start,
|
|
1682
|
+
end
|
|
1683
|
+
];
|
|
1684
|
+
};
|
|
1685
|
+
var LineWidget = class extends WidgetType2 {
|
|
1686
|
+
constructor(_className) {
|
|
1687
|
+
super();
|
|
1688
|
+
this._className = _className;
|
|
1689
|
+
}
|
|
1690
|
+
toDOM() {
|
|
1691
|
+
const el = document.createElement("span");
|
|
1692
|
+
el.innerHTML = " ";
|
|
1693
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1694
|
+
return el;
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1698
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1699
|
+
var buildDecorations = (view) => {
|
|
1700
|
+
const builder = new RangeSetBuilder();
|
|
1701
|
+
const { state } = view;
|
|
1702
|
+
const blocks = view.viewportLineBlocks;
|
|
1703
|
+
const cursor = state.selection.main.head;
|
|
1704
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1705
|
+
syntaxTree(state).iterate({
|
|
1706
|
+
enter: (node) => {
|
|
1707
|
+
if (node.name === "FencedCode") {
|
|
1708
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1709
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1710
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1711
|
+
const block = blocks[i];
|
|
1712
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1713
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1714
|
+
widget: i === range[0] ? top : bottom
|
|
1715
|
+
}));
|
|
1716
|
+
} else {
|
|
1717
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1718
|
+
class: mx2("cm-code cm-codeblock")
|
|
1719
|
+
}));
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
from,
|
|
1725
|
+
to
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
return builder.finish();
|
|
1729
|
+
};
|
|
1730
|
+
var code2 = () => {
|
|
1731
|
+
return [
|
|
1732
|
+
ViewPlugin3.fromClass(class {
|
|
1733
|
+
constructor(view) {
|
|
1734
|
+
this.decorations = buildDecorations(view);
|
|
1735
|
+
}
|
|
1736
|
+
update(update2) {
|
|
1737
|
+
this.decorations = buildDecorations(update2.view);
|
|
1738
|
+
}
|
|
1739
|
+
}, {
|
|
1740
|
+
decorations: (value) => value.decorations
|
|
1741
|
+
}),
|
|
1742
|
+
styles3
|
|
1743
|
+
];
|
|
1744
|
+
};
|
|
1745
|
+
|
|
1746
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1747
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1748
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1749
|
+
import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1750
|
+
var buildDecorations2 = (view) => {
|
|
1751
|
+
const builder = new RangeSetBuilder2();
|
|
1752
|
+
const { state } = view;
|
|
1753
|
+
const cursor = state.selection.main.head;
|
|
1754
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1755
|
+
syntaxTree2(state).iterate({
|
|
1756
|
+
enter: (node) => {
|
|
1757
|
+
switch (node.name) {
|
|
1758
|
+
case "ATXHeading1":
|
|
1759
|
+
case "ATXHeading2":
|
|
1760
|
+
case "ATXHeading3":
|
|
1761
|
+
case "ATXHeading4":
|
|
1762
|
+
case "ATXHeading5":
|
|
1763
|
+
case "ATXHeading6": {
|
|
1764
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1765
|
+
if (mark2) {
|
|
1766
|
+
if (view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1767
|
+
builder.add(mark2.from, mark2.to + 1, Decoration4.replace({}));
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
from,
|
|
1774
|
+
to
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
return builder.finish();
|
|
1778
|
+
};
|
|
1779
|
+
var heading2 = () => {
|
|
1780
|
+
return [
|
|
1781
|
+
ViewPlugin4.fromClass(class {
|
|
1782
|
+
constructor(view) {
|
|
1783
|
+
this.decorations = buildDecorations2(view);
|
|
1784
|
+
}
|
|
1785
|
+
update(update2) {
|
|
1786
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1787
|
+
}
|
|
1788
|
+
}, {
|
|
1789
|
+
decorations: (value) => value.decorations
|
|
1790
|
+
})
|
|
1791
|
+
];
|
|
1792
|
+
};
|
|
1793
|
+
|
|
1794
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
1795
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1796
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1797
|
+
import { Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1798
|
+
var styles4 = EditorView9.baseTheme({
|
|
1799
|
+
"& .cm-hr": {
|
|
1800
|
+
// Note that block-level decorations should not have vertical margins,
|
|
1801
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1804
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1805
|
+
toDOM() {
|
|
1806
|
+
const el = document.createElement("div");
|
|
1807
|
+
el.className = "cm-hr";
|
|
1808
|
+
return el;
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
var decoration = Decoration5.replace({
|
|
1812
|
+
widget: new HorizontalRuleWidget()
|
|
1813
|
+
});
|
|
1814
|
+
var buildDecorations3 = (view) => {
|
|
1815
|
+
const builder = new RangeSetBuilder3();
|
|
1816
|
+
const { state } = view;
|
|
1817
|
+
const cursor = state.selection.main.head;
|
|
1818
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1819
|
+
syntaxTree3(state).iterate({
|
|
1820
|
+
enter: (node) => {
|
|
1821
|
+
if (node.name === "HorizontalRule") {
|
|
1822
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1823
|
+
builder.add(node.from, node.to, decoration);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
from,
|
|
1828
|
+
to
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
return builder.finish();
|
|
1832
|
+
};
|
|
1833
|
+
var hr = () => {
|
|
1834
|
+
return [
|
|
1835
|
+
ViewPlugin5.fromClass(class {
|
|
1836
|
+
constructor(view) {
|
|
1837
|
+
this.decorations = buildDecorations3(view);
|
|
1838
|
+
}
|
|
1839
|
+
update(update2) {
|
|
1840
|
+
this.decorations = buildDecorations3(update2.view);
|
|
1841
|
+
}
|
|
1842
|
+
}, {
|
|
1843
|
+
decorations: (value) => value.decorations
|
|
1844
|
+
}),
|
|
1845
|
+
styles4
|
|
1846
|
+
];
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
1850
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
1851
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1852
|
+
import { Decoration as Decoration6, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1853
|
+
var image = (options = {}) => {
|
|
1854
|
+
return StateField3.define({
|
|
1855
|
+
create: (state) => {
|
|
1856
|
+
return Decoration6.set(buildDecorations4(0, state.doc.length, state));
|
|
1857
|
+
},
|
|
1858
|
+
update: (value, tr) => {
|
|
1859
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1860
|
+
return value;
|
|
1861
|
+
}
|
|
1862
|
+
const cursor = tr.state.selection.main.head;
|
|
1863
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1864
|
+
let from = Math.min(cursor, oldCursor);
|
|
1865
|
+
let to = Math.max(cursor, oldCursor);
|
|
1866
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1867
|
+
from = Math.min(from, fromB);
|
|
1868
|
+
to = Math.max(to, toB);
|
|
1869
|
+
});
|
|
1870
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1871
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1872
|
+
return value.map(tr.changes).update({
|
|
1873
|
+
filterFrom: from,
|
|
1874
|
+
filterTo: to,
|
|
1875
|
+
filter: () => false,
|
|
1876
|
+
add: buildDecorations4(from, to, tr.state)
|
|
1877
|
+
});
|
|
1878
|
+
},
|
|
1879
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
1880
|
+
});
|
|
1881
|
+
};
|
|
1882
|
+
var buildDecorations4 = (from, to, state) => {
|
|
1883
|
+
const decorations = [];
|
|
1884
|
+
const cursor = state.selection.main.head;
|
|
1885
|
+
syntaxTree4(state).iterate({
|
|
1886
|
+
enter: (node) => {
|
|
1887
|
+
if (node.name === "Image") {
|
|
1888
|
+
const urlNode = node.node.getChild("URL");
|
|
1889
|
+
if (urlNode) {
|
|
1890
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1891
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1892
|
+
decorations.push(Decoration6.replace({
|
|
1893
|
+
block: true,
|
|
1894
|
+
widget: new ImageWidget(url)
|
|
1895
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
},
|
|
1899
|
+
from,
|
|
1900
|
+
to
|
|
1901
|
+
});
|
|
1902
|
+
return decorations;
|
|
1903
|
+
};
|
|
1904
|
+
var ImageWidget = class extends WidgetType4 {
|
|
1905
|
+
constructor(_url) {
|
|
1906
|
+
super();
|
|
1907
|
+
this._url = _url;
|
|
1908
|
+
}
|
|
1909
|
+
eq(other) {
|
|
1910
|
+
return this._url === other._url;
|
|
1911
|
+
}
|
|
1912
|
+
toDOM(view) {
|
|
1913
|
+
const img = document.createElement("img");
|
|
1914
|
+
img.setAttribute("src", this._url);
|
|
1915
|
+
img.setAttribute("class", "cm-image");
|
|
1916
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1917
|
+
return img;
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
1922
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
1923
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
1924
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration7, ViewPlugin as ViewPlugin6, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1925
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1926
|
+
var link = (options = {}) => {
|
|
1927
|
+
const extensions = [
|
|
1928
|
+
ViewPlugin6.fromClass(class {
|
|
1929
|
+
constructor(view) {
|
|
1930
|
+
this.decorations = buildDecorations5(view, options);
|
|
1931
|
+
}
|
|
1932
|
+
update(update2) {
|
|
1933
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1934
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}, {
|
|
1938
|
+
decorations: (value) => value.decorations
|
|
1939
|
+
})
|
|
1940
|
+
];
|
|
1941
|
+
if (options.onHover) {
|
|
1942
|
+
extensions.push(
|
|
1943
|
+
// https://codemirror.net/examples/tooltip
|
|
1944
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1945
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1946
|
+
hoverTooltip2((view, pos, side) => {
|
|
1947
|
+
const syntax = syntaxTree5(view.state).resolveInner(pos, side);
|
|
1948
|
+
let link2 = null;
|
|
1949
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1950
|
+
link2 = node.name === "Link" ? node : null;
|
|
1951
|
+
}
|
|
1952
|
+
const url = link2 && link2.getChild("URL");
|
|
1953
|
+
if (!url || !link2) {
|
|
1954
|
+
return null;
|
|
1955
|
+
}
|
|
1956
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1957
|
+
return {
|
|
1958
|
+
pos: link2.from,
|
|
1959
|
+
end: link2.to,
|
|
1960
|
+
above: true,
|
|
1961
|
+
create: () => {
|
|
1962
|
+
const el = document.createElement("div");
|
|
1963
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1964
|
+
options.onHover(el, urlText);
|
|
1965
|
+
return {
|
|
1966
|
+
dom: el,
|
|
1967
|
+
offset: {
|
|
1968
|
+
x: 0,
|
|
1969
|
+
y: 4
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
};
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
return extensions;
|
|
1978
|
+
};
|
|
1979
|
+
var LinkButton = class extends WidgetType5 {
|
|
1980
|
+
constructor(_url, _onAttach) {
|
|
1981
|
+
super();
|
|
1982
|
+
this._url = _url;
|
|
1983
|
+
this._onAttach = _onAttach;
|
|
1984
|
+
}
|
|
1985
|
+
eq(other) {
|
|
1986
|
+
return this._url === other._url;
|
|
1987
|
+
}
|
|
1988
|
+
toDOM(view) {
|
|
1989
|
+
const el = document.createElement("span");
|
|
1990
|
+
this._onAttach(el, this._url);
|
|
1991
|
+
return el;
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
var LinkText = class extends WidgetType5 {
|
|
1995
|
+
constructor(_text, _url) {
|
|
1996
|
+
super();
|
|
1997
|
+
this._text = _text;
|
|
1998
|
+
this._url = _url;
|
|
1999
|
+
}
|
|
2000
|
+
eq(other) {
|
|
2001
|
+
return this._url === other._url;
|
|
2002
|
+
}
|
|
2003
|
+
toDOM(view) {
|
|
2004
|
+
const link2 = document.createElement("a");
|
|
2005
|
+
link2.setAttribute("class", "cm-link");
|
|
2006
|
+
link2.textContent = this._text;
|
|
2007
|
+
if (this._url) {
|
|
2008
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2009
|
+
link2.setAttribute("target", "_blank");
|
|
2010
|
+
link2.href = this._url;
|
|
2011
|
+
} else {
|
|
2012
|
+
link2.onclick = () => {
|
|
2013
|
+
view.dispatch({
|
|
2014
|
+
selection: {
|
|
2015
|
+
anchor: view.posAtDOM(link2)
|
|
2016
|
+
}
|
|
2017
|
+
});
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
return link2;
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
var buildDecorations5 = (view, options) => {
|
|
2024
|
+
const builder = new RangeSetBuilder4();
|
|
2025
|
+
const { state } = view;
|
|
2026
|
+
const cursor = state.selection.main.head;
|
|
2027
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2028
|
+
syntaxTree5(state).iterate({
|
|
2029
|
+
enter: (node) => {
|
|
2030
|
+
if (node.name === "Link") {
|
|
2031
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
2032
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
2033
|
+
const urlNode = node.node.getChild("URL");
|
|
2034
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2035
|
+
if (!url) {
|
|
2036
|
+
return false;
|
|
2037
|
+
}
|
|
2038
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2039
|
+
builder.add(node.from, node.to, Decoration7.replace({
|
|
2040
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2041
|
+
}));
|
|
2042
|
+
}
|
|
2043
|
+
if (options.onRender) {
|
|
2044
|
+
builder.add(node.to, node.to, Decoration7.replace({
|
|
2045
|
+
widget: new LinkButton(url, options.onRender)
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
return false;
|
|
1977
2049
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
};
|
|
1985
|
-
}
|
|
1986
|
-
]
|
|
1987
|
-
});
|
|
2050
|
+
},
|
|
2051
|
+
from,
|
|
2052
|
+
to
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
return builder.finish();
|
|
1988
2056
|
};
|
|
1989
2057
|
|
|
1990
|
-
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1991
|
-
import { syntaxTree as
|
|
1992
|
-
import { RangeSetBuilder as
|
|
1993
|
-
import { Decoration as
|
|
2058
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2059
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2060
|
+
import { RangeSetBuilder as RangeSetBuilder5, StateField as StateField4 } from "@codemirror/state";
|
|
2061
|
+
import { Decoration as Decoration8, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1994
2062
|
var table = (options = {}) => {
|
|
1995
2063
|
return StateField4.define({
|
|
1996
2064
|
create: (state) => update(state, options),
|
|
1997
2065
|
update: (_, tr) => update(tr.state, options),
|
|
1998
|
-
provide: (field) =>
|
|
2066
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1999
2067
|
});
|
|
2000
2068
|
};
|
|
2001
2069
|
var update = (state, options) => {
|
|
2002
|
-
const builder = new
|
|
2070
|
+
const builder = new RangeSetBuilder5();
|
|
2003
2071
|
const cursor = state.selection.main.head;
|
|
2004
2072
|
const tables = [];
|
|
2005
2073
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2007,7 +2075,7 @@ var update = (state, options) => {
|
|
|
2007
2075
|
const table2 = getTable();
|
|
2008
2076
|
return table2.rows?.[table2.rows.length - 1];
|
|
2009
2077
|
};
|
|
2010
|
-
|
|
2078
|
+
syntaxTree6(state).iterate({
|
|
2011
2079
|
enter: (node) => {
|
|
2012
2080
|
switch (node.name) {
|
|
2013
2081
|
case "Table": {
|
|
@@ -2039,11 +2107,10 @@ var update = (state, options) => {
|
|
|
2039
2107
|
});
|
|
2040
2108
|
tables.forEach((table2) => {
|
|
2041
2109
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2042
|
-
hide && builder.add(table2.from, table2.to,
|
|
2043
|
-
block: true,
|
|
2110
|
+
hide && builder.add(table2.from, table2.to, Decoration8.replace({
|
|
2044
2111
|
widget: new TableWidget(table2)
|
|
2045
2112
|
}));
|
|
2046
|
-
builder.add(table2.from, table2.to,
|
|
2113
|
+
builder.add(table2.from, table2.to, Decoration8.mark({
|
|
2047
2114
|
class: "cm-table"
|
|
2048
2115
|
}));
|
|
2049
2116
|
});
|
|
@@ -2081,92 +2148,142 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2081
2148
|
}
|
|
2082
2149
|
return table2;
|
|
2083
2150
|
}
|
|
2151
|
+
ignoreEvent(e) {
|
|
2152
|
+
return !/^mouse/.test(e.type);
|
|
2153
|
+
}
|
|
2084
2154
|
};
|
|
2085
2155
|
|
|
2086
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2087
|
-
import {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2156
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2157
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2158
|
+
import { RangeSetBuilder as RangeSetBuilder6 } from "@codemirror/state";
|
|
2159
|
+
import { EditorView as EditorView12, Decoration as Decoration9, WidgetType as WidgetType7, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
|
|
2160
|
+
var styles5 = EditorView12.baseTheme({
|
|
2161
|
+
"& .cm-task": {
|
|
2162
|
+
color: getToken("extend.colors.blue.500")
|
|
2163
|
+
},
|
|
2164
|
+
"& .cm-task-checkbox": {
|
|
2165
|
+
marginLeft: "4px",
|
|
2166
|
+
marginRight: "4px"
|
|
2092
2167
|
}
|
|
2093
2168
|
});
|
|
2094
2169
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2095
|
-
constructor(_checked
|
|
2170
|
+
constructor(_checked) {
|
|
2096
2171
|
super();
|
|
2097
2172
|
this._checked = _checked;
|
|
2098
|
-
this._indent = _indent;
|
|
2099
|
-
this._onCheck = _onCheck;
|
|
2100
2173
|
}
|
|
2101
2174
|
eq(other) {
|
|
2102
|
-
return this._checked === other._checked
|
|
2175
|
+
return this._checked === other._checked;
|
|
2103
2176
|
}
|
|
2104
2177
|
toDOM(view) {
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2108
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2109
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2178
|
+
const input = document.createElement("input");
|
|
2179
|
+
input.className = "cm-task-checkbox";
|
|
2110
2180
|
input.type = "checkbox";
|
|
2111
2181
|
input.checked = this._checked;
|
|
2112
|
-
if (
|
|
2182
|
+
if (view.state.readOnly) {
|
|
2113
2183
|
input.setAttribute("disabled", "true");
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2184
|
+
} else {
|
|
2185
|
+
input.onmousedown = (event) => {
|
|
2186
|
+
const pos = view.posAtDOM(input);
|
|
2187
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2188
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2189
|
+
view.dispatch({
|
|
2190
|
+
changes: {
|
|
2191
|
+
from: pos + 1,
|
|
2192
|
+
to: pos + 2,
|
|
2193
|
+
insert: this._checked ? " " : "x"
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
event.preventDefault();
|
|
2197
|
+
}
|
|
2119
2198
|
};
|
|
2120
2199
|
}
|
|
2121
|
-
return
|
|
2200
|
+
return input;
|
|
2122
2201
|
}
|
|
2123
2202
|
ignoreEvent() {
|
|
2124
2203
|
return false;
|
|
2125
2204
|
}
|
|
2126
2205
|
};
|
|
2206
|
+
var checkedDecoration = Decoration9.replace({
|
|
2207
|
+
widget: new CheckboxWidget(true)
|
|
2208
|
+
});
|
|
2209
|
+
var uncheckedDecoration = Decoration9.replace({
|
|
2210
|
+
widget: new CheckboxWidget(false)
|
|
2211
|
+
});
|
|
2212
|
+
var buildDecorations6 = (view) => {
|
|
2213
|
+
const builder = new RangeSetBuilder6();
|
|
2214
|
+
const { state } = view;
|
|
2215
|
+
const cursor = state.selection.main.head;
|
|
2216
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2217
|
+
syntaxTree7(state).iterate({
|
|
2218
|
+
enter: (node) => {
|
|
2219
|
+
if (node.name === "TaskMarker") {
|
|
2220
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2221
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2222
|
+
builder.add(node.from - 2, node.from - 1, Decoration9.mark({
|
|
2223
|
+
class: "cm-task"
|
|
2224
|
+
}));
|
|
2225
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
},
|
|
2229
|
+
from,
|
|
2230
|
+
to
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
return builder.finish();
|
|
2234
|
+
};
|
|
2127
2235
|
var tasklist = (options = {}) => {
|
|
2128
|
-
const taskMatcher = new MatchDecorator3({
|
|
2129
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2130
|
-
decoration: (match, view, pos) => {
|
|
2131
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2132
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2133
|
-
return Decoration8.replace({
|
|
2134
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2135
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2136
|
-
view.dispatch({
|
|
2137
|
-
changes: {
|
|
2138
|
-
from: idx,
|
|
2139
|
-
to: idx + 1,
|
|
2140
|
-
insert: checked2 ? "x" : " "
|
|
2141
|
-
},
|
|
2142
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2143
|
-
selection: {
|
|
2144
|
-
anchor: idx + 3
|
|
2145
|
-
}
|
|
2146
|
-
});
|
|
2147
|
-
})
|
|
2148
|
-
});
|
|
2149
|
-
}
|
|
2150
|
-
});
|
|
2151
|
-
const tasks = ViewPlugin7.fromClass(class {
|
|
2152
|
-
constructor(view) {
|
|
2153
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2154
|
-
}
|
|
2155
|
-
update(update2) {
|
|
2156
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2157
|
-
}
|
|
2158
|
-
}, {
|
|
2159
|
-
decorations: (value) => value.tasks,
|
|
2160
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2161
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2162
|
-
})
|
|
2163
|
-
});
|
|
2164
2236
|
return [
|
|
2165
|
-
|
|
2237
|
+
ViewPlugin7.fromClass(class {
|
|
2238
|
+
constructor(view) {
|
|
2239
|
+
this.decorations = buildDecorations6(view);
|
|
2240
|
+
}
|
|
2241
|
+
update(update2) {
|
|
2242
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2243
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}, {
|
|
2247
|
+
decorations: (value) => value.decorations
|
|
2248
|
+
}),
|
|
2166
2249
|
styles5
|
|
2167
2250
|
];
|
|
2168
2251
|
};
|
|
2169
2252
|
|
|
2253
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2254
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2255
|
+
var mention = ({ onSearch }) => {
|
|
2256
|
+
return autocompletion2({
|
|
2257
|
+
// TODO(burdon): Not working.
|
|
2258
|
+
activateOnTyping: true,
|
|
2259
|
+
// activateOnTypingDelay: 100,
|
|
2260
|
+
// selectOnOpen: true,
|
|
2261
|
+
closeOnBlur: false,
|
|
2262
|
+
// defaultKeymap: false,
|
|
2263
|
+
icons: false,
|
|
2264
|
+
override: [
|
|
2265
|
+
(context) => {
|
|
2266
|
+
console.log(context);
|
|
2267
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2268
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2269
|
+
return null;
|
|
2270
|
+
}
|
|
2271
|
+
return {
|
|
2272
|
+
from: match.from,
|
|
2273
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2274
|
+
label: `@${value}`
|
|
2275
|
+
}))
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
]
|
|
2279
|
+
});
|
|
2280
|
+
};
|
|
2281
|
+
|
|
2282
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2283
|
+
var outliner = (options = {}) => {
|
|
2284
|
+
return [];
|
|
2285
|
+
};
|
|
2286
|
+
|
|
2170
2287
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2171
2288
|
import { keymap as keymap5 } from "@codemirror/view";
|
|
2172
2289
|
var defaultItems = [
|
|
@@ -2224,27 +2341,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2224
2341
|
];
|
|
2225
2342
|
};
|
|
2226
2343
|
|
|
2227
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2228
|
-
import { yCollab } from "y-codemirror.next";
|
|
2229
|
-
|
|
2230
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2231
|
-
import * as Y from "yjs";
|
|
2232
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2233
|
-
var cursorConverter2 = (text) => ({
|
|
2234
|
-
toCursor: (index, assoc) => {
|
|
2235
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2236
|
-
},
|
|
2237
|
-
fromCursor: (cursor) => {
|
|
2238
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2239
|
-
}
|
|
2240
|
-
});
|
|
2241
|
-
|
|
2242
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2243
|
-
var yjs = (content, awareness2) => [
|
|
2244
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2245
|
-
yCollab(content, awareness2)
|
|
2246
|
-
];
|
|
2247
|
-
|
|
2248
2344
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2249
2345
|
import get3 from "lodash.get";
|
|
2250
2346
|
var defaultTheme = {
|
|
@@ -2338,33 +2434,6 @@ var defaultTheme = {
|
|
|
2338
2434
|
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2339
2435
|
},
|
|
2340
2436
|
//
|
|
2341
|
-
// collaboration
|
|
2342
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2343
|
-
//
|
|
2344
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2345
|
-
mixBlendMode: "multiply"
|
|
2346
|
-
},
|
|
2347
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2348
|
-
mixBlendMode: "screen"
|
|
2349
|
-
},
|
|
2350
|
-
".cm-ySelectionInfo": {
|
|
2351
|
-
padding: "2px 4px",
|
|
2352
|
-
marginBlockStart: "-4px"
|
|
2353
|
-
},
|
|
2354
|
-
".cm-ySelection, & .cm-selectionMatch": {
|
|
2355
|
-
paddingBlockStart: ".15em",
|
|
2356
|
-
paddingBlockEnd: ".15em"
|
|
2357
|
-
},
|
|
2358
|
-
".cm-ySelectionCaret": {
|
|
2359
|
-
display: "inline-block",
|
|
2360
|
-
insetBlockStart: ".1em",
|
|
2361
|
-
blockSize: "1.4em",
|
|
2362
|
-
verticalAlign: "top"
|
|
2363
|
-
},
|
|
2364
|
-
".cm-yLineSelection": {
|
|
2365
|
-
margin: 0
|
|
2366
|
-
},
|
|
2367
|
-
//
|
|
2368
2437
|
// link
|
|
2369
2438
|
//
|
|
2370
2439
|
".cm-link": {
|
|
@@ -2401,13 +2470,6 @@ var defaultTheme = {
|
|
|
2401
2470
|
textDecoration: "none"
|
|
2402
2471
|
},
|
|
2403
2472
|
//
|
|
2404
|
-
// widgets
|
|
2405
|
-
//
|
|
2406
|
-
".cm-widgetBuffer": {
|
|
2407
|
-
display: "none",
|
|
2408
|
-
height: 0
|
|
2409
|
-
},
|
|
2410
|
-
//
|
|
2411
2473
|
// table
|
|
2412
2474
|
//
|
|
2413
2475
|
".cm-table *": {
|
|
@@ -2438,27 +2500,17 @@ var defaultTheme = {
|
|
|
2438
2500
|
},
|
|
2439
2501
|
//
|
|
2440
2502
|
// font size
|
|
2441
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2503
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2504
|
+
// but it's far more verbose than it needs to be.
|
|
2442
2505
|
//
|
|
2443
|
-
...Object.keys(
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2452
|
-
height
|
|
2453
|
-
};
|
|
2454
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2455
|
-
height
|
|
2456
|
-
};
|
|
2457
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2458
|
-
height
|
|
2459
|
-
};
|
|
2460
|
-
return acc;
|
|
2461
|
-
}, {}),
|
|
2506
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2507
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2508
|
+
//
|
|
2509
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2510
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2511
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2512
|
+
// return acc;
|
|
2513
|
+
// }, {}),
|
|
2462
2514
|
/**
|
|
2463
2515
|
* Panels
|
|
2464
2516
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2509,7 +2561,9 @@ var textTheme = {
|
|
|
2509
2561
|
}
|
|
2510
2562
|
};
|
|
2511
2563
|
var markdownTheme = {
|
|
2512
|
-
|
|
2564
|
+
".cm-scroller": {
|
|
2565
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2566
|
+
},
|
|
2513
2567
|
".cm-placeholder": {
|
|
2514
2568
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2515
2569
|
}
|
|
@@ -2524,95 +2578,89 @@ var codeTheme = {
|
|
|
2524
2578
|
};
|
|
2525
2579
|
|
|
2526
2580
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2581
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2527
2582
|
var EditorModes = [
|
|
2528
2583
|
"default",
|
|
2529
2584
|
"vim"
|
|
2530
2585
|
];
|
|
2531
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2532
|
-
const { themeMode } = useThemeContext();
|
|
2586
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2533
2587
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2534
2588
|
tabBehavior: "limited"
|
|
2535
2589
|
});
|
|
2536
|
-
const
|
|
2537
|
-
const
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
state,
|
|
2590
|
+
const { themeMode } = useThemeContext();
|
|
2591
|
+
const rootRef = useRef(null);
|
|
2592
|
+
const [view, setView] = useState(null);
|
|
2593
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2541
2594
|
view
|
|
2542
|
-
}), [
|
|
2543
|
-
view,
|
|
2544
|
-
state,
|
|
2545
|
-
root
|
|
2546
|
-
]);
|
|
2547
|
-
const { awareness: awareness2, peer } = model;
|
|
2548
|
-
useEffect(() => {
|
|
2549
|
-
if (awareness2 && peer) {
|
|
2550
|
-
awareness2.setLocalStateField("user", {
|
|
2551
|
-
name: peer.name ?? generateName(peer.id),
|
|
2552
|
-
color: getColorForValue({
|
|
2553
|
-
value: peer.id,
|
|
2554
|
-
type: "color"
|
|
2555
|
-
}),
|
|
2556
|
-
colorLight: getColorForValue({
|
|
2557
|
-
value: peer.id,
|
|
2558
|
-
themeMode,
|
|
2559
|
-
type: "highlight"
|
|
2560
|
-
})
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
}, [
|
|
2564
|
-
awareness2,
|
|
2565
|
-
peer,
|
|
2566
|
-
themeMode
|
|
2567
2595
|
]);
|
|
2568
|
-
|
|
2569
|
-
if (
|
|
2570
|
-
view
|
|
2571
|
-
effects: setCommentRange.of({
|
|
2572
|
-
model,
|
|
2573
|
-
comments: comments2
|
|
2574
|
-
})
|
|
2575
|
-
});
|
|
2596
|
+
useEffect2(() => {
|
|
2597
|
+
if (autoFocus) {
|
|
2598
|
+
view?.focus();
|
|
2576
2599
|
}
|
|
2577
2600
|
}, [
|
|
2578
2601
|
view,
|
|
2579
|
-
|
|
2602
|
+
autoFocus
|
|
2580
2603
|
]);
|
|
2581
|
-
|
|
2582
|
-
if (!
|
|
2604
|
+
useEffect2(() => {
|
|
2605
|
+
if (!model || !rootRef.current) {
|
|
2583
2606
|
return;
|
|
2584
2607
|
}
|
|
2585
|
-
const
|
|
2608
|
+
const state = EditorState2.create({
|
|
2586
2609
|
doc: model.text(),
|
|
2610
|
+
selection,
|
|
2587
2611
|
extensions: [
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2612
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2613
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2614
|
+
log2.catch(err, void 0, {
|
|
2615
|
+
F: __dxlog_file5,
|
|
2616
|
+
L: 123,
|
|
2617
|
+
S: void 0,
|
|
2618
|
+
C: (f, a) => f(...a)
|
|
2619
|
+
});
|
|
2620
|
+
}),
|
|
2591
2621
|
// Theme.
|
|
2592
|
-
// TODO(burdon): Make
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2622
|
+
// TODO(burdon): Make configurable.
|
|
2623
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2624
|
+
EditorView13.theme(theme ?? {}),
|
|
2625
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2626
|
+
EditorView13.editorAttributes.of({
|
|
2627
|
+
class: slots.editor?.className ?? ""
|
|
2628
|
+
}),
|
|
2629
|
+
EditorView13.contentAttributes.of({
|
|
2630
|
+
class: slots.content?.className ?? ""
|
|
2631
|
+
}),
|
|
2632
|
+
// State.
|
|
2633
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2596
2634
|
// Storage and replication.
|
|
2635
|
+
// NOTE: This must come before user extensions.
|
|
2597
2636
|
model.extension,
|
|
2637
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2638
|
+
editorMode === "vim" && vim(),
|
|
2598
2639
|
// Custom.
|
|
2599
2640
|
...extensions
|
|
2600
2641
|
].filter(Boolean)
|
|
2601
2642
|
});
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2643
|
+
const newView = new EditorView13({
|
|
2644
|
+
state,
|
|
2645
|
+
parent: rootRef.current,
|
|
2646
|
+
scrollTo,
|
|
2647
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2648
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2649
|
+
dispatchTransactions: (trs, view2) => {
|
|
2650
|
+
if (debug) {
|
|
2651
|
+
logChanges(trs);
|
|
2652
|
+
}
|
|
2653
|
+
view2.update(trs);
|
|
2654
|
+
}
|
|
2609
2655
|
});
|
|
2656
|
+
view?.destroy();
|
|
2657
|
+
setView(newView);
|
|
2610
2658
|
return () => {
|
|
2611
|
-
|
|
2612
|
-
|
|
2659
|
+
newView?.destroy();
|
|
2660
|
+
setView(null);
|
|
2613
2661
|
};
|
|
2614
2662
|
}, [
|
|
2615
|
-
|
|
2663
|
+
rootRef,
|
|
2616
2664
|
model,
|
|
2617
2665
|
readonly,
|
|
2618
2666
|
editorMode,
|
|
@@ -2622,11 +2670,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2622
2670
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2623
2671
|
switch (key) {
|
|
2624
2672
|
case "Enter": {
|
|
2625
|
-
view?.
|
|
2673
|
+
view?.focus();
|
|
2626
2674
|
break;
|
|
2627
2675
|
}
|
|
2628
2676
|
case "Escape": {
|
|
2629
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2677
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2678
|
+
rootRef.current?.focus();
|
|
2679
|
+
}
|
|
2630
2680
|
break;
|
|
2631
2681
|
}
|
|
2632
2682
|
}
|
|
@@ -2636,83 +2686,78 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2636
2686
|
]);
|
|
2637
2687
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2638
2688
|
key: model.id,
|
|
2639
|
-
|
|
2689
|
+
role: "none",
|
|
2640
2690
|
tabIndex: 0,
|
|
2641
|
-
|
|
2691
|
+
onKeyUp: handleKeyUp,
|
|
2692
|
+
...slots.root,
|
|
2642
2693
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2643
|
-
|
|
2694
|
+
ref: rootRef
|
|
2644
2695
|
});
|
|
2645
2696
|
});
|
|
2646
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2697
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2647
2698
|
const { themeMode } = useThemeContext();
|
|
2648
|
-
const
|
|
2699
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2649
2700
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2650
2701
|
ref: forwardedRef,
|
|
2651
2702
|
readonly,
|
|
2652
2703
|
extensions: [
|
|
2653
2704
|
basicBundle({
|
|
2654
|
-
readonly,
|
|
2655
2705
|
themeMode,
|
|
2656
|
-
placeholder:
|
|
2706
|
+
placeholder: placeholder3,
|
|
2707
|
+
lineWrapping
|
|
2657
2708
|
}),
|
|
2658
2709
|
...extensions
|
|
2659
2710
|
],
|
|
2660
|
-
|
|
2711
|
+
theme,
|
|
2712
|
+
slots: updatedSlots,
|
|
2661
2713
|
...props
|
|
2662
2714
|
});
|
|
2663
2715
|
});
|
|
2664
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2716
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2665
2717
|
const { themeMode } = useThemeContext();
|
|
2666
|
-
const
|
|
2718
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2667
2719
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2668
2720
|
ref: forwardedRef,
|
|
2669
2721
|
readonly,
|
|
2670
2722
|
extensions: [
|
|
2671
2723
|
markdownBundle({
|
|
2672
|
-
readonly,
|
|
2673
2724
|
themeMode,
|
|
2674
|
-
placeholder:
|
|
2725
|
+
placeholder: placeholder3
|
|
2675
2726
|
}),
|
|
2676
2727
|
...extensions
|
|
2677
2728
|
],
|
|
2678
|
-
|
|
2729
|
+
theme,
|
|
2730
|
+
slots: updatedSlots,
|
|
2679
2731
|
...props
|
|
2680
2732
|
});
|
|
2681
2733
|
});
|
|
2682
2734
|
var defaultSlots = {
|
|
2683
2735
|
root: {
|
|
2684
|
-
|
|
2736
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2737
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2738
|
+
},
|
|
2739
|
+
editor: {
|
|
2740
|
+
className: "h-full p-2"
|
|
2685
2741
|
}
|
|
2686
2742
|
};
|
|
2687
2743
|
var defaultTextSlots = {
|
|
2688
|
-
...defaultSlots
|
|
2689
|
-
editor: {
|
|
2690
|
-
theme: textTheme
|
|
2691
|
-
}
|
|
2744
|
+
...defaultSlots
|
|
2692
2745
|
};
|
|
2693
2746
|
var defaultMarkdownSlots = {
|
|
2694
|
-
...defaultSlots
|
|
2695
|
-
editor: {
|
|
2696
|
-
theme: markdownTheme
|
|
2697
|
-
}
|
|
2747
|
+
...defaultSlots
|
|
2698
2748
|
};
|
|
2699
2749
|
|
|
2700
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2701
|
-
import get4 from "lodash.get";
|
|
2702
|
-
import { getRawDoc } from "@dxos/echo-schema";
|
|
2703
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2704
|
-
|
|
2705
2750
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2706
2751
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2707
2752
|
import { Context as Context2 } from "@dxos/context";
|
|
2708
|
-
import { invariant as
|
|
2753
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2709
2754
|
import { log as log3 } from "@dxos/log";
|
|
2710
|
-
var
|
|
2755
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2711
2756
|
var DEBOUNCE_INTERVAL = 100;
|
|
2712
2757
|
var SpaceAwarenessProvider = class {
|
|
2713
2758
|
constructor(params) {
|
|
2714
|
-
this.remoteStateChange = new Event2();
|
|
2715
2759
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2760
|
+
this.remoteStateChange = new Event2();
|
|
2716
2761
|
this._space = params.space;
|
|
2717
2762
|
this._channel = params.channel;
|
|
2718
2763
|
this._peerId = params.peerId;
|
|
@@ -2729,7 +2774,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2729
2774
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2730
2775
|
}
|
|
2731
2776
|
});
|
|
2732
|
-
|
|
2777
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2733
2778
|
switch (message.payload.kind) {
|
|
2734
2779
|
case "query": {
|
|
2735
2780
|
this._handleQueryMessage();
|
|
@@ -2740,16 +2785,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2740
2785
|
break;
|
|
2741
2786
|
}
|
|
2742
2787
|
}
|
|
2743
|
-
});
|
|
2744
|
-
this._ctx.onDispose(unsubscribe);
|
|
2788
|
+
}));
|
|
2745
2789
|
void this._space.postMessage(this._channel, {
|
|
2746
2790
|
kind: "query"
|
|
2747
2791
|
}).catch((err) => {
|
|
2748
2792
|
log3.debug("failed to query awareness", {
|
|
2749
2793
|
err
|
|
2750
2794
|
}, {
|
|
2751
|
-
F:
|
|
2752
|
-
L:
|
|
2795
|
+
F: __dxlog_file6,
|
|
2796
|
+
L: 89,
|
|
2753
2797
|
S: this,
|
|
2754
2798
|
C: (f, a) => f(...a)
|
|
2755
2799
|
});
|
|
@@ -2760,10 +2804,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2760
2804
|
this._ctx = void 0;
|
|
2761
2805
|
this._postTask = void 0;
|
|
2762
2806
|
}
|
|
2807
|
+
getRemoteStates() {
|
|
2808
|
+
return Array.from(this._remoteStates.values());
|
|
2809
|
+
}
|
|
2763
2810
|
update(position) {
|
|
2764
|
-
|
|
2765
|
-
F:
|
|
2766
|
-
L:
|
|
2811
|
+
invariant4(this._postTask, void 0, {
|
|
2812
|
+
F: __dxlog_file6,
|
|
2813
|
+
L: 104,
|
|
2767
2814
|
S: this,
|
|
2768
2815
|
A: [
|
|
2769
2816
|
"this._postTask",
|
|
@@ -2777,13 +2824,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2777
2824
|
};
|
|
2778
2825
|
this._postTask.schedule();
|
|
2779
2826
|
}
|
|
2780
|
-
getRemoteStates() {
|
|
2781
|
-
return Array.from(this._remoteStates.values());
|
|
2782
|
-
}
|
|
2783
2827
|
_handleQueryMessage() {
|
|
2784
|
-
|
|
2785
|
-
F:
|
|
2786
|
-
L:
|
|
2828
|
+
invariant4(this._postTask, void 0, {
|
|
2829
|
+
F: __dxlog_file6,
|
|
2830
|
+
L: 115,
|
|
2787
2831
|
S: this,
|
|
2788
2832
|
A: [
|
|
2789
2833
|
"this._postTask",
|
|
@@ -2793,9 +2837,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2793
2837
|
this._postTask.schedule();
|
|
2794
2838
|
}
|
|
2795
2839
|
_handlePostMessage(message) {
|
|
2796
|
-
|
|
2797
|
-
F:
|
|
2798
|
-
L:
|
|
2840
|
+
invariant4(message.kind === "post", void 0, {
|
|
2841
|
+
F: __dxlog_file6,
|
|
2842
|
+
L: 120,
|
|
2799
2843
|
S: this,
|
|
2800
2844
|
A: [
|
|
2801
2845
|
"message.kind === 'post'",
|
|
@@ -2807,201 +2851,54 @@ var SpaceAwarenessProvider = class {
|
|
|
2807
2851
|
}
|
|
2808
2852
|
};
|
|
2809
2853
|
|
|
2810
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2854
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2811
2855
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2812
|
-
|
|
2813
|
-
|
|
2856
|
+
var modelState = StateField5.define({
|
|
2857
|
+
create: () => void 0,
|
|
2858
|
+
update: (model) => model
|
|
2859
|
+
});
|
|
2814
2860
|
|
|
2815
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2816
|
-
import
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
import { log as log4 } from "@dxos/log";
|
|
2823
|
-
import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
|
|
2824
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2825
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2826
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2827
|
-
F: __dxlog_file5,
|
|
2828
|
-
L: 23,
|
|
2829
|
-
S: void 0,
|
|
2830
|
-
A: [
|
|
2831
|
-
"text?.doc && text?.content",
|
|
2832
|
-
""
|
|
2833
|
-
]
|
|
2834
|
-
});
|
|
2835
|
-
const provider = space ? new YAwarenessProvider({
|
|
2836
|
-
space,
|
|
2837
|
-
doc: text.doc,
|
|
2838
|
-
channel: `yjs.awareness.${text.id}`
|
|
2839
|
-
}) : void 0;
|
|
2840
|
-
const model = {
|
|
2841
|
-
id: text.doc.guid,
|
|
2842
|
-
content: text.content,
|
|
2843
|
-
text: () => text.content.toString(),
|
|
2844
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2845
|
-
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2846
|
-
getCursorFromRange: (range) => {
|
|
2847
|
-
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2848
|
-
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2849
|
-
return [
|
|
2850
|
-
arrayToString2(from),
|
|
2851
|
-
arrayToString2(to)
|
|
2852
|
-
].join(":");
|
|
2853
|
-
},
|
|
2854
|
-
getRangeFromCursor: (cursor) => {
|
|
2855
|
-
invariant4(text.doc, void 0, {
|
|
2856
|
-
F: __dxlog_file5,
|
|
2857
|
-
L: 40,
|
|
2858
|
-
S: void 0,
|
|
2859
|
-
A: [
|
|
2860
|
-
"text.doc",
|
|
2861
|
-
""
|
|
2862
|
-
]
|
|
2863
|
-
});
|
|
2864
|
-
const parts = cursor.split(":");
|
|
2865
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2866
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2867
|
-
return from && to ? {
|
|
2868
|
-
from: from.index,
|
|
2869
|
-
to: to.index
|
|
2870
|
-
} : void 0;
|
|
2861
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
2862
|
+
import { useState as useState2 } from "react";
|
|
2863
|
+
var useTextEditor = () => {
|
|
2864
|
+
const [view, setView] = useState2(null);
|
|
2865
|
+
return [
|
|
2866
|
+
(ref) => {
|
|
2867
|
+
setView(ref);
|
|
2871
2868
|
},
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
yjs(text.content, provider?.awareness)
|
|
2875
|
-
],
|
|
2876
|
-
awareness: provider?.awareness,
|
|
2877
|
-
peer: identity ? {
|
|
2878
|
-
id: identity.identityKey.toHex(),
|
|
2879
|
-
name: identity.profile?.displayName
|
|
2880
|
-
} : void 0
|
|
2881
|
-
};
|
|
2882
|
-
return model;
|
|
2883
|
-
};
|
|
2884
|
-
var messageAwareness = 1;
|
|
2885
|
-
var messageQueryAwareness = 3;
|
|
2886
|
-
var YAwarenessProvider = class extends Observable {
|
|
2887
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2888
|
-
super();
|
|
2889
|
-
this._space = space;
|
|
2890
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2891
|
-
this._channel = channel;
|
|
2892
|
-
this._clientId = doc.clientID;
|
|
2893
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2894
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2895
|
-
if (typeof window !== "undefined") {
|
|
2896
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2897
|
-
} else if (typeof process !== "undefined") {
|
|
2898
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2899
|
-
}
|
|
2900
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2901
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2902
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2903
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2904
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2905
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2906
|
-
this._clientId
|
|
2907
|
-
]));
|
|
2908
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2909
|
-
}
|
|
2910
|
-
get awareness() {
|
|
2911
|
-
return this._awareness;
|
|
2912
|
-
}
|
|
2913
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2914
|
-
log4("awareness update", {
|
|
2915
|
-
added,
|
|
2916
|
-
updated,
|
|
2917
|
-
removed,
|
|
2918
|
-
origin
|
|
2919
|
-
}, {
|
|
2920
|
-
F: __dxlog_file5,
|
|
2921
|
-
L: 122,
|
|
2922
|
-
S: this,
|
|
2923
|
-
C: (f, a) => f(...a)
|
|
2924
|
-
});
|
|
2925
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2926
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2927
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2928
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2929
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2930
|
-
}
|
|
2931
|
-
_handleSpaceMessage({ payload }) {
|
|
2932
|
-
log4("space message", payload, {
|
|
2933
|
-
F: __dxlog_file5,
|
|
2934
|
-
L: 131,
|
|
2935
|
-
S: this,
|
|
2936
|
-
C: (f, a) => f(...a)
|
|
2937
|
-
});
|
|
2938
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2939
|
-
const encoder = this._readMessage(data);
|
|
2940
|
-
if (encoder) {
|
|
2941
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2942
|
-
}
|
|
2943
|
-
}
|
|
2944
|
-
_readMessage(message) {
|
|
2945
|
-
const decoder = decoding.createDecoder(message);
|
|
2946
|
-
const encoder = encoding.createEncoder();
|
|
2947
|
-
const messageType = decoding.readVarUint(decoder);
|
|
2948
|
-
let sendReply = false;
|
|
2949
|
-
switch (messageType) {
|
|
2950
|
-
case messageAwareness: {
|
|
2951
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2952
|
-
break;
|
|
2953
|
-
}
|
|
2954
|
-
case messageQueryAwareness: {
|
|
2955
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
2956
|
-
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2957
|
-
sendReply = true;
|
|
2958
|
-
break;
|
|
2959
|
-
}
|
|
2960
|
-
default: {
|
|
2961
|
-
console.error("Invalid message:", messageType);
|
|
2962
|
-
return encoder;
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
|
-
if (!sendReply) {
|
|
2966
|
-
return null;
|
|
2967
|
-
}
|
|
2968
|
-
return encoder;
|
|
2969
|
-
}
|
|
2970
|
-
_handleBeforeUnload() {
|
|
2971
|
-
YP.removeAwarenessStates(this._awareness, [
|
|
2972
|
-
this._clientId
|
|
2973
|
-
], "window unload");
|
|
2974
|
-
}
|
|
2869
|
+
view
|
|
2870
|
+
];
|
|
2975
2871
|
};
|
|
2976
2872
|
|
|
2977
2873
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
}
|
|
2874
|
+
import get4 from "lodash.get";
|
|
2875
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
2876
|
+
import { generateName } from "@dxos/display-name";
|
|
2877
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2878
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2879
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2880
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2881
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2982
2882
|
var useTextModel = (props) => {
|
|
2983
2883
|
const { identity, space, text } = props;
|
|
2984
|
-
const [model, setModel] =
|
|
2985
|
-
|
|
2884
|
+
const [model, setModel] = useState3();
|
|
2885
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2986
2886
|
identity,
|
|
2987
2887
|
space,
|
|
2988
2888
|
text
|
|
2989
2889
|
]);
|
|
2990
2890
|
return model;
|
|
2991
2891
|
};
|
|
2992
|
-
var createModel = (
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
};
|
|
3002
|
-
|
|
3003
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
3004
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2892
|
+
var createModel = ({ space, identity, text }) => {
|
|
2893
|
+
invariant5(isAutomergeObject(text), void 0, {
|
|
2894
|
+
F: __dxlog_file7,
|
|
2895
|
+
L: 35,
|
|
2896
|
+
S: void 0,
|
|
2897
|
+
A: [
|
|
2898
|
+
"isAutomergeObject(text)",
|
|
2899
|
+
""
|
|
2900
|
+
]
|
|
2901
|
+
});
|
|
3005
2902
|
const obj = text;
|
|
3006
2903
|
const doc = getRawDoc(obj, [
|
|
3007
2904
|
obj.field
|
|
@@ -3010,7 +2907,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3010
2907
|
space,
|
|
3011
2908
|
channel: `automerge.awareness.${obj.id}`,
|
|
3012
2909
|
info: {
|
|
3013
|
-
displayName: identity
|
|
2910
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
3014
2911
|
color: cursorColor.color,
|
|
3015
2912
|
lightColor: cursorColor.light
|
|
3016
2913
|
},
|
|
@@ -3020,7 +2917,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3020
2917
|
id: obj.id,
|
|
3021
2918
|
content: doc,
|
|
3022
2919
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3023
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
3024
2920
|
extension: [
|
|
3025
2921
|
modelState.init(() => model),
|
|
3026
2922
|
automerge3({
|
|
@@ -3040,6 +2936,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3040
2936
|
export {
|
|
3041
2937
|
AwarenessProvider,
|
|
3042
2938
|
BaseTextEditor,
|
|
2939
|
+
Cursor,
|
|
3043
2940
|
Doc,
|
|
3044
2941
|
EditorModes,
|
|
3045
2942
|
MarkdownEditor,
|
|
@@ -3047,7 +2944,6 @@ export {
|
|
|
3047
2944
|
SpaceAwarenessProvider,
|
|
3048
2945
|
TextEditor,
|
|
3049
2946
|
TextKind,
|
|
3050
|
-
YAwarenessProvider,
|
|
3051
2947
|
YText,
|
|
3052
2948
|
YXmlFragment,
|
|
3053
2949
|
autocomplete,
|
|
@@ -3055,21 +2951,22 @@ export {
|
|
|
3055
2951
|
awareness,
|
|
3056
2952
|
basicBundle,
|
|
3057
2953
|
blast,
|
|
2954
|
+
callbackWrapper,
|
|
3058
2955
|
code2 as code,
|
|
3059
2956
|
codeTheme,
|
|
3060
2957
|
comments,
|
|
3061
|
-
createAutomergeModel,
|
|
3062
|
-
createYjsModel,
|
|
3063
2958
|
defaultMarkdownSlots,
|
|
3064
2959
|
defaultOptions,
|
|
3065
2960
|
defaultSlots,
|
|
3066
2961
|
defaultTextSlots,
|
|
3067
2962
|
defaultTheme,
|
|
3068
2963
|
getToken,
|
|
2964
|
+
heading2 as heading,
|
|
3069
2965
|
hr,
|
|
3070
2966
|
image,
|
|
3071
2967
|
link,
|
|
3072
2968
|
listener,
|
|
2969
|
+
logChanges,
|
|
3073
2970
|
markdownBundle,
|
|
3074
2971
|
markdownHighlightStyle,
|
|
3075
2972
|
markdownTags,
|
|
@@ -3077,7 +2974,8 @@ export {
|
|
|
3077
2974
|
markdownTheme,
|
|
3078
2975
|
mention,
|
|
3079
2976
|
modelState,
|
|
3080
|
-
|
|
2977
|
+
outliner,
|
|
2978
|
+
setComments,
|
|
3081
2979
|
setFocus,
|
|
3082
2980
|
setSelection,
|
|
3083
2981
|
table,
|
|
@@ -3085,7 +2983,8 @@ export {
|
|
|
3085
2983
|
tasklist,
|
|
3086
2984
|
textTheme,
|
|
3087
2985
|
typewriter,
|
|
3088
|
-
|
|
3089
|
-
|
|
2986
|
+
useComments,
|
|
2987
|
+
useTextEditor,
|
|
2988
|
+
useTextModel
|
|
3090
2989
|
};
|
|
3091
2990
|
//# sourceMappingURL=index.mjs.map
|