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