@dxos/react-ui-editor 0.3.11-main.4d95695 → 0.3.11-main.4faaf44
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 +1020 -1022
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -14
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +13 -5
- 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.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 +6 -8
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +6 -6
- 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 +18 -14
- 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 +91 -66
- package/src/components/TextEditor/comments.stories.tsx +45 -43
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.ts +35 -39
- package/src/extensions/automerge/defs.ts +8 -33
- package/src/extensions/automerge/semaphore.ts +17 -12
- package/src/extensions/automerge/update-automerge.ts +2 -2
- package/src/extensions/awareness.ts +14 -14
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/comments.ts +161 -141
- 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} +1 -2
- package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +48 -34
- 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 +2 -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 -104
- package/src/extensions/hr.ts +0 -72
- 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
|
|
@@ -52,8 +54,9 @@ var autocomplete = ({ onSearch }) => {
|
|
|
52
54
|
|
|
53
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
56
|
import { StateField } from "@codemirror/state";
|
|
55
|
-
import { ViewPlugin } from "@codemirror/view";
|
|
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";
|
|
@@ -92,18 +95,15 @@ var cursorConverter = (handle, path) => ({
|
|
|
92
95
|
});
|
|
93
96
|
|
|
94
97
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
|
-
import { Annotation, StateEffect
|
|
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
|
-
var semaphoreFacet = Facet.define({
|
|
105
|
-
combine: (values) => values.at(-1)
|
|
106
|
-
});
|
|
107
107
|
|
|
108
108
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
109
|
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
@@ -240,59 +240,62 @@ var charPath = (textPath, candidatePath) => {
|
|
|
240
240
|
|
|
241
241
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
242
|
var PatchSemaphore = class {
|
|
243
|
-
|
|
243
|
+
// prettier-ignore
|
|
244
|
+
constructor(_handle, _state) {
|
|
244
245
|
this._handle = _handle;
|
|
245
|
-
this.
|
|
246
|
+
this._state = _state;
|
|
246
247
|
this._inReconcile = false;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
annotations: reconcileAnnotationType.of(true)
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
let newHeads = updateAutomerge(this._field, this._handle, transactions, view.state);
|
|
266
|
-
if (newHeads === null || newHeads === void 0) {
|
|
267
|
-
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
268
|
-
}
|
|
269
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
270
|
-
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);
|
|
271
263
|
view.dispatch({
|
|
272
|
-
|
|
273
|
-
annotations: reconcileAnnotationType.of(
|
|
264
|
+
changes: inverted,
|
|
265
|
+
annotations: reconcileAnnotationType.of(true)
|
|
274
266
|
});
|
|
275
|
-
|
|
276
|
-
|
|
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;
|
|
277
279
|
}
|
|
278
280
|
};
|
|
279
281
|
|
|
280
282
|
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
281
|
-
import { Facet
|
|
283
|
+
import { Facet } from "@codemirror/state";
|
|
282
284
|
var defaultCursorConverter = {
|
|
283
285
|
toCursor: (position) => position.toString(),
|
|
284
286
|
fromCursor: (cursor) => parseInt(cursor)
|
|
285
287
|
};
|
|
286
|
-
var Cursor = class {
|
|
288
|
+
var Cursor = class _Cursor {
|
|
287
289
|
static {
|
|
288
|
-
this.converter =
|
|
290
|
+
this.converter = Facet.define({
|
|
289
291
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
290
292
|
});
|
|
291
293
|
}
|
|
292
294
|
static {
|
|
293
|
-
this.getCursorFromRange = (
|
|
294
|
-
const
|
|
295
|
-
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);
|
|
296
299
|
return [
|
|
297
300
|
from,
|
|
298
301
|
to
|
|
@@ -300,10 +303,11 @@ var Cursor = class {
|
|
|
300
303
|
};
|
|
301
304
|
}
|
|
302
305
|
static {
|
|
303
|
-
this.getRangeFromCursor = (
|
|
306
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
304
308
|
const parts = cursor.split(":");
|
|
305
|
-
const from =
|
|
306
|
-
const to =
|
|
309
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
310
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
307
311
|
return from !== void 0 && to !== void 0 ? {
|
|
308
312
|
from,
|
|
309
313
|
to
|
|
@@ -313,18 +317,19 @@ var Cursor = class {
|
|
|
313
317
|
};
|
|
314
318
|
|
|
315
319
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
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(handle,
|
|
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,39 +572,41 @@ 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",
|
|
609
|
+
borderRadius: "2px",
|
|
598
610
|
// These should be separate.
|
|
599
611
|
opacity: 0,
|
|
600
612
|
transitionDelay: "0s",
|
|
@@ -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,165 +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 buildDecorations4 = (view) => {
|
|
1063
|
-
const decorations = [];
|
|
1064
|
-
const text = view.state.doc.sliceString(0);
|
|
1065
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1066
|
-
const blocks = view.viewportLineBlocks;
|
|
1067
|
-
for (const match of matches) {
|
|
1068
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1069
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1070
|
-
const block = blocks[i];
|
|
1071
|
-
decorations.push(Decoration2.line({
|
|
1072
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1073
|
-
}).range(block.from));
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
return Decoration2.set(decorations);
|
|
1077
|
-
};
|
|
1078
|
-
return [
|
|
1079
|
-
ViewPlugin3.fromClass(class {
|
|
1080
|
-
constructor(view) {
|
|
1081
|
-
this.hasFocus = false;
|
|
1082
|
-
this.decorations = buildDecorations4(view);
|
|
1083
|
-
}
|
|
1084
|
-
update(update2) {
|
|
1085
|
-
if (
|
|
1086
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1087
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1088
|
-
) {
|
|
1089
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1090
|
-
this.decorations = buildDecorations4(update2.view);
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}, {
|
|
1094
|
-
decorations: (value) => value.decorations
|
|
1095
|
-
}),
|
|
1096
|
-
styles2
|
|
1097
|
-
];
|
|
1098
|
-
};
|
|
1099
|
-
|
|
1100
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1101
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1102
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
1103
|
-
import sortBy from "lodash.sortby";
|
|
1104
|
-
import { debounce } from "@dxos/async";
|
|
1105
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1106
|
-
import { nonNullable } from "@dxos/util";
|
|
1107
|
-
|
|
1108
1026
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1109
1027
|
import { log } from "@dxos/log";
|
|
1110
|
-
var
|
|
1028
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1111
1029
|
var callbackWrapper = (fn) => (...args) => {
|
|
1112
1030
|
try {
|
|
1113
1031
|
return fn(...args);
|
|
1114
|
-
} catch (
|
|
1115
|
-
log.catch(
|
|
1116
|
-
F:
|
|
1117
|
-
L:
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
log.catch(err, void 0, {
|
|
1034
|
+
F: __dxlog_file3,
|
|
1035
|
+
L: 18,
|
|
1118
1036
|
S: void 0,
|
|
1119
1037
|
C: (f, a) => f(...a)
|
|
1120
1038
|
});
|
|
1121
1039
|
}
|
|
1122
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
|
+
};
|
|
1123
1060
|
|
|
1124
1061
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1125
|
-
var
|
|
1126
|
-
var
|
|
1062
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1063
|
+
var styles2 = EditorView5.baseTheme({
|
|
1127
1064
|
"& .cm-comment": {
|
|
1128
1065
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1129
1066
|
},
|
|
1130
|
-
"& .cm-comment-
|
|
1067
|
+
"& .cm-comment-current": {
|
|
1131
1068
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1132
1069
|
}
|
|
1133
1070
|
});
|
|
1134
1071
|
var marks = {
|
|
1135
|
-
highlight:
|
|
1072
|
+
highlight: Decoration2.mark({
|
|
1136
1073
|
class: "cm-comment"
|
|
1137
1074
|
}),
|
|
1138
|
-
highlightActive:
|
|
1139
|
-
class: "cm-comment-
|
|
1075
|
+
highlightActive: Decoration2.mark({
|
|
1076
|
+
class: "cm-comment-current"
|
|
1140
1077
|
})
|
|
1141
1078
|
};
|
|
1142
|
-
var setFocus = (view,
|
|
1143
|
-
const
|
|
1144
|
-
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) {
|
|
1145
1082
|
return;
|
|
1146
1083
|
}
|
|
1147
|
-
view.
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
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
|
+
}
|
|
1156
1101
|
};
|
|
1157
|
-
var
|
|
1102
|
+
var setComments = StateEffect2.define();
|
|
1158
1103
|
var setSelection = StateEffect2.define();
|
|
1159
1104
|
var setCommentState = StateEffect2.define();
|
|
1160
|
-
var
|
|
1105
|
+
var commentsState = StateField2.define({
|
|
1161
1106
|
create: () => ({
|
|
1162
|
-
|
|
1107
|
+
comments: [],
|
|
1108
|
+
selection: {}
|
|
1163
1109
|
}),
|
|
1164
1110
|
update: (value, tr) => {
|
|
1165
|
-
const cursorConverter3 = tr.state.facet(Cursor.converter);
|
|
1166
1111
|
for (const effect of tr.effects) {
|
|
1167
1112
|
if (effect.is(setSelection)) {
|
|
1168
1113
|
return {
|
|
1169
1114
|
...value,
|
|
1170
|
-
|
|
1115
|
+
selection: effect.value
|
|
1171
1116
|
};
|
|
1172
1117
|
}
|
|
1173
|
-
if (effect.is(
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
|
|
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);
|
|
1177
1124
|
return range && {
|
|
1178
|
-
|
|
1179
|
-
|
|
1125
|
+
comment,
|
|
1126
|
+
range
|
|
1180
1127
|
};
|
|
1181
1128
|
}).filter(nonNullable);
|
|
1182
1129
|
return {
|
|
1183
1130
|
...value,
|
|
1184
|
-
|
|
1131
|
+
comments: comments2
|
|
1185
1132
|
};
|
|
1186
1133
|
}
|
|
1187
1134
|
if (effect.is(setCommentState)) {
|
|
@@ -1192,38 +1139,36 @@ var commentsStateField = StateField2.define({
|
|
|
1192
1139
|
}
|
|
1193
1140
|
});
|
|
1194
1141
|
var highlightDecorations = EditorView5.decorations.compute([
|
|
1195
|
-
|
|
1142
|
+
commentsState
|
|
1196
1143
|
], (state) => {
|
|
1197
|
-
const {
|
|
1198
|
-
const decorations = sortBy(
|
|
1199
|
-
|
|
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);
|
|
1200
1149
|
return void 0;
|
|
1201
1150
|
}
|
|
1202
|
-
|
|
1203
|
-
from: selection.from,
|
|
1204
|
-
to: selection.to
|
|
1205
|
-
};
|
|
1206
|
-
if (selection.id === active) {
|
|
1151
|
+
if (comment.comment.id === current) {
|
|
1207
1152
|
return marks.highlightActive.range(range.from, range.to);
|
|
1208
1153
|
} else {
|
|
1209
1154
|
return marks.highlight.range(range.from, range.to);
|
|
1210
1155
|
}
|
|
1211
|
-
}).filter(nonNullable)
|
|
1212
|
-
return
|
|
1156
|
+
}).filter(nonNullable);
|
|
1157
|
+
return Decoration2.set(decorations);
|
|
1213
1158
|
});
|
|
1214
1159
|
var trackPastedComments = (onUpdate) => {
|
|
1215
1160
|
let tracked = null;
|
|
1216
1161
|
const handleTrack = (event, view) => {
|
|
1217
|
-
const comments2 = view.state.field(
|
|
1162
|
+
const comments2 = view.state.field(commentsState);
|
|
1218
1163
|
const { main } = view.state.selection;
|
|
1219
|
-
const selectedRanges = comments2.
|
|
1164
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1220
1165
|
if (!selectedRanges.length) {
|
|
1221
1166
|
tracked = null;
|
|
1222
1167
|
} else {
|
|
1223
1168
|
tracked = {
|
|
1224
1169
|
text: view.state.doc.slice(main.from, main.to),
|
|
1225
|
-
comments: selectedRanges.map((range) => ({
|
|
1226
|
-
id:
|
|
1170
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1171
|
+
id: comment.id,
|
|
1227
1172
|
from: range.from - main.from,
|
|
1228
1173
|
to: range.to - main.from
|
|
1229
1174
|
}))
|
|
@@ -1250,18 +1195,13 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1250
1195
|
}
|
|
1251
1196
|
});
|
|
1252
1197
|
if (found > -1) {
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
to: found + moved.to
|
|
1261
|
-
};
|
|
1262
|
-
const cursor = Cursor.getCursorFromRange(state.facet(Cursor.converter), range);
|
|
1263
|
-
onUpdate(moved.id, cursor);
|
|
1264
|
-
}
|
|
1198
|
+
for (const moved of tracked.comments) {
|
|
1199
|
+
const range = {
|
|
1200
|
+
from: found + moved.from,
|
|
1201
|
+
to: found + moved.to
|
|
1202
|
+
};
|
|
1203
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1204
|
+
onUpdate(moved.id, cursor);
|
|
1265
1205
|
}
|
|
1266
1206
|
}
|
|
1267
1207
|
tracked = null;
|
|
@@ -1274,10 +1214,9 @@ var comments = (options = {}) => {
|
|
|
1274
1214
|
const { key: shortcut = "meta-'" } = options;
|
|
1275
1215
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1276
1216
|
const createCommentThread = (view) => {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
L: 264,
|
|
1217
|
+
invariant3(options.onCreate, void 0, {
|
|
1218
|
+
F: __dxlog_file4,
|
|
1219
|
+
L: 259,
|
|
1281
1220
|
S: void 0,
|
|
1282
1221
|
A: [
|
|
1283
1222
|
"options.onCreate",
|
|
@@ -1288,16 +1227,24 @@ var comments = (options = {}) => {
|
|
|
1288
1227
|
if (from === to) {
|
|
1289
1228
|
return false;
|
|
1290
1229
|
}
|
|
1291
|
-
|
|
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, {
|
|
1292
1239
|
from,
|
|
1293
1240
|
to
|
|
1294
1241
|
});
|
|
1295
1242
|
if (cursor) {
|
|
1296
|
-
const id =
|
|
1243
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1297
1244
|
if (id) {
|
|
1298
1245
|
view.dispatch({
|
|
1299
1246
|
effects: setSelection.of({
|
|
1300
|
-
|
|
1247
|
+
current: id
|
|
1301
1248
|
}),
|
|
1302
1249
|
selection: {
|
|
1303
1250
|
anchor: from
|
|
@@ -1309,9 +1256,9 @@ var comments = (options = {}) => {
|
|
|
1309
1256
|
return false;
|
|
1310
1257
|
};
|
|
1311
1258
|
return [
|
|
1312
|
-
|
|
1259
|
+
commentsState,
|
|
1313
1260
|
highlightDecorations,
|
|
1314
|
-
|
|
1261
|
+
styles2,
|
|
1315
1262
|
//
|
|
1316
1263
|
// Keymap.
|
|
1317
1264
|
//
|
|
@@ -1352,386 +1299,145 @@ var comments = (options = {}) => {
|
|
|
1352
1299
|
hoverTime: 1e3
|
|
1353
1300
|
}) : [],
|
|
1354
1301
|
//
|
|
1355
|
-
//
|
|
1356
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1302
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1357
1303
|
//
|
|
1358
1304
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1359
|
-
|
|
1360
|
-
{
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
1367
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1368
|
-
options.onDelete?.(range.id);
|
|
1369
|
-
}
|
|
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);
|
|
1370
1313
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
}
|
|
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
|
+
})
|
|
1377
1328
|
});
|
|
1378
|
-
if (mod) {
|
|
1379
|
-
view.dispatch({
|
|
1380
|
-
effects: setCommentState.of({
|
|
1381
|
-
active,
|
|
1382
|
-
ranges
|
|
1383
|
-
})
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
1329
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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));
|
|
1400
1346
|
if (d < min) {
|
|
1401
|
-
|
|
1347
|
+
selection.closest = comment.id;
|
|
1402
1348
|
min = d;
|
|
1403
1349
|
}
|
|
1404
|
-
});
|
|
1405
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1406
|
-
view.dispatch({
|
|
1407
|
-
effects: setSelection.of(selected)
|
|
1408
|
-
});
|
|
1409
|
-
handleSelect({
|
|
1410
|
-
...selected,
|
|
1411
|
-
ranges: ranges.map((range) => ({
|
|
1412
|
-
...range,
|
|
1413
|
-
location: view.coordsAtPos(range.from)
|
|
1414
|
-
}))
|
|
1415
|
-
});
|
|
1416
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
|
+
});
|
|
1417
1364
|
}
|
|
1418
1365
|
}),
|
|
1419
1366
|
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1420
1367
|
];
|
|
1421
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
|
+
};
|
|
1422
1381
|
|
|
1423
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1424
|
-
import {
|
|
1425
|
-
var
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
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
|
+
}
|
|
1430
1433
|
}
|
|
1431
1434
|
});
|
|
1432
|
-
var
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
return this._pos === other._pos;
|
|
1439
|
-
}
|
|
1440
|
-
toDOM(view) {
|
|
1441
|
-
const el = document.createElement("div");
|
|
1442
|
-
el.className = "cm-hr";
|
|
1443
|
-
return el;
|
|
1444
|
-
}
|
|
1445
|
-
};
|
|
1446
|
-
var placeholderMatcher = new MatchDecorator({
|
|
1447
|
-
// regexp: /(?<=\n\n)---/gs,
|
|
1448
|
-
regexp: /^---$/gs,
|
|
1449
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1450
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1451
|
-
})
|
|
1452
|
-
});
|
|
1453
|
-
var hr = () => [
|
|
1454
|
-
styles4,
|
|
1455
|
-
ViewPlugin4.fromClass(class {
|
|
1456
|
-
constructor(view) {
|
|
1457
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1458
|
-
}
|
|
1459
|
-
update(update2) {
|
|
1460
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1461
|
-
}
|
|
1462
|
-
}, {
|
|
1463
|
-
decorations: (instance) => instance.rules
|
|
1464
|
-
})
|
|
1465
|
-
];
|
|
1466
|
-
|
|
1467
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1468
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1469
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1470
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1471
|
-
var image = (options = {}) => {
|
|
1472
|
-
return StateField3.define({
|
|
1473
|
-
create: (state) => {
|
|
1474
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1475
|
-
},
|
|
1476
|
-
update: (value, tr) => {
|
|
1477
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1478
|
-
return value;
|
|
1479
|
-
}
|
|
1480
|
-
const cursor = tr.state.selection.main.head;
|
|
1481
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1482
|
-
let from = Math.min(cursor, oldCursor);
|
|
1483
|
-
let to = Math.max(cursor, oldCursor);
|
|
1484
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1485
|
-
from = Math.min(from, fromB);
|
|
1486
|
-
to = Math.max(to, toB);
|
|
1487
|
-
});
|
|
1488
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1489
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1490
|
-
return value.map(tr.changes).update({
|
|
1491
|
-
filterFrom: from,
|
|
1492
|
-
filterTo: to,
|
|
1493
|
-
filter: () => false,
|
|
1494
|
-
add: buildDecorations(from, to, tr.state)
|
|
1495
|
-
});
|
|
1496
|
-
},
|
|
1497
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1498
|
-
});
|
|
1499
|
-
};
|
|
1500
|
-
var buildDecorations = (from, to, state) => {
|
|
1501
|
-
const decorations = [];
|
|
1502
|
-
const cursor = state.selection.main.head;
|
|
1503
|
-
syntaxTree(state).iterate({
|
|
1504
|
-
enter: (node) => {
|
|
1505
|
-
if (node.name === "Image") {
|
|
1506
|
-
const urlNode = node.node.getChild("URL");
|
|
1507
|
-
if (urlNode) {
|
|
1508
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1509
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1510
|
-
decorations.push(Decoration5.replace({
|
|
1511
|
-
block: true,
|
|
1512
|
-
widget: new ImageWidget(url)
|
|
1513
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
},
|
|
1517
|
-
from,
|
|
1518
|
-
to
|
|
1519
|
-
});
|
|
1520
|
-
return decorations;
|
|
1521
|
-
};
|
|
1522
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1523
|
-
constructor(_url) {
|
|
1524
|
-
super();
|
|
1525
|
-
this._url = _url;
|
|
1526
|
-
}
|
|
1527
|
-
eq(other) {
|
|
1528
|
-
return this._url === other._url;
|
|
1529
|
-
}
|
|
1530
|
-
toDOM(view) {
|
|
1531
|
-
const img = document.createElement("img");
|
|
1532
|
-
img.setAttribute("src", this._url);
|
|
1533
|
-
img.setAttribute("class", "cm-image");
|
|
1534
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1535
|
-
return img;
|
|
1536
|
-
}
|
|
1537
|
-
};
|
|
1538
|
-
|
|
1539
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1540
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1541
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1542
|
-
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1543
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1544
|
-
var link = (options = {}) => {
|
|
1545
|
-
const extensions = [
|
|
1546
|
-
ViewPlugin5.fromClass(class {
|
|
1547
|
-
constructor(view) {
|
|
1548
|
-
this.decorations = buildDecorations2(view, options);
|
|
1549
|
-
}
|
|
1550
|
-
update(update2) {
|
|
1551
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1552
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
}, {
|
|
1556
|
-
decorations: (v) => v.decorations
|
|
1557
|
-
})
|
|
1558
|
-
];
|
|
1559
|
-
if (options.onHover) {
|
|
1560
|
-
extensions.push(
|
|
1561
|
-
// https://codemirror.net/examples/tooltip
|
|
1562
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1563
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1564
|
-
hoverTooltip2((view, pos, side) => {
|
|
1565
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1566
|
-
let link2 = null;
|
|
1567
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1568
|
-
link2 = node.name === "Link" ? node : null;
|
|
1569
|
-
}
|
|
1570
|
-
const url = link2 && link2.getChild("URL");
|
|
1571
|
-
if (!url || !link2) {
|
|
1572
|
-
return null;
|
|
1573
|
-
}
|
|
1574
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1575
|
-
return {
|
|
1576
|
-
pos: link2.from,
|
|
1577
|
-
end: link2.to,
|
|
1578
|
-
above: true,
|
|
1579
|
-
create: () => {
|
|
1580
|
-
const el = document.createElement("div");
|
|
1581
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1582
|
-
options.onHover(el, urlText);
|
|
1583
|
-
return {
|
|
1584
|
-
dom: el,
|
|
1585
|
-
offset: {
|
|
1586
|
-
x: 0,
|
|
1587
|
-
y: 4
|
|
1588
|
-
}
|
|
1589
|
-
};
|
|
1590
|
-
}
|
|
1591
|
-
};
|
|
1592
|
-
})
|
|
1593
|
-
);
|
|
1594
|
-
}
|
|
1595
|
-
return extensions;
|
|
1596
|
-
};
|
|
1597
|
-
var LinkButton = class extends WidgetType4 {
|
|
1598
|
-
constructor(_url, _onAttach) {
|
|
1599
|
-
super();
|
|
1600
|
-
this._url = _url;
|
|
1601
|
-
this._onAttach = _onAttach;
|
|
1602
|
-
}
|
|
1603
|
-
eq(other) {
|
|
1604
|
-
return this._url === other._url;
|
|
1605
|
-
}
|
|
1606
|
-
toDOM(view) {
|
|
1607
|
-
const el = document.createElement("span");
|
|
1608
|
-
this._onAttach(el, this._url);
|
|
1609
|
-
return el;
|
|
1610
|
-
}
|
|
1611
|
-
};
|
|
1612
|
-
var LinkText = class extends WidgetType4 {
|
|
1613
|
-
constructor(_text, _url) {
|
|
1614
|
-
super();
|
|
1615
|
-
this._text = _text;
|
|
1616
|
-
this._url = _url;
|
|
1617
|
-
}
|
|
1618
|
-
eq(other) {
|
|
1619
|
-
return this._url === other._url;
|
|
1620
|
-
}
|
|
1621
|
-
toDOM(view) {
|
|
1622
|
-
const link2 = document.createElement("a");
|
|
1623
|
-
link2.setAttribute("class", "cm-link");
|
|
1624
|
-
link2.textContent = this._text;
|
|
1625
|
-
if (this._url) {
|
|
1626
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1627
|
-
link2.setAttribute("target", "_blank");
|
|
1628
|
-
link2.href = this._url;
|
|
1629
|
-
} else {
|
|
1630
|
-
link2.onclick = () => {
|
|
1631
|
-
view.dispatch({
|
|
1632
|
-
selection: {
|
|
1633
|
-
anchor: view.posAtDOM(link2)
|
|
1634
|
-
}
|
|
1635
|
-
});
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
return link2;
|
|
1639
|
-
}
|
|
1640
|
-
};
|
|
1641
|
-
var buildDecorations2 = (view, options) => {
|
|
1642
|
-
const builder = new RangeSetBuilder();
|
|
1643
|
-
const { state } = view;
|
|
1644
|
-
const cursor = state.selection.main.head;
|
|
1645
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1646
|
-
syntaxTree2(state).iterate({
|
|
1647
|
-
enter: (node) => {
|
|
1648
|
-
if (node.name === "Link") {
|
|
1649
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1650
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1651
|
-
const urlNode = node.node.getChild("URL");
|
|
1652
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1653
|
-
if (!url) {
|
|
1654
|
-
return false;
|
|
1655
|
-
}
|
|
1656
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1657
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1658
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1659
|
-
}));
|
|
1660
|
-
}
|
|
1661
|
-
if (options.onRender) {
|
|
1662
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1663
|
-
widget: new LinkButton(url, options.onRender)
|
|
1664
|
-
}));
|
|
1665
|
-
}
|
|
1666
|
-
return false;
|
|
1667
|
-
}
|
|
1668
|
-
},
|
|
1669
|
-
from,
|
|
1670
|
-
to
|
|
1671
|
-
});
|
|
1672
|
-
}
|
|
1673
|
-
return builder.finish();
|
|
1674
|
-
};
|
|
1675
|
-
|
|
1676
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1677
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1678
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1679
|
-
const extensions = [];
|
|
1680
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1681
|
-
onFocus(focused);
|
|
1682
|
-
return null;
|
|
1683
|
-
}));
|
|
1684
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1685
|
-
onChange(update2.state.doc.toString());
|
|
1686
|
-
}));
|
|
1687
|
-
return extensions;
|
|
1688
|
-
};
|
|
1689
|
-
|
|
1690
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1691
|
-
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1692
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1693
|
-
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1694
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1695
|
-
import { languages } from "@codemirror/language-data";
|
|
1696
|
-
import { searchKeymap } from "@codemirror/search";
|
|
1697
|
-
import { EditorState } from "@codemirror/state";
|
|
1698
|
-
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1699
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1700
|
-
|
|
1701
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1702
|
-
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1703
|
-
import { HighlightStyle } from "@codemirror/language";
|
|
1704
|
-
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1705
|
-
import { Table } from "@lezer/markdown";
|
|
1706
|
-
var markdownTags = {
|
|
1707
|
-
Blockquote: Tag.define(),
|
|
1708
|
-
CodeMark: Tag.define(),
|
|
1709
|
-
CodeText: Tag.define(),
|
|
1710
|
-
EmphasisMark: Tag.define(),
|
|
1711
|
-
HeaderMark: Tag.define(),
|
|
1712
|
-
InlineCode: Tag.define(),
|
|
1713
|
-
LinkLabel: Tag.define(),
|
|
1714
|
-
LinkReference: Tag.define(),
|
|
1715
|
-
ListMark: Tag.define(),
|
|
1716
|
-
QuoteMark: Tag.define(),
|
|
1717
|
-
URL: Tag.define(),
|
|
1718
|
-
// Custom.
|
|
1719
|
-
TableCell: Tag.define()
|
|
1720
|
-
};
|
|
1721
|
-
Table.defineNodes?.forEach((node) => {
|
|
1722
|
-
switch (node?.name) {
|
|
1723
|
-
case "TableCell": {
|
|
1724
|
-
node.style = markdownTags.TableCell;
|
|
1725
|
-
break;
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
});
|
|
1729
|
-
var markdownTagsExtensions = [
|
|
1730
|
-
Table,
|
|
1731
|
-
{
|
|
1732
|
-
props: [
|
|
1733
|
-
styleTags(markdownTags)
|
|
1734
|
-
]
|
|
1435
|
+
var markdownTagsExtensions = [
|
|
1436
|
+
Table,
|
|
1437
|
+
{
|
|
1438
|
+
props: [
|
|
1439
|
+
styleTags(markdownTags)
|
|
1440
|
+
]
|
|
1735
1441
|
}
|
|
1736
1442
|
];
|
|
1737
1443
|
var markdownHighlightStyle = (readonly) => {
|
|
@@ -1793,7 +1499,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1793
1499
|
markdownTags.QuoteMark,
|
|
1794
1500
|
markdownTags.EmphasisMark
|
|
1795
1501
|
],
|
|
1796
|
-
class:
|
|
1502
|
+
class: mark
|
|
1797
1503
|
},
|
|
1798
1504
|
// E.g., code block language (after ```).
|
|
1799
1505
|
{
|
|
@@ -1801,7 +1507,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1801
1507
|
tags.function(tags.variableName),
|
|
1802
1508
|
tags.labelName
|
|
1803
1509
|
],
|
|
1804
|
-
class:
|
|
1510
|
+
class: codeMark
|
|
1805
1511
|
},
|
|
1806
1512
|
{
|
|
1807
1513
|
tag: [
|
|
@@ -1812,27 +1518,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1812
1518
|
// Headings.
|
|
1813
1519
|
{
|
|
1814
1520
|
tag: tags.heading1,
|
|
1815
|
-
class: heading(1
|
|
1521
|
+
class: heading(1)
|
|
1816
1522
|
},
|
|
1817
1523
|
{
|
|
1818
1524
|
tag: tags.heading2,
|
|
1819
|
-
class: heading(2
|
|
1525
|
+
class: heading(2)
|
|
1820
1526
|
},
|
|
1821
1527
|
{
|
|
1822
1528
|
tag: tags.heading3,
|
|
1823
|
-
class: heading(3
|
|
1529
|
+
class: heading(3)
|
|
1824
1530
|
},
|
|
1825
1531
|
{
|
|
1826
1532
|
tag: tags.heading4,
|
|
1827
|
-
class: heading(4
|
|
1533
|
+
class: heading(4)
|
|
1828
1534
|
},
|
|
1829
1535
|
{
|
|
1830
1536
|
tag: tags.heading5,
|
|
1831
|
-
class: heading(5
|
|
1537
|
+
class: heading(5)
|
|
1832
1538
|
},
|
|
1833
1539
|
{
|
|
1834
1540
|
tag: tags.heading6,
|
|
1835
|
-
class: heading(6
|
|
1541
|
+
class: heading(6)
|
|
1836
1542
|
},
|
|
1837
1543
|
// Emphasis.
|
|
1838
1544
|
{
|
|
@@ -1858,7 +1564,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1858
1564
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1859
1565
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1860
1566
|
// the code, but all other CSS properties will be inherited.
|
|
1861
|
-
// 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.
|
|
1862
1568
|
{
|
|
1863
1569
|
tag: [
|
|
1864
1570
|
markdownTags.CodeText,
|
|
@@ -1887,21 +1593,21 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1887
1593
|
};
|
|
1888
1594
|
|
|
1889
1595
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1890
|
-
var markdownBundle = ({
|
|
1596
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1891
1597
|
return [
|
|
1892
1598
|
EditorState.allowMultipleSelections.of(true),
|
|
1893
1599
|
EditorState.tabSize.of(2),
|
|
1894
|
-
|
|
1895
|
-
|
|
1600
|
+
EditorView7.lineWrapping,
|
|
1601
|
+
// https://github.com/codemirror/basic-setup
|
|
1896
1602
|
bracketMatching2(),
|
|
1897
1603
|
closeBrackets2(),
|
|
1898
1604
|
crosshairCursor(),
|
|
1899
1605
|
dropCursor(),
|
|
1900
1606
|
drawSelection2(),
|
|
1901
|
-
|
|
1902
|
-
|
|
1607
|
+
highlightActiveLine2(),
|
|
1608
|
+
history2(),
|
|
1903
1609
|
indentOnInput(),
|
|
1904
|
-
_placeholder
|
|
1610
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1905
1611
|
// Main extension.
|
|
1906
1612
|
// https://github.com/codemirror/lang-markdown
|
|
1907
1613
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1923,58 +1629,445 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1923
1629
|
// https://github.com/codemirror/theme-one-dark
|
|
1924
1630
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1925
1631
|
// Custom styles.
|
|
1926
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
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
|
+
};
|
|
1941
1647
|
|
|
1942
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1943
|
-
import {
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
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) {
|
|
1951
1954
|
return null;
|
|
1952
1955
|
}
|
|
1953
|
-
|
|
1954
|
-
return {
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
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();
|
|
1963
2056
|
};
|
|
1964
2057
|
|
|
1965
|
-
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1966
|
-
import { syntaxTree as
|
|
1967
|
-
import { RangeSetBuilder as
|
|
1968
|
-
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";
|
|
1969
2062
|
var table = (options = {}) => {
|
|
1970
2063
|
return StateField4.define({
|
|
1971
2064
|
create: (state) => update(state, options),
|
|
1972
2065
|
update: (_, tr) => update(tr.state, options),
|
|
1973
|
-
provide: (field) =>
|
|
2066
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1974
2067
|
});
|
|
1975
2068
|
};
|
|
1976
2069
|
var update = (state, options) => {
|
|
1977
|
-
const builder = new
|
|
2070
|
+
const builder = new RangeSetBuilder5();
|
|
1978
2071
|
const cursor = state.selection.main.head;
|
|
1979
2072
|
const tables = [];
|
|
1980
2073
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1982,7 +2075,7 @@ var update = (state, options) => {
|
|
|
1982
2075
|
const table2 = getTable();
|
|
1983
2076
|
return table2.rows?.[table2.rows.length - 1];
|
|
1984
2077
|
};
|
|
1985
|
-
|
|
2078
|
+
syntaxTree6(state).iterate({
|
|
1986
2079
|
enter: (node) => {
|
|
1987
2080
|
switch (node.name) {
|
|
1988
2081
|
case "Table": {
|
|
@@ -2014,16 +2107,16 @@ var update = (state, options) => {
|
|
|
2014
2107
|
});
|
|
2015
2108
|
tables.forEach((table2) => {
|
|
2016
2109
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2017
|
-
hide && builder.add(table2.from, table2.to,
|
|
2110
|
+
hide && builder.add(table2.from, table2.to, Decoration8.replace({
|
|
2018
2111
|
widget: new TableWidget(table2)
|
|
2019
2112
|
}));
|
|
2020
|
-
builder.add(table2.from, table2.to,
|
|
2113
|
+
builder.add(table2.from, table2.to, Decoration8.mark({
|
|
2021
2114
|
class: "cm-table"
|
|
2022
2115
|
}));
|
|
2023
2116
|
});
|
|
2024
2117
|
return builder.finish();
|
|
2025
2118
|
};
|
|
2026
|
-
var TableWidget = class extends
|
|
2119
|
+
var TableWidget = class extends WidgetType6 {
|
|
2027
2120
|
constructor(_table) {
|
|
2028
2121
|
super();
|
|
2029
2122
|
this._table = _table;
|
|
@@ -2060,11 +2153,20 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2060
2153
|
}
|
|
2061
2154
|
};
|
|
2062
2155
|
|
|
2063
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2064
|
-
import { syntaxTree as
|
|
2065
|
-
import { RangeSetBuilder as
|
|
2066
|
-
import { EditorView as
|
|
2067
|
-
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 {
|
|
2068
2170
|
constructor(_checked) {
|
|
2069
2171
|
super();
|
|
2070
2172
|
this._checked = _checked;
|
|
@@ -2074,6 +2176,7 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2074
2176
|
}
|
|
2075
2177
|
toDOM(view) {
|
|
2076
2178
|
const input = document.createElement("input");
|
|
2179
|
+
input.className = "cm-task-checkbox";
|
|
2077
2180
|
input.type = "checkbox";
|
|
2078
2181
|
input.checked = this._checked;
|
|
2079
2182
|
if (view.state.readOnly) {
|
|
@@ -2100,40 +2203,27 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2100
2203
|
return false;
|
|
2101
2204
|
}
|
|
2102
2205
|
};
|
|
2103
|
-
var
|
|
2206
|
+
var checkedDecoration = Decoration9.replace({
|
|
2104
2207
|
widget: new CheckboxWidget(true)
|
|
2105
2208
|
});
|
|
2106
|
-
var
|
|
2209
|
+
var uncheckedDecoration = Decoration9.replace({
|
|
2107
2210
|
widget: new CheckboxWidget(false)
|
|
2108
2211
|
});
|
|
2109
|
-
var
|
|
2110
|
-
|
|
2111
|
-
constructor(view) {
|
|
2112
|
-
this.decorations = buildDecorations3(view);
|
|
2113
|
-
}
|
|
2114
|
-
update(update2) {
|
|
2115
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2116
|
-
this.decorations = buildDecorations3(update2.view);
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
}, {
|
|
2120
|
-
decorations: (v) => v.decorations,
|
|
2121
|
-
// TODO(burdon): Is this still required?
|
|
2122
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2123
|
-
return view.plugin(plugin)?.decorations || Decoration8.none;
|
|
2124
|
-
})
|
|
2125
|
-
});
|
|
2126
|
-
};
|
|
2127
|
-
var buildDecorations3 = (view) => {
|
|
2128
|
-
const builder = new RangeSetBuilder3();
|
|
2212
|
+
var buildDecorations6 = (view) => {
|
|
2213
|
+
const builder = new RangeSetBuilder6();
|
|
2129
2214
|
const { state } = view;
|
|
2130
2215
|
const cursor = state.selection.main.head;
|
|
2131
2216
|
for (const { from, to } of view.visibleRanges) {
|
|
2132
|
-
|
|
2217
|
+
syntaxTree7(state).iterate({
|
|
2133
2218
|
enter: (node) => {
|
|
2134
|
-
if (node.name === "TaskMarker"
|
|
2135
|
-
|
|
2136
|
-
|
|
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
|
+
}
|
|
2137
2227
|
}
|
|
2138
2228
|
},
|
|
2139
2229
|
from,
|
|
@@ -2142,6 +2232,57 @@ var buildDecorations3 = (view) => {
|
|
|
2142
2232
|
}
|
|
2143
2233
|
return builder.finish();
|
|
2144
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
|
+
};
|
|
2145
2286
|
|
|
2146
2287
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2147
2288
|
import { keymap as keymap5 } from "@codemirror/view";
|
|
@@ -2200,27 +2341,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2200
2341
|
];
|
|
2201
2342
|
};
|
|
2202
2343
|
|
|
2203
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2204
|
-
import { yCollab } from "y-codemirror.next";
|
|
2205
|
-
|
|
2206
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2207
|
-
import * as Y from "yjs";
|
|
2208
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2209
|
-
var cursorConverter2 = (text) => ({
|
|
2210
|
-
toCursor: (index, assoc) => {
|
|
2211
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2212
|
-
},
|
|
2213
|
-
fromCursor: (cursor) => {
|
|
2214
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2215
|
-
}
|
|
2216
|
-
});
|
|
2217
|
-
|
|
2218
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2219
|
-
var yjs = (content, awareness2) => [
|
|
2220
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2221
|
-
yCollab(content, awareness2)
|
|
2222
|
-
];
|
|
2223
|
-
|
|
2224
2344
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2225
2345
|
import get3 from "lodash.get";
|
|
2226
2346
|
var defaultTheme = {
|
|
@@ -2458,11 +2578,12 @@ var codeTheme = {
|
|
|
2458
2578
|
};
|
|
2459
2579
|
|
|
2460
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";
|
|
2461
2582
|
var EditorModes = [
|
|
2462
2583
|
"default",
|
|
2463
2584
|
"vim"
|
|
2464
2585
|
];
|
|
2465
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2586
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2466
2587
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2467
2588
|
tabBehavior: "limited"
|
|
2468
2589
|
});
|
|
@@ -2472,76 +2593,67 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2472
2593
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2473
2594
|
view
|
|
2474
2595
|
]);
|
|
2475
|
-
|
|
2476
|
-
if (
|
|
2596
|
+
useEffect2(() => {
|
|
2597
|
+
if (autoFocus) {
|
|
2477
2598
|
view?.focus();
|
|
2478
2599
|
}
|
|
2479
|
-
}, [
|
|
2480
|
-
autofocus,
|
|
2481
|
-
view
|
|
2482
|
-
]);
|
|
2483
|
-
const { awareness: awareness2, peer } = model;
|
|
2484
|
-
useEffect(() => {
|
|
2485
|
-
if (awareness2 && peer) {
|
|
2486
|
-
awareness2.setLocalStateField("user", {
|
|
2487
|
-
name: peer.name ?? generateName(peer.id),
|
|
2488
|
-
color: getColorForValue({
|
|
2489
|
-
value: peer.id,
|
|
2490
|
-
type: "color"
|
|
2491
|
-
}),
|
|
2492
|
-
colorLight: getColorForValue({
|
|
2493
|
-
value: peer.id,
|
|
2494
|
-
themeMode,
|
|
2495
|
-
type: "highlight"
|
|
2496
|
-
})
|
|
2497
|
-
});
|
|
2498
|
-
}
|
|
2499
|
-
}, [
|
|
2500
|
-
awareness2,
|
|
2501
|
-
peer,
|
|
2502
|
-
themeMode
|
|
2503
|
-
]);
|
|
2504
|
-
useEffect(() => {
|
|
2505
|
-
if (view && comments2 !== void 0) {
|
|
2506
|
-
view.dispatch({
|
|
2507
|
-
effects: setCommentRange.of({
|
|
2508
|
-
model,
|
|
2509
|
-
comments: comments2
|
|
2510
|
-
})
|
|
2511
|
-
});
|
|
2512
|
-
}
|
|
2513
2600
|
}, [
|
|
2514
2601
|
view,
|
|
2515
|
-
|
|
2602
|
+
autoFocus
|
|
2516
2603
|
]);
|
|
2517
|
-
|
|
2604
|
+
useEffect2(() => {
|
|
2518
2605
|
if (!model || !rootRef.current) {
|
|
2519
2606
|
return;
|
|
2520
2607
|
}
|
|
2521
2608
|
const state = EditorState2.create({
|
|
2522
2609
|
doc: model.text(),
|
|
2523
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2524
2610
|
selection,
|
|
2525
2611
|
extensions: [
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
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
|
+
}),
|
|
2529
2621
|
// Theme.
|
|
2530
|
-
// TODO(burdon): Make
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
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),
|
|
2534
2634
|
// Storage and replication.
|
|
2635
|
+
// NOTE: This must come before user extensions.
|
|
2535
2636
|
model.extension,
|
|
2637
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2638
|
+
editorMode === "vim" && vim(),
|
|
2536
2639
|
// Custom.
|
|
2537
2640
|
...extensions
|
|
2538
2641
|
].filter(Boolean)
|
|
2539
2642
|
});
|
|
2540
|
-
|
|
2541
|
-
|
|
2643
|
+
const newView = new EditorView13({
|
|
2644
|
+
state,
|
|
2542
2645
|
parent: rootRef.current,
|
|
2543
|
-
|
|
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
|
+
}
|
|
2544
2655
|
});
|
|
2656
|
+
view?.destroy();
|
|
2545
2657
|
setView(newView);
|
|
2546
2658
|
return () => {
|
|
2547
2659
|
newView?.destroy();
|
|
@@ -2557,8 +2669,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2557
2669
|
const handleKeyUp = useCallback((event) => {
|
|
2558
2670
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2559
2671
|
switch (key) {
|
|
2672
|
+
case "Enter": {
|
|
2673
|
+
view?.focus();
|
|
2674
|
+
break;
|
|
2675
|
+
}
|
|
2560
2676
|
case "Escape": {
|
|
2561
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2677
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2678
|
+
rootRef.current?.focus();
|
|
2679
|
+
}
|
|
2562
2680
|
break;
|
|
2563
2681
|
}
|
|
2564
2682
|
}
|
|
@@ -2576,7 +2694,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2576
2694
|
ref: rootRef
|
|
2577
2695
|
});
|
|
2578
2696
|
});
|
|
2579
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2697
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2580
2698
|
const { themeMode } = useThemeContext();
|
|
2581
2699
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2582
2700
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
@@ -2584,9 +2702,9 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2584
2702
|
readonly,
|
|
2585
2703
|
extensions: [
|
|
2586
2704
|
basicBundle({
|
|
2587
|
-
readonly,
|
|
2588
2705
|
themeMode,
|
|
2589
|
-
placeholder: placeholder3
|
|
2706
|
+
placeholder: placeholder3,
|
|
2707
|
+
lineWrapping
|
|
2590
2708
|
}),
|
|
2591
2709
|
...extensions
|
|
2592
2710
|
],
|
|
@@ -2595,7 +2713,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2595
2713
|
...props
|
|
2596
2714
|
});
|
|
2597
2715
|
});
|
|
2598
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2716
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2599
2717
|
const { themeMode } = useThemeContext();
|
|
2600
2718
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2601
2719
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
@@ -2603,7 +2721,6 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2603
2721
|
readonly,
|
|
2604
2722
|
extensions: [
|
|
2605
2723
|
markdownBundle({
|
|
2606
|
-
readonly,
|
|
2607
2724
|
themeMode,
|
|
2608
2725
|
placeholder: placeholder3
|
|
2609
2726
|
}),
|
|
@@ -2616,7 +2733,11 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2616
2733
|
});
|
|
2617
2734
|
var defaultSlots = {
|
|
2618
2735
|
root: {
|
|
2619
|
-
|
|
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"
|
|
2620
2741
|
}
|
|
2621
2742
|
};
|
|
2622
2743
|
var defaultTextSlots = {
|
|
@@ -2626,22 +2747,17 @@ var defaultMarkdownSlots = {
|
|
|
2626
2747
|
...defaultSlots
|
|
2627
2748
|
};
|
|
2628
2749
|
|
|
2629
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2630
|
-
import get4 from "lodash.get";
|
|
2631
|
-
import { getRawDoc } from "@dxos/echo-schema";
|
|
2632
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2633
|
-
|
|
2634
2750
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2635
2751
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2636
2752
|
import { Context as Context2 } from "@dxos/context";
|
|
2637
|
-
import { invariant as
|
|
2638
|
-
import { log as
|
|
2639
|
-
var
|
|
2753
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2754
|
+
import { log as log3 } from "@dxos/log";
|
|
2755
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2640
2756
|
var DEBOUNCE_INTERVAL = 100;
|
|
2641
2757
|
var SpaceAwarenessProvider = class {
|
|
2642
2758
|
constructor(params) {
|
|
2643
|
-
this.remoteStateChange = new Event2();
|
|
2644
2759
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2760
|
+
this.remoteStateChange = new Event2();
|
|
2645
2761
|
this._space = params.space;
|
|
2646
2762
|
this._channel = params.channel;
|
|
2647
2763
|
this._peerId = params.peerId;
|
|
@@ -2658,7 +2774,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2658
2774
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2659
2775
|
}
|
|
2660
2776
|
});
|
|
2661
|
-
|
|
2777
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2662
2778
|
switch (message.payload.kind) {
|
|
2663
2779
|
case "query": {
|
|
2664
2780
|
this._handleQueryMessage();
|
|
@@ -2669,16 +2785,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2669
2785
|
break;
|
|
2670
2786
|
}
|
|
2671
2787
|
}
|
|
2672
|
-
});
|
|
2673
|
-
this._ctx.onDispose(unsubscribe);
|
|
2788
|
+
}));
|
|
2674
2789
|
void this._space.postMessage(this._channel, {
|
|
2675
2790
|
kind: "query"
|
|
2676
2791
|
}).catch((err) => {
|
|
2677
|
-
|
|
2792
|
+
log3.debug("failed to query awareness", {
|
|
2678
2793
|
err
|
|
2679
2794
|
}, {
|
|
2680
|
-
F:
|
|
2681
|
-
L:
|
|
2795
|
+
F: __dxlog_file6,
|
|
2796
|
+
L: 89,
|
|
2682
2797
|
S: this,
|
|
2683
2798
|
C: (f, a) => f(...a)
|
|
2684
2799
|
});
|
|
@@ -2689,10 +2804,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2689
2804
|
this._ctx = void 0;
|
|
2690
2805
|
this._postTask = void 0;
|
|
2691
2806
|
}
|
|
2807
|
+
getRemoteStates() {
|
|
2808
|
+
return Array.from(this._remoteStates.values());
|
|
2809
|
+
}
|
|
2692
2810
|
update(position) {
|
|
2693
|
-
|
|
2694
|
-
F:
|
|
2695
|
-
L:
|
|
2811
|
+
invariant4(this._postTask, void 0, {
|
|
2812
|
+
F: __dxlog_file6,
|
|
2813
|
+
L: 104,
|
|
2696
2814
|
S: this,
|
|
2697
2815
|
A: [
|
|
2698
2816
|
"this._postTask",
|
|
@@ -2706,13 +2824,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2706
2824
|
};
|
|
2707
2825
|
this._postTask.schedule();
|
|
2708
2826
|
}
|
|
2709
|
-
getRemoteStates() {
|
|
2710
|
-
return Array.from(this._remoteStates.values());
|
|
2711
|
-
}
|
|
2712
2827
|
_handleQueryMessage() {
|
|
2713
|
-
|
|
2714
|
-
F:
|
|
2715
|
-
L:
|
|
2828
|
+
invariant4(this._postTask, void 0, {
|
|
2829
|
+
F: __dxlog_file6,
|
|
2830
|
+
L: 115,
|
|
2716
2831
|
S: this,
|
|
2717
2832
|
A: [
|
|
2718
2833
|
"this._postTask",
|
|
@@ -2722,9 +2837,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2722
2837
|
this._postTask.schedule();
|
|
2723
2838
|
}
|
|
2724
2839
|
_handlePostMessage(message) {
|
|
2725
|
-
|
|
2726
|
-
F:
|
|
2727
|
-
L:
|
|
2840
|
+
invariant4(message.kind === "post", void 0, {
|
|
2841
|
+
F: __dxlog_file6,
|
|
2842
|
+
L: 120,
|
|
2728
2843
|
S: this,
|
|
2729
2844
|
A: [
|
|
2730
2845
|
"message.kind === 'post'",
|
|
@@ -2736,171 +2851,54 @@ var SpaceAwarenessProvider = class {
|
|
|
2736
2851
|
}
|
|
2737
2852
|
};
|
|
2738
2853
|
|
|
2739
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2854
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2740
2855
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2741
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
2742
|
-
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2743
|
-
|
|
2744
|
-
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2745
|
-
import * as decoding from "lib0/decoding";
|
|
2746
|
-
import * as encoding from "lib0/encoding";
|
|
2747
|
-
import { Observable } from "lib0/observable";
|
|
2748
|
-
import * as YP from "y-protocols/awareness";
|
|
2749
|
-
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2750
|
-
import { log as log3 } from "@dxos/log";
|
|
2751
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2752
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2753
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2754
|
-
F: __dxlog_file5,
|
|
2755
|
-
L: 21,
|
|
2756
|
-
S: void 0,
|
|
2757
|
-
A: [
|
|
2758
|
-
"text?.doc && text?.content",
|
|
2759
|
-
""
|
|
2760
|
-
]
|
|
2761
|
-
});
|
|
2762
|
-
const provider = space ? new YAwarenessProvider({
|
|
2763
|
-
space,
|
|
2764
|
-
doc: text.doc,
|
|
2765
|
-
channel: `yjs.awareness.${text.id}`
|
|
2766
|
-
}) : void 0;
|
|
2767
|
-
const model = {
|
|
2768
|
-
id: text.doc.guid,
|
|
2769
|
-
content: text.content,
|
|
2770
|
-
text: () => text.content.toString(),
|
|
2771
|
-
extension: [
|
|
2772
|
-
modelState.init(() => model),
|
|
2773
|
-
yjs(text.content, provider?.awareness)
|
|
2774
|
-
],
|
|
2775
|
-
awareness: provider?.awareness,
|
|
2776
|
-
peer: identity ? {
|
|
2777
|
-
id: identity.identityKey.toHex(),
|
|
2778
|
-
name: identity.profile?.displayName
|
|
2779
|
-
} : void 0
|
|
2780
|
-
};
|
|
2781
|
-
return model;
|
|
2782
|
-
};
|
|
2783
|
-
var messageAwareness = 1;
|
|
2784
|
-
var messageQueryAwareness = 3;
|
|
2785
|
-
var YAwarenessProvider = class extends Observable {
|
|
2786
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2787
|
-
super();
|
|
2788
|
-
this._space = space;
|
|
2789
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2790
|
-
this._channel = channel;
|
|
2791
|
-
this._clientId = doc.clientID;
|
|
2792
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2793
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2794
|
-
if (typeof window !== "undefined") {
|
|
2795
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2796
|
-
} else if (typeof process !== "undefined") {
|
|
2797
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2798
|
-
}
|
|
2799
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2800
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2801
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2802
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2803
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2804
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2805
|
-
this._clientId
|
|
2806
|
-
]));
|
|
2807
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2808
|
-
}
|
|
2809
|
-
get awareness() {
|
|
2810
|
-
return this._awareness;
|
|
2811
|
-
}
|
|
2812
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2813
|
-
log3("awareness update", {
|
|
2814
|
-
added,
|
|
2815
|
-
updated,
|
|
2816
|
-
removed,
|
|
2817
|
-
origin
|
|
2818
|
-
}, {
|
|
2819
|
-
F: __dxlog_file5,
|
|
2820
|
-
L: 100,
|
|
2821
|
-
S: this,
|
|
2822
|
-
C: (f, a) => f(...a)
|
|
2823
|
-
});
|
|
2824
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2825
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2826
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2827
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2828
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2829
|
-
}
|
|
2830
|
-
_handleSpaceMessage({ payload }) {
|
|
2831
|
-
log3("space message", payload, {
|
|
2832
|
-
F: __dxlog_file5,
|
|
2833
|
-
L: 109,
|
|
2834
|
-
S: this,
|
|
2835
|
-
C: (f, a) => f(...a)
|
|
2836
|
-
});
|
|
2837
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2838
|
-
const encoder = this._readMessage(data);
|
|
2839
|
-
if (encoder) {
|
|
2840
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2843
|
-
_readMessage(message) {
|
|
2844
|
-
const decoder = decoding.createDecoder(message);
|
|
2845
|
-
const encoder = encoding.createEncoder();
|
|
2846
|
-
const messageType = decoding.readVarUint(decoder);
|
|
2847
|
-
let sendReply = false;
|
|
2848
|
-
switch (messageType) {
|
|
2849
|
-
case messageAwareness: {
|
|
2850
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2851
|
-
break;
|
|
2852
|
-
}
|
|
2853
|
-
case messageQueryAwareness: {
|
|
2854
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
2855
|
-
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2856
|
-
sendReply = true;
|
|
2857
|
-
break;
|
|
2858
|
-
}
|
|
2859
|
-
default: {
|
|
2860
|
-
console.error("Invalid message:", messageType);
|
|
2861
|
-
return encoder;
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
if (!sendReply) {
|
|
2865
|
-
return null;
|
|
2866
|
-
}
|
|
2867
|
-
return encoder;
|
|
2868
|
-
}
|
|
2869
|
-
_handleBeforeUnload() {
|
|
2870
|
-
YP.removeAwarenessStates(this._awareness, [
|
|
2871
|
-
this._clientId
|
|
2872
|
-
], "window unload");
|
|
2873
|
-
}
|
|
2874
|
-
};
|
|
2875
|
-
|
|
2876
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2877
2856
|
var modelState = StateField5.define({
|
|
2878
2857
|
create: () => void 0,
|
|
2879
2858
|
update: (model) => model
|
|
2880
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";
|
|
2881
2882
|
var useTextModel = (props) => {
|
|
2882
2883
|
const { identity, space, text } = props;
|
|
2883
|
-
const [model, setModel] =
|
|
2884
|
-
|
|
2884
|
+
const [model, setModel] = useState3();
|
|
2885
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2885
2886
|
identity,
|
|
2886
2887
|
space,
|
|
2887
2888
|
text
|
|
2888
2889
|
]);
|
|
2889
2890
|
return model;
|
|
2890
2891
|
};
|
|
2891
|
-
var createModel = (
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
};
|
|
2901
|
-
|
|
2902
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2903
|
-
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
|
+
});
|
|
2904
2902
|
const obj = text;
|
|
2905
2903
|
const doc = getRawDoc(obj, [
|
|
2906
2904
|
obj.field
|
|
@@ -2909,7 +2907,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2909
2907
|
space,
|
|
2910
2908
|
channel: `automerge.awareness.${obj.id}`,
|
|
2911
2909
|
info: {
|
|
2912
|
-
displayName: identity
|
|
2910
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2913
2911
|
color: cursorColor.color,
|
|
2914
2912
|
lightColor: cursorColor.light
|
|
2915
2913
|
},
|
|
@@ -2919,7 +2917,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2919
2917
|
id: obj.id,
|
|
2920
2918
|
content: doc,
|
|
2921
2919
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2922
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2923
2920
|
extension: [
|
|
2924
2921
|
modelState.init(() => model),
|
|
2925
2922
|
automerge3({
|
|
@@ -2947,7 +2944,6 @@ export {
|
|
|
2947
2944
|
SpaceAwarenessProvider,
|
|
2948
2945
|
TextEditor,
|
|
2949
2946
|
TextKind,
|
|
2950
|
-
YAwarenessProvider,
|
|
2951
2947
|
YText,
|
|
2952
2948
|
YXmlFragment,
|
|
2953
2949
|
autocomplete,
|
|
@@ -2959,18 +2955,18 @@ export {
|
|
|
2959
2955
|
code2 as code,
|
|
2960
2956
|
codeTheme,
|
|
2961
2957
|
comments,
|
|
2962
|
-
createAutomergeModel,
|
|
2963
|
-
createYjsModel,
|
|
2964
2958
|
defaultMarkdownSlots,
|
|
2965
2959
|
defaultOptions,
|
|
2966
2960
|
defaultSlots,
|
|
2967
2961
|
defaultTextSlots,
|
|
2968
2962
|
defaultTheme,
|
|
2969
2963
|
getToken,
|
|
2964
|
+
heading2 as heading,
|
|
2970
2965
|
hr,
|
|
2971
2966
|
image,
|
|
2972
2967
|
link,
|
|
2973
2968
|
listener,
|
|
2969
|
+
logChanges,
|
|
2974
2970
|
markdownBundle,
|
|
2975
2971
|
markdownHighlightStyle,
|
|
2976
2972
|
markdownTags,
|
|
@@ -2978,7 +2974,8 @@ export {
|
|
|
2978
2974
|
markdownTheme,
|
|
2979
2975
|
mention,
|
|
2980
2976
|
modelState,
|
|
2981
|
-
|
|
2977
|
+
outliner,
|
|
2978
|
+
setComments,
|
|
2982
2979
|
setFocus,
|
|
2983
2980
|
setSelection,
|
|
2984
2981
|
table,
|
|
@@ -2986,7 +2983,8 @@ export {
|
|
|
2986
2983
|
tasklist,
|
|
2987
2984
|
textTheme,
|
|
2988
2985
|
typewriter,
|
|
2989
|
-
|
|
2990
|
-
|
|
2986
|
+
useComments,
|
|
2987
|
+
useTextEditor,
|
|
2988
|
+
useTextModel
|
|
2991
2989
|
};
|
|
2992
2990
|
//# sourceMappingURL=index.mjs.map
|