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