@dxos/react-ui-editor 0.3.11-main.0e40963 → 0.3.11-main.1b2c8cb
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 +1274 -811
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/yjs → components/TextEditor}/yjs.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +9 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +5 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +26 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/{hooks → extensions}/automerge/semaphore.d.ts +4 -4
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/comments.d.ts +3 -1
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +3 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +4 -0
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/index.d.ts +2 -0
- package/dist/types/src/extensions/yjs/index.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/yjs.d.ts +4 -0
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge.d.ts +3 -0
- package/dist/types/src/hooks/automerge.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +28 -0
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +8 -7
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/hooks/{yjs/space-provider.d.ts → yjs.d.ts} +8 -8
- package/dist/types/src/hooks/yjs.d.ts.map +1 -0
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts +2 -2
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/dist/types/src/util/cursor.d.ts +17 -0
- package/dist/types/src/util/cursor.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +3 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/util.d.ts.map +1 -0
- package/package.json +22 -21
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -0
- package/src/components/TextEditor/TextEditor.tsx +1 -1
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/codemirror.stories.ts +3 -2
- package/src/{hooks/yjs → components/TextEditor}/yjs.stories.tsx +1 -1
- package/src/extensions/automerge/automerge.ts +94 -0
- package/src/extensions/automerge/cursor.ts +51 -0
- package/src/extensions/automerge/defs.ts +62 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +14 -12
- package/src/{hooks → extensions}/automerge/update-automerge.ts +5 -6
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +13 -5
- package/src/extensions/awareness.ts +316 -0
- package/src/extensions/comments.ts +45 -15
- package/src/extensions/index.ts +3 -0
- package/src/extensions/yjs/cursor.ts +21 -0
- package/src/extensions/yjs/index.ts +5 -0
- package/src/{hooks → extensions}/yjs/yjs.test.ts +1 -25
- package/src/extensions/yjs/yjs.ts +16 -0
- package/src/hooks/automerge.ts +52 -0
- package/src/hooks/awareness-provider.ts +120 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTextModel.ts +19 -93
- package/src/hooks/{yjs/space-provider.ts → yjs.ts} +71 -19
- package/src/styles/index.ts +1 -0
- package/src/testing/replicator.ts +10 -15
- package/src/util/cursor.ts +29 -0
- package/src/util/index.ts +6 -0
- package/dist/types/src/extensions/util.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/handle.d.ts +0 -9
- package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/index.d.ts +0 -3
- package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts +0 -26
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/semaphore.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-automerge.d.ts +0 -6
- package/dist/types/src/hooks/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/index.d.ts +0 -3
- package/dist/types/src/hooks/yjs/index.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.test.d.ts.map +0 -1
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -134
- package/src/hooks/yjs/index.ts +0 -6
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.d.ts +0 -0
- /package/dist/types/src/{hooks → extensions}/yjs/yjs.test.d.ts +0 -0
- /package/dist/types/src/{hooks/yjs → styles}/cursors.d.ts +0 -0
- /package/dist/types/src/{extensions → util}/util.d.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{extensions → util}/util.ts +0 -0
|
@@ -7,11 +7,11 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
7
7
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
9
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
11
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
15
15
|
import { generateName } from "@dxos/display-name";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
17
|
import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
@@ -49,13 +49,565 @@ var autocomplete = ({ onSearch }) => {
|
|
|
49
49
|
];
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
53
|
+
import { Facet as Facet2, StateField } from "@codemirror/state";
|
|
54
|
+
import { ViewPlugin } from "@codemirror/view";
|
|
55
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
56
|
+
|
|
57
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
58
|
+
import get from "lodash.get";
|
|
59
|
+
import { next as automerge } from "@dxos/automerge/automerge";
|
|
60
|
+
var cursorConverter = (handle, path) => ({
|
|
61
|
+
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
62
|
+
toCursor: (pos) => {
|
|
63
|
+
const doc = handle.docSync();
|
|
64
|
+
if (!doc) {
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
const value = get(doc, path);
|
|
68
|
+
if (typeof value === "string" && value.length <= pos) {
|
|
69
|
+
return "end";
|
|
70
|
+
}
|
|
71
|
+
return automerge.getCursor(doc, path.slice(), pos);
|
|
72
|
+
},
|
|
73
|
+
fromCursor: (cursor) => {
|
|
74
|
+
if (cursor === "") {
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
const doc = handle.docSync();
|
|
78
|
+
if (!doc) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
if (cursor === "end") {
|
|
82
|
+
const value = get(doc, path);
|
|
83
|
+
if (typeof value === "string") {
|
|
84
|
+
return value.length;
|
|
85
|
+
} else {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return automerge.getCursorPosition(doc, path.slice(), cursor);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
94
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
95
|
+
var effectType = StateEffect.define({});
|
|
96
|
+
var updateHeads = (newHeads) => effectType.of({
|
|
97
|
+
newHeads
|
|
98
|
+
});
|
|
99
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var reconcileAnnotationType = Annotation.define();
|
|
102
|
+
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
103
|
+
|
|
104
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
105
|
+
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
106
|
+
|
|
107
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
108
|
+
import { next as am } from "@dxos/automerge/automerge";
|
|
109
|
+
var updateAutomerge = (field, handle, transactions, state) => {
|
|
110
|
+
const { lastHeads, path } = state.field(field);
|
|
111
|
+
let hasChanges = false;
|
|
112
|
+
for (const tr of transactions) {
|
|
113
|
+
tr.changes.iterChanges(() => {
|
|
114
|
+
hasChanges = true;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (!hasChanges) {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
121
|
+
for (const tr of transactions) {
|
|
122
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
123
|
+
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return newHeads ?? void 0;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-codemirror.ts
|
|
131
|
+
import { ChangeSet } from "@codemirror/state";
|
|
132
|
+
var updateCodeMirror = (view, selection, target, patches) => {
|
|
133
|
+
for (const patch of patches) {
|
|
134
|
+
const changeSpec = handlePatch(patch, target, view.state);
|
|
135
|
+
if (changeSpec != null) {
|
|
136
|
+
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
137
|
+
selection = selection.map(changeSet, 1);
|
|
138
|
+
view.dispatch({
|
|
139
|
+
changes: changeSet,
|
|
140
|
+
annotations: reconcileAnnotationType.of({})
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
view.dispatch({
|
|
145
|
+
selection,
|
|
146
|
+
annotations: reconcileAnnotationType.of({})
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
var handlePatch = (patch, target, state) => {
|
|
150
|
+
if (patch.action === "insert") {
|
|
151
|
+
return handleInsert(target, patch);
|
|
152
|
+
} else if (patch.action === "splice") {
|
|
153
|
+
return handleSplice(target, patch);
|
|
154
|
+
} else if (patch.action === "del") {
|
|
155
|
+
return handleDel(target, patch);
|
|
156
|
+
} else if (patch.action === "put") {
|
|
157
|
+
return handlePut(target, patch, state);
|
|
158
|
+
} else {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
var handleInsert = (target, patch) => {
|
|
163
|
+
const index = charPath(target, patch.path);
|
|
164
|
+
if (index == null) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
168
|
+
return [
|
|
169
|
+
{
|
|
170
|
+
from: index,
|
|
171
|
+
to: index,
|
|
172
|
+
insert: text
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
};
|
|
176
|
+
var handleSplice = (target, patch) => {
|
|
177
|
+
const index = charPath(target, patch.path);
|
|
178
|
+
if (index == null) {
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
return [
|
|
182
|
+
{
|
|
183
|
+
from: index,
|
|
184
|
+
insert: patch.value
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
};
|
|
188
|
+
var handleDel = (target, patch) => {
|
|
189
|
+
const index = charPath(target, patch.path);
|
|
190
|
+
if (index == null) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const length = patch.length || 1;
|
|
194
|
+
return [
|
|
195
|
+
{
|
|
196
|
+
from: index,
|
|
197
|
+
to: index + length
|
|
198
|
+
}
|
|
199
|
+
];
|
|
200
|
+
};
|
|
201
|
+
var handlePut = (target, patch, state) => {
|
|
202
|
+
const index = charPath(target, [
|
|
203
|
+
...patch.path,
|
|
204
|
+
0
|
|
205
|
+
]);
|
|
206
|
+
if (index == null) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
const length = state.doc.length;
|
|
210
|
+
if (typeof patch.value !== "string") {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
return [
|
|
214
|
+
{
|
|
215
|
+
from: 0,
|
|
216
|
+
to: length,
|
|
217
|
+
insert: patch.value
|
|
218
|
+
}
|
|
219
|
+
];
|
|
220
|
+
};
|
|
221
|
+
var charPath = (textPath, candidatePath) => {
|
|
222
|
+
if (candidatePath.length !== textPath.length + 1) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
226
|
+
if (textPath[i] !== candidatePath[i]) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
231
|
+
if (typeof index === "number") {
|
|
232
|
+
return index;
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
238
|
+
var PatchSemaphore = class {
|
|
239
|
+
constructor(_field) {
|
|
240
|
+
this._field = _field;
|
|
241
|
+
this._inReconcile = false;
|
|
242
|
+
this._queue = [];
|
|
243
|
+
this.reconcile = (handle, view) => {
|
|
244
|
+
if (this._inReconcile) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
this._inReconcile = true;
|
|
248
|
+
const path = getPath(view.state, this._field);
|
|
249
|
+
const oldHeads = getLastHeads(view.state, this._field);
|
|
250
|
+
let selection = view.state.selection;
|
|
251
|
+
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
252
|
+
const toInvert = transactions.slice().reverse();
|
|
253
|
+
for (const tx of toInvert) {
|
|
254
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
255
|
+
selection = selection.map(inverted);
|
|
256
|
+
view.dispatch({
|
|
257
|
+
changes: inverted,
|
|
258
|
+
annotations: reconcileAnnotationType.of(true)
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
262
|
+
if (newHeads === null || newHeads === void 0) {
|
|
263
|
+
newHeads = automerge2.getHeads(handle.docSync());
|
|
264
|
+
}
|
|
265
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
266
|
+
updateCodeMirror(view, selection, path, diff);
|
|
267
|
+
view.dispatch({
|
|
268
|
+
effects: updateHeads(newHeads),
|
|
269
|
+
annotations: reconcileAnnotationType.of({})
|
|
270
|
+
});
|
|
271
|
+
this._inReconcile = false;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// packages/ui/react-ui-editor/src/util/cursor.ts
|
|
277
|
+
import { Facet } from "@codemirror/state";
|
|
278
|
+
var DEFAULT_CURSOR_CONVERTER = {
|
|
279
|
+
toCursor: (position) => position.toString(),
|
|
280
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
281
|
+
};
|
|
282
|
+
var CursorConverter = Facet.define({
|
|
283
|
+
combine: (providers) => providers[0] ?? DEFAULT_CURSOR_CONVERTER
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// packages/ui/react-ui-editor/src/util/util.ts
|
|
287
|
+
import { log } from "@dxos/log";
|
|
288
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
289
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
290
|
+
try {
|
|
291
|
+
return fn(...args);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
log.catch(error, void 0, {
|
|
294
|
+
F: __dxlog_file,
|
|
295
|
+
L: 16,
|
|
296
|
+
S: void 0,
|
|
297
|
+
C: (f, a) => f(...a)
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
303
|
+
var semaphoreFacet = Facet2.define({
|
|
304
|
+
combine: (values) => values.at(-1)
|
|
305
|
+
});
|
|
306
|
+
var automerge3 = ({ handle, path }) => {
|
|
307
|
+
const stateField = StateField.define({
|
|
308
|
+
create: () => ({
|
|
309
|
+
lastHeads: A.getHeads(handle.docSync()),
|
|
310
|
+
unreconciledTransactions: [],
|
|
311
|
+
path: path.slice()
|
|
312
|
+
}),
|
|
313
|
+
update: (value, tr) => {
|
|
314
|
+
const result = {
|
|
315
|
+
lastHeads: value.lastHeads,
|
|
316
|
+
unreconciledTransactions: value.unreconciledTransactions.slice(),
|
|
317
|
+
path: path.slice()
|
|
318
|
+
};
|
|
319
|
+
let clearUnreconciled = false;
|
|
320
|
+
for (const effect of tr.effects) {
|
|
321
|
+
if (effect.is(effectType)) {
|
|
322
|
+
result.lastHeads = effect.value.newHeads;
|
|
323
|
+
clearUnreconciled = true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (clearUnreconciled) {
|
|
327
|
+
result.unreconciledTransactions = [];
|
|
328
|
+
} else {
|
|
329
|
+
if (!isReconcileTx(tr)) {
|
|
330
|
+
result.unreconciledTransactions.push(tr);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return result;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
const semaphore = new PatchSemaphore(stateField);
|
|
337
|
+
const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
338
|
+
constructor(_view) {
|
|
339
|
+
this._view = _view;
|
|
340
|
+
this._handleChange = () => {
|
|
341
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
342
|
+
};
|
|
343
|
+
handle.addListener("change", this._handleChange);
|
|
344
|
+
}
|
|
345
|
+
update(update4) {
|
|
346
|
+
if (update4.transactions.length > 0 && update4.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
347
|
+
queueMicrotask(() => {
|
|
348
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
destroy() {
|
|
353
|
+
handle.addListener("change", this._handleChange);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
return {
|
|
357
|
+
extension: [
|
|
358
|
+
CursorConverter.of(cursorConverter(handle, path)),
|
|
359
|
+
semaphoreFacet.of(semaphore),
|
|
360
|
+
stateField,
|
|
361
|
+
viewPlugin
|
|
362
|
+
]
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
367
|
+
import { Annotation as Annotation2, Facet as Facet3, RangeSet } from "@codemirror/state";
|
|
368
|
+
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
369
|
+
import { Event } from "@dxos/async";
|
|
370
|
+
import { Context } from "@dxos/context";
|
|
371
|
+
var dummyProvider = {
|
|
372
|
+
remoteStateChange: new Event(),
|
|
373
|
+
open: () => {
|
|
374
|
+
},
|
|
375
|
+
close: () => {
|
|
376
|
+
},
|
|
377
|
+
update: () => {
|
|
378
|
+
},
|
|
379
|
+
getRemoteStates: () => []
|
|
380
|
+
};
|
|
381
|
+
var AwarenessProvider = Facet3.define({
|
|
382
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
383
|
+
});
|
|
384
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
385
|
+
var awareness = (provider = dummyProvider) => {
|
|
386
|
+
return [
|
|
387
|
+
AwarenessProvider.of(provider),
|
|
388
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
389
|
+
decorations: (value) => value.decorations
|
|
390
|
+
}),
|
|
391
|
+
styles
|
|
392
|
+
];
|
|
393
|
+
};
|
|
394
|
+
var RemoteSelectionsDecorator = class {
|
|
395
|
+
constructor(view) {
|
|
396
|
+
this.decorations = RangeSet.of([]);
|
|
397
|
+
this._ctx = new Context();
|
|
398
|
+
this._lastAnchor = void 0;
|
|
399
|
+
this._lastHead = void 0;
|
|
400
|
+
this._cursorConverter = view.state.facet(CursorConverter);
|
|
401
|
+
this._provider = view.state.facet(AwarenessProvider);
|
|
402
|
+
this._provider.open();
|
|
403
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
404
|
+
view.dispatch({
|
|
405
|
+
annotations: [
|
|
406
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
407
|
+
]
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
destroy() {
|
|
412
|
+
void this._ctx.dispose();
|
|
413
|
+
this._provider.close();
|
|
414
|
+
}
|
|
415
|
+
update(update4) {
|
|
416
|
+
this._updateLocalSelection(update4);
|
|
417
|
+
this._updateRemoteSelections(update4);
|
|
418
|
+
}
|
|
419
|
+
_updateLocalSelection(update4) {
|
|
420
|
+
const hasFocus = update4.view.hasFocus && update4.view.dom.ownerDocument.hasFocus();
|
|
421
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update4.state.selection.main : {};
|
|
422
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
this._lastAnchor = anchor;
|
|
426
|
+
this._lastHead = head;
|
|
427
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
428
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
429
|
+
head: this._cursorConverter.toCursor(head)
|
|
430
|
+
} : void 0);
|
|
431
|
+
}
|
|
432
|
+
_updateRemoteSelections(update4) {
|
|
433
|
+
const decorations = [];
|
|
434
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
435
|
+
for (const state of awarenessStates) {
|
|
436
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
437
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
438
|
+
if (anchor == null || head == null) {
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
const start = Math.min(Math.min(anchor, head), update4.view.state.doc.length);
|
|
442
|
+
const end = Math.min(Math.max(anchor, head), update4.view.state.doc.length);
|
|
443
|
+
const startLine = update4.view.state.doc.lineAt(start);
|
|
444
|
+
const endLine = update4.view.state.doc.lineAt(end);
|
|
445
|
+
const color = state.info.color ?? "#30bced";
|
|
446
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
447
|
+
if (startLine.number === endLine.number) {
|
|
448
|
+
decorations.push({
|
|
449
|
+
from: start,
|
|
450
|
+
to: end,
|
|
451
|
+
value: Decoration.mark({
|
|
452
|
+
attributes: {
|
|
453
|
+
style: `background-color: ${lightColor}`
|
|
454
|
+
},
|
|
455
|
+
class: "cm-ySelection"
|
|
456
|
+
})
|
|
457
|
+
});
|
|
458
|
+
} else {
|
|
459
|
+
decorations.push({
|
|
460
|
+
from: start,
|
|
461
|
+
to: startLine.from + startLine.length,
|
|
462
|
+
value: Decoration.mark({
|
|
463
|
+
attributes: {
|
|
464
|
+
style: `background-color: ${color}`
|
|
465
|
+
},
|
|
466
|
+
class: "cm-ySelection"
|
|
467
|
+
})
|
|
468
|
+
});
|
|
469
|
+
decorations.push({
|
|
470
|
+
from: endLine.from,
|
|
471
|
+
to: end,
|
|
472
|
+
value: Decoration.mark({
|
|
473
|
+
attributes: {
|
|
474
|
+
style: `background-color: ${color}`
|
|
475
|
+
},
|
|
476
|
+
class: "cm-ySelection"
|
|
477
|
+
})
|
|
478
|
+
});
|
|
479
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
480
|
+
const linePos = update4.view.state.doc.line(i).from;
|
|
481
|
+
decorations.push({
|
|
482
|
+
from: linePos,
|
|
483
|
+
to: linePos,
|
|
484
|
+
value: Decoration.line({
|
|
485
|
+
attributes: {
|
|
486
|
+
style: `background-color: ${color}`,
|
|
487
|
+
class: "cm-yLineSelection"
|
|
488
|
+
}
|
|
489
|
+
})
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
decorations.push({
|
|
494
|
+
from: head,
|
|
495
|
+
to: head,
|
|
496
|
+
value: Decoration.widget({
|
|
497
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
498
|
+
block: false,
|
|
499
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
500
|
+
})
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
this.decorations = Decoration.set(decorations, true);
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
507
|
+
constructor(name, color) {
|
|
508
|
+
super();
|
|
509
|
+
this.name = name;
|
|
510
|
+
this.color = color;
|
|
511
|
+
this.name = name;
|
|
512
|
+
this.color = color;
|
|
513
|
+
}
|
|
514
|
+
toDOM() {
|
|
515
|
+
const span = document.createElement("span");
|
|
516
|
+
span.className = "cm-ySelectionCaret";
|
|
517
|
+
span.style.backgroundColor = this.color;
|
|
518
|
+
span.style.borderColor = this.color;
|
|
519
|
+
const dot = document.createElement("div");
|
|
520
|
+
dot.className = "cm-ySelectionCaretDot";
|
|
521
|
+
const info = document.createElement("div");
|
|
522
|
+
info.className = "cm-ySelectionInfo";
|
|
523
|
+
info.innerText = this.name;
|
|
524
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
525
|
+
span.appendChild(dot);
|
|
526
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
527
|
+
span.appendChild(info);
|
|
528
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
529
|
+
return span;
|
|
530
|
+
}
|
|
531
|
+
eq(widget) {
|
|
532
|
+
return widget.color === this.color;
|
|
533
|
+
}
|
|
534
|
+
compare(widget) {
|
|
535
|
+
return widget.color === this.color;
|
|
536
|
+
}
|
|
537
|
+
updateDOM() {
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
get estimatedHeight() {
|
|
541
|
+
return -1;
|
|
542
|
+
}
|
|
543
|
+
ignoreEvent() {
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
var styles = EditorView.baseTheme({
|
|
548
|
+
".cm-ySelection": {},
|
|
549
|
+
".cm-yLineSelection": {
|
|
550
|
+
padding: 0,
|
|
551
|
+
margin: "0px 2px 0px 4px"
|
|
552
|
+
},
|
|
553
|
+
".cm-ySelectionCaret": {
|
|
554
|
+
position: "relative",
|
|
555
|
+
borderLeft: "1px solid black",
|
|
556
|
+
borderRight: "1px solid black",
|
|
557
|
+
marginLeft: "-1px",
|
|
558
|
+
marginRight: "-1px",
|
|
559
|
+
boxSizing: "border-box",
|
|
560
|
+
display: "inline"
|
|
561
|
+
},
|
|
562
|
+
".cm-ySelectionCaretDot": {
|
|
563
|
+
borderRadius: "50%",
|
|
564
|
+
position: "absolute",
|
|
565
|
+
width: ".4em",
|
|
566
|
+
height: ".4em",
|
|
567
|
+
top: "-.2em",
|
|
568
|
+
left: "-.2em",
|
|
569
|
+
backgroundColor: "inherit",
|
|
570
|
+
transition: "transform .3s ease-in-out",
|
|
571
|
+
boxSizing: "border-box"
|
|
572
|
+
},
|
|
573
|
+
".cm-ySelectionCaret:hover > .cm-ySelectionCaretDot": {
|
|
574
|
+
transformOrigin: "bottom center",
|
|
575
|
+
transform: "scale(0)"
|
|
576
|
+
},
|
|
577
|
+
".cm-ySelectionInfo": {
|
|
578
|
+
position: "absolute",
|
|
579
|
+
top: "-1.05em",
|
|
580
|
+
left: "-1px",
|
|
581
|
+
fontSize: ".75em",
|
|
582
|
+
fontFamily: "serif",
|
|
583
|
+
fontStyle: "normal",
|
|
584
|
+
fontWeight: "normal",
|
|
585
|
+
lineHeight: "normal",
|
|
586
|
+
userSelect: "none",
|
|
587
|
+
color: "white",
|
|
588
|
+
paddingLeft: "2px",
|
|
589
|
+
paddingRight: "2px",
|
|
590
|
+
zIndex: 101,
|
|
591
|
+
transition: "opacity .3s ease-in-out",
|
|
592
|
+
backgroundColor: "inherit",
|
|
593
|
+
// these should be separate
|
|
594
|
+
opacity: 0,
|
|
595
|
+
transitionDelay: "0s",
|
|
596
|
+
whiteSpace: "nowrap"
|
|
597
|
+
},
|
|
598
|
+
".cm-ySelectionCaret:hover > .cm-ySelectionInfo": {
|
|
599
|
+
opacity: 1,
|
|
600
|
+
transitionDelay: "0s"
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
52
604
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
53
605
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
54
606
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
55
607
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
56
|
-
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
608
|
+
import { drawSelection, EditorView as EditorView2, placeholder } from "@codemirror/view";
|
|
57
609
|
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
58
|
-
|
|
610
|
+
EditorView2.lineWrapping,
|
|
59
611
|
// TODO(burdon): Compare with minimalSetup.
|
|
60
612
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
61
613
|
bracketMatching(),
|
|
@@ -67,10 +619,10 @@ var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
|
67
619
|
].filter(Boolean);
|
|
68
620
|
|
|
69
621
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
70
|
-
import { EditorView as
|
|
622
|
+
import { EditorView as EditorView3, keymap as keymap2 } from "@codemirror/view";
|
|
71
623
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
72
624
|
import { invariant } from "@dxos/invariant";
|
|
73
|
-
var
|
|
625
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
74
626
|
var defaultOptions = {
|
|
75
627
|
effect: 2,
|
|
76
628
|
maxParticles: 200,
|
|
@@ -115,7 +667,7 @@ var blast = (options = defaultOptions) => {
|
|
|
115
667
|
};
|
|
116
668
|
return [
|
|
117
669
|
// Cursor moved.
|
|
118
|
-
|
|
670
|
+
EditorView3.updateListener.of((update4) => {
|
|
119
671
|
if (blaster?.node !== update4.view.scrollDOM) {
|
|
120
672
|
if (blaster) {
|
|
121
673
|
blaster.destroy();
|
|
@@ -197,7 +749,7 @@ var Blaster = class {
|
|
|
197
749
|
}
|
|
198
750
|
initialize() {
|
|
199
751
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
200
|
-
F:
|
|
752
|
+
F: __dxlog_file2,
|
|
201
753
|
L: 138,
|
|
202
754
|
S: this,
|
|
203
755
|
A: [
|
|
@@ -234,7 +786,7 @@ var Blaster = class {
|
|
|
234
786
|
}
|
|
235
787
|
start() {
|
|
236
788
|
invariant(this._canvas && this._ctx, void 0, {
|
|
237
|
-
F:
|
|
789
|
+
F: __dxlog_file2,
|
|
238
790
|
L: 177,
|
|
239
791
|
S: this,
|
|
240
792
|
A: [
|
|
@@ -330,707 +882,223 @@ var Effect2 = class extends Effect {
|
|
|
330
882
|
particle.vy *= particle.drag;
|
|
331
883
|
particle.theta += random(-0.5, 0.5);
|
|
332
884
|
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
333
|
-
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
334
|
-
particle.size *= this._options.particleShrinkRate;
|
|
335
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
336
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
337
|
-
ctx.beginPath();
|
|
338
|
-
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
339
|
-
ctx.fill();
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
function throttle(callback, limit) {
|
|
343
|
-
let wait = false;
|
|
344
|
-
return function(...args) {
|
|
345
|
-
if (!wait) {
|
|
346
|
-
callback.apply(this, args);
|
|
347
|
-
wait = true;
|
|
348
|
-
setTimeout(() => {
|
|
349
|
-
wait = false;
|
|
350
|
-
}, limit);
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
var getRGBComponents = (node, color) => {
|
|
355
|
-
if (typeof color === "function") {
|
|
356
|
-
return color();
|
|
357
|
-
}
|
|
358
|
-
const bgColor = getComputedStyle(node).color;
|
|
359
|
-
if (bgColor) {
|
|
360
|
-
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
361
|
-
if (x) {
|
|
362
|
-
return x;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
return [
|
|
366
|
-
50,
|
|
367
|
-
50,
|
|
368
|
-
50
|
|
369
|
-
];
|
|
370
|
-
};
|
|
371
|
-
var random = (min, max) => {
|
|
372
|
-
if (!max) {
|
|
373
|
-
max = min;
|
|
374
|
-
min = 0;
|
|
375
|
-
}
|
|
376
|
-
return min + ~~(Math.random() * (max - min + 1));
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
380
|
-
import { ViewPlugin, EditorView as EditorView3, Decoration } from "@codemirror/view";
|
|
381
|
-
import get from "lodash.get";
|
|
382
|
-
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
383
|
-
|
|
384
|
-
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
385
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
386
|
-
var headings = {
|
|
387
|
-
1: [
|
|
388
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
389
|
-
"-ml-[10px]"
|
|
390
|
-
],
|
|
391
|
-
2: [
|
|
392
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
393
|
-
"-ml-[8px]"
|
|
394
|
-
],
|
|
395
|
-
3: [
|
|
396
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
397
|
-
"-ml-[7px]"
|
|
398
|
-
],
|
|
399
|
-
4: [
|
|
400
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
401
|
-
"-ml-[6px]"
|
|
402
|
-
],
|
|
403
|
-
5: [
|
|
404
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
405
|
-
"-ml-[5px]"
|
|
406
|
-
],
|
|
407
|
-
6: [
|
|
408
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
409
|
-
"-ml-[4px]"
|
|
410
|
-
]
|
|
411
|
-
};
|
|
412
|
-
var heading = (level, readonly) => {
|
|
413
|
-
const [style, offset] = headings[level];
|
|
414
|
-
return mx(style, readonly && offset);
|
|
415
|
-
};
|
|
416
|
-
var light = "text-neutral-200 dark:text-neutral-800";
|
|
417
|
-
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
418
|
-
var bold = "font-bold";
|
|
419
|
-
var italic = "italic";
|
|
420
|
-
var strikethrough = "line-through";
|
|
421
|
-
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
422
|
-
var codeMark = "font-mono text-primary-500";
|
|
423
|
-
var inlineUrl = mx(code, "px-1");
|
|
424
|
-
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
425
|
-
|
|
426
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
427
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
428
|
-
var tokens = tailwindConfig({}).theme;
|
|
429
|
-
|
|
430
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
431
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
432
|
-
var styles = EditorView3.baseTheme({
|
|
433
|
-
"& .cm-codeblock": {
|
|
434
|
-
fontFamily: get(tokens, "fontFamily.mono", []).join(",")
|
|
435
|
-
},
|
|
436
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
437
|
-
background: get(tokens, "extend.colors.neutral.50")
|
|
438
|
-
},
|
|
439
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
440
|
-
background: get(tokens, "extend.colors.neutral.850")
|
|
441
|
-
},
|
|
442
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
443
|
-
display: "block",
|
|
444
|
-
paddingInline: "4px !important"
|
|
445
|
-
},
|
|
446
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
447
|
-
paddingTop: "4px !important",
|
|
448
|
-
borderTopLeftRadius: "4px",
|
|
449
|
-
borderTopRightRadius: "4px"
|
|
450
|
-
},
|
|
451
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
452
|
-
paddingBottom: "4px !important",
|
|
453
|
-
borderBottomLeftRadius: "4px",
|
|
454
|
-
borderBottomRightRadius: "4px"
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
var getLineRange = (lines, from, to) => {
|
|
458
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
459
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
460
|
-
return [
|
|
461
|
-
start,
|
|
462
|
-
end
|
|
463
|
-
];
|
|
464
|
-
};
|
|
465
|
-
var code2 = () => {
|
|
466
|
-
const getDecorations = (view) => {
|
|
467
|
-
const decorations = [];
|
|
468
|
-
if (view.state.readOnly) {
|
|
469
|
-
const text = view.state.doc.sliceString(0);
|
|
470
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
471
|
-
const blocks = view.viewportLineBlocks;
|
|
472
|
-
for (const match of matches) {
|
|
473
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
474
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
475
|
-
const block = blocks[i];
|
|
476
|
-
decorations.push(Decoration.line({
|
|
477
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
478
|
-
}).range(block.from));
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return Decoration.set(decorations);
|
|
483
|
-
};
|
|
484
|
-
return [
|
|
485
|
-
ViewPlugin.fromClass(class {
|
|
486
|
-
constructor(view) {
|
|
487
|
-
this.decorations = getDecorations(view);
|
|
488
|
-
}
|
|
489
|
-
update(update4) {
|
|
490
|
-
if (update4.docChanged || update4.viewportChanged) {
|
|
491
|
-
this.decorations = getDecorations(update4.view);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}, {
|
|
495
|
-
decorations: (value) => value.decorations
|
|
496
|
-
}),
|
|
497
|
-
styles
|
|
498
|
-
];
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
502
|
-
import { StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
|
|
503
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin3, WidgetType } from "@codemirror/view";
|
|
504
|
-
import sortBy from "lodash.sortby";
|
|
505
|
-
import { debounce } from "@dxos/async";
|
|
506
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
507
|
-
import { log as log3 } from "@dxos/log";
|
|
508
|
-
import { nonNullable } from "@dxos/util";
|
|
509
|
-
|
|
510
|
-
// packages/ui/react-ui-editor/src/extensions/util.ts
|
|
511
|
-
import { log } from "@dxos/log";
|
|
512
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/util.ts";
|
|
513
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
514
|
-
try {
|
|
515
|
-
return fn(...args);
|
|
516
|
-
} catch (error) {
|
|
517
|
-
log.catch(error, void 0, {
|
|
518
|
-
F: __dxlog_file2,
|
|
519
|
-
L: 16,
|
|
520
|
-
S: void 0,
|
|
521
|
-
C: (f, a) => f(...a)
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
527
|
-
import { StateField as StateField2 } from "@codemirror/state";
|
|
528
|
-
import get2 from "lodash.get";
|
|
529
|
-
import { useEffect, useState } from "react";
|
|
530
|
-
import { yCollab } from "y-codemirror.next";
|
|
531
|
-
import * as Y from "yjs";
|
|
532
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
533
|
-
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
534
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
535
|
-
|
|
536
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
537
|
-
import { Annotation, Facet, StateEffect, StateField } from "@codemirror/state";
|
|
538
|
-
import { ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
539
|
-
import * as automerge2 from "@dxos/automerge/automerge";
|
|
540
|
-
|
|
541
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/semaphore.ts
|
|
542
|
-
import { next as automerge } from "@dxos/automerge/automerge";
|
|
543
|
-
|
|
544
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-automerge.ts
|
|
545
|
-
import { next as am } from "@dxos/automerge/automerge";
|
|
546
|
-
var updateAutomerge = (field, handle, transactions, state) => {
|
|
547
|
-
const { lastHeads, path } = state.field(field);
|
|
548
|
-
let hasChanges = false;
|
|
549
|
-
for (const tr of transactions) {
|
|
550
|
-
tr.changes.iterChanges(() => {
|
|
551
|
-
hasChanges = true;
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
if (!hasChanges) {
|
|
555
|
-
return void 0;
|
|
556
|
-
}
|
|
557
|
-
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
558
|
-
for (const tr of transactions) {
|
|
559
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
560
|
-
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
return newHeads ?? void 0;
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-codemirror.ts
|
|
568
|
-
import { ChangeSet } from "@codemirror/state";
|
|
569
|
-
var updateCodeMirror = (view, selection, target, patches) => {
|
|
570
|
-
for (const patch of patches) {
|
|
571
|
-
const changeSpec = handlePatch(patch, target, view.state);
|
|
572
|
-
if (changeSpec != null) {
|
|
573
|
-
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
574
|
-
selection = selection.map(changeSet, 1);
|
|
575
|
-
view.dispatch({
|
|
576
|
-
changes: changeSet,
|
|
577
|
-
annotations: reconcileAnnotationType.of({})
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
view.dispatch({
|
|
582
|
-
selection,
|
|
583
|
-
annotations: reconcileAnnotationType.of({})
|
|
584
|
-
});
|
|
585
|
-
};
|
|
586
|
-
var handlePatch = (patch, target, state) => {
|
|
587
|
-
if (patch.action === "insert") {
|
|
588
|
-
return handleInsert(target, patch);
|
|
589
|
-
} else if (patch.action === "splice") {
|
|
590
|
-
return handleSplice(target, patch);
|
|
591
|
-
} else if (patch.action === "del") {
|
|
592
|
-
return handleDel(target, patch);
|
|
593
|
-
} else if (patch.action === "put") {
|
|
594
|
-
return handlePut(target, patch, state);
|
|
595
|
-
} else {
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
var handleInsert = (target, patch) => {
|
|
600
|
-
const index = charPath(target, patch.path);
|
|
601
|
-
if (index == null) {
|
|
602
|
-
return [];
|
|
885
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
886
|
+
particle.size *= this._options.particleShrinkRate;
|
|
887
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
888
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
889
|
+
ctx.beginPath();
|
|
890
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
891
|
+
ctx.fill();
|
|
603
892
|
}
|
|
604
|
-
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
605
|
-
return [
|
|
606
|
-
{
|
|
607
|
-
from: index,
|
|
608
|
-
to: index,
|
|
609
|
-
insert: text
|
|
610
|
-
}
|
|
611
|
-
];
|
|
612
893
|
};
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
894
|
+
function throttle(callback, limit) {
|
|
895
|
+
let wait = false;
|
|
896
|
+
return function(...args) {
|
|
897
|
+
if (!wait) {
|
|
898
|
+
callback.apply(this, args);
|
|
899
|
+
wait = true;
|
|
900
|
+
setTimeout(() => {
|
|
901
|
+
wait = false;
|
|
902
|
+
}, limit);
|
|
622
903
|
}
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
var
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return [];
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
var getRGBComponents = (node, color) => {
|
|
907
|
+
if (typeof color === "function") {
|
|
908
|
+
return color();
|
|
629
909
|
}
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
910
|
+
const bgColor = getComputedStyle(node).color;
|
|
911
|
+
if (bgColor) {
|
|
912
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
913
|
+
if (x) {
|
|
914
|
+
return x;
|
|
635
915
|
}
|
|
636
|
-
];
|
|
637
|
-
};
|
|
638
|
-
var handlePut = (target, patch, state) => {
|
|
639
|
-
const index = charPath(target, [
|
|
640
|
-
...patch.path,
|
|
641
|
-
0
|
|
642
|
-
]);
|
|
643
|
-
if (index == null) {
|
|
644
|
-
return [];
|
|
645
|
-
}
|
|
646
|
-
const length = state.doc.length;
|
|
647
|
-
if (typeof patch.value !== "string") {
|
|
648
|
-
return [];
|
|
649
916
|
}
|
|
650
917
|
return [
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
insert: patch.value
|
|
655
|
-
}
|
|
918
|
+
50,
|
|
919
|
+
50,
|
|
920
|
+
50
|
|
656
921
|
];
|
|
657
922
|
};
|
|
658
|
-
var
|
|
659
|
-
if (
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
for (let i = 0; i < textPath.length; i++) {
|
|
663
|
-
if (textPath[i] !== candidatePath[i]) {
|
|
664
|
-
return null;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
const index = candidatePath[candidatePath.length - 1];
|
|
668
|
-
if (typeof index === "number") {
|
|
669
|
-
return index;
|
|
923
|
+
var random = (min, max) => {
|
|
924
|
+
if (!max) {
|
|
925
|
+
max = min;
|
|
926
|
+
min = 0;
|
|
670
927
|
}
|
|
671
|
-
return
|
|
928
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
672
929
|
};
|
|
673
930
|
|
|
674
|
-
// packages/ui/react-ui-editor/src/
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
931
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
932
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView4, Decoration as Decoration2 } from "@codemirror/view";
|
|
933
|
+
import get2 from "lodash.get";
|
|
934
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
935
|
+
|
|
936
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
|
+
import * as random2 from "lib0/random";
|
|
938
|
+
var cursorColors = [
|
|
939
|
+
{
|
|
940
|
+
color: "#30bced",
|
|
941
|
+
light: "#30bced33"
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
color: "#6eeb83",
|
|
945
|
+
light: "#6eeb8333"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
color: "#ffbc42",
|
|
949
|
+
light: "#ffbc4233"
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
color: "#ecd444",
|
|
953
|
+
light: "#ecd44433"
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
color: "#ee6352",
|
|
957
|
+
light: "#ee635233"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
color: "#9ac2c9",
|
|
961
|
+
light: "#9ac2c933"
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
color: "#8acb88",
|
|
965
|
+
light: "#8acb8833"
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
color: "#1be7ff",
|
|
969
|
+
light: "#1be7ff33"
|
|
712
970
|
}
|
|
713
|
-
|
|
971
|
+
];
|
|
972
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
714
973
|
|
|
715
|
-
// packages/ui/react-ui-editor/src/
|
|
716
|
-
|
|
717
|
-
var
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
result.unreconciledTransactions = [];
|
|
747
|
-
} else {
|
|
748
|
-
if (!isReconcileTx(tr)) {
|
|
749
|
-
result.unreconciledTransactions.push(tr);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
return result;
|
|
753
|
-
}
|
|
754
|
-
});
|
|
755
|
-
const semaphore = new PatchSemaphore(stateField);
|
|
756
|
-
const viewPlugin = ViewPlugin2.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
757
|
-
constructor(view) {
|
|
758
|
-
this._handleChange = () => {
|
|
759
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
760
|
-
};
|
|
761
|
-
this._view = view;
|
|
762
|
-
handle.addListener("change", this._handleChange);
|
|
763
|
-
}
|
|
764
|
-
update(update4) {
|
|
765
|
-
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
766
|
-
queueMicrotask(() => {
|
|
767
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
destroy() {
|
|
772
|
-
handle.addListener("change", this._handleChange);
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
|
-
return {
|
|
776
|
-
extension: [
|
|
777
|
-
stateField,
|
|
778
|
-
semaphoreFacet.of(semaphore),
|
|
779
|
-
viewPlugin
|
|
780
|
-
]
|
|
781
|
-
};
|
|
974
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
976
|
+
var headings = {
|
|
977
|
+
1: [
|
|
978
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
979
|
+
"-ml-[10px]"
|
|
980
|
+
],
|
|
981
|
+
2: [
|
|
982
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
983
|
+
"-ml-[8px]"
|
|
984
|
+
],
|
|
985
|
+
3: [
|
|
986
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
987
|
+
"-ml-[7px]"
|
|
988
|
+
],
|
|
989
|
+
4: [
|
|
990
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
991
|
+
"-ml-[6px]"
|
|
992
|
+
],
|
|
993
|
+
5: [
|
|
994
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
995
|
+
"-ml-[5px]"
|
|
996
|
+
],
|
|
997
|
+
6: [
|
|
998
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
999
|
+
"-ml-[4px]"
|
|
1000
|
+
]
|
|
1001
|
+
};
|
|
1002
|
+
var heading = (level, readonly) => {
|
|
1003
|
+
const [style, offset] = headings[level];
|
|
1004
|
+
return mx(style, readonly && offset);
|
|
782
1005
|
};
|
|
783
|
-
var
|
|
784
|
-
var
|
|
1006
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1008
|
+
var bold = "font-bold";
|
|
1009
|
+
var italic = "italic";
|
|
1010
|
+
var strikethrough = "line-through";
|
|
1011
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1012
|
+
var codeMark = "font-mono text-primary-500";
|
|
1013
|
+
var inlineUrl = mx(code, "px-1");
|
|
1014
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
785
1015
|
|
|
786
|
-
// packages/ui/react-ui-editor/src/
|
|
787
|
-
import
|
|
788
|
-
var
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
{
|
|
794
|
-
|
|
795
|
-
light: "#6eeb8333"
|
|
796
|
-
},
|
|
797
|
-
{
|
|
798
|
-
color: "#ffbc42",
|
|
799
|
-
light: "#ffbc4233"
|
|
1016
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1017
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1018
|
+
var tokens = tailwindConfig({}).theme;
|
|
1019
|
+
|
|
1020
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1021
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1022
|
+
var styles2 = EditorView4.baseTheme({
|
|
1023
|
+
"& .cm-codeblock": {
|
|
1024
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
800
1025
|
},
|
|
801
|
-
{
|
|
802
|
-
|
|
803
|
-
light: "#ecd44433"
|
|
1026
|
+
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1027
|
+
background: get2(tokens, "extend.colors.neutral.50")
|
|
804
1028
|
},
|
|
805
|
-
{
|
|
806
|
-
|
|
807
|
-
light: "#ee635233"
|
|
1029
|
+
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1030
|
+
background: get2(tokens, "extend.colors.neutral.850")
|
|
808
1031
|
},
|
|
809
|
-
{
|
|
810
|
-
|
|
811
|
-
|
|
1032
|
+
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1033
|
+
display: "block",
|
|
1034
|
+
paddingInline: "4px !important"
|
|
812
1035
|
},
|
|
813
|
-
{
|
|
814
|
-
|
|
815
|
-
|
|
1036
|
+
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1037
|
+
paddingTop: "4px !important",
|
|
1038
|
+
borderTopLeftRadius: "4px",
|
|
1039
|
+
borderTopRightRadius: "4px"
|
|
816
1040
|
},
|
|
817
|
-
{
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
];
|
|
822
|
-
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
823
|
-
|
|
824
|
-
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
825
|
-
import * as decoding from "lib0/decoding";
|
|
826
|
-
import * as encoding from "lib0/encoding";
|
|
827
|
-
import { Observable } from "lib0/observable";
|
|
828
|
-
import * as awarenessProtocol from "y-protocols/awareness";
|
|
829
|
-
import { log as log2 } from "@dxos/log";
|
|
830
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
831
|
-
var messageAwareness = 1;
|
|
832
|
-
var messageQueryAwareness = 3;
|
|
833
|
-
var SpaceAwarenessProvider = class extends Observable {
|
|
834
|
-
constructor({ space, doc, channel, awareness }) {
|
|
835
|
-
super();
|
|
836
|
-
this._space = space;
|
|
837
|
-
this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
|
|
838
|
-
this._channel = channel;
|
|
839
|
-
this._clientId = doc.clientID;
|
|
840
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
841
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
842
|
-
if (typeof window !== "undefined") {
|
|
843
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
844
|
-
} else if (typeof process !== "undefined") {
|
|
845
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
846
|
-
}
|
|
847
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
848
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
849
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
850
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
851
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
852
|
-
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
853
|
-
this._clientId
|
|
854
|
-
]));
|
|
855
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
856
|
-
}
|
|
857
|
-
get awareness() {
|
|
858
|
-
return this._awareness;
|
|
859
|
-
}
|
|
860
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
861
|
-
log2("awareness update", {
|
|
862
|
-
added,
|
|
863
|
-
updated,
|
|
864
|
-
removed,
|
|
865
|
-
origin
|
|
866
|
-
}, {
|
|
867
|
-
F: __dxlog_file3,
|
|
868
|
-
L: 67,
|
|
869
|
-
S: this,
|
|
870
|
-
C: (f, a) => f(...a)
|
|
871
|
-
});
|
|
872
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
873
|
-
const encoderAwareness = encoding.createEncoder();
|
|
874
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
875
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
876
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
877
|
-
}
|
|
878
|
-
_handleSpaceMessage({ payload }) {
|
|
879
|
-
log2("space message", payload, {
|
|
880
|
-
F: __dxlog_file3,
|
|
881
|
-
L: 79,
|
|
882
|
-
S: this,
|
|
883
|
-
C: (f, a) => f(...a)
|
|
884
|
-
});
|
|
885
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
886
|
-
const encoder = this._readMessage(data);
|
|
887
|
-
if (encoder) {
|
|
888
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
_readMessage(message) {
|
|
892
|
-
const decoder = decoding.createDecoder(message);
|
|
893
|
-
const encoder = encoding.createEncoder();
|
|
894
|
-
const messageType = decoding.readVarUint(decoder);
|
|
895
|
-
let sendReply = false;
|
|
896
|
-
switch (messageType) {
|
|
897
|
-
case messageAwareness: {
|
|
898
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
899
|
-
break;
|
|
900
|
-
}
|
|
901
|
-
case messageQueryAwareness: {
|
|
902
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
903
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
904
|
-
sendReply = true;
|
|
905
|
-
break;
|
|
906
|
-
}
|
|
907
|
-
default: {
|
|
908
|
-
console.error("Invalid message:", messageType);
|
|
909
|
-
return encoder;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (!sendReply) {
|
|
913
|
-
return null;
|
|
914
|
-
}
|
|
915
|
-
return encoder;
|
|
916
|
-
}
|
|
917
|
-
_handleBeforeUnload() {
|
|
918
|
-
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
919
|
-
this._clientId
|
|
920
|
-
], "window unload");
|
|
1041
|
+
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1042
|
+
paddingBottom: "4px !important",
|
|
1043
|
+
borderBottomLeftRadius: "4px",
|
|
1044
|
+
borderBottomRightRadius: "4px"
|
|
921
1045
|
}
|
|
922
|
-
};
|
|
923
|
-
|
|
924
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
925
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
926
|
-
var modelState = StateField2.define({
|
|
927
|
-
create: () => void 0,
|
|
928
|
-
update: (model) => model
|
|
929
1046
|
});
|
|
930
|
-
var
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
]);
|
|
938
|
-
return model;
|
|
1047
|
+
var getLineRange = (lines, from, to) => {
|
|
1048
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1049
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1050
|
+
return [
|
|
1051
|
+
start,
|
|
1052
|
+
end
|
|
1053
|
+
];
|
|
939
1054
|
};
|
|
940
|
-
var
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1055
|
+
var code2 = () => {
|
|
1056
|
+
const getDecorations = (view) => {
|
|
1057
|
+
const decorations = [];
|
|
1058
|
+
if (view.state.readOnly) {
|
|
1059
|
+
const text = view.state.doc.sliceString(0);
|
|
1060
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1061
|
+
const blocks = view.viewportLineBlocks;
|
|
1062
|
+
for (const match of matches) {
|
|
1063
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1064
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1065
|
+
const block = blocks[i];
|
|
1066
|
+
decorations.push(Decoration2.line({
|
|
1067
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1068
|
+
}).range(block.from));
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
947
1071
|
}
|
|
948
|
-
return
|
|
949
|
-
}
|
|
950
|
-
};
|
|
951
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
952
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
953
|
-
F: __dxlog_file4,
|
|
954
|
-
L: 97,
|
|
955
|
-
S: void 0,
|
|
956
|
-
A: [
|
|
957
|
-
"text?.doc && text?.content",
|
|
958
|
-
""
|
|
959
|
-
]
|
|
960
|
-
});
|
|
961
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
962
|
-
space,
|
|
963
|
-
doc: text.doc,
|
|
964
|
-
channel: `yjs.awareness.${text.id}`
|
|
965
|
-
}) : void 0;
|
|
966
|
-
const model = {
|
|
967
|
-
id: text.doc.guid,
|
|
968
|
-
content: text.content,
|
|
969
|
-
text: () => text.content.toString(),
|
|
970
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
971
|
-
getCursorFromRange: (range) => {
|
|
972
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
973
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
974
|
-
return [
|
|
975
|
-
arrayToString(from),
|
|
976
|
-
arrayToString(to)
|
|
977
|
-
].join(":");
|
|
978
|
-
},
|
|
979
|
-
getRangeFromCursor: (cursor) => {
|
|
980
|
-
invariant2(text.doc, void 0, {
|
|
981
|
-
F: __dxlog_file4,
|
|
982
|
-
L: 113,
|
|
983
|
-
S: void 0,
|
|
984
|
-
A: [
|
|
985
|
-
"text.doc",
|
|
986
|
-
""
|
|
987
|
-
]
|
|
988
|
-
});
|
|
989
|
-
const parts = cursor.split(":");
|
|
990
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
991
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
992
|
-
return from && to ? {
|
|
993
|
-
from: from.index,
|
|
994
|
-
to: to.index
|
|
995
|
-
} : void 0;
|
|
996
|
-
},
|
|
997
|
-
extension: [
|
|
998
|
-
yCollab(text.content, provider?.awareness),
|
|
999
|
-
modelState.init(() => model)
|
|
1000
|
-
],
|
|
1001
|
-
awareness: provider?.awareness,
|
|
1002
|
-
peer: identity ? {
|
|
1003
|
-
id: identity.identityKey.toHex(),
|
|
1004
|
-
name: identity.profile?.displayName
|
|
1005
|
-
} : void 0
|
|
1006
|
-
};
|
|
1007
|
-
return model;
|
|
1008
|
-
};
|
|
1009
|
-
var createAutomergeModel = ({ identity, text }) => {
|
|
1010
|
-
const obj = text;
|
|
1011
|
-
const doc = getRawDoc(obj, [
|
|
1012
|
-
obj.field
|
|
1013
|
-
]);
|
|
1014
|
-
const model = {
|
|
1015
|
-
id: obj.id,
|
|
1016
|
-
content: doc,
|
|
1017
|
-
text: () => get2(doc.handle.docSync(), doc.path),
|
|
1018
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
1019
|
-
extension: [
|
|
1020
|
-
automergePlugin(doc.handle, doc.path),
|
|
1021
|
-
modelState.init(() => model)
|
|
1022
|
-
],
|
|
1023
|
-
peer: identity ? {
|
|
1024
|
-
id: identity.identityKey.toHex(),
|
|
1025
|
-
name: identity.profile?.displayName
|
|
1026
|
-
} : void 0
|
|
1072
|
+
return Decoration2.set(decorations);
|
|
1027
1073
|
};
|
|
1028
|
-
return
|
|
1074
|
+
return [
|
|
1075
|
+
ViewPlugin3.fromClass(class {
|
|
1076
|
+
constructor(view) {
|
|
1077
|
+
this.decorations = getDecorations(view);
|
|
1078
|
+
}
|
|
1079
|
+
update(update4) {
|
|
1080
|
+
if (update4.docChanged || update4.viewportChanged) {
|
|
1081
|
+
this.decorations = getDecorations(update4.view);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}, {
|
|
1085
|
+
decorations: (value) => value.decorations
|
|
1086
|
+
}),
|
|
1087
|
+
styles2
|
|
1088
|
+
];
|
|
1029
1089
|
};
|
|
1030
1090
|
|
|
1031
1091
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1032
|
-
|
|
1033
|
-
|
|
1092
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1093
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1094
|
+
import get3 from "lodash.get";
|
|
1095
|
+
import sortBy from "lodash.sortby";
|
|
1096
|
+
import { debounce } from "@dxos/async";
|
|
1097
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1098
|
+
import { log as log2 } from "@dxos/log";
|
|
1099
|
+
import { nonNullable } from "@dxos/util";
|
|
1100
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1101
|
+
var styles3 = EditorView5.baseTheme({
|
|
1034
1102
|
"& .cm-bookmark": {
|
|
1035
1103
|
cursor: "pointer",
|
|
1036
1104
|
margin: "4px",
|
|
@@ -1041,28 +1109,44 @@ var styles2 = EditorView4.baseTheme({
|
|
|
1041
1109
|
backgroundColor: "orange"
|
|
1042
1110
|
},
|
|
1043
1111
|
"& .cm-comment": {
|
|
1044
|
-
backgroundColor: "yellow"
|
|
1112
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.50")
|
|
1045
1113
|
},
|
|
1046
1114
|
"& .cm-comment-active": {
|
|
1047
|
-
backgroundColor: "
|
|
1115
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
1048
1116
|
}
|
|
1049
1117
|
});
|
|
1050
1118
|
var marks = {
|
|
1051
|
-
highlight:
|
|
1119
|
+
highlight: Decoration3.mark({
|
|
1052
1120
|
class: "cm-comment"
|
|
1053
1121
|
}),
|
|
1054
|
-
highlightActive:
|
|
1122
|
+
highlightActive: Decoration3.mark({
|
|
1055
1123
|
class: "cm-comment-active"
|
|
1056
1124
|
})
|
|
1057
1125
|
};
|
|
1126
|
+
var setFocus = (view, thread) => {
|
|
1127
|
+
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1128
|
+
if (!range) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
view.dispatch({
|
|
1132
|
+
effects: setSelection.of({
|
|
1133
|
+
active: thread
|
|
1134
|
+
}),
|
|
1135
|
+
selection: {
|
|
1136
|
+
anchor: range.from
|
|
1137
|
+
},
|
|
1138
|
+
scrollIntoView: true
|
|
1139
|
+
});
|
|
1140
|
+
};
|
|
1058
1141
|
var setCommentRange = StateEffect2.define();
|
|
1059
1142
|
var setSelection = StateEffect2.define();
|
|
1060
1143
|
var setCommentState = StateEffect2.define();
|
|
1061
|
-
var commentsStateField =
|
|
1144
|
+
var commentsStateField = StateField2.define({
|
|
1062
1145
|
create: () => ({
|
|
1063
1146
|
ranges: []
|
|
1064
1147
|
}),
|
|
1065
1148
|
update: (value, tr) => {
|
|
1149
|
+
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1066
1150
|
for (const effect of tr.effects) {
|
|
1067
1151
|
if (effect.is(setSelection)) {
|
|
1068
1152
|
return {
|
|
@@ -1071,9 +1155,9 @@ var commentsStateField = StateField3.define({
|
|
|
1071
1155
|
};
|
|
1072
1156
|
}
|
|
1073
1157
|
if (effect.is(setCommentRange)) {
|
|
1074
|
-
const {
|
|
1158
|
+
const { comments: comments2 } = effect.value;
|
|
1075
1159
|
const ranges = comments2.map((comment) => {
|
|
1076
|
-
const range =
|
|
1160
|
+
const range = getRangeFromCursor(cursorConverter3, comment.cursor);
|
|
1077
1161
|
return range && {
|
|
1078
1162
|
...comment,
|
|
1079
1163
|
...range
|
|
@@ -1091,7 +1175,7 @@ var commentsStateField = StateField3.define({
|
|
|
1091
1175
|
return value;
|
|
1092
1176
|
}
|
|
1093
1177
|
});
|
|
1094
|
-
var highlightDecorations =
|
|
1178
|
+
var highlightDecorations = EditorView5.decorations.compute([
|
|
1095
1179
|
commentsStateField
|
|
1096
1180
|
], (state) => {
|
|
1097
1181
|
const { active, ranges } = state.field(commentsStateField);
|
|
@@ -1109,17 +1193,17 @@ var highlightDecorations = EditorView4.decorations.compute([
|
|
|
1109
1193
|
return marks.highlight.range(range.from, range.to);
|
|
1110
1194
|
}
|
|
1111
1195
|
}).filter(nonNullable) ?? [];
|
|
1112
|
-
return
|
|
1196
|
+
return Decoration3.set(decorations);
|
|
1113
1197
|
});
|
|
1114
|
-
var BookmarkWidget = class extends
|
|
1198
|
+
var BookmarkWidget = class extends WidgetType2 {
|
|
1115
1199
|
constructor(_anchor, _id, _handleClick) {
|
|
1116
1200
|
super();
|
|
1117
1201
|
this._anchor = _anchor;
|
|
1118
1202
|
this._id = _id;
|
|
1119
1203
|
this._handleClick = _handleClick;
|
|
1120
|
-
|
|
1121
|
-
F:
|
|
1122
|
-
L:
|
|
1204
|
+
invariant2(this._id, void 0, {
|
|
1205
|
+
F: __dxlog_file3,
|
|
1206
|
+
L: 169,
|
|
1123
1207
|
S: this,
|
|
1124
1208
|
A: [
|
|
1125
1209
|
"this._id",
|
|
@@ -1143,9 +1227,10 @@ var BookmarkWidget = class extends WidgetType {
|
|
|
1143
1227
|
var comments = (options = {}) => {
|
|
1144
1228
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1145
1229
|
const createCommentThread = (view) => {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1230
|
+
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1231
|
+
invariant2(options.onCreate, void 0, {
|
|
1232
|
+
F: __dxlog_file3,
|
|
1233
|
+
L: 225,
|
|
1149
1234
|
S: void 0,
|
|
1150
1235
|
A: [
|
|
1151
1236
|
"options.onCreate",
|
|
@@ -1156,8 +1241,7 @@ var comments = (options = {}) => {
|
|
|
1156
1241
|
if (from === to) {
|
|
1157
1242
|
return false;
|
|
1158
1243
|
}
|
|
1159
|
-
const
|
|
1160
|
-
const relPos = model?.getCursorFromRange?.({
|
|
1244
|
+
const relPos = getCursorFromRange(cursorConverter3, {
|
|
1161
1245
|
from,
|
|
1162
1246
|
to
|
|
1163
1247
|
});
|
|
@@ -1189,7 +1273,7 @@ var comments = (options = {}) => {
|
|
|
1189
1273
|
}
|
|
1190
1274
|
return false;
|
|
1191
1275
|
};
|
|
1192
|
-
const bookmarksViewPlugin =
|
|
1276
|
+
const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
|
|
1193
1277
|
static {
|
|
1194
1278
|
// Match markdown footnotes (option).
|
|
1195
1279
|
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
@@ -1197,7 +1281,7 @@ var comments = (options = {}) => {
|
|
|
1197
1281
|
regexp: /\[\^(\w+)\]/g,
|
|
1198
1282
|
decoration: (match, view, pos) => {
|
|
1199
1283
|
const id = match[1];
|
|
1200
|
-
return
|
|
1284
|
+
return Decoration3.replace({
|
|
1201
1285
|
id,
|
|
1202
1286
|
widget: new BookmarkWidget(pos, id)
|
|
1203
1287
|
});
|
|
@@ -1212,15 +1296,15 @@ var comments = (options = {}) => {
|
|
|
1212
1296
|
}
|
|
1213
1297
|
}, {
|
|
1214
1298
|
decorations: (instance) => instance.bookmarks,
|
|
1215
|
-
provide: (plugin) =>
|
|
1216
|
-
return view.plugin(plugin)?.bookmarks ||
|
|
1299
|
+
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1300
|
+
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1217
1301
|
})
|
|
1218
1302
|
});
|
|
1219
1303
|
return [
|
|
1220
1304
|
bookmarksViewPlugin,
|
|
1221
1305
|
commentsStateField,
|
|
1222
1306
|
highlightDecorations,
|
|
1223
|
-
|
|
1307
|
+
styles3,
|
|
1224
1308
|
//
|
|
1225
1309
|
// Keymap.
|
|
1226
1310
|
//
|
|
@@ -1263,37 +1347,28 @@ var comments = (options = {}) => {
|
|
|
1263
1347
|
// Monitor cursor movement and text updates.
|
|
1264
1348
|
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1265
1349
|
//
|
|
1266
|
-
|
|
1350
|
+
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1351
|
+
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1267
1352
|
{
|
|
1268
1353
|
let mod = false;
|
|
1269
|
-
const model = state.field(modelState);
|
|
1270
1354
|
const { active, ranges } = state.field(commentsStateField);
|
|
1271
1355
|
changes.iterChanges((from, to, from2, to2) => {
|
|
1272
|
-
invariant3(model, void 0, {
|
|
1273
|
-
F: __dxlog_file5,
|
|
1274
|
-
L: 336,
|
|
1275
|
-
S: void 0,
|
|
1276
|
-
A: [
|
|
1277
|
-
"model",
|
|
1278
|
-
""
|
|
1279
|
-
]
|
|
1280
|
-
});
|
|
1281
1356
|
ranges.forEach((range) => {
|
|
1282
1357
|
if (from2 === to2) {
|
|
1283
|
-
const newRange =
|
|
1358
|
+
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1284
1359
|
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1285
|
-
|
|
1360
|
+
log2.info("deleted comment", {
|
|
1286
1361
|
thread: range.id
|
|
1287
1362
|
}, {
|
|
1288
|
-
F:
|
|
1289
|
-
L:
|
|
1363
|
+
F: __dxlog_file3,
|
|
1364
|
+
L: 359,
|
|
1290
1365
|
S: void 0,
|
|
1291
1366
|
C: (f, a) => f(...a)
|
|
1292
1367
|
});
|
|
1293
1368
|
}
|
|
1294
1369
|
}
|
|
1295
1370
|
if (from <= range.to) {
|
|
1296
|
-
const newRange =
|
|
1371
|
+
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1297
1372
|
Object.assign(range, newRange);
|
|
1298
1373
|
mod = true;
|
|
1299
1374
|
}
|
|
@@ -1342,18 +1417,35 @@ var comments = (options = {}) => {
|
|
|
1342
1417
|
})
|
|
1343
1418
|
];
|
|
1344
1419
|
};
|
|
1420
|
+
var getCursorFromRange = (cursorConverter3, range) => {
|
|
1421
|
+
const from = cursorConverter3.toCursor(range.from);
|
|
1422
|
+
const to = cursorConverter3.toCursor(range.to, -1);
|
|
1423
|
+
return [
|
|
1424
|
+
from,
|
|
1425
|
+
to
|
|
1426
|
+
].join(":");
|
|
1427
|
+
};
|
|
1428
|
+
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1429
|
+
const parts = cursor.split(":");
|
|
1430
|
+
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1431
|
+
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1432
|
+
return from && to ? {
|
|
1433
|
+
from,
|
|
1434
|
+
to
|
|
1435
|
+
} : void 0;
|
|
1436
|
+
};
|
|
1345
1437
|
|
|
1346
1438
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1347
|
-
import { Decoration as
|
|
1348
|
-
import
|
|
1349
|
-
var
|
|
1439
|
+
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1440
|
+
import get4 from "lodash.get";
|
|
1441
|
+
var styles4 = EditorView6.baseTheme({
|
|
1350
1442
|
"& .cm-hr": {
|
|
1351
1443
|
// TODO(burdon): ???
|
|
1352
1444
|
// Note that block-level decorations should not have vertical margins,
|
|
1353
|
-
borderBottom: `1px solid ${
|
|
1445
|
+
borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
|
|
1354
1446
|
}
|
|
1355
1447
|
});
|
|
1356
|
-
var HorizontalRuleWidget = class extends
|
|
1448
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1357
1449
|
constructor(_pos) {
|
|
1358
1450
|
super();
|
|
1359
1451
|
this._pos = _pos;
|
|
@@ -1369,13 +1461,13 @@ var HorizontalRuleWidget = class extends WidgetType2 {
|
|
|
1369
1461
|
};
|
|
1370
1462
|
var placeholderMatcher = new MatchDecorator2({
|
|
1371
1463
|
regexp: /^---$/g,
|
|
1372
|
-
decoration: (match, view, pos) =>
|
|
1464
|
+
decoration: (match, view, pos) => Decoration4.replace({
|
|
1373
1465
|
widget: new HorizontalRuleWidget(pos)
|
|
1374
1466
|
})
|
|
1375
1467
|
});
|
|
1376
1468
|
var hr = () => [
|
|
1377
|
-
|
|
1378
|
-
|
|
1469
|
+
styles4,
|
|
1470
|
+
ViewPlugin5.fromClass(class {
|
|
1379
1471
|
constructor(view) {
|
|
1380
1472
|
this.rules = placeholderMatcher.createDeco(view);
|
|
1381
1473
|
}
|
|
@@ -1385,21 +1477,21 @@ var hr = () => [
|
|
|
1385
1477
|
}, {
|
|
1386
1478
|
decorations: (instance) => instance.rules,
|
|
1387
1479
|
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1388
|
-
provide: (plugin) =>
|
|
1389
|
-
return view.plugin(plugin)?.rules ||
|
|
1480
|
+
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
+
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1390
1482
|
})
|
|
1391
1483
|
})
|
|
1392
1484
|
];
|
|
1393
1485
|
|
|
1394
1486
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1395
1487
|
import { syntaxTree } from "@codemirror/language";
|
|
1396
|
-
import { RangeSetBuilder, StateField as
|
|
1397
|
-
import { Decoration as
|
|
1488
|
+
import { RangeSetBuilder, StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
+
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1398
1490
|
var image = (options = {}) => {
|
|
1399
|
-
return
|
|
1491
|
+
return StateField3.define({
|
|
1400
1492
|
create: (state) => update(state, options),
|
|
1401
1493
|
update: (_, tr) => update(tr.state, options),
|
|
1402
|
-
provide: (field) =>
|
|
1494
|
+
provide: (field) => EditorView7.decorations.from(field)
|
|
1403
1495
|
});
|
|
1404
1496
|
};
|
|
1405
1497
|
var update = (state, options) => {
|
|
@@ -1412,7 +1504,7 @@ var update = (state, options) => {
|
|
|
1412
1504
|
if (urlNode) {
|
|
1413
1505
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1414
1506
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1415
|
-
builder.add(hide ? node.from : node.to, node.to,
|
|
1507
|
+
builder.add(hide ? node.from : node.to, node.to, Decoration5.replace({
|
|
1416
1508
|
block: true,
|
|
1417
1509
|
widget: new ImageWidget(url)
|
|
1418
1510
|
}));
|
|
@@ -1422,7 +1514,7 @@ var update = (state, options) => {
|
|
|
1422
1514
|
});
|
|
1423
1515
|
return builder.finish();
|
|
1424
1516
|
};
|
|
1425
|
-
var ImageWidget = class extends
|
|
1517
|
+
var ImageWidget = class extends WidgetType4 {
|
|
1426
1518
|
constructor(_url) {
|
|
1427
1519
|
super();
|
|
1428
1520
|
this._url = _url;
|
|
@@ -1441,16 +1533,16 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1441
1533
|
|
|
1442
1534
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1443
1535
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1444
|
-
import { RangeSetBuilder as RangeSetBuilder2, StateField as
|
|
1445
|
-
import { Decoration as
|
|
1536
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
|
|
1537
|
+
import { Decoration as Decoration6, EditorView as EditorView8, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2 } from "@codemirror/view";
|
|
1446
1538
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1447
1539
|
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1448
1540
|
var link = (options = {}) => {
|
|
1449
1541
|
const extensions = [
|
|
1450
|
-
|
|
1542
|
+
StateField4.define({
|
|
1451
1543
|
create: (state) => update2(state, options),
|
|
1452
1544
|
update: (_, tr) => update2(tr.state, options),
|
|
1453
|
-
provide: (field) =>
|
|
1545
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1454
1546
|
})
|
|
1455
1547
|
];
|
|
1456
1548
|
if (options.onHover) {
|
|
@@ -1501,7 +1593,7 @@ var link = (options = {}) => {
|
|
|
1501
1593
|
}
|
|
1502
1594
|
return extensions;
|
|
1503
1595
|
};
|
|
1504
|
-
var LinkButton = class extends
|
|
1596
|
+
var LinkButton = class extends WidgetType5 {
|
|
1505
1597
|
constructor(_pos, _url, _onAttach) {
|
|
1506
1598
|
super();
|
|
1507
1599
|
this._pos = _pos;
|
|
@@ -1517,7 +1609,7 @@ var LinkButton = class extends WidgetType4 {
|
|
|
1517
1609
|
return el;
|
|
1518
1610
|
}
|
|
1519
1611
|
};
|
|
1520
|
-
var LinkText = class extends
|
|
1612
|
+
var LinkText = class extends WidgetType5 {
|
|
1521
1613
|
constructor(_text, _url) {
|
|
1522
1614
|
super();
|
|
1523
1615
|
this._text = _text;
|
|
@@ -1560,12 +1652,12 @@ var update2 = (state, options) => {
|
|
|
1560
1652
|
return false;
|
|
1561
1653
|
}
|
|
1562
1654
|
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1563
|
-
builder.add(node.from, node.to,
|
|
1655
|
+
builder.add(node.from, node.to, Decoration6.replace({
|
|
1564
1656
|
widget: new LinkText(text, options.link ? url : void 0)
|
|
1565
1657
|
}));
|
|
1566
1658
|
}
|
|
1567
1659
|
if (options.onRender) {
|
|
1568
|
-
builder.add(node.to, node.to,
|
|
1660
|
+
builder.add(node.to, node.to, Decoration6.replace({
|
|
1569
1661
|
widget: new LinkButton(node.from, url, options.onRender)
|
|
1570
1662
|
}));
|
|
1571
1663
|
}
|
|
@@ -1577,14 +1669,14 @@ var update2 = (state, options) => {
|
|
|
1577
1669
|
};
|
|
1578
1670
|
|
|
1579
1671
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1580
|
-
import { EditorView as
|
|
1672
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1581
1673
|
var listener = ({ onFocus, onChange }) => {
|
|
1582
1674
|
const extensions = [];
|
|
1583
|
-
onFocus && extensions.push(
|
|
1675
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1584
1676
|
onFocus(focused);
|
|
1585
1677
|
return null;
|
|
1586
1678
|
}));
|
|
1587
|
-
onChange && extensions.push(
|
|
1679
|
+
onChange && extensions.push(EditorView9.updateListener.of((update4) => {
|
|
1588
1680
|
onChange(update4.state.doc.toString());
|
|
1589
1681
|
}));
|
|
1590
1682
|
return extensions;
|
|
@@ -1599,14 +1691,14 @@ import { languages } from "@codemirror/language-data";
|
|
|
1599
1691
|
import { searchKeymap } from "@codemirror/search";
|
|
1600
1692
|
import { EditorState } from "@codemirror/state";
|
|
1601
1693
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1602
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1694
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1603
1695
|
|
|
1604
1696
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1605
1697
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1606
1698
|
import { HighlightStyle } from "@codemirror/language";
|
|
1607
1699
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1608
1700
|
import { Table } from "@lezer/markdown";
|
|
1609
|
-
import
|
|
1701
|
+
import get5 from "lodash.get";
|
|
1610
1702
|
var markdownTags = {
|
|
1611
1703
|
Blockquote: Tag.define(),
|
|
1612
1704
|
CodeMark: Tag.define(),
|
|
@@ -1792,7 +1884,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1792
1884
|
], {
|
|
1793
1885
|
scope: markdownLanguage,
|
|
1794
1886
|
all: {
|
|
1795
|
-
fontFamily:
|
|
1887
|
+
fontFamily: get5(tokens, "fontFamily.body", []).join(",")
|
|
1796
1888
|
}
|
|
1797
1889
|
});
|
|
1798
1890
|
};
|
|
@@ -1802,7 +1894,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1802
1894
|
return [
|
|
1803
1895
|
EditorState.allowMultipleSelections.of(true),
|
|
1804
1896
|
EditorState.tabSize.of(2),
|
|
1805
|
-
|
|
1897
|
+
EditorView10.lineWrapping,
|
|
1806
1898
|
customKeymap(),
|
|
1807
1899
|
bracketMatching2(),
|
|
1808
1900
|
closeBrackets2(),
|
|
@@ -1880,13 +1972,13 @@ var mermaid = () => {
|
|
|
1880
1972
|
|
|
1881
1973
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1882
1974
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1883
|
-
import { RangeSetBuilder as RangeSetBuilder3, StateField as
|
|
1884
|
-
import { Decoration as
|
|
1975
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1976
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1885
1977
|
var table = (options = {}) => {
|
|
1886
|
-
return
|
|
1978
|
+
return StateField5.define({
|
|
1887
1979
|
create: (state) => update3(state, options),
|
|
1888
1980
|
update: (_, tr) => update3(tr.state, options),
|
|
1889
|
-
provide: (field) =>
|
|
1981
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1890
1982
|
});
|
|
1891
1983
|
};
|
|
1892
1984
|
var update3 = (state, options) => {
|
|
@@ -1930,17 +2022,17 @@ var update3 = (state, options) => {
|
|
|
1930
2022
|
});
|
|
1931
2023
|
tables.forEach((table2) => {
|
|
1932
2024
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1933
|
-
hide && builder.add(table2.from, table2.to,
|
|
2025
|
+
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
1934
2026
|
block: true,
|
|
1935
2027
|
widget: new TableWidget(table2)
|
|
1936
2028
|
}));
|
|
1937
|
-
builder.add(table2.from, table2.to,
|
|
2029
|
+
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
1938
2030
|
class: "cm-table"
|
|
1939
2031
|
}));
|
|
1940
2032
|
});
|
|
1941
2033
|
return builder.finish();
|
|
1942
2034
|
};
|
|
1943
|
-
var TableWidget = class extends
|
|
2035
|
+
var TableWidget = class extends WidgetType6 {
|
|
1944
2036
|
constructor(_table) {
|
|
1945
2037
|
super();
|
|
1946
2038
|
this._table = _table;
|
|
@@ -1975,14 +2067,14 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1975
2067
|
};
|
|
1976
2068
|
|
|
1977
2069
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
1978
|
-
import { EditorView as
|
|
1979
|
-
var
|
|
2070
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType7, MatchDecorator as MatchDecorator3, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
2071
|
+
var styles5 = EditorView12.baseTheme({
|
|
1980
2072
|
"& .cm-task-item": {
|
|
1981
2073
|
paddingLeft: "4px",
|
|
1982
2074
|
paddingRight: "8px"
|
|
1983
2075
|
}
|
|
1984
2076
|
});
|
|
1985
|
-
var CheckboxWidget = class extends
|
|
2077
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
1986
2078
|
constructor(_pos, _checked, _indent, _onCheck) {
|
|
1987
2079
|
super();
|
|
1988
2080
|
this._pos = _pos;
|
|
@@ -2022,7 +2114,7 @@ var tasklist = (options = {}) => {
|
|
|
2022
2114
|
decoration: (match, view, pos) => {
|
|
2023
2115
|
const indent = Math.floor(match[1].length / 2);
|
|
2024
2116
|
const checked = match[2] === "x" || match[2] === "X";
|
|
2025
|
-
return
|
|
2117
|
+
return Decoration8.replace({
|
|
2026
2118
|
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2027
2119
|
const idx = pos + match[0].indexOf("[") + 1;
|
|
2028
2120
|
view.dispatch({
|
|
@@ -2040,7 +2132,7 @@ var tasklist = (options = {}) => {
|
|
|
2040
2132
|
});
|
|
2041
2133
|
}
|
|
2042
2134
|
});
|
|
2043
|
-
const tasks =
|
|
2135
|
+
const tasks = ViewPlugin6.fromClass(class {
|
|
2044
2136
|
constructor(view) {
|
|
2045
2137
|
this.tasks = taskMatcher.createDeco(view);
|
|
2046
2138
|
}
|
|
@@ -2049,13 +2141,13 @@ var tasklist = (options = {}) => {
|
|
|
2049
2141
|
}
|
|
2050
2142
|
}, {
|
|
2051
2143
|
decorations: (value) => value.tasks,
|
|
2052
|
-
provide: (plugin) =>
|
|
2053
|
-
return view.plugin(plugin)?.tasks ||
|
|
2144
|
+
provide: (plugin) => EditorView12.atomicRanges.of((view) => {
|
|
2145
|
+
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2054
2146
|
})
|
|
2055
2147
|
});
|
|
2056
2148
|
return [
|
|
2057
2149
|
tasks,
|
|
2058
|
-
|
|
2150
|
+
styles5
|
|
2059
2151
|
];
|
|
2060
2152
|
};
|
|
2061
2153
|
|
|
@@ -2116,8 +2208,29 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2116
2208
|
];
|
|
2117
2209
|
};
|
|
2118
2210
|
|
|
2211
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2212
|
+
import { yCollab } from "y-codemirror.next";
|
|
2213
|
+
|
|
2214
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2215
|
+
import * as Y from "yjs";
|
|
2216
|
+
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2217
|
+
var cursorConverter2 = (text) => ({
|
|
2218
|
+
toCursor: (index, assoc) => {
|
|
2219
|
+
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2220
|
+
},
|
|
2221
|
+
fromCursor: (cursor) => {
|
|
2222
|
+
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
|
|
2226
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2227
|
+
var yjs = (content, awareness2) => [
|
|
2228
|
+
CursorConverter.of(cursorConverter2(content)),
|
|
2229
|
+
yCollab(content, awareness2)
|
|
2230
|
+
];
|
|
2231
|
+
|
|
2119
2232
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2120
|
-
import
|
|
2233
|
+
import get6 from "lodash.get";
|
|
2121
2234
|
var defaultTheme = {
|
|
2122
2235
|
//
|
|
2123
2236
|
// Main layout:
|
|
@@ -2148,7 +2261,7 @@ var defaultTheme = {
|
|
|
2148
2261
|
},
|
|
2149
2262
|
"& .cm-scroller": {
|
|
2150
2263
|
overflow: "visible",
|
|
2151
|
-
fontFamily:
|
|
2264
|
+
fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
|
|
2152
2265
|
},
|
|
2153
2266
|
"& .cm-content": {
|
|
2154
2267
|
padding: 0,
|
|
@@ -2156,11 +2269,11 @@ var defaultTheme = {
|
|
|
2156
2269
|
fontSize: "16px"
|
|
2157
2270
|
},
|
|
2158
2271
|
"&light .cm-content": {
|
|
2159
|
-
color:
|
|
2272
|
+
color: get6(tokens, "extend.colors.neutral.900", "black"),
|
|
2160
2273
|
caretColor: "black"
|
|
2161
2274
|
},
|
|
2162
2275
|
"&dark .cm-content": {
|
|
2163
|
-
color:
|
|
2276
|
+
color: get6(tokens, "extend.colors.neutral.100", "white"),
|
|
2164
2277
|
caretColor: "white"
|
|
2165
2278
|
},
|
|
2166
2279
|
//
|
|
@@ -2188,25 +2301,25 @@ var defaultTheme = {
|
|
|
2188
2301
|
// Selection
|
|
2189
2302
|
//
|
|
2190
2303
|
"&light .cm-selectionBackground": {
|
|
2191
|
-
background:
|
|
2304
|
+
background: get6(tokens, "extend.colors.primary.100")
|
|
2192
2305
|
},
|
|
2193
2306
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2194
|
-
background:
|
|
2307
|
+
background: get6(tokens, "extend.colors.primary.200")
|
|
2195
2308
|
},
|
|
2196
2309
|
"&dark .cm-selectionBackground": {
|
|
2197
|
-
background:
|
|
2310
|
+
background: get6(tokens, "extend.colors.primary.700")
|
|
2198
2311
|
},
|
|
2199
2312
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2200
|
-
background:
|
|
2313
|
+
background: get6(tokens, "extend.colors.primary.600")
|
|
2201
2314
|
},
|
|
2202
2315
|
//
|
|
2203
2316
|
// Search
|
|
2204
2317
|
//
|
|
2205
2318
|
"&light .cm-searchMatch": {
|
|
2206
|
-
backgroundColor:
|
|
2319
|
+
backgroundColor: get6(tokens, "extend.colors.yellow.100")
|
|
2207
2320
|
},
|
|
2208
2321
|
"&dark .cm-searchMatch": {
|
|
2209
|
-
backgroundColor:
|
|
2322
|
+
backgroundColor: get6(tokens, "extend.colors.yellow.700")
|
|
2210
2323
|
},
|
|
2211
2324
|
//
|
|
2212
2325
|
// collaboration
|
|
@@ -2239,12 +2352,12 @@ var defaultTheme = {
|
|
|
2239
2352
|
// link
|
|
2240
2353
|
//
|
|
2241
2354
|
"& .cm-link": {
|
|
2242
|
-
color:
|
|
2355
|
+
color: get6(tokens, "extend.colors.primary.500"),
|
|
2243
2356
|
textDecorationLine: "underline",
|
|
2244
2357
|
textDecorationThickness: "1px",
|
|
2245
2358
|
textUnderlineOffset: "2px",
|
|
2246
2359
|
borderRadius: ".125rem",
|
|
2247
|
-
fontFamily:
|
|
2360
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2248
2361
|
},
|
|
2249
2362
|
//
|
|
2250
2363
|
// tooltip
|
|
@@ -2266,7 +2379,7 @@ var defaultTheme = {
|
|
|
2266
2379
|
display: "none"
|
|
2267
2380
|
},
|
|
2268
2381
|
"& .cm-completionLabel": {
|
|
2269
|
-
fontFamily:
|
|
2382
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2270
2383
|
},
|
|
2271
2384
|
"& .cm-completionMatchedText": {
|
|
2272
2385
|
textDecoration: "none"
|
|
@@ -2282,15 +2395,15 @@ var defaultTheme = {
|
|
|
2282
2395
|
// table
|
|
2283
2396
|
//
|
|
2284
2397
|
"& .cm-table *": {
|
|
2285
|
-
fontFamily: `${
|
|
2398
|
+
fontFamily: `${get6(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2286
2399
|
textDecoration: "none !important"
|
|
2287
2400
|
},
|
|
2288
2401
|
"& .cm-table-head": {
|
|
2289
2402
|
padding: "2px 16px 2px 0px",
|
|
2290
|
-
borderBottom: `1px solid ${
|
|
2403
|
+
borderBottom: `1px solid ${get6(tokens, "extend.colors.neutral.500")}`,
|
|
2291
2404
|
fontWeight: 100,
|
|
2292
2405
|
textAlign: "left",
|
|
2293
|
-
color:
|
|
2406
|
+
color: get6(tokens, "extend.colors.neutral.500")
|
|
2294
2407
|
},
|
|
2295
2408
|
"& .cm-table-cell": {
|
|
2296
2409
|
padding: "2px 16px 2px 0px"
|
|
@@ -2305,8 +2418,8 @@ var defaultTheme = {
|
|
|
2305
2418
|
// font size
|
|
2306
2419
|
// TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
|
|
2307
2420
|
//
|
|
2308
|
-
...Object.keys(
|
|
2309
|
-
const height =
|
|
2421
|
+
...Object.keys(get6(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
2422
|
+
const height = get6(tokens, [
|
|
2310
2423
|
"extend",
|
|
2311
2424
|
"fontSize",
|
|
2312
2425
|
fontSize,
|
|
@@ -2341,23 +2454,23 @@ var defaultTheme = {
|
|
|
2341
2454
|
* </div
|
|
2342
2455
|
*/
|
|
2343
2456
|
"& .cm-panels": {
|
|
2344
|
-
border: `1px solid ${
|
|
2457
|
+
border: `1px solid ${get6(tokens, "extend.colors.neutral.200")}`
|
|
2345
2458
|
},
|
|
2346
2459
|
"& .cm-panel": {
|
|
2347
|
-
background:
|
|
2348
|
-
fontFamily:
|
|
2460
|
+
background: get6(tokens, "extend.colors.neutral.50"),
|
|
2461
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2349
2462
|
},
|
|
2350
2463
|
"& .cm-button": {
|
|
2351
2464
|
margin: "4px",
|
|
2352
|
-
fontFamily:
|
|
2353
|
-
background:
|
|
2465
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(","),
|
|
2466
|
+
background: get6(tokens, "extend.colors.neutral.100"),
|
|
2354
2467
|
backgroundImage: "none",
|
|
2355
2468
|
border: "none",
|
|
2356
2469
|
"&:hover": {
|
|
2357
|
-
background:
|
|
2470
|
+
background: get6(tokens, "extend.colors.neutral.200")
|
|
2358
2471
|
},
|
|
2359
2472
|
"&:active": {
|
|
2360
|
-
background:
|
|
2473
|
+
background: get6(tokens, "extend.colors.neutral.300"),
|
|
2361
2474
|
backgroundImage: "none"
|
|
2362
2475
|
}
|
|
2363
2476
|
},
|
|
@@ -2367,24 +2480,24 @@ var defaultTheme = {
|
|
|
2367
2480
|
};
|
|
2368
2481
|
var textTheme = {
|
|
2369
2482
|
"& .cm-scroller": {
|
|
2370
|
-
fontFamily:
|
|
2483
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2371
2484
|
},
|
|
2372
2485
|
"& .cm-placeholder": {
|
|
2373
|
-
fontFamily:
|
|
2486
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2374
2487
|
}
|
|
2375
2488
|
};
|
|
2376
2489
|
var markdownTheme = {
|
|
2377
2490
|
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
2378
2491
|
"& .cm-placeholder": {
|
|
2379
|
-
fontFamily:
|
|
2492
|
+
fontFamily: get6(tokens, "fontFamily.body", []).join(",")
|
|
2380
2493
|
}
|
|
2381
2494
|
};
|
|
2382
2495
|
var codeTheme = {
|
|
2383
2496
|
"& .cm-scroller": {
|
|
2384
|
-
fontFamily:
|
|
2497
|
+
fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
|
|
2385
2498
|
},
|
|
2386
2499
|
"& .cm-placeholder": {
|
|
2387
|
-
fontFamily:
|
|
2500
|
+
fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
|
|
2388
2501
|
}
|
|
2389
2502
|
};
|
|
2390
2503
|
|
|
@@ -2398,8 +2511,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2398
2511
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2399
2512
|
tabBehavior: "limited"
|
|
2400
2513
|
});
|
|
2401
|
-
const [root, setRoot] =
|
|
2402
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] =
|
|
2514
|
+
const [root, setRoot] = useState(null);
|
|
2515
|
+
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2403
2516
|
useImperativeHandle(forwardedRef, () => ({
|
|
2404
2517
|
root,
|
|
2405
2518
|
state,
|
|
@@ -2409,10 +2522,10 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2409
2522
|
state,
|
|
2410
2523
|
root
|
|
2411
2524
|
]);
|
|
2412
|
-
const { awareness, peer } = model;
|
|
2413
|
-
|
|
2414
|
-
if (
|
|
2415
|
-
|
|
2525
|
+
const { awareness: awareness2, peer } = model;
|
|
2526
|
+
useEffect(() => {
|
|
2527
|
+
if (awareness2 && peer) {
|
|
2528
|
+
awareness2.setLocalStateField("user", {
|
|
2416
2529
|
name: peer.name ?? generateName(peer.id),
|
|
2417
2530
|
color: getColorForValue({
|
|
2418
2531
|
value: peer.id,
|
|
@@ -2426,11 +2539,11 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2426
2539
|
});
|
|
2427
2540
|
}
|
|
2428
2541
|
}, [
|
|
2429
|
-
|
|
2542
|
+
awareness2,
|
|
2430
2543
|
peer,
|
|
2431
2544
|
themeMode
|
|
2432
2545
|
]);
|
|
2433
|
-
|
|
2546
|
+
useEffect(() => {
|
|
2434
2547
|
if (view && comments2?.length) {
|
|
2435
2548
|
view.dispatch({
|
|
2436
2549
|
effects: setCommentRange.of({
|
|
@@ -2443,7 +2556,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2443
2556
|
view,
|
|
2444
2557
|
comments2
|
|
2445
2558
|
]);
|
|
2446
|
-
|
|
2559
|
+
useEffect(() => {
|
|
2447
2560
|
if (!root) {
|
|
2448
2561
|
return;
|
|
2449
2562
|
}
|
|
@@ -2455,9 +2568,9 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2455
2568
|
editorMode === "vim" && vim(),
|
|
2456
2569
|
// Theme.
|
|
2457
2570
|
// TODO(burdon): Make theme configurable.
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2571
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2572
|
+
EditorView13.theme(slots?.editor?.theme ?? {}),
|
|
2573
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2461
2574
|
// Storage and replication.
|
|
2462
2575
|
model.extension,
|
|
2463
2576
|
// Custom.
|
|
@@ -2467,7 +2580,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2467
2580
|
view?.destroy();
|
|
2468
2581
|
setEditor({
|
|
2469
2582
|
state: state2,
|
|
2470
|
-
view: new
|
|
2583
|
+
view: new EditorView13({
|
|
2471
2584
|
state: state2,
|
|
2472
2585
|
parent: root
|
|
2473
2586
|
})
|
|
@@ -2561,23 +2674,370 @@ var defaultMarkdownSlots = {
|
|
|
2561
2674
|
theme: markdownTheme
|
|
2562
2675
|
}
|
|
2563
2676
|
};
|
|
2677
|
+
|
|
2678
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2679
|
+
import get7 from "lodash.get";
|
|
2680
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2681
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2682
|
+
|
|
2683
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2684
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2685
|
+
import { Context as Context2 } from "@dxos/context";
|
|
2686
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2687
|
+
import { log as log3 } from "@dxos/log";
|
|
2688
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2689
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
2690
|
+
var SpaceAwarenessProvider = class {
|
|
2691
|
+
constructor(params) {
|
|
2692
|
+
this.remoteStateChange = new Event2();
|
|
2693
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2694
|
+
this._space = params.space;
|
|
2695
|
+
this._channel = params.channel;
|
|
2696
|
+
this._peerId = params.peerId;
|
|
2697
|
+
this._info = params.info;
|
|
2698
|
+
}
|
|
2699
|
+
open() {
|
|
2700
|
+
this._ctx = new Context2();
|
|
2701
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
2702
|
+
if (this._localState) {
|
|
2703
|
+
await this._space.postMessage(this._channel, {
|
|
2704
|
+
kind: "post",
|
|
2705
|
+
state: this._localState
|
|
2706
|
+
});
|
|
2707
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
2708
|
+
}
|
|
2709
|
+
});
|
|
2710
|
+
const unsubscribe = this._space.listen(this._channel, (message) => {
|
|
2711
|
+
switch (message.payload.kind) {
|
|
2712
|
+
case "query": {
|
|
2713
|
+
this._handleQueryMessage();
|
|
2714
|
+
break;
|
|
2715
|
+
}
|
|
2716
|
+
case "post": {
|
|
2717
|
+
this._handlePostMessage(message.payload);
|
|
2718
|
+
break;
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
});
|
|
2722
|
+
this._ctx.onDispose(unsubscribe);
|
|
2723
|
+
void this._space.postMessage(this._channel, {
|
|
2724
|
+
kind: "query"
|
|
2725
|
+
}).catch((err) => {
|
|
2726
|
+
log3.debug("failed to query awareness", {
|
|
2727
|
+
err
|
|
2728
|
+
}, {
|
|
2729
|
+
F: __dxlog_file4,
|
|
2730
|
+
L: 85,
|
|
2731
|
+
S: this,
|
|
2732
|
+
C: (f, a) => f(...a)
|
|
2733
|
+
});
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
close() {
|
|
2737
|
+
void this._ctx?.dispose();
|
|
2738
|
+
this._ctx = void 0;
|
|
2739
|
+
this._postTask = void 0;
|
|
2740
|
+
}
|
|
2741
|
+
update(position) {
|
|
2742
|
+
invariant3(this._postTask, void 0, {
|
|
2743
|
+
F: __dxlog_file4,
|
|
2744
|
+
L: 96,
|
|
2745
|
+
S: this,
|
|
2746
|
+
A: [
|
|
2747
|
+
"this._postTask",
|
|
2748
|
+
""
|
|
2749
|
+
]
|
|
2750
|
+
});
|
|
2751
|
+
this._localState = {
|
|
2752
|
+
peerId: this._peerId,
|
|
2753
|
+
position,
|
|
2754
|
+
info: this._info
|
|
2755
|
+
};
|
|
2756
|
+
this._postTask.schedule();
|
|
2757
|
+
}
|
|
2758
|
+
getRemoteStates() {
|
|
2759
|
+
return Array.from(this._remoteStates.values());
|
|
2760
|
+
}
|
|
2761
|
+
_handleQueryMessage() {
|
|
2762
|
+
invariant3(this._postTask, void 0, {
|
|
2763
|
+
F: __dxlog_file4,
|
|
2764
|
+
L: 111,
|
|
2765
|
+
S: this,
|
|
2766
|
+
A: [
|
|
2767
|
+
"this._postTask",
|
|
2768
|
+
""
|
|
2769
|
+
]
|
|
2770
|
+
});
|
|
2771
|
+
this._postTask.schedule();
|
|
2772
|
+
}
|
|
2773
|
+
_handlePostMessage(message) {
|
|
2774
|
+
invariant3(message.kind === "post", void 0, {
|
|
2775
|
+
F: __dxlog_file4,
|
|
2776
|
+
L: 116,
|
|
2777
|
+
S: this,
|
|
2778
|
+
A: [
|
|
2779
|
+
"message.kind === 'post'",
|
|
2780
|
+
""
|
|
2781
|
+
]
|
|
2782
|
+
});
|
|
2783
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
2784
|
+
this.remoteStateChange.emit();
|
|
2785
|
+
}
|
|
2786
|
+
};
|
|
2787
|
+
|
|
2788
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2789
|
+
import { StateField as StateField6 } from "@codemirror/state";
|
|
2790
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
2791
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2792
|
+
|
|
2793
|
+
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2794
|
+
import * as decoding from "lib0/decoding";
|
|
2795
|
+
import * as encoding from "lib0/encoding";
|
|
2796
|
+
import { Observable } from "lib0/observable";
|
|
2797
|
+
import * as YP from "y-protocols/awareness";
|
|
2798
|
+
import * as Y2 from "yjs";
|
|
2799
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2800
|
+
import { log as log4 } from "@dxos/log";
|
|
2801
|
+
import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
|
|
2802
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2803
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
2804
|
+
invariant4(text?.doc && text?.content, void 0, {
|
|
2805
|
+
F: __dxlog_file5,
|
|
2806
|
+
L: 23,
|
|
2807
|
+
S: void 0,
|
|
2808
|
+
A: [
|
|
2809
|
+
"text?.doc && text?.content",
|
|
2810
|
+
""
|
|
2811
|
+
]
|
|
2812
|
+
});
|
|
2813
|
+
const provider = space ? new YAwarenessProvider({
|
|
2814
|
+
space,
|
|
2815
|
+
doc: text.doc,
|
|
2816
|
+
channel: `yjs.awareness.${text.id}`
|
|
2817
|
+
}) : void 0;
|
|
2818
|
+
const model = {
|
|
2819
|
+
id: text.doc.guid,
|
|
2820
|
+
content: text.content,
|
|
2821
|
+
text: () => text.content.toString(),
|
|
2822
|
+
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2823
|
+
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2824
|
+
getCursorFromRange: (range) => {
|
|
2825
|
+
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2826
|
+
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2827
|
+
return [
|
|
2828
|
+
arrayToString2(from),
|
|
2829
|
+
arrayToString2(to)
|
|
2830
|
+
].join(":");
|
|
2831
|
+
},
|
|
2832
|
+
getRangeFromCursor: (cursor) => {
|
|
2833
|
+
invariant4(text.doc, void 0, {
|
|
2834
|
+
F: __dxlog_file5,
|
|
2835
|
+
L: 40,
|
|
2836
|
+
S: void 0,
|
|
2837
|
+
A: [
|
|
2838
|
+
"text.doc",
|
|
2839
|
+
""
|
|
2840
|
+
]
|
|
2841
|
+
});
|
|
2842
|
+
const parts = cursor.split(":");
|
|
2843
|
+
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2844
|
+
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2845
|
+
return from && to ? {
|
|
2846
|
+
from: from.index,
|
|
2847
|
+
to: to.index
|
|
2848
|
+
} : void 0;
|
|
2849
|
+
},
|
|
2850
|
+
extension: [
|
|
2851
|
+
modelState.init(() => model),
|
|
2852
|
+
yjs(text.content, provider?.awareness)
|
|
2853
|
+
],
|
|
2854
|
+
awareness: provider?.awareness,
|
|
2855
|
+
peer: identity ? {
|
|
2856
|
+
id: identity.identityKey.toHex(),
|
|
2857
|
+
name: identity.profile?.displayName
|
|
2858
|
+
} : void 0
|
|
2859
|
+
};
|
|
2860
|
+
return model;
|
|
2861
|
+
};
|
|
2862
|
+
var messageAwareness = 1;
|
|
2863
|
+
var messageQueryAwareness = 3;
|
|
2864
|
+
var YAwarenessProvider = class extends Observable {
|
|
2865
|
+
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2866
|
+
super();
|
|
2867
|
+
this._space = space;
|
|
2868
|
+
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2869
|
+
this._channel = channel;
|
|
2870
|
+
this._clientId = doc.clientID;
|
|
2871
|
+
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2872
|
+
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2873
|
+
if (typeof window !== "undefined") {
|
|
2874
|
+
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2875
|
+
} else if (typeof process !== "undefined") {
|
|
2876
|
+
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2877
|
+
}
|
|
2878
|
+
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2879
|
+
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2880
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2881
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
2882
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2883
|
+
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2884
|
+
this._clientId
|
|
2885
|
+
]));
|
|
2886
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2887
|
+
}
|
|
2888
|
+
get awareness() {
|
|
2889
|
+
return this._awareness;
|
|
2890
|
+
}
|
|
2891
|
+
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2892
|
+
log4("awareness update", {
|
|
2893
|
+
added,
|
|
2894
|
+
updated,
|
|
2895
|
+
removed,
|
|
2896
|
+
origin
|
|
2897
|
+
}, {
|
|
2898
|
+
F: __dxlog_file5,
|
|
2899
|
+
L: 122,
|
|
2900
|
+
S: this,
|
|
2901
|
+
C: (f, a) => f(...a)
|
|
2902
|
+
});
|
|
2903
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
2904
|
+
const encoderAwareness = encoding.createEncoder();
|
|
2905
|
+
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2906
|
+
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2907
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2908
|
+
}
|
|
2909
|
+
_handleSpaceMessage({ payload }) {
|
|
2910
|
+
log4("space message", payload, {
|
|
2911
|
+
F: __dxlog_file5,
|
|
2912
|
+
L: 131,
|
|
2913
|
+
S: this,
|
|
2914
|
+
C: (f, a) => f(...a)
|
|
2915
|
+
});
|
|
2916
|
+
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2917
|
+
const encoder = this._readMessage(data);
|
|
2918
|
+
if (encoder) {
|
|
2919
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
_readMessage(message) {
|
|
2923
|
+
const decoder = decoding.createDecoder(message);
|
|
2924
|
+
const encoder = encoding.createEncoder();
|
|
2925
|
+
const messageType = decoding.readVarUint(decoder);
|
|
2926
|
+
let sendReply = false;
|
|
2927
|
+
switch (messageType) {
|
|
2928
|
+
case messageAwareness: {
|
|
2929
|
+
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2930
|
+
break;
|
|
2931
|
+
}
|
|
2932
|
+
case messageQueryAwareness: {
|
|
2933
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
2934
|
+
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2935
|
+
sendReply = true;
|
|
2936
|
+
break;
|
|
2937
|
+
}
|
|
2938
|
+
default: {
|
|
2939
|
+
console.error("Invalid message:", messageType);
|
|
2940
|
+
return encoder;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
if (!sendReply) {
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
return encoder;
|
|
2947
|
+
}
|
|
2948
|
+
_handleBeforeUnload() {
|
|
2949
|
+
YP.removeAwarenessStates(this._awareness, [
|
|
2950
|
+
this._clientId
|
|
2951
|
+
], "window unload");
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
|
|
2955
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2956
|
+
var modelState = StateField6.define({
|
|
2957
|
+
create: () => void 0,
|
|
2958
|
+
update: (model) => model
|
|
2959
|
+
});
|
|
2960
|
+
var useTextModel = (props) => {
|
|
2961
|
+
const { identity, space, text } = props;
|
|
2962
|
+
const [model, setModel] = useState2(() => createModel(props));
|
|
2963
|
+
useEffect2(() => setModel(createModel(props)), [
|
|
2964
|
+
identity,
|
|
2965
|
+
space,
|
|
2966
|
+
text
|
|
2967
|
+
]);
|
|
2968
|
+
return model;
|
|
2969
|
+
};
|
|
2970
|
+
var createModel = (props) => {
|
|
2971
|
+
const { text } = props;
|
|
2972
|
+
if (isAutomergeObject(text)) {
|
|
2973
|
+
return createAutomergeModel(props);
|
|
2974
|
+
} else if (text?.doc) {
|
|
2975
|
+
return createYjsModel(props);
|
|
2976
|
+
} else {
|
|
2977
|
+
return void 0;
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
|
|
2981
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2982
|
+
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2983
|
+
const obj = text;
|
|
2984
|
+
const doc = getRawDoc(obj, [
|
|
2985
|
+
obj.field
|
|
2986
|
+
]);
|
|
2987
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2988
|
+
space,
|
|
2989
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2990
|
+
info: {
|
|
2991
|
+
displayName: identity?.profile?.displayName ?? "",
|
|
2992
|
+
color: cursorColor.color,
|
|
2993
|
+
lightColor: cursorColor.light
|
|
2994
|
+
},
|
|
2995
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2996
|
+
});
|
|
2997
|
+
const model = {
|
|
2998
|
+
id: obj.id,
|
|
2999
|
+
content: doc,
|
|
3000
|
+
text: () => get7(doc.handle.docSync(), doc.path),
|
|
3001
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
3002
|
+
extension: [
|
|
3003
|
+
modelState.init(() => model),
|
|
3004
|
+
automerge3({
|
|
3005
|
+
handle: doc.handle,
|
|
3006
|
+
path: doc.path
|
|
3007
|
+
}),
|
|
3008
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3009
|
+
awareness()
|
|
3010
|
+
].filter(isNotNullOrUndefined),
|
|
3011
|
+
peer: identity ? {
|
|
3012
|
+
id: identity.identityKey.toHex(),
|
|
3013
|
+
name: identity.profile?.displayName
|
|
3014
|
+
} : void 0
|
|
3015
|
+
};
|
|
3016
|
+
return model;
|
|
3017
|
+
};
|
|
2564
3018
|
export {
|
|
3019
|
+
AwarenessProvider,
|
|
2565
3020
|
BaseTextEditor,
|
|
2566
3021
|
Doc,
|
|
2567
3022
|
EditorModes,
|
|
2568
3023
|
MarkdownEditor,
|
|
3024
|
+
RemoteSelectionsDecorator,
|
|
2569
3025
|
SpaceAwarenessProvider,
|
|
2570
3026
|
TextEditor,
|
|
2571
3027
|
TextKind,
|
|
3028
|
+
YAwarenessProvider,
|
|
2572
3029
|
YText,
|
|
2573
3030
|
YXmlFragment,
|
|
2574
3031
|
autocomplete,
|
|
3032
|
+
automerge3 as automerge,
|
|
3033
|
+
awareness,
|
|
2575
3034
|
basicBundle,
|
|
2576
3035
|
blast,
|
|
2577
3036
|
code2 as code,
|
|
2578
3037
|
codeTheme,
|
|
2579
3038
|
comments,
|
|
2580
|
-
|
|
3039
|
+
createAutomergeModel,
|
|
3040
|
+
createYjsModel,
|
|
2581
3041
|
defaultMarkdownSlots,
|
|
2582
3042
|
defaultOptions,
|
|
2583
3043
|
defaultSlots,
|
|
@@ -2596,11 +3056,14 @@ export {
|
|
|
2596
3056
|
mermaid,
|
|
2597
3057
|
modelState,
|
|
2598
3058
|
setCommentRange,
|
|
3059
|
+
setFocus,
|
|
3060
|
+
setSelection,
|
|
2599
3061
|
table,
|
|
2600
3062
|
tags2 as tags,
|
|
2601
3063
|
tasklist,
|
|
2602
3064
|
textTheme,
|
|
2603
3065
|
typewriter,
|
|
2604
|
-
useTextModel
|
|
3066
|
+
useTextModel,
|
|
3067
|
+
yjs
|
|
2605
3068
|
};
|
|
2606
3069
|
//# sourceMappingURL=index.mjs.map
|