@dxos/react-ui-editor 0.3.11-main.9c729f3 → 0.3.11-main.9de2c34
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 +939 -1067
- 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/code.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/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/image.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +2 -2
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -5
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
- package/dist/types/src/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 +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.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 +77 -80
- 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/code.ts +28 -23
- package/src/extensions/comments.ts +249 -242
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/hr.ts +50 -52
- package/src/extensions/image.ts +40 -22
- package/src/extensions/index.ts +2 -2
- package/src/extensions/link.ts +86 -88
- package/src/extensions/markdown/bundle.ts +18 -24
- package/src/extensions/markdown/highlight.ts +3 -12
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/extensions/table.ts +10 -4
- package/src/extensions/tasklist.ts +78 -88
- 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 +3 -0
- package/src/styles/markdown.ts +0 -2
- package/src/styles/tokens.ts +3 -0
- package/src/themes/default.ts +51 -78
- 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/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.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/mermaid.ts +0 -11
- 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
|
@@ -11,48 +11,52 @@ 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, () => {
|
|
@@ -412,13 +432,13 @@ var RemoteSelectionsDecorator = class {
|
|
|
412
432
|
void this._ctx.dispose();
|
|
413
433
|
this._provider.close();
|
|
414
434
|
}
|
|
415
|
-
update(
|
|
416
|
-
this._updateLocalSelection(
|
|
417
|
-
this._updateRemoteSelections(
|
|
435
|
+
update(update2) {
|
|
436
|
+
this._updateLocalSelection(update2);
|
|
437
|
+
this._updateRemoteSelections(update2);
|
|
418
438
|
}
|
|
419
|
-
_updateLocalSelection(
|
|
420
|
-
const hasFocus =
|
|
421
|
-
const { anchor = void 0, head = void 0 } = hasFocus ?
|
|
439
|
+
_updateLocalSelection(update2) {
|
|
440
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
441
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
422
442
|
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
423
443
|
return;
|
|
424
444
|
}
|
|
@@ -429,7 +449,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
429
449
|
head: this._cursorConverter.toCursor(head)
|
|
430
450
|
} : void 0);
|
|
431
451
|
}
|
|
432
|
-
_updateRemoteSelections(
|
|
452
|
+
_updateRemoteSelections(update2) {
|
|
433
453
|
const decorations = [];
|
|
434
454
|
const awarenessStates = this._provider.getRemoteStates();
|
|
435
455
|
for (const state of awarenessStates) {
|
|
@@ -438,10 +458,10 @@ var RemoteSelectionsDecorator = class {
|
|
|
438
458
|
if (anchor == null || head == null) {
|
|
439
459
|
continue;
|
|
440
460
|
}
|
|
441
|
-
const start = Math.min(Math.min(anchor, head),
|
|
442
|
-
const end = Math.min(Math.max(anchor, head),
|
|
443
|
-
const startLine =
|
|
444
|
-
const endLine =
|
|
461
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
462
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
463
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
464
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
445
465
|
const color = state.info.color ?? "#30bced";
|
|
446
466
|
const lightColor = state.info.lightColor ?? color + "33";
|
|
447
467
|
if (startLine.number === endLine.number) {
|
|
@@ -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,18 +493,18 @@ 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++) {
|
|
480
|
-
const linePos =
|
|
500
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
481
501
|
decorations.push({
|
|
482
502
|
from: linePos,
|
|
483
503
|
to: linePos,
|
|
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,
|
|
@@ -667,12 +686,12 @@ var blast = (options = defaultOptions) => {
|
|
|
667
686
|
};
|
|
668
687
|
return [
|
|
669
688
|
// Cursor moved.
|
|
670
|
-
|
|
671
|
-
if (blaster?.node !==
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
690
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
691
|
if (blaster) {
|
|
673
692
|
blaster.destroy();
|
|
674
693
|
}
|
|
675
|
-
blaster = new Blaster(
|
|
694
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
676
695
|
particleGravity: 0.2,
|
|
677
696
|
particleShrinkRate: 0.995,
|
|
678
697
|
color: () => [
|
|
@@ -686,10 +705,10 @@ var blast = (options = defaultOptions) => {
|
|
|
686
705
|
} else {
|
|
687
706
|
blaster.resize();
|
|
688
707
|
}
|
|
689
|
-
const current =
|
|
708
|
+
const current = update2.state.selection.main.head;
|
|
690
709
|
if (current !== last) {
|
|
691
710
|
last = current;
|
|
692
|
-
const { element, point } = getPoint(
|
|
711
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
693
712
|
if (element && point) {
|
|
694
713
|
blaster.spawn({
|
|
695
714
|
element,
|
|
@@ -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,
|
|
@@ -929,8 +948,7 @@ var random = (min, max) => {
|
|
|
929
948
|
};
|
|
930
949
|
|
|
931
950
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
932
|
-
import { ViewPlugin as ViewPlugin3, EditorView as
|
|
933
|
-
import get2 from "lodash.get";
|
|
951
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
|
|
934
952
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
935
953
|
|
|
936
954
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
@@ -1014,20 +1032,22 @@ var inlineUrl = mx(code, "px-1");
|
|
|
1014
1032
|
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1015
1033
|
|
|
1016
1034
|
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1035
|
+
import get2 from "lodash.get";
|
|
1017
1036
|
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1018
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1038
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1019
1039
|
|
|
1020
1040
|
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1021
1041
|
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1022
|
-
var styles2 =
|
|
1042
|
+
var styles2 = EditorView5.baseTheme({
|
|
1023
1043
|
"& .cm-codeblock": {
|
|
1024
|
-
fontFamily:
|
|
1044
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1025
1045
|
},
|
|
1026
1046
|
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1027
|
-
background:
|
|
1047
|
+
background: getToken("extend.colors.neutral.50")
|
|
1028
1048
|
},
|
|
1029
1049
|
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1030
|
-
background:
|
|
1050
|
+
background: getToken("extend.colors.neutral.850")
|
|
1031
1051
|
},
|
|
1032
1052
|
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1033
1053
|
display: "block",
|
|
@@ -1053,20 +1073,18 @@ var getLineRange = (lines, from, to) => {
|
|
|
1053
1073
|
];
|
|
1054
1074
|
};
|
|
1055
1075
|
var code2 = () => {
|
|
1056
|
-
const
|
|
1076
|
+
const buildDecorations5 = (view) => {
|
|
1057
1077
|
const decorations = [];
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
}).range(block.from));
|
|
1069
|
-
}
|
|
1078
|
+
const text = view.state.doc.sliceString(0);
|
|
1079
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1080
|
+
const blocks = view.viewportLineBlocks;
|
|
1081
|
+
for (const match of matches) {
|
|
1082
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1083
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1084
|
+
const block = blocks[i];
|
|
1085
|
+
decorations.push(Decoration2.line({
|
|
1086
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1087
|
+
}).range(block.from));
|
|
1070
1088
|
}
|
|
1071
1089
|
}
|
|
1072
1090
|
return Decoration2.set(decorations);
|
|
@@ -1074,11 +1092,16 @@ var code2 = () => {
|
|
|
1074
1092
|
return [
|
|
1075
1093
|
ViewPlugin3.fromClass(class {
|
|
1076
1094
|
constructor(view) {
|
|
1077
|
-
this.
|
|
1095
|
+
this.hasFocus = false;
|
|
1096
|
+
this.decorations = buildDecorations5(view);
|
|
1078
1097
|
}
|
|
1079
|
-
update(
|
|
1080
|
-
if (
|
|
1081
|
-
|
|
1098
|
+
update(update2) {
|
|
1099
|
+
if (
|
|
1100
|
+
// TODO(burdon): Generalize for other extensions.
|
|
1101
|
+
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1102
|
+
) {
|
|
1103
|
+
this.hasFocus = update2.view.hasFocus;
|
|
1104
|
+
this.decorations = buildDecorations5(update2.view);
|
|
1082
1105
|
}
|
|
1083
1106
|
}
|
|
1084
1107
|
}, {
|
|
@@ -1090,29 +1113,56 @@ var code2 = () => {
|
|
|
1090
1113
|
|
|
1091
1114
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1092
1115
|
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1093
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as
|
|
1094
|
-
import get3 from "lodash.get";
|
|
1116
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1095
1117
|
import sortBy from "lodash.sortby";
|
|
1118
|
+
import { useEffect } from "react";
|
|
1096
1119
|
import { debounce } from "@dxos/async";
|
|
1097
|
-
import { invariant as
|
|
1098
|
-
import { log as log2 } from "@dxos/log";
|
|
1120
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1099
1121
|
import { nonNullable } from "@dxos/util";
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1122
|
+
|
|
1123
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1124
|
+
import { log } from "@dxos/log";
|
|
1125
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1126
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1127
|
+
try {
|
|
1128
|
+
return fn(...args);
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
log.catch(err, void 0, {
|
|
1131
|
+
F: __dxlog_file3,
|
|
1132
|
+
L: 18,
|
|
1133
|
+
S: void 0,
|
|
1134
|
+
C: (f, a) => f(...a)
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
var logChanges = (trs) => {
|
|
1139
|
+
const changes = trs.flatMap((tr) => {
|
|
1140
|
+
if (tr.changes.empty) {
|
|
1141
|
+
return void 0;
|
|
1142
|
+
}
|
|
1143
|
+
const changes2 = [];
|
|
1144
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1145
|
+
fromA,
|
|
1146
|
+
toA,
|
|
1147
|
+
fromB,
|
|
1148
|
+
toB,
|
|
1149
|
+
inserted: inserted.toString()
|
|
1150
|
+
})));
|
|
1151
|
+
return changes2;
|
|
1152
|
+
}).filter(Boolean);
|
|
1153
|
+
if (changes.length) {
|
|
1154
|
+
console.log("changes", changes);
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1159
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1160
|
+
var styles3 = EditorView6.baseTheme({
|
|
1111
1161
|
"& .cm-comment": {
|
|
1112
|
-
backgroundColor:
|
|
1162
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1163
|
},
|
|
1114
|
-
"& .cm-comment-
|
|
1115
|
-
backgroundColor:
|
|
1164
|
+
"& .cm-comment-current": {
|
|
1165
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1116
1166
|
}
|
|
1117
1167
|
});
|
|
1118
1168
|
var marks = {
|
|
@@ -1120,52 +1170,62 @@ var marks = {
|
|
|
1120
1170
|
class: "cm-comment"
|
|
1121
1171
|
}),
|
|
1122
1172
|
highlightActive: Decoration3.mark({
|
|
1123
|
-
class: "cm-comment-
|
|
1173
|
+
class: "cm-comment-current"
|
|
1124
1174
|
})
|
|
1125
1175
|
};
|
|
1126
|
-
var setFocus = (view,
|
|
1127
|
-
const
|
|
1128
|
-
if (!
|
|
1176
|
+
var setFocus = (view, id, center = true) => {
|
|
1177
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1178
|
+
if (!comment?.comment.cursor) {
|
|
1129
1179
|
return;
|
|
1130
1180
|
}
|
|
1131
|
-
view.
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1181
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1182
|
+
if (range) {
|
|
1183
|
+
view.dispatch({
|
|
1184
|
+
selection: {
|
|
1185
|
+
anchor: range.from
|
|
1186
|
+
},
|
|
1187
|
+
effects: [
|
|
1188
|
+
//
|
|
1189
|
+
EditorView6.scrollIntoView(range.from, center ? {
|
|
1190
|
+
y: "center"
|
|
1191
|
+
} : void 0),
|
|
1192
|
+
setSelection.of({
|
|
1193
|
+
current: id
|
|
1194
|
+
})
|
|
1195
|
+
]
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1140
1198
|
};
|
|
1141
|
-
var
|
|
1199
|
+
var setComments = StateEffect2.define();
|
|
1142
1200
|
var setSelection = StateEffect2.define();
|
|
1143
1201
|
var setCommentState = StateEffect2.define();
|
|
1144
|
-
var
|
|
1202
|
+
var commentsState = StateField2.define({
|
|
1145
1203
|
create: () => ({
|
|
1146
|
-
|
|
1204
|
+
comments: [],
|
|
1205
|
+
selection: {}
|
|
1147
1206
|
}),
|
|
1148
1207
|
update: (value, tr) => {
|
|
1149
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1150
1208
|
for (const effect of tr.effects) {
|
|
1151
1209
|
if (effect.is(setSelection)) {
|
|
1152
1210
|
return {
|
|
1153
1211
|
...value,
|
|
1154
|
-
|
|
1212
|
+
selection: effect.value
|
|
1155
1213
|
};
|
|
1156
1214
|
}
|
|
1157
|
-
if (effect.is(
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1215
|
+
if (effect.is(setComments)) {
|
|
1216
|
+
const comments2 = effect.value.map((comment) => {
|
|
1217
|
+
if (!comment.cursor) {
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1161
1221
|
return range && {
|
|
1162
|
-
|
|
1163
|
-
|
|
1222
|
+
comment,
|
|
1223
|
+
range
|
|
1164
1224
|
};
|
|
1165
1225
|
}).filter(nonNullable);
|
|
1166
1226
|
return {
|
|
1167
1227
|
...value,
|
|
1168
|
-
|
|
1228
|
+
comments: comments2
|
|
1169
1229
|
};
|
|
1170
1230
|
}
|
|
1171
1231
|
if (effect.is(setCommentState)) {
|
|
@@ -1175,134 +1235,125 @@ var commentsStateField = StateField2.define({
|
|
|
1175
1235
|
return value;
|
|
1176
1236
|
}
|
|
1177
1237
|
});
|
|
1178
|
-
var highlightDecorations =
|
|
1179
|
-
|
|
1238
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1239
|
+
commentsState
|
|
1180
1240
|
], (state) => {
|
|
1181
|
-
const {
|
|
1182
|
-
const decorations = sortBy(
|
|
1183
|
-
|
|
1241
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1242
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1243
|
+
const range = comment.range;
|
|
1244
|
+
if (!range || range.from === range.to) {
|
|
1245
|
+
console.warn("Invalid range:", range);
|
|
1184
1246
|
return void 0;
|
|
1185
1247
|
}
|
|
1186
|
-
|
|
1187
|
-
from: selection.from,
|
|
1188
|
-
to: selection.to
|
|
1189
|
-
};
|
|
1190
|
-
if (selection.id === active) {
|
|
1248
|
+
if (comment.comment.id === current) {
|
|
1191
1249
|
return marks.highlightActive.range(range.from, range.to);
|
|
1192
1250
|
} else {
|
|
1193
1251
|
return marks.highlight.range(range.from, range.to);
|
|
1194
1252
|
}
|
|
1195
|
-
}).filter(nonNullable)
|
|
1253
|
+
}).filter(nonNullable);
|
|
1196
1254
|
return Decoration3.set(decorations);
|
|
1197
1255
|
});
|
|
1198
|
-
var
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1216
|
-
}
|
|
1217
|
-
toDOM() {
|
|
1218
|
-
const span = document.createElement("span");
|
|
1219
|
-
span.className = "cm-bookmark";
|
|
1220
|
-
span.textContent = "\u203B";
|
|
1221
|
-
if (this._handleClick) {
|
|
1222
|
-
span.onclick = () => this._handleClick();
|
|
1256
|
+
var trackPastedComments = (onUpdate) => {
|
|
1257
|
+
let tracked = null;
|
|
1258
|
+
const handleTrack = (event, view) => {
|
|
1259
|
+
const comments2 = view.state.field(commentsState);
|
|
1260
|
+
const { main } = view.state.selection;
|
|
1261
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1262
|
+
if (!selectedRanges.length) {
|
|
1263
|
+
tracked = null;
|
|
1264
|
+
} else {
|
|
1265
|
+
tracked = {
|
|
1266
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1267
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1268
|
+
id: comment.id,
|
|
1269
|
+
from: range.from - main.from,
|
|
1270
|
+
to: range.to - main.from
|
|
1271
|
+
}))
|
|
1272
|
+
};
|
|
1223
1273
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1274
|
+
};
|
|
1275
|
+
return [
|
|
1276
|
+
EditorView6.domEventHandlers({
|
|
1277
|
+
cut: handleTrack,
|
|
1278
|
+
copy: handleTrack
|
|
1279
|
+
}),
|
|
1280
|
+
// Handle paste.
|
|
1281
|
+
EditorView6.updateListener.of(({ view, state, transactions }) => {
|
|
1282
|
+
if (tracked) {
|
|
1283
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1284
|
+
if (paste) {
|
|
1285
|
+
let found = -1;
|
|
1286
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1287
|
+
if (text.eq(tracked.text)) {
|
|
1288
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1289
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1290
|
+
}
|
|
1291
|
+
found = fromB;
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
if (found > -1) {
|
|
1295
|
+
for (const moved of tracked.comments) {
|
|
1296
|
+
const range = {
|
|
1297
|
+
from: found + moved.from,
|
|
1298
|
+
to: found + moved.to
|
|
1299
|
+
};
|
|
1300
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1301
|
+
onUpdate(moved.id, cursor);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
tracked = null;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
})
|
|
1308
|
+
];
|
|
1226
1309
|
};
|
|
1227
1310
|
var comments = (options = {}) => {
|
|
1311
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1228
1312
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1229
1313
|
const createCommentThread = (view) => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
L: 225,
|
|
1314
|
+
invariant3(options.onCreate, void 0, {
|
|
1315
|
+
F: __dxlog_file4,
|
|
1316
|
+
L: 259,
|
|
1234
1317
|
S: void 0,
|
|
1235
1318
|
A: [
|
|
1236
1319
|
"options.onCreate",
|
|
1237
1320
|
""
|
|
1238
1321
|
]
|
|
1239
1322
|
});
|
|
1240
|
-
const {
|
|
1323
|
+
const { from, to } = view.state.selection.main;
|
|
1241
1324
|
if (from === to) {
|
|
1242
1325
|
return false;
|
|
1243
1326
|
}
|
|
1244
|
-
|
|
1327
|
+
if (to === view.state.doc.length) {
|
|
1328
|
+
view.dispatch({
|
|
1329
|
+
changes: {
|
|
1330
|
+
from: to,
|
|
1331
|
+
insert: "\n"
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1245
1336
|
from,
|
|
1246
1337
|
to
|
|
1247
1338
|
});
|
|
1248
|
-
if (
|
|
1249
|
-
const id =
|
|
1339
|
+
if (cursor) {
|
|
1340
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1250
1341
|
if (id) {
|
|
1251
1342
|
view.dispatch({
|
|
1252
1343
|
effects: setSelection.of({
|
|
1253
|
-
|
|
1344
|
+
current: id
|
|
1254
1345
|
}),
|
|
1255
1346
|
selection: {
|
|
1256
1347
|
anchor: from
|
|
1257
1348
|
}
|
|
1258
1349
|
});
|
|
1259
|
-
if (options.footnote) {
|
|
1260
|
-
const tag = `[^${id}]`;
|
|
1261
|
-
view.dispatch({
|
|
1262
|
-
changes: {
|
|
1263
|
-
from: head,
|
|
1264
|
-
insert: tag
|
|
1265
|
-
},
|
|
1266
|
-
selection: {
|
|
1267
|
-
anchor: head + tag.length
|
|
1268
|
-
}
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
1350
|
return true;
|
|
1272
1351
|
}
|
|
1273
1352
|
}
|
|
1274
1353
|
return false;
|
|
1275
1354
|
};
|
|
1276
|
-
const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
|
|
1277
|
-
static {
|
|
1278
|
-
// Match markdown footnotes (option).
|
|
1279
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1280
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1281
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1282
|
-
decoration: (match, view, pos) => {
|
|
1283
|
-
const id = match[1];
|
|
1284
|
-
return Decoration3.replace({
|
|
1285
|
-
id,
|
|
1286
|
-
widget: new BookmarkWidget(pos, id)
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
constructor(view) {
|
|
1292
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1293
|
-
}
|
|
1294
|
-
update(update4) {
|
|
1295
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
1296
|
-
}
|
|
1297
|
-
}, {
|
|
1298
|
-
decorations: (instance) => instance.bookmarks,
|
|
1299
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1300
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1301
|
-
})
|
|
1302
|
-
});
|
|
1303
1355
|
return [
|
|
1304
|
-
|
|
1305
|
-
commentsStateField,
|
|
1356
|
+
commentsState,
|
|
1306
1357
|
highlightDecorations,
|
|
1307
1358
|
styles3,
|
|
1308
1359
|
//
|
|
@@ -1310,7 +1361,7 @@ var comments = (options = {}) => {
|
|
|
1310
1361
|
//
|
|
1311
1362
|
options.onCreate ? keymap3.of([
|
|
1312
1363
|
{
|
|
1313
|
-
key:
|
|
1364
|
+
key: shortcut,
|
|
1314
1365
|
run: callbackWrapper(createCommentThread)
|
|
1315
1366
|
}
|
|
1316
1367
|
]) : [],
|
|
@@ -1327,7 +1378,7 @@ var comments = (options = {}) => {
|
|
|
1327
1378
|
above: true,
|
|
1328
1379
|
create: () => {
|
|
1329
1380
|
const el = document.createElement("div");
|
|
1330
|
-
options.onHover
|
|
1381
|
+
options.onHover(el, shortcut);
|
|
1331
1382
|
return {
|
|
1332
1383
|
dom: el,
|
|
1333
1384
|
offset: {
|
|
@@ -1340,186 +1391,206 @@ var comments = (options = {}) => {
|
|
|
1340
1391
|
}
|
|
1341
1392
|
return null;
|
|
1342
1393
|
}, {
|
|
1343
|
-
|
|
1394
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1395
|
+
// hideOnChange: true,
|
|
1344
1396
|
hoverTime: 1e3
|
|
1345
1397
|
}) : [],
|
|
1346
1398
|
//
|
|
1347
|
-
//
|
|
1348
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1399
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1349
1400
|
//
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
{
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1360
|
-
log2.info("deleted comment", {
|
|
1361
|
-
thread: range.id
|
|
1362
|
-
}, {
|
|
1363
|
-
F: __dxlog_file3,
|
|
1364
|
-
L: 359,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
if (from <= range.to) {
|
|
1371
|
-
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1372
|
-
Object.assign(range, newRange);
|
|
1373
|
-
mod = true;
|
|
1401
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1402
|
+
let mod = false;
|
|
1403
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1404
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1405
|
+
comments2.forEach(({ comment, range }) => {
|
|
1406
|
+
if (from2 === to2) {
|
|
1407
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1408
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1409
|
+
options.onDelete?.(comment.id);
|
|
1374
1410
|
}
|
|
1375
|
-
}
|
|
1411
|
+
}
|
|
1412
|
+
if (from <= range.to) {
|
|
1413
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1414
|
+
Object.assign(range, newRange);
|
|
1415
|
+
mod = true;
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1419
|
+
if (mod) {
|
|
1420
|
+
view.dispatch({
|
|
1421
|
+
effects: setCommentState.of({
|
|
1422
|
+
comments: comments2,
|
|
1423
|
+
...value
|
|
1424
|
+
})
|
|
1376
1425
|
});
|
|
1377
|
-
if (mod) {
|
|
1378
|
-
view.dispatch({
|
|
1379
|
-
effects: setCommentState.of({
|
|
1380
|
-
active,
|
|
1381
|
-
ranges
|
|
1382
|
-
})
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
1426
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1427
|
+
}),
|
|
1428
|
+
//
|
|
1429
|
+
// Track selection/proximity.
|
|
1430
|
+
//
|
|
1431
|
+
EditorView6.updateListener.of(({ view, state }) => {
|
|
1432
|
+
let min = Infinity;
|
|
1433
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1434
|
+
const { head } = state.selection.main;
|
|
1435
|
+
const selection = {};
|
|
1436
|
+
comments2.forEach(({ comment, range }) => {
|
|
1437
|
+
if (head >= range.from && head <= range.to) {
|
|
1438
|
+
selection.current = comment.id;
|
|
1439
|
+
selection.closest = void 0;
|
|
1440
|
+
}
|
|
1441
|
+
if (!selection.current) {
|
|
1442
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1399
1443
|
if (d < min) {
|
|
1400
|
-
|
|
1444
|
+
selection.closest = comment.id;
|
|
1401
1445
|
min = d;
|
|
1402
1446
|
}
|
|
1403
|
-
});
|
|
1404
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1405
|
-
view.dispatch({
|
|
1406
|
-
effects: setSelection.of(selected)
|
|
1407
|
-
});
|
|
1408
|
-
handleSelect({
|
|
1409
|
-
...selected,
|
|
1410
|
-
ranges: ranges.map((range) => ({
|
|
1411
|
-
...range,
|
|
1412
|
-
location: view.coordsAtPos(range.from)
|
|
1413
|
-
}))
|
|
1414
|
-
});
|
|
1415
1447
|
}
|
|
1448
|
+
});
|
|
1449
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1450
|
+
view.dispatch({
|
|
1451
|
+
effects: setSelection.of(selection)
|
|
1452
|
+
});
|
|
1453
|
+
handleSelect({
|
|
1454
|
+
selection,
|
|
1455
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1456
|
+
comment,
|
|
1457
|
+
range,
|
|
1458
|
+
location: view.coordsAtPos(range.from)
|
|
1459
|
+
}))
|
|
1460
|
+
});
|
|
1416
1461
|
}
|
|
1417
|
-
})
|
|
1462
|
+
}),
|
|
1463
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1418
1464
|
];
|
|
1419
1465
|
};
|
|
1420
|
-
var
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1432
|
-
return from && to ? {
|
|
1433
|
-
from,
|
|
1434
|
-
to
|
|
1435
|
-
} : void 0;
|
|
1466
|
+
var useComments = (view, comments2 = []) => {
|
|
1467
|
+
useEffect(() => {
|
|
1468
|
+
if (view) {
|
|
1469
|
+
view.dispatch({
|
|
1470
|
+
effects: setComments.of(comments2)
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}, [
|
|
1474
|
+
view,
|
|
1475
|
+
comments2
|
|
1476
|
+
]);
|
|
1436
1477
|
};
|
|
1437
1478
|
|
|
1438
1479
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1439
|
-
import {
|
|
1440
|
-
import
|
|
1441
|
-
|
|
1480
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1481
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1482
|
+
import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1483
|
+
var styles4 = EditorView7.baseTheme({
|
|
1442
1484
|
"& .cm-hr": {
|
|
1443
|
-
// TODO(burdon): ???
|
|
1444
1485
|
// Note that block-level decorations should not have vertical margins,
|
|
1445
|
-
|
|
1486
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1446
1487
|
}
|
|
1447
1488
|
});
|
|
1448
|
-
var HorizontalRuleWidget = class extends
|
|
1449
|
-
|
|
1450
|
-
super();
|
|
1451
|
-
this._pos = _pos;
|
|
1452
|
-
}
|
|
1453
|
-
eq(other) {
|
|
1454
|
-
return this._pos === other._pos;
|
|
1455
|
-
}
|
|
1456
|
-
toDOM(view) {
|
|
1489
|
+
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1490
|
+
toDOM() {
|
|
1457
1491
|
const el = document.createElement("div");
|
|
1458
1492
|
el.className = "cm-hr";
|
|
1459
1493
|
return el;
|
|
1460
1494
|
}
|
|
1461
1495
|
};
|
|
1462
|
-
var
|
|
1463
|
-
|
|
1464
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1465
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1466
|
-
})
|
|
1496
|
+
var decoration = Decoration4.replace({
|
|
1497
|
+
widget: new HorizontalRuleWidget()
|
|
1467
1498
|
});
|
|
1468
|
-
var
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1499
|
+
var buildDecorations = (view) => {
|
|
1500
|
+
const builder = new RangeSetBuilder();
|
|
1501
|
+
const { state } = view;
|
|
1502
|
+
const cursor = state.selection.main.head;
|
|
1503
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1504
|
+
syntaxTree(state).iterate({
|
|
1505
|
+
enter: (node) => {
|
|
1506
|
+
if (node.name === "HorizontalRule") {
|
|
1507
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1508
|
+
builder.add(node.from, node.to, decoration);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
from,
|
|
1513
|
+
to
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return builder.finish();
|
|
1517
|
+
};
|
|
1518
|
+
var hr = () => {
|
|
1519
|
+
return [
|
|
1520
|
+
styles4,
|
|
1521
|
+
ViewPlugin4.fromClass(class {
|
|
1522
|
+
constructor(view) {
|
|
1523
|
+
this.decorations = buildDecorations(view);
|
|
1524
|
+
}
|
|
1525
|
+
update(update2) {
|
|
1526
|
+
this.decorations = buildDecorations(update2.view);
|
|
1527
|
+
}
|
|
1528
|
+
}, {
|
|
1529
|
+
decorations: (v) => v.decorations
|
|
1482
1530
|
})
|
|
1483
|
-
|
|
1484
|
-
|
|
1531
|
+
];
|
|
1532
|
+
};
|
|
1485
1533
|
|
|
1486
1534
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1487
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1488
|
-
import {
|
|
1489
|
-
import { Decoration as Decoration5, EditorView as
|
|
1535
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1536
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1537
|
+
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1490
1538
|
var image = (options = {}) => {
|
|
1491
1539
|
return StateField3.define({
|
|
1492
|
-
create: (state) =>
|
|
1493
|
-
|
|
1494
|
-
|
|
1540
|
+
create: (state) => {
|
|
1541
|
+
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1542
|
+
},
|
|
1543
|
+
update: (value, tr) => {
|
|
1544
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1545
|
+
return value;
|
|
1546
|
+
}
|
|
1547
|
+
const cursor = tr.state.selection.main.head;
|
|
1548
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1549
|
+
let from = Math.min(cursor, oldCursor);
|
|
1550
|
+
let to = Math.max(cursor, oldCursor);
|
|
1551
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1552
|
+
from = Math.min(from, fromB);
|
|
1553
|
+
to = Math.max(to, toB);
|
|
1554
|
+
});
|
|
1555
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1556
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1557
|
+
return value.map(tr.changes).update({
|
|
1558
|
+
filterFrom: from,
|
|
1559
|
+
filterTo: to,
|
|
1560
|
+
filter: () => false,
|
|
1561
|
+
add: buildDecorations2(from, to, tr.state)
|
|
1562
|
+
});
|
|
1563
|
+
},
|
|
1564
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1495
1565
|
});
|
|
1496
1566
|
};
|
|
1497
|
-
var
|
|
1498
|
-
const
|
|
1567
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1568
|
+
const decorations = [];
|
|
1499
1569
|
const cursor = state.selection.main.head;
|
|
1500
|
-
|
|
1570
|
+
syntaxTree2(state).iterate({
|
|
1501
1571
|
enter: (node) => {
|
|
1502
1572
|
if (node.name === "Image") {
|
|
1503
1573
|
const urlNode = node.node.getChild("URL");
|
|
1504
1574
|
if (urlNode) {
|
|
1505
1575
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1506
1576
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1507
|
-
|
|
1577
|
+
decorations.push(Decoration5.replace({
|
|
1508
1578
|
block: true,
|
|
1509
1579
|
widget: new ImageWidget(url)
|
|
1510
|
-
}));
|
|
1580
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1511
1581
|
}
|
|
1512
1582
|
}
|
|
1513
|
-
}
|
|
1583
|
+
},
|
|
1584
|
+
from,
|
|
1585
|
+
to
|
|
1514
1586
|
});
|
|
1515
|
-
return
|
|
1587
|
+
return decorations;
|
|
1516
1588
|
};
|
|
1517
|
-
var ImageWidget = class extends
|
|
1589
|
+
var ImageWidget = class extends WidgetType3 {
|
|
1518
1590
|
constructor(_url) {
|
|
1519
1591
|
super();
|
|
1520
1592
|
this._url = _url;
|
|
1521
1593
|
}
|
|
1522
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1523
1594
|
eq(other) {
|
|
1524
1595
|
return this._url === other._url;
|
|
1525
1596
|
}
|
|
@@ -1527,22 +1598,29 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
1527
1598
|
const img = document.createElement("img");
|
|
1528
1599
|
img.setAttribute("src", this._url);
|
|
1529
1600
|
img.setAttribute("class", "cm-image");
|
|
1601
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1530
1602
|
return img;
|
|
1531
1603
|
}
|
|
1532
1604
|
};
|
|
1533
1605
|
|
|
1534
1606
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1535
|
-
import { syntaxTree as
|
|
1536
|
-
import { RangeSetBuilder as RangeSetBuilder2
|
|
1537
|
-
import {
|
|
1607
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1608
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1609
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1538
1610
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1539
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1540
1611
|
var link = (options = {}) => {
|
|
1541
1612
|
const extensions = [
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1613
|
+
ViewPlugin5.fromClass(class {
|
|
1614
|
+
constructor(view) {
|
|
1615
|
+
this.decorations = buildDecorations3(view, options);
|
|
1616
|
+
}
|
|
1617
|
+
update(update2) {
|
|
1618
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1619
|
+
this.decorations = buildDecorations3(update2.view, options);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}, {
|
|
1623
|
+
decorations: (v) => v.decorations
|
|
1546
1624
|
})
|
|
1547
1625
|
];
|
|
1548
1626
|
if (options.onHover) {
|
|
@@ -1550,35 +1628,25 @@ var link = (options = {}) => {
|
|
|
1550
1628
|
// https://codemirror.net/examples/tooltip
|
|
1551
1629
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1552
1630
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1553
|
-
hoverTooltip2((view, pos) => {
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
let
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
match = void 0;
|
|
1562
|
-
break;
|
|
1563
|
-
}
|
|
1564
|
-
idx = text.indexOf(match[0]);
|
|
1565
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1566
|
-
break;
|
|
1567
|
-
}
|
|
1568
|
-
idx += match[0].length;
|
|
1569
|
-
} while (true);
|
|
1570
|
-
if (!match) {
|
|
1631
|
+
hoverTooltip2((view, pos, side) => {
|
|
1632
|
+
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1633
|
+
let link2 = null;
|
|
1634
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1635
|
+
link2 = node.name === "Link" ? node : null;
|
|
1636
|
+
}
|
|
1637
|
+
const url = link2 && link2.getChild("URL");
|
|
1638
|
+
if (!url || !link2) {
|
|
1571
1639
|
return null;
|
|
1572
1640
|
}
|
|
1573
|
-
const
|
|
1641
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1574
1642
|
return {
|
|
1575
|
-
pos:
|
|
1576
|
-
end:
|
|
1643
|
+
pos: link2.from,
|
|
1644
|
+
end: link2.to,
|
|
1577
1645
|
above: true,
|
|
1578
1646
|
create: () => {
|
|
1579
1647
|
const el = document.createElement("div");
|
|
1580
1648
|
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1581
|
-
options.onHover(el,
|
|
1649
|
+
options.onHover(el, urlText);
|
|
1582
1650
|
return {
|
|
1583
1651
|
dom: el,
|
|
1584
1652
|
offset: {
|
|
@@ -1593,15 +1661,14 @@ var link = (options = {}) => {
|
|
|
1593
1661
|
}
|
|
1594
1662
|
return extensions;
|
|
1595
1663
|
};
|
|
1596
|
-
var LinkButton = class extends
|
|
1597
|
-
constructor(
|
|
1664
|
+
var LinkButton = class extends WidgetType4 {
|
|
1665
|
+
constructor(_url, _onAttach) {
|
|
1598
1666
|
super();
|
|
1599
|
-
this._pos = _pos;
|
|
1600
1667
|
this._url = _url;
|
|
1601
1668
|
this._onAttach = _onAttach;
|
|
1602
1669
|
}
|
|
1603
1670
|
eq(other) {
|
|
1604
|
-
return this.
|
|
1671
|
+
return this._url === other._url;
|
|
1605
1672
|
}
|
|
1606
1673
|
toDOM(view) {
|
|
1607
1674
|
const el = document.createElement("span");
|
|
@@ -1609,7 +1676,7 @@ var LinkButton = class extends WidgetType5 {
|
|
|
1609
1676
|
return el;
|
|
1610
1677
|
}
|
|
1611
1678
|
};
|
|
1612
|
-
var LinkText = class extends
|
|
1679
|
+
var LinkText = class extends WidgetType4 {
|
|
1613
1680
|
constructor(_text, _url) {
|
|
1614
1681
|
super();
|
|
1615
1682
|
this._text = _text;
|
|
@@ -1638,33 +1705,38 @@ var LinkText = class extends WidgetType5 {
|
|
|
1638
1705
|
return link2;
|
|
1639
1706
|
}
|
|
1640
1707
|
};
|
|
1641
|
-
var
|
|
1708
|
+
var buildDecorations3 = (view, options) => {
|
|
1642
1709
|
const builder = new RangeSetBuilder2();
|
|
1710
|
+
const { state } = view;
|
|
1643
1711
|
const cursor = state.selection.main.head;
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1712
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1713
|
+
syntaxTree3(state).iterate({
|
|
1714
|
+
enter: (node) => {
|
|
1715
|
+
if (node.name === "Link") {
|
|
1716
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
1717
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1718
|
+
const urlNode = node.node.getChild("URL");
|
|
1719
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1720
|
+
if (!url) {
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1724
|
+
builder.add(node.from, node.to, Decoration6.replace({
|
|
1725
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
1726
|
+
}));
|
|
1727
|
+
}
|
|
1728
|
+
if (options.onRender) {
|
|
1729
|
+
builder.add(node.to, node.to, Decoration6.replace({
|
|
1730
|
+
widget: new LinkButton(url, options.onRender)
|
|
1731
|
+
}));
|
|
1732
|
+
}
|
|
1652
1733
|
return false;
|
|
1653
1734
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
if (options.onRender) {
|
|
1660
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1661
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1662
|
-
}));
|
|
1663
|
-
}
|
|
1664
|
-
return false;
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
});
|
|
1735
|
+
},
|
|
1736
|
+
from,
|
|
1737
|
+
to
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1668
1740
|
return builder.finish();
|
|
1669
1741
|
};
|
|
1670
1742
|
|
|
@@ -1676,36 +1748,34 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1676
1748
|
onFocus(focused);
|
|
1677
1749
|
return null;
|
|
1678
1750
|
}));
|
|
1679
|
-
onChange && extensions.push(EditorView9.updateListener.of((
|
|
1680
|
-
onChange(
|
|
1751
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1752
|
+
onChange(update2.state.doc.toString());
|
|
1681
1753
|
}));
|
|
1682
1754
|
return extensions;
|
|
1683
1755
|
};
|
|
1684
1756
|
|
|
1685
1757
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1686
1758
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1687
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1688
|
-
import { markdownLanguage as
|
|
1759
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1760
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1689
1761
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1690
1762
|
import { languages } from "@codemirror/language-data";
|
|
1691
1763
|
import { searchKeymap } from "@codemirror/search";
|
|
1692
1764
|
import { EditorState } from "@codemirror/state";
|
|
1693
1765
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1694
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1766
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1695
1767
|
|
|
1696
1768
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1697
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1769
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1698
1770
|
import { HighlightStyle } from "@codemirror/language";
|
|
1699
1771
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1700
1772
|
import { Table } from "@lezer/markdown";
|
|
1701
|
-
import get5 from "lodash.get";
|
|
1702
1773
|
var markdownTags = {
|
|
1703
1774
|
Blockquote: Tag.define(),
|
|
1704
1775
|
CodeMark: Tag.define(),
|
|
1705
1776
|
CodeText: Tag.define(),
|
|
1706
1777
|
EmphasisMark: Tag.define(),
|
|
1707
1778
|
HeaderMark: Tag.define(),
|
|
1708
|
-
// HorizontalRule: Tag.define(),
|
|
1709
1779
|
InlineCode: Tag.define(),
|
|
1710
1780
|
LinkLabel: Tag.define(),
|
|
1711
1781
|
LinkReference: Tag.define(),
|
|
@@ -1869,12 +1939,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1869
1939
|
],
|
|
1870
1940
|
class: blockquote
|
|
1871
1941
|
},
|
|
1872
|
-
// TODO(burdon): Replace with extension.
|
|
1873
|
-
// {
|
|
1874
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1875
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1876
|
-
// },
|
|
1877
|
-
// TODO(burdon): Only if being edited.
|
|
1878
1942
|
{
|
|
1879
1943
|
tag: [
|
|
1880
1944
|
markdownTags.TableCell
|
|
@@ -1882,9 +1946,9 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1882
1946
|
class: "font-mono"
|
|
1883
1947
|
}
|
|
1884
1948
|
], {
|
|
1885
|
-
scope:
|
|
1949
|
+
scope: markdownLanguage2,
|
|
1886
1950
|
all: {
|
|
1887
|
-
fontFamily:
|
|
1951
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1888
1952
|
}
|
|
1889
1953
|
});
|
|
1890
1954
|
};
|
|
@@ -1895,16 +1959,16 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1895
1959
|
EditorState.allowMultipleSelections.of(true),
|
|
1896
1960
|
EditorState.tabSize.of(2),
|
|
1897
1961
|
EditorView10.lineWrapping,
|
|
1898
|
-
|
|
1962
|
+
// https://github.com/codemirror/basic-setup
|
|
1899
1963
|
bracketMatching2(),
|
|
1900
1964
|
closeBrackets2(),
|
|
1901
1965
|
crosshairCursor(),
|
|
1902
1966
|
dropCursor(),
|
|
1903
1967
|
drawSelection2(),
|
|
1904
|
-
|
|
1905
|
-
|
|
1968
|
+
highlightActiveLine2(),
|
|
1969
|
+
history2(),
|
|
1906
1970
|
indentOnInput(),
|
|
1907
|
-
_placeholder
|
|
1971
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1908
1972
|
// Main extension.
|
|
1909
1973
|
// https://github.com/codemirror/lang-markdown
|
|
1910
1974
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1914,7 +1978,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1914
1978
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1915
1979
|
// https://github.github.com/gfm
|
|
1916
1980
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1917
|
-
base:
|
|
1981
|
+
base: markdownLanguage3,
|
|
1918
1982
|
// Languages for syntax highlighting fenced code blocks.
|
|
1919
1983
|
codeLanguages: languages,
|
|
1920
1984
|
// Parser extensions.
|
|
@@ -1926,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1926
1990
|
// https://github.com/codemirror/theme-one-dark
|
|
1927
1991
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1928
1992
|
// Custom styles.
|
|
1929
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1993
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly)),
|
|
1994
|
+
keymap4.of([
|
|
1995
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1996
|
+
indentWithTab,
|
|
1997
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1998
|
+
...closeBracketsKeymap,
|
|
1999
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2000
|
+
...historyKeymap,
|
|
2001
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2002
|
+
...searchKeymap,
|
|
2003
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2004
|
+
...standardKeymap
|
|
2005
|
+
])
|
|
2006
|
+
];
|
|
2007
|
+
};
|
|
1944
2008
|
|
|
1945
2009
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1946
2010
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1947
2011
|
var mention = ({ onSearch }) => {
|
|
1948
2012
|
return autocompletion2({
|
|
2013
|
+
// TODO(burdon): Not working.
|
|
2014
|
+
activateOnTyping: true,
|
|
2015
|
+
// activateOnTypingDelay: 100,
|
|
2016
|
+
// selectOnOpen: true,
|
|
1949
2017
|
closeOnBlur: false,
|
|
2018
|
+
// defaultKeymap: false,
|
|
2019
|
+
icons: false,
|
|
1950
2020
|
override: [
|
|
1951
2021
|
(context) => {
|
|
2022
|
+
console.log(context);
|
|
1952
2023
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1953
2024
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1954
2025
|
return null;
|
|
1955
2026
|
}
|
|
1956
|
-
console.log(match);
|
|
1957
2027
|
return {
|
|
1958
2028
|
from: match.from,
|
|
1959
2029
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1965,23 +2035,23 @@ var mention = ({ onSearch }) => {
|
|
|
1965
2035
|
});
|
|
1966
2036
|
};
|
|
1967
2037
|
|
|
1968
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1969
|
-
var
|
|
2038
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2039
|
+
var outliner = (options = {}) => {
|
|
1970
2040
|
return [];
|
|
1971
2041
|
};
|
|
1972
2042
|
|
|
1973
2043
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1974
|
-
import { syntaxTree as
|
|
1975
|
-
import { RangeSetBuilder as RangeSetBuilder3, StateField as
|
|
1976
|
-
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as
|
|
2044
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2045
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
|
|
2046
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1977
2047
|
var table = (options = {}) => {
|
|
1978
|
-
return
|
|
1979
|
-
create: (state) =>
|
|
1980
|
-
update: (_, tr) =>
|
|
2048
|
+
return StateField4.define({
|
|
2049
|
+
create: (state) => update(state, options),
|
|
2050
|
+
update: (_, tr) => update(tr.state, options),
|
|
1981
2051
|
provide: (field) => EditorView11.decorations.from(field)
|
|
1982
2052
|
});
|
|
1983
2053
|
};
|
|
1984
|
-
var
|
|
2054
|
+
var update = (state, options) => {
|
|
1985
2055
|
const builder = new RangeSetBuilder3();
|
|
1986
2056
|
const cursor = state.selection.main.head;
|
|
1987
2057
|
const tables = [];
|
|
@@ -1990,7 +2060,7 @@ var update3 = (state, options) => {
|
|
|
1990
2060
|
const table2 = getTable();
|
|
1991
2061
|
return table2.rows?.[table2.rows.length - 1];
|
|
1992
2062
|
};
|
|
1993
|
-
|
|
2063
|
+
syntaxTree4(state).iterate({
|
|
1994
2064
|
enter: (node) => {
|
|
1995
2065
|
switch (node.name) {
|
|
1996
2066
|
case "Table": {
|
|
@@ -2023,7 +2093,6 @@ var update3 = (state, options) => {
|
|
|
2023
2093
|
tables.forEach((table2) => {
|
|
2024
2094
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2025
2095
|
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
2026
|
-
block: true,
|
|
2027
2096
|
widget: new TableWidget(table2)
|
|
2028
2097
|
}));
|
|
2029
2098
|
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
@@ -2032,13 +2101,13 @@ var update3 = (state, options) => {
|
|
|
2032
2101
|
});
|
|
2033
2102
|
return builder.finish();
|
|
2034
2103
|
};
|
|
2035
|
-
var TableWidget = class extends
|
|
2104
|
+
var TableWidget = class extends WidgetType5 {
|
|
2036
2105
|
constructor(_table) {
|
|
2037
2106
|
super();
|
|
2038
2107
|
this._table = _table;
|
|
2039
2108
|
}
|
|
2040
2109
|
eq(other) {
|
|
2041
|
-
return this._table.
|
|
2110
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
2042
2111
|
}
|
|
2043
2112
|
toDOM(view) {
|
|
2044
2113
|
const table2 = document.createElement("table");
|
|
@@ -2064,89 +2133,104 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2064
2133
|
}
|
|
2065
2134
|
return table2;
|
|
2066
2135
|
}
|
|
2136
|
+
ignoreEvent(e) {
|
|
2137
|
+
return !/^mouse/.test(e.type);
|
|
2138
|
+
}
|
|
2067
2139
|
};
|
|
2068
2140
|
|
|
2069
2141
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2070
|
-
import {
|
|
2142
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2143
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2144
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
2071
2145
|
var styles5 = EditorView12.baseTheme({
|
|
2072
|
-
"& .cm-task
|
|
2073
|
-
|
|
2074
|
-
|
|
2146
|
+
"& .cm-task": {
|
|
2147
|
+
color: getToken("extend.colors.blue.500")
|
|
2148
|
+
},
|
|
2149
|
+
"& .cm-task-checkbox": {
|
|
2150
|
+
marginLeft: "4px",
|
|
2151
|
+
marginRight: "4px"
|
|
2075
2152
|
}
|
|
2076
2153
|
});
|
|
2077
|
-
var CheckboxWidget = class extends
|
|
2078
|
-
constructor(
|
|
2154
|
+
var CheckboxWidget = class extends WidgetType6 {
|
|
2155
|
+
constructor(_checked) {
|
|
2079
2156
|
super();
|
|
2080
|
-
this._pos = _pos;
|
|
2081
2157
|
this._checked = _checked;
|
|
2082
|
-
this._indent = _indent;
|
|
2083
|
-
this._onCheck = _onCheck;
|
|
2084
2158
|
}
|
|
2085
2159
|
eq(other) {
|
|
2086
|
-
return this.
|
|
2160
|
+
return this._checked === other._checked;
|
|
2087
2161
|
}
|
|
2088
2162
|
toDOM(view) {
|
|
2089
|
-
const
|
|
2090
|
-
|
|
2091
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2092
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2093
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2163
|
+
const input = document.createElement("input");
|
|
2164
|
+
input.className = "cm-task-checkbox";
|
|
2094
2165
|
input.type = "checkbox";
|
|
2095
2166
|
input.checked = this._checked;
|
|
2096
|
-
if (
|
|
2167
|
+
if (view.state.readOnly) {
|
|
2097
2168
|
input.setAttribute("disabled", "true");
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2169
|
+
} else {
|
|
2170
|
+
input.onmousedown = (event) => {
|
|
2171
|
+
const pos = view.posAtDOM(input);
|
|
2172
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2173
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2174
|
+
view.dispatch({
|
|
2175
|
+
changes: {
|
|
2176
|
+
from: pos + 1,
|
|
2177
|
+
to: pos + 2,
|
|
2178
|
+
insert: this._checked ? " " : "x"
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
event.preventDefault();
|
|
2182
|
+
}
|
|
2103
2183
|
};
|
|
2104
2184
|
}
|
|
2105
|
-
return
|
|
2185
|
+
return input;
|
|
2106
2186
|
}
|
|
2107
2187
|
ignoreEvent() {
|
|
2108
2188
|
return false;
|
|
2109
2189
|
}
|
|
2110
2190
|
};
|
|
2191
|
+
var checkedDecoration = Decoration8.replace({
|
|
2192
|
+
widget: new CheckboxWidget(true)
|
|
2193
|
+
});
|
|
2194
|
+
var uncheckedDecoration = Decoration8.replace({
|
|
2195
|
+
widget: new CheckboxWidget(false)
|
|
2196
|
+
});
|
|
2197
|
+
var buildDecorations4 = (view) => {
|
|
2198
|
+
const builder = new RangeSetBuilder4();
|
|
2199
|
+
const { state } = view;
|
|
2200
|
+
const cursor = state.selection.main.head;
|
|
2201
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2202
|
+
syntaxTree5(state).iterate({
|
|
2203
|
+
enter: (node) => {
|
|
2204
|
+
if (node.name === "TaskMarker") {
|
|
2205
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2206
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2207
|
+
builder.add(node.from - 2, node.from - 1, Decoration8.mark({
|
|
2208
|
+
class: "cm-task"
|
|
2209
|
+
}));
|
|
2210
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
from,
|
|
2215
|
+
to
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
return builder.finish();
|
|
2219
|
+
};
|
|
2111
2220
|
var tasklist = (options = {}) => {
|
|
2112
|
-
const taskMatcher = new MatchDecorator3({
|
|
2113
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2114
|
-
decoration: (match, view, pos) => {
|
|
2115
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2116
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2117
|
-
return Decoration8.replace({
|
|
2118
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2119
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2120
|
-
view.dispatch({
|
|
2121
|
-
changes: {
|
|
2122
|
-
from: idx,
|
|
2123
|
-
to: idx + 1,
|
|
2124
|
-
insert: checked2 ? "x" : " "
|
|
2125
|
-
},
|
|
2126
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2127
|
-
selection: {
|
|
2128
|
-
anchor: idx + 3
|
|
2129
|
-
}
|
|
2130
|
-
});
|
|
2131
|
-
})
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
});
|
|
2135
|
-
const tasks = ViewPlugin6.fromClass(class {
|
|
2136
|
-
constructor(view) {
|
|
2137
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2138
|
-
}
|
|
2139
|
-
update(update4) {
|
|
2140
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
2141
|
-
}
|
|
2142
|
-
}, {
|
|
2143
|
-
decorations: (value) => value.tasks,
|
|
2144
|
-
provide: (plugin) => EditorView12.atomicRanges.of((view) => {
|
|
2145
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2146
|
-
})
|
|
2147
|
-
});
|
|
2148
2221
|
return [
|
|
2149
|
-
|
|
2222
|
+
ViewPlugin6.fromClass(class {
|
|
2223
|
+
constructor(view) {
|
|
2224
|
+
this.decorations = buildDecorations4(view);
|
|
2225
|
+
}
|
|
2226
|
+
update(update2) {
|
|
2227
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2228
|
+
this.decorations = buildDecorations4(update2.view);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}, {
|
|
2232
|
+
decorations: (v) => v.decorations
|
|
2233
|
+
}),
|
|
2150
2234
|
styles5
|
|
2151
2235
|
];
|
|
2152
2236
|
};
|
|
@@ -2208,29 +2292,8 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2208
2292
|
];
|
|
2209
2293
|
};
|
|
2210
2294
|
|
|
2211
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2212
|
-
import { yCollab } from "y-codemirror.next";
|
|
2213
|
-
|
|
2214
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2215
|
-
import * as Y from "yjs";
|
|
2216
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2217
|
-
var cursorConverter2 = (text) => ({
|
|
2218
|
-
toCursor: (index, assoc) => {
|
|
2219
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2220
|
-
},
|
|
2221
|
-
fromCursor: (cursor) => {
|
|
2222
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2223
|
-
}
|
|
2224
|
-
});
|
|
2225
|
-
|
|
2226
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2227
|
-
var yjs = (content, awareness2) => [
|
|
2228
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2229
|
-
yCollab(content, awareness2)
|
|
2230
|
-
];
|
|
2231
|
-
|
|
2232
2295
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2233
|
-
import
|
|
2296
|
+
import get3 from "lodash.get";
|
|
2234
2297
|
var defaultTheme = {
|
|
2235
2298
|
//
|
|
2236
2299
|
// Main layout:
|
|
@@ -2259,21 +2322,21 @@ var defaultTheme = {
|
|
|
2259
2322
|
"&.cm-focused": {
|
|
2260
2323
|
outline: "none"
|
|
2261
2324
|
},
|
|
2262
|
-
"
|
|
2325
|
+
".cm-scroller": {
|
|
2263
2326
|
overflow: "visible",
|
|
2264
|
-
fontFamily:
|
|
2327
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2265
2328
|
},
|
|
2266
|
-
"
|
|
2329
|
+
".cm-content": {
|
|
2267
2330
|
padding: 0,
|
|
2268
2331
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2269
2332
|
fontSize: "16px"
|
|
2270
2333
|
},
|
|
2271
2334
|
"&light .cm-content": {
|
|
2272
|
-
color:
|
|
2335
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2273
2336
|
caretColor: "black"
|
|
2274
2337
|
},
|
|
2275
2338
|
"&dark .cm-content": {
|
|
2276
|
-
color:
|
|
2339
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2277
2340
|
caretColor: "white"
|
|
2278
2341
|
},
|
|
2279
2342
|
//
|
|
@@ -2285,158 +2348,120 @@ var defaultTheme = {
|
|
|
2285
2348
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2286
2349
|
borderLeft: "2px solid white"
|
|
2287
2350
|
},
|
|
2288
|
-
"
|
|
2351
|
+
".cm-placeholder": {
|
|
2289
2352
|
fontWeight: 100
|
|
2290
2353
|
},
|
|
2291
2354
|
//
|
|
2292
2355
|
// line
|
|
2293
2356
|
//
|
|
2294
|
-
"
|
|
2357
|
+
".cm-line": {
|
|
2295
2358
|
paddingInline: 0
|
|
2296
2359
|
},
|
|
2297
|
-
"
|
|
2360
|
+
".cm-activeLine": {
|
|
2298
2361
|
background: "inherit"
|
|
2299
2362
|
},
|
|
2300
2363
|
//
|
|
2301
2364
|
// Selection
|
|
2302
2365
|
//
|
|
2303
2366
|
"&light .cm-selectionBackground": {
|
|
2304
|
-
background:
|
|
2367
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2305
2368
|
},
|
|
2306
2369
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2307
|
-
background:
|
|
2370
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2308
2371
|
},
|
|
2309
2372
|
"&dark .cm-selectionBackground": {
|
|
2310
|
-
background:
|
|
2373
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2311
2374
|
},
|
|
2312
2375
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2313
|
-
background:
|
|
2376
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2314
2377
|
},
|
|
2315
2378
|
//
|
|
2316
2379
|
// Search
|
|
2317
2380
|
//
|
|
2318
2381
|
"&light .cm-searchMatch": {
|
|
2319
|
-
backgroundColor:
|
|
2382
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2320
2383
|
},
|
|
2321
2384
|
"&dark .cm-searchMatch": {
|
|
2322
|
-
backgroundColor:
|
|
2323
|
-
},
|
|
2324
|
-
//
|
|
2325
|
-
// collaboration
|
|
2326
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2327
|
-
//
|
|
2328
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2329
|
-
mixBlendMode: "multiply"
|
|
2330
|
-
},
|
|
2331
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2332
|
-
mixBlendMode: "screen"
|
|
2333
|
-
},
|
|
2334
|
-
"& .cm-ySelectionInfo": {
|
|
2335
|
-
padding: "2px 4px",
|
|
2336
|
-
marginBlockStart: "-4px"
|
|
2337
|
-
},
|
|
2338
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2339
|
-
paddingBlockStart: ".15em",
|
|
2340
|
-
paddingBlockEnd: ".15em"
|
|
2341
|
-
},
|
|
2342
|
-
"& .cm-ySelectionCaret": {
|
|
2343
|
-
display: "inline-block",
|
|
2344
|
-
insetBlockStart: ".1em",
|
|
2345
|
-
blockSize: "1.4em",
|
|
2346
|
-
verticalAlign: "top"
|
|
2347
|
-
},
|
|
2348
|
-
"& .cm-yLineSelection": {
|
|
2349
|
-
margin: 0
|
|
2385
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2350
2386
|
},
|
|
2351
2387
|
//
|
|
2352
2388
|
// link
|
|
2353
2389
|
//
|
|
2354
|
-
"
|
|
2355
|
-
color:
|
|
2390
|
+
".cm-link": {
|
|
2391
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2356
2392
|
textDecorationLine: "underline",
|
|
2357
2393
|
textDecorationThickness: "1px",
|
|
2358
2394
|
textUnderlineOffset: "2px",
|
|
2359
2395
|
borderRadius: ".125rem",
|
|
2360
|
-
fontFamily:
|
|
2396
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2361
2397
|
},
|
|
2362
2398
|
//
|
|
2363
2399
|
// tooltip
|
|
2364
2400
|
//
|
|
2365
|
-
"
|
|
2401
|
+
".cm-tooltip": {
|
|
2366
2402
|
border: "none"
|
|
2367
2403
|
},
|
|
2368
|
-
"
|
|
2404
|
+
".cm-tooltip-below": {},
|
|
2369
2405
|
//
|
|
2370
2406
|
// autocomplete
|
|
2371
2407
|
//
|
|
2372
|
-
"
|
|
2408
|
+
".cm-tooltip-autocomplete": {
|
|
2373
2409
|
marginTop: "4px",
|
|
2374
2410
|
marginLeft: "-3px"
|
|
2375
2411
|
},
|
|
2376
|
-
"
|
|
2377
|
-
"
|
|
2378
|
-
"
|
|
2412
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2413
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2414
|
+
".cm-completionIcon": {
|
|
2379
2415
|
display: "none"
|
|
2380
2416
|
},
|
|
2381
|
-
"
|
|
2382
|
-
fontFamily:
|
|
2417
|
+
".cm-completionLabel": {
|
|
2418
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2383
2419
|
},
|
|
2384
|
-
"
|
|
2420
|
+
".cm-completionMatchedText": {
|
|
2385
2421
|
textDecoration: "none"
|
|
2386
2422
|
},
|
|
2387
2423
|
//
|
|
2388
|
-
// widgets
|
|
2389
|
-
//
|
|
2390
|
-
"& .cm-widgetBuffer": {
|
|
2391
|
-
display: "none",
|
|
2392
|
-
height: 0
|
|
2393
|
-
},
|
|
2394
|
-
//
|
|
2395
2424
|
// table
|
|
2396
2425
|
//
|
|
2397
|
-
"
|
|
2398
|
-
fontFamily: `${
|
|
2426
|
+
".cm-table *": {
|
|
2427
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2399
2428
|
textDecoration: "none !important"
|
|
2400
2429
|
},
|
|
2401
|
-
"
|
|
2430
|
+
".cm-table-head": {
|
|
2402
2431
|
padding: "2px 16px 2px 0px",
|
|
2403
|
-
borderBottom: `1px solid ${
|
|
2432
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2404
2433
|
fontWeight: 100,
|
|
2405
2434
|
textAlign: "left",
|
|
2406
|
-
color:
|
|
2435
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2407
2436
|
},
|
|
2408
|
-
"
|
|
2437
|
+
".cm-table-cell": {
|
|
2409
2438
|
padding: "2px 16px 2px 0px"
|
|
2410
2439
|
},
|
|
2411
2440
|
//
|
|
2412
2441
|
// image
|
|
2413
2442
|
//
|
|
2414
|
-
"
|
|
2415
|
-
|
|
2443
|
+
".cm-image": {
|
|
2444
|
+
display: "block",
|
|
2445
|
+
height: "0"
|
|
2446
|
+
},
|
|
2447
|
+
".cm-image.cm-loaded-image": {
|
|
2448
|
+
height: "auto",
|
|
2449
|
+
borderTop: "0.5rem solid transparent",
|
|
2450
|
+
borderBottom: "0.5rem solid transparent"
|
|
2416
2451
|
},
|
|
2417
2452
|
//
|
|
2418
2453
|
// font size
|
|
2419
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2454
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2455
|
+
// but it's far more verbose than it needs to be.
|
|
2420
2456
|
//
|
|
2421
|
-
...Object.keys(
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2430
|
-
height
|
|
2431
|
-
};
|
|
2432
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2433
|
-
height
|
|
2434
|
-
};
|
|
2435
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2436
|
-
height
|
|
2437
|
-
};
|
|
2438
|
-
return acc;
|
|
2439
|
-
}, {}),
|
|
2457
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2458
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2459
|
+
//
|
|
2460
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2461
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2462
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2463
|
+
// return acc;
|
|
2464
|
+
// }, {}),
|
|
2440
2465
|
/**
|
|
2441
2466
|
* Panels
|
|
2442
2467
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2453,144 +2478,140 @@ var defaultTheme = {
|
|
|
2453
2478
|
* </div>
|
|
2454
2479
|
* </div
|
|
2455
2480
|
*/
|
|
2456
|
-
"
|
|
2457
|
-
border: `1px solid ${
|
|
2481
|
+
".cm-panels": {
|
|
2482
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2458
2483
|
},
|
|
2459
|
-
"
|
|
2460
|
-
background:
|
|
2461
|
-
fontFamily:
|
|
2484
|
+
".cm-panel": {
|
|
2485
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2486
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2462
2487
|
},
|
|
2463
|
-
"
|
|
2488
|
+
".cm-button": {
|
|
2464
2489
|
margin: "4px",
|
|
2465
|
-
fontFamily:
|
|
2466
|
-
background:
|
|
2490
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2491
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2467
2492
|
backgroundImage: "none",
|
|
2468
2493
|
border: "none",
|
|
2469
2494
|
"&:hover": {
|
|
2470
|
-
background:
|
|
2495
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2471
2496
|
},
|
|
2472
2497
|
"&:active": {
|
|
2473
|
-
background:
|
|
2498
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2474
2499
|
backgroundImage: "none"
|
|
2475
2500
|
}
|
|
2476
2501
|
},
|
|
2477
|
-
"
|
|
2502
|
+
".cm-panel input[type=checkbox]": {
|
|
2478
2503
|
marginRight: "0.4rem !important"
|
|
2479
2504
|
}
|
|
2480
2505
|
};
|
|
2481
2506
|
var textTheme = {
|
|
2482
|
-
"
|
|
2483
|
-
fontFamily:
|
|
2507
|
+
".cm-scroller": {
|
|
2508
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2484
2509
|
},
|
|
2485
|
-
"
|
|
2486
|
-
fontFamily:
|
|
2510
|
+
".cm-placeholder": {
|
|
2511
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2487
2512
|
}
|
|
2488
2513
|
};
|
|
2489
2514
|
var markdownTheme = {
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2515
|
+
".cm-scroller": {
|
|
2516
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2517
|
+
},
|
|
2518
|
+
".cm-placeholder": {
|
|
2519
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2493
2520
|
}
|
|
2494
2521
|
};
|
|
2495
2522
|
var codeTheme = {
|
|
2496
|
-
"
|
|
2497
|
-
fontFamily:
|
|
2523
|
+
".cm-scroller": {
|
|
2524
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2498
2525
|
},
|
|
2499
|
-
"
|
|
2500
|
-
fontFamily:
|
|
2526
|
+
".cm-placeholder": {
|
|
2527
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2501
2528
|
}
|
|
2502
2529
|
};
|
|
2503
2530
|
|
|
2504
2531
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2532
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2505
2533
|
var EditorModes = [
|
|
2506
2534
|
"default",
|
|
2507
2535
|
"vim"
|
|
2508
2536
|
];
|
|
2509
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2510
|
-
const { themeMode } = useThemeContext();
|
|
2537
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2511
2538
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2512
2539
|
tabBehavior: "limited"
|
|
2513
2540
|
});
|
|
2514
|
-
const
|
|
2515
|
-
const
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
state,
|
|
2541
|
+
const { themeMode } = useThemeContext();
|
|
2542
|
+
const rootRef = useRef(null);
|
|
2543
|
+
const [view, setView] = useState(null);
|
|
2544
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2519
2545
|
view
|
|
2520
|
-
}), [
|
|
2521
|
-
view,
|
|
2522
|
-
state,
|
|
2523
|
-
root
|
|
2524
2546
|
]);
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
awareness2.setLocalStateField("user", {
|
|
2529
|
-
name: peer.name ?? generateName(peer.id),
|
|
2530
|
-
color: getColorForValue({
|
|
2531
|
-
value: peer.id,
|
|
2532
|
-
type: "color"
|
|
2533
|
-
}),
|
|
2534
|
-
colorLight: getColorForValue({
|
|
2535
|
-
value: peer.id,
|
|
2536
|
-
themeMode,
|
|
2537
|
-
type: "highlight"
|
|
2538
|
-
})
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
}, [
|
|
2542
|
-
awareness2,
|
|
2543
|
-
peer,
|
|
2544
|
-
themeMode
|
|
2545
|
-
]);
|
|
2546
|
-
useEffect(() => {
|
|
2547
|
-
if (view && comments2?.length) {
|
|
2548
|
-
view.dispatch({
|
|
2549
|
-
effects: setCommentRange.of({
|
|
2550
|
-
model,
|
|
2551
|
-
comments: comments2
|
|
2552
|
-
})
|
|
2553
|
-
});
|
|
2547
|
+
useEffect2(() => {
|
|
2548
|
+
if (autoFocus) {
|
|
2549
|
+
view?.focus();
|
|
2554
2550
|
}
|
|
2555
2551
|
}, [
|
|
2556
2552
|
view,
|
|
2557
|
-
|
|
2553
|
+
autoFocus
|
|
2558
2554
|
]);
|
|
2559
|
-
|
|
2560
|
-
if (!
|
|
2555
|
+
useEffect2(() => {
|
|
2556
|
+
if (!model || !rootRef.current) {
|
|
2561
2557
|
return;
|
|
2562
2558
|
}
|
|
2563
|
-
const
|
|
2559
|
+
const state = EditorState2.create({
|
|
2564
2560
|
doc: model.text(),
|
|
2561
|
+
selection,
|
|
2565
2562
|
extensions: [
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2563
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2564
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2565
|
+
log2.catch(err, void 0, {
|
|
2566
|
+
F: __dxlog_file5,
|
|
2567
|
+
L: 123,
|
|
2568
|
+
S: void 0,
|
|
2569
|
+
C: (f, a) => f(...a)
|
|
2570
|
+
});
|
|
2571
|
+
}),
|
|
2569
2572
|
// Theme.
|
|
2570
|
-
// TODO(burdon): Make
|
|
2573
|
+
// TODO(burdon): Make configurable.
|
|
2571
2574
|
EditorView13.baseTheme(defaultTheme),
|
|
2572
|
-
EditorView13.theme(
|
|
2575
|
+
EditorView13.theme(theme ?? {}),
|
|
2573
2576
|
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2577
|
+
EditorView13.editorAttributes.of({
|
|
2578
|
+
class: slots.editor?.className ?? ""
|
|
2579
|
+
}),
|
|
2580
|
+
EditorView13.contentAttributes.of({
|
|
2581
|
+
class: slots.content?.className ?? ""
|
|
2582
|
+
}),
|
|
2583
|
+
// State.
|
|
2584
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2574
2585
|
// Storage and replication.
|
|
2586
|
+
// NOTE: This must come before user extensions.
|
|
2575
2587
|
model.extension,
|
|
2588
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2589
|
+
editorMode === "vim" && vim(),
|
|
2576
2590
|
// Custom.
|
|
2577
2591
|
...extensions
|
|
2578
2592
|
].filter(Boolean)
|
|
2579
2593
|
});
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2594
|
+
const newView = new EditorView13({
|
|
2595
|
+
state,
|
|
2596
|
+
parent: rootRef.current,
|
|
2597
|
+
scrollTo,
|
|
2598
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2599
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2600
|
+
dispatchTransactions: (trs, view2) => {
|
|
2601
|
+
if (debug) {
|
|
2602
|
+
logChanges(trs);
|
|
2603
|
+
}
|
|
2604
|
+
view2.update(trs);
|
|
2605
|
+
}
|
|
2587
2606
|
});
|
|
2607
|
+
view?.destroy();
|
|
2608
|
+
setView(newView);
|
|
2588
2609
|
return () => {
|
|
2589
|
-
|
|
2590
|
-
|
|
2610
|
+
newView?.destroy();
|
|
2611
|
+
setView(null);
|
|
2591
2612
|
};
|
|
2592
2613
|
}, [
|
|
2593
|
-
|
|
2614
|
+
rootRef,
|
|
2594
2615
|
model,
|
|
2595
2616
|
readonly,
|
|
2596
2617
|
editorMode,
|
|
@@ -2600,11 +2621,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2600
2621
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2601
2622
|
switch (key) {
|
|
2602
2623
|
case "Enter": {
|
|
2603
|
-
view?.
|
|
2624
|
+
view?.focus();
|
|
2604
2625
|
break;
|
|
2605
2626
|
}
|
|
2606
2627
|
case "Escape": {
|
|
2607
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2628
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2629
|
+
rootRef.current?.focus();
|
|
2630
|
+
}
|
|
2608
2631
|
break;
|
|
2609
2632
|
}
|
|
2610
2633
|
}
|
|
@@ -2614,83 +2637,79 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2614
2637
|
]);
|
|
2615
2638
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2616
2639
|
key: model.id,
|
|
2617
|
-
|
|
2640
|
+
role: "none",
|
|
2618
2641
|
tabIndex: 0,
|
|
2619
|
-
|
|
2642
|
+
onKeyUp: handleKeyUp,
|
|
2643
|
+
...slots.root,
|
|
2620
2644
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2621
|
-
|
|
2645
|
+
ref: rootRef
|
|
2622
2646
|
});
|
|
2623
2647
|
});
|
|
2624
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2648
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2625
2649
|
const { themeMode } = useThemeContext();
|
|
2626
|
-
const
|
|
2650
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2627
2651
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2628
2652
|
ref: forwardedRef,
|
|
2629
2653
|
readonly,
|
|
2630
2654
|
extensions: [
|
|
2631
2655
|
basicBundle({
|
|
2632
|
-
readonly,
|
|
2633
2656
|
themeMode,
|
|
2634
|
-
placeholder:
|
|
2657
|
+
placeholder: placeholder3,
|
|
2658
|
+
lineWrapping
|
|
2635
2659
|
}),
|
|
2636
2660
|
...extensions
|
|
2637
2661
|
],
|
|
2638
|
-
|
|
2662
|
+
theme,
|
|
2663
|
+
slots: updatedSlots,
|
|
2639
2664
|
...props
|
|
2640
2665
|
});
|
|
2641
2666
|
});
|
|
2642
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2667
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2643
2668
|
const { themeMode } = useThemeContext();
|
|
2644
|
-
const
|
|
2669
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2645
2670
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2646
2671
|
ref: forwardedRef,
|
|
2647
2672
|
readonly,
|
|
2648
2673
|
extensions: [
|
|
2649
2674
|
markdownBundle({
|
|
2650
|
-
readonly,
|
|
2651
2675
|
themeMode,
|
|
2652
|
-
|
|
2676
|
+
readonly,
|
|
2677
|
+
placeholder: placeholder3
|
|
2653
2678
|
}),
|
|
2654
2679
|
...extensions
|
|
2655
2680
|
],
|
|
2656
|
-
|
|
2681
|
+
theme,
|
|
2682
|
+
slots: updatedSlots,
|
|
2657
2683
|
...props
|
|
2658
2684
|
});
|
|
2659
2685
|
});
|
|
2660
2686
|
var defaultSlots = {
|
|
2661
2687
|
root: {
|
|
2662
|
-
|
|
2688
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2689
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2690
|
+
},
|
|
2691
|
+
editor: {
|
|
2692
|
+
className: "h-full p-2"
|
|
2663
2693
|
}
|
|
2664
2694
|
};
|
|
2665
2695
|
var defaultTextSlots = {
|
|
2666
|
-
...defaultSlots
|
|
2667
|
-
editor: {
|
|
2668
|
-
theme: textTheme
|
|
2669
|
-
}
|
|
2696
|
+
...defaultSlots
|
|
2670
2697
|
};
|
|
2671
2698
|
var defaultMarkdownSlots = {
|
|
2672
|
-
...defaultSlots
|
|
2673
|
-
editor: {
|
|
2674
|
-
theme: markdownTheme
|
|
2675
|
-
}
|
|
2699
|
+
...defaultSlots
|
|
2676
2700
|
};
|
|
2677
2701
|
|
|
2678
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2679
|
-
import get7 from "lodash.get";
|
|
2680
|
-
import { getRawDoc } from "@dxos/echo-schema";
|
|
2681
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2682
|
-
|
|
2683
2702
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2684
2703
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2685
2704
|
import { Context as Context2 } from "@dxos/context";
|
|
2686
|
-
import { invariant as
|
|
2705
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2687
2706
|
import { log as log3 } from "@dxos/log";
|
|
2688
|
-
var
|
|
2707
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2689
2708
|
var DEBOUNCE_INTERVAL = 100;
|
|
2690
2709
|
var SpaceAwarenessProvider = class {
|
|
2691
2710
|
constructor(params) {
|
|
2692
|
-
this.remoteStateChange = new Event2();
|
|
2693
2711
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2712
|
+
this.remoteStateChange = new Event2();
|
|
2694
2713
|
this._space = params.space;
|
|
2695
2714
|
this._channel = params.channel;
|
|
2696
2715
|
this._peerId = params.peerId;
|
|
@@ -2707,7 +2726,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2707
2726
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2708
2727
|
}
|
|
2709
2728
|
});
|
|
2710
|
-
|
|
2729
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2711
2730
|
switch (message.payload.kind) {
|
|
2712
2731
|
case "query": {
|
|
2713
2732
|
this._handleQueryMessage();
|
|
@@ -2718,16 +2737,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2718
2737
|
break;
|
|
2719
2738
|
}
|
|
2720
2739
|
}
|
|
2721
|
-
});
|
|
2722
|
-
this._ctx.onDispose(unsubscribe);
|
|
2740
|
+
}));
|
|
2723
2741
|
void this._space.postMessage(this._channel, {
|
|
2724
2742
|
kind: "query"
|
|
2725
2743
|
}).catch((err) => {
|
|
2726
2744
|
log3.debug("failed to query awareness", {
|
|
2727
2745
|
err
|
|
2728
2746
|
}, {
|
|
2729
|
-
F:
|
|
2730
|
-
L:
|
|
2747
|
+
F: __dxlog_file6,
|
|
2748
|
+
L: 89,
|
|
2731
2749
|
S: this,
|
|
2732
2750
|
C: (f, a) => f(...a)
|
|
2733
2751
|
});
|
|
@@ -2738,10 +2756,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2738
2756
|
this._ctx = void 0;
|
|
2739
2757
|
this._postTask = void 0;
|
|
2740
2758
|
}
|
|
2759
|
+
getRemoteStates() {
|
|
2760
|
+
return Array.from(this._remoteStates.values());
|
|
2761
|
+
}
|
|
2741
2762
|
update(position) {
|
|
2742
|
-
|
|
2743
|
-
F:
|
|
2744
|
-
L:
|
|
2763
|
+
invariant4(this._postTask, void 0, {
|
|
2764
|
+
F: __dxlog_file6,
|
|
2765
|
+
L: 104,
|
|
2745
2766
|
S: this,
|
|
2746
2767
|
A: [
|
|
2747
2768
|
"this._postTask",
|
|
@@ -2755,13 +2776,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2755
2776
|
};
|
|
2756
2777
|
this._postTask.schedule();
|
|
2757
2778
|
}
|
|
2758
|
-
getRemoteStates() {
|
|
2759
|
-
return Array.from(this._remoteStates.values());
|
|
2760
|
-
}
|
|
2761
2779
|
_handleQueryMessage() {
|
|
2762
|
-
|
|
2763
|
-
F:
|
|
2764
|
-
L:
|
|
2780
|
+
invariant4(this._postTask, void 0, {
|
|
2781
|
+
F: __dxlog_file6,
|
|
2782
|
+
L: 115,
|
|
2765
2783
|
S: this,
|
|
2766
2784
|
A: [
|
|
2767
2785
|
"this._postTask",
|
|
@@ -2771,9 +2789,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2771
2789
|
this._postTask.schedule();
|
|
2772
2790
|
}
|
|
2773
2791
|
_handlePostMessage(message) {
|
|
2774
|
-
|
|
2775
|
-
F:
|
|
2776
|
-
L:
|
|
2792
|
+
invariant4(message.kind === "post", void 0, {
|
|
2793
|
+
F: __dxlog_file6,
|
|
2794
|
+
L: 120,
|
|
2777
2795
|
S: this,
|
|
2778
2796
|
A: [
|
|
2779
2797
|
"message.kind === 'post'",
|
|
@@ -2785,201 +2803,54 @@ var SpaceAwarenessProvider = class {
|
|
|
2785
2803
|
}
|
|
2786
2804
|
};
|
|
2787
2805
|
|
|
2788
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2789
|
-
import { StateField as
|
|
2790
|
-
|
|
2791
|
-
|
|
2806
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2807
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
2808
|
+
var modelState = StateField5.define({
|
|
2809
|
+
create: () => void 0,
|
|
2810
|
+
update: (model) => model
|
|
2811
|
+
});
|
|
2792
2812
|
|
|
2793
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2794
|
-
import
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
import { log as log4 } from "@dxos/log";
|
|
2801
|
-
import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
|
|
2802
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2803
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2804
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2805
|
-
F: __dxlog_file5,
|
|
2806
|
-
L: 23,
|
|
2807
|
-
S: void 0,
|
|
2808
|
-
A: [
|
|
2809
|
-
"text?.doc && text?.content",
|
|
2810
|
-
""
|
|
2811
|
-
]
|
|
2812
|
-
});
|
|
2813
|
-
const provider = space ? new YAwarenessProvider({
|
|
2814
|
-
space,
|
|
2815
|
-
doc: text.doc,
|
|
2816
|
-
channel: `yjs.awareness.${text.id}`
|
|
2817
|
-
}) : void 0;
|
|
2818
|
-
const model = {
|
|
2819
|
-
id: text.doc.guid,
|
|
2820
|
-
content: text.content,
|
|
2821
|
-
text: () => text.content.toString(),
|
|
2822
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2823
|
-
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2824
|
-
getCursorFromRange: (range) => {
|
|
2825
|
-
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2826
|
-
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2827
|
-
return [
|
|
2828
|
-
arrayToString2(from),
|
|
2829
|
-
arrayToString2(to)
|
|
2830
|
-
].join(":");
|
|
2831
|
-
},
|
|
2832
|
-
getRangeFromCursor: (cursor) => {
|
|
2833
|
-
invariant4(text.doc, void 0, {
|
|
2834
|
-
F: __dxlog_file5,
|
|
2835
|
-
L: 40,
|
|
2836
|
-
S: void 0,
|
|
2837
|
-
A: [
|
|
2838
|
-
"text.doc",
|
|
2839
|
-
""
|
|
2840
|
-
]
|
|
2841
|
-
});
|
|
2842
|
-
const parts = cursor.split(":");
|
|
2843
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2844
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2845
|
-
return from && to ? {
|
|
2846
|
-
from: from.index,
|
|
2847
|
-
to: to.index
|
|
2848
|
-
} : void 0;
|
|
2813
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
2814
|
+
import { useState as useState2 } from "react";
|
|
2815
|
+
var useTextEditor = () => {
|
|
2816
|
+
const [view, setView] = useState2(null);
|
|
2817
|
+
return [
|
|
2818
|
+
(ref) => {
|
|
2819
|
+
setView(ref);
|
|
2849
2820
|
},
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
yjs(text.content, provider?.awareness)
|
|
2853
|
-
],
|
|
2854
|
-
awareness: provider?.awareness,
|
|
2855
|
-
peer: identity ? {
|
|
2856
|
-
id: identity.identityKey.toHex(),
|
|
2857
|
-
name: identity.profile?.displayName
|
|
2858
|
-
} : void 0
|
|
2859
|
-
};
|
|
2860
|
-
return model;
|
|
2861
|
-
};
|
|
2862
|
-
var messageAwareness = 1;
|
|
2863
|
-
var messageQueryAwareness = 3;
|
|
2864
|
-
var YAwarenessProvider = class extends Observable {
|
|
2865
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2866
|
-
super();
|
|
2867
|
-
this._space = space;
|
|
2868
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2869
|
-
this._channel = channel;
|
|
2870
|
-
this._clientId = doc.clientID;
|
|
2871
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2872
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2873
|
-
if (typeof window !== "undefined") {
|
|
2874
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2875
|
-
} else if (typeof process !== "undefined") {
|
|
2876
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2877
|
-
}
|
|
2878
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2879
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2880
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2881
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2882
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2883
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2884
|
-
this._clientId
|
|
2885
|
-
]));
|
|
2886
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2887
|
-
}
|
|
2888
|
-
get awareness() {
|
|
2889
|
-
return this._awareness;
|
|
2890
|
-
}
|
|
2891
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2892
|
-
log4("awareness update", {
|
|
2893
|
-
added,
|
|
2894
|
-
updated,
|
|
2895
|
-
removed,
|
|
2896
|
-
origin
|
|
2897
|
-
}, {
|
|
2898
|
-
F: __dxlog_file5,
|
|
2899
|
-
L: 122,
|
|
2900
|
-
S: this,
|
|
2901
|
-
C: (f, a) => f(...a)
|
|
2902
|
-
});
|
|
2903
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2904
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2905
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2906
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2907
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2908
|
-
}
|
|
2909
|
-
_handleSpaceMessage({ payload }) {
|
|
2910
|
-
log4("space message", payload, {
|
|
2911
|
-
F: __dxlog_file5,
|
|
2912
|
-
L: 131,
|
|
2913
|
-
S: this,
|
|
2914
|
-
C: (f, a) => f(...a)
|
|
2915
|
-
});
|
|
2916
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2917
|
-
const encoder = this._readMessage(data);
|
|
2918
|
-
if (encoder) {
|
|
2919
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
_readMessage(message) {
|
|
2923
|
-
const decoder = decoding.createDecoder(message);
|
|
2924
|
-
const encoder = encoding.createEncoder();
|
|
2925
|
-
const messageType = decoding.readVarUint(decoder);
|
|
2926
|
-
let sendReply = false;
|
|
2927
|
-
switch (messageType) {
|
|
2928
|
-
case messageAwareness: {
|
|
2929
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2930
|
-
break;
|
|
2931
|
-
}
|
|
2932
|
-
case messageQueryAwareness: {
|
|
2933
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
2934
|
-
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2935
|
-
sendReply = true;
|
|
2936
|
-
break;
|
|
2937
|
-
}
|
|
2938
|
-
default: {
|
|
2939
|
-
console.error("Invalid message:", messageType);
|
|
2940
|
-
return encoder;
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
if (!sendReply) {
|
|
2944
|
-
return null;
|
|
2945
|
-
}
|
|
2946
|
-
return encoder;
|
|
2947
|
-
}
|
|
2948
|
-
_handleBeforeUnload() {
|
|
2949
|
-
YP.removeAwarenessStates(this._awareness, [
|
|
2950
|
-
this._clientId
|
|
2951
|
-
], "window unload");
|
|
2952
|
-
}
|
|
2821
|
+
view
|
|
2822
|
+
];
|
|
2953
2823
|
};
|
|
2954
2824
|
|
|
2955
2825
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
}
|
|
2826
|
+
import get4 from "lodash.get";
|
|
2827
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
2828
|
+
import { generateName } from "@dxos/display-name";
|
|
2829
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2830
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2831
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2832
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2833
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2960
2834
|
var useTextModel = (props) => {
|
|
2961
2835
|
const { identity, space, text } = props;
|
|
2962
|
-
const [model, setModel] =
|
|
2963
|
-
|
|
2836
|
+
const [model, setModel] = useState3();
|
|
2837
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2964
2838
|
identity,
|
|
2965
2839
|
space,
|
|
2966
2840
|
text
|
|
2967
2841
|
]);
|
|
2968
2842
|
return model;
|
|
2969
2843
|
};
|
|
2970
|
-
var createModel = (
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
};
|
|
2980
|
-
|
|
2981
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2982
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2844
|
+
var createModel = ({ space, identity, text }) => {
|
|
2845
|
+
invariant5(isAutomergeObject(text), void 0, {
|
|
2846
|
+
F: __dxlog_file7,
|
|
2847
|
+
L: 35,
|
|
2848
|
+
S: void 0,
|
|
2849
|
+
A: [
|
|
2850
|
+
"isAutomergeObject(text)",
|
|
2851
|
+
""
|
|
2852
|
+
]
|
|
2853
|
+
});
|
|
2983
2854
|
const obj = text;
|
|
2984
2855
|
const doc = getRawDoc(obj, [
|
|
2985
2856
|
obj.field
|
|
@@ -2988,7 +2859,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2988
2859
|
space,
|
|
2989
2860
|
channel: `automerge.awareness.${obj.id}`,
|
|
2990
2861
|
info: {
|
|
2991
|
-
displayName: identity
|
|
2862
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2992
2863
|
color: cursorColor.color,
|
|
2993
2864
|
lightColor: cursorColor.light
|
|
2994
2865
|
},
|
|
@@ -2997,8 +2868,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2997
2868
|
const model = {
|
|
2998
2869
|
id: obj.id,
|
|
2999
2870
|
content: doc,
|
|
3000
|
-
text: () =>
|
|
3001
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2871
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3002
2872
|
extension: [
|
|
3003
2873
|
modelState.init(() => model),
|
|
3004
2874
|
automerge3({
|
|
@@ -3018,6 +2888,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3018
2888
|
export {
|
|
3019
2889
|
AwarenessProvider,
|
|
3020
2890
|
BaseTextEditor,
|
|
2891
|
+
Cursor,
|
|
3021
2892
|
Doc,
|
|
3022
2893
|
EditorModes,
|
|
3023
2894
|
MarkdownEditor,
|
|
@@ -3025,7 +2896,6 @@ export {
|
|
|
3025
2896
|
SpaceAwarenessProvider,
|
|
3026
2897
|
TextEditor,
|
|
3027
2898
|
TextKind,
|
|
3028
|
-
YAwarenessProvider,
|
|
3029
2899
|
YText,
|
|
3030
2900
|
YXmlFragment,
|
|
3031
2901
|
autocomplete,
|
|
@@ -3033,29 +2903,30 @@ export {
|
|
|
3033
2903
|
awareness,
|
|
3034
2904
|
basicBundle,
|
|
3035
2905
|
blast,
|
|
2906
|
+
callbackWrapper,
|
|
3036
2907
|
code2 as code,
|
|
3037
2908
|
codeTheme,
|
|
3038
2909
|
comments,
|
|
3039
|
-
createAutomergeModel,
|
|
3040
|
-
createYjsModel,
|
|
3041
2910
|
defaultMarkdownSlots,
|
|
3042
2911
|
defaultOptions,
|
|
3043
2912
|
defaultSlots,
|
|
3044
2913
|
defaultTextSlots,
|
|
3045
2914
|
defaultTheme,
|
|
2915
|
+
getToken,
|
|
3046
2916
|
hr,
|
|
3047
2917
|
image,
|
|
3048
2918
|
link,
|
|
3049
2919
|
listener,
|
|
2920
|
+
logChanges,
|
|
3050
2921
|
markdownBundle,
|
|
3051
2922
|
markdownHighlightStyle,
|
|
3052
2923
|
markdownTags,
|
|
3053
2924
|
markdownTagsExtensions,
|
|
3054
2925
|
markdownTheme,
|
|
3055
2926
|
mention,
|
|
3056
|
-
mermaid,
|
|
3057
2927
|
modelState,
|
|
3058
|
-
|
|
2928
|
+
outliner,
|
|
2929
|
+
setComments,
|
|
3059
2930
|
setFocus,
|
|
3060
2931
|
setSelection,
|
|
3061
2932
|
table,
|
|
@@ -3063,7 +2934,8 @@ export {
|
|
|
3063
2934
|
tasklist,
|
|
3064
2935
|
textTheme,
|
|
3065
2936
|
typewriter,
|
|
3066
|
-
|
|
3067
|
-
|
|
2937
|
+
useComments,
|
|
2938
|
+
useTextEditor,
|
|
2939
|
+
useTextModel
|
|
3068
2940
|
};
|
|
3069
2941
|
//# sourceMappingURL=index.mjs.map
|