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