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