@dxos/react-ui-editor 0.3.11-main.42059c4 → 0.3.11-main.47875f3
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 +72 -57
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -2
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +4 -4
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +9 -4
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +4 -9
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/components/TextEditor/TextEditor.tsx +10 -10
- package/src/components/TextEditor/comments.stories.tsx +48 -74
- package/src/extensions/automerge/automerge.ts +11 -11
- package/src/extensions/automerge/defs.ts +9 -13
- package/src/extensions/automerge/semaphore.ts +12 -10
- package/src/extensions/comments.ts +49 -61
- package/src/hooks/index.ts +1 -2
|
@@ -51,7 +51,7 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
|
-
import { StateField } from "@codemirror/state";
|
|
54
|
+
import { Facet as Facet2, StateField } from "@codemirror/state";
|
|
55
55
|
import { ViewPlugin } from "@codemirror/view";
|
|
56
56
|
import { next as A } from "@dxos/automerge/automerge";
|
|
57
57
|
|
|
@@ -92,7 +92,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
|
-
import { Annotation, StateEffect
|
|
95
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
96
|
var effectType = StateEffect.define({});
|
|
97
97
|
var updateHeads = (newHeads) => effectType.of({
|
|
98
98
|
newHeads
|
|
@@ -101,9 +101,6 @@ var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
|
101
101
|
var getPath = (state, field) => state.field(field).path;
|
|
102
102
|
var reconcileAnnotationType = Annotation.define();
|
|
103
103
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
104
|
-
var semaphoreFacet = Facet.define({
|
|
105
|
-
combine: (values) => values.at(-1)
|
|
106
|
-
});
|
|
107
104
|
|
|
108
105
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
106
|
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
@@ -240,11 +237,11 @@ var charPath = (textPath, candidatePath) => {
|
|
|
240
237
|
|
|
241
238
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
239
|
var PatchSemaphore = class {
|
|
243
|
-
constructor(
|
|
244
|
-
this._handle = _handle;
|
|
240
|
+
constructor(_field) {
|
|
245
241
|
this._field = _field;
|
|
246
242
|
this._inReconcile = false;
|
|
247
|
-
this.
|
|
243
|
+
this._queue = [];
|
|
244
|
+
this.reconcile = (handle, view) => {
|
|
248
245
|
if (this._inReconcile) {
|
|
249
246
|
return;
|
|
250
247
|
}
|
|
@@ -262,11 +259,11 @@ var PatchSemaphore = class {
|
|
|
262
259
|
annotations: reconcileAnnotationType.of(true)
|
|
263
260
|
});
|
|
264
261
|
}
|
|
265
|
-
let newHeads = updateAutomerge(this._field,
|
|
262
|
+
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
266
263
|
if (newHeads === null || newHeads === void 0) {
|
|
267
|
-
newHeads = automerge2.getHeads(
|
|
264
|
+
newHeads = automerge2.getHeads(handle.docSync());
|
|
268
265
|
}
|
|
269
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(
|
|
266
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
270
267
|
updateCodeMirror(view, selection, path, diff);
|
|
271
268
|
view.dispatch({
|
|
272
269
|
effects: updateHeads(newHeads),
|
|
@@ -278,14 +275,14 @@ var PatchSemaphore = class {
|
|
|
278
275
|
};
|
|
279
276
|
|
|
280
277
|
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
281
|
-
import { Facet
|
|
278
|
+
import { Facet } from "@codemirror/state";
|
|
282
279
|
var defaultCursorConverter = {
|
|
283
280
|
toCursor: (position) => position.toString(),
|
|
284
281
|
fromCursor: (cursor) => parseInt(cursor)
|
|
285
282
|
};
|
|
286
283
|
var Cursor = class {
|
|
287
284
|
static {
|
|
288
|
-
this.converter =
|
|
285
|
+
this.converter = Facet.define({
|
|
289
286
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
290
287
|
});
|
|
291
288
|
}
|
|
@@ -313,6 +310,9 @@ var Cursor = class {
|
|
|
313
310
|
};
|
|
314
311
|
|
|
315
312
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
313
|
+
var semaphoreFacet = Facet2.define({
|
|
314
|
+
combine: (values) => values.at(-1)
|
|
315
|
+
});
|
|
316
316
|
var automerge3 = ({ handle, path }) => {
|
|
317
317
|
const stateField = StateField.define({
|
|
318
318
|
create: () => ({
|
|
@@ -343,19 +343,19 @@ var automerge3 = ({ handle, path }) => {
|
|
|
343
343
|
return result;
|
|
344
344
|
}
|
|
345
345
|
});
|
|
346
|
-
const semaphore = new PatchSemaphore(
|
|
347
|
-
const viewPlugin = ViewPlugin.fromClass(class
|
|
346
|
+
const semaphore = new PatchSemaphore(stateField);
|
|
347
|
+
const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
348
348
|
constructor(_view) {
|
|
349
349
|
this._view = _view;
|
|
350
350
|
this._handleChange = () => {
|
|
351
|
-
this._view.state.facet(semaphoreFacet).reconcile(this._view);
|
|
351
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
352
352
|
};
|
|
353
353
|
handle.addListener("change", this._handleChange);
|
|
354
354
|
}
|
|
355
355
|
update(update2) {
|
|
356
356
|
if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
357
357
|
queueMicrotask(() => {
|
|
358
|
-
this._view.state.facet(semaphoreFacet).reconcile(this._view);
|
|
358
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
}
|
|
@@ -1105,6 +1105,7 @@ import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView
|
|
|
1105
1105
|
import sortBy from "lodash.sortby";
|
|
1106
1106
|
import { debounce } from "@dxos/async";
|
|
1107
1107
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1108
|
+
import { log as log2 } from "@dxos/log";
|
|
1108
1109
|
import { nonNullable } from "@dxos/util";
|
|
1109
1110
|
|
|
1110
1111
|
// packages/ui/react-ui-editor/src/util.ts
|
|
@@ -1172,7 +1173,7 @@ var commentsStateField = StateField2.define({
|
|
|
1172
1173
|
...effect.value
|
|
1173
1174
|
};
|
|
1174
1175
|
}
|
|
1175
|
-
if (effect.is(setCommentRange)
|
|
1176
|
+
if (effect.is(setCommentRange)) {
|
|
1176
1177
|
const { comments: comments2 } = effect.value;
|
|
1177
1178
|
const ranges = comments2.map((comment) => {
|
|
1178
1179
|
const range = Cursor.getRangeFromCursor(cursorConverter3, comment.cursor);
|
|
@@ -1213,56 +1214,51 @@ var highlightDecorations = EditorView5.decorations.compute([
|
|
|
1213
1214
|
}).filter(nonNullable) ?? [];
|
|
1214
1215
|
return Decoration3.set(decorations);
|
|
1215
1216
|
});
|
|
1216
|
-
var trackPastedComments = (
|
|
1217
|
+
var trackPastedComments = (onMove) => {
|
|
1217
1218
|
let tracked = null;
|
|
1218
|
-
const
|
|
1219
|
+
const registerCopy = (event, view) => {
|
|
1219
1220
|
const comments2 = view.state.field(commentsStateField);
|
|
1220
1221
|
const { main } = view.state.selection;
|
|
1221
|
-
const
|
|
1222
|
-
if (!
|
|
1222
|
+
const inSel = comments2.ranges.filter((range) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1223
|
+
if (!inSel.length) {
|
|
1223
1224
|
tracked = null;
|
|
1224
1225
|
} else {
|
|
1225
1226
|
tracked = {
|
|
1226
1227
|
text: view.state.doc.slice(main.from, main.to),
|
|
1227
|
-
comments:
|
|
1228
|
-
id: range.id,
|
|
1228
|
+
comments: inSel.map((range) => ({
|
|
1229
1229
|
from: range.from - main.from,
|
|
1230
|
-
to: range.to - main.from
|
|
1230
|
+
to: range.to - main.from,
|
|
1231
|
+
id: range.id
|
|
1231
1232
|
}))
|
|
1232
1233
|
};
|
|
1233
1234
|
}
|
|
1234
1235
|
};
|
|
1235
1236
|
return [
|
|
1236
1237
|
EditorView5.domEventHandlers({
|
|
1237
|
-
cut:
|
|
1238
|
-
copy:
|
|
1238
|
+
cut: registerCopy,
|
|
1239
|
+
copy: registerCopy
|
|
1239
1240
|
}),
|
|
1240
|
-
|
|
1241
|
-
EditorView5.updateListener.of(({ view, state, transactions }) => {
|
|
1241
|
+
EditorView5.updateListener.of((update2) => {
|
|
1242
1242
|
if (tracked) {
|
|
1243
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1243
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1244
1244
|
if (paste) {
|
|
1245
1245
|
let found = -1;
|
|
1246
1246
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1247
1247
|
if (text.eq(tracked.text)) {
|
|
1248
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1249
|
-
fromB = transactions[i].changes.mapPos(fromB);
|
|
1248
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1249
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1250
1250
|
}
|
|
1251
1251
|
found = fromB;
|
|
1252
1252
|
}
|
|
1253
1253
|
});
|
|
1254
1254
|
if (found > -1) {
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1257
|
-
const active = state.field(commentsStateField).ranges;
|
|
1258
|
-
for (const moved of comments2) {
|
|
1255
|
+
const active = update2.view.state.field(commentsStateField).ranges;
|
|
1256
|
+
for (const moved of tracked.comments) {
|
|
1259
1257
|
if (active.some((range) => range.id === moved.id && range.from === range.to)) {
|
|
1260
|
-
|
|
1258
|
+
onMove(moved.id, Cursor.getCursorFromRange(update2.view.state.facet(Cursor.converter), {
|
|
1261
1259
|
from: found + moved.from,
|
|
1262
1260
|
to: found + moved.to
|
|
1263
|
-
};
|
|
1264
|
-
const cursor = Cursor.getCursorFromRange(state.facet(Cursor.converter), range);
|
|
1265
|
-
onUpdate(moved.id, cursor);
|
|
1261
|
+
}));
|
|
1266
1262
|
}
|
|
1267
1263
|
}
|
|
1268
1264
|
}
|
|
@@ -1279,14 +1275,14 @@ var comments = (options = {}) => {
|
|
|
1279
1275
|
const cursorConverter3 = view.state.facet(Cursor.converter);
|
|
1280
1276
|
invariant2(options.onCreate, void 0, {
|
|
1281
1277
|
F: __dxlog_file3,
|
|
1282
|
-
L:
|
|
1278
|
+
L: 240,
|
|
1283
1279
|
S: void 0,
|
|
1284
1280
|
A: [
|
|
1285
1281
|
"options.onCreate",
|
|
1286
1282
|
""
|
|
1287
1283
|
]
|
|
1288
1284
|
});
|
|
1289
|
-
const { from, to } = view.state.selection.main;
|
|
1285
|
+
const { head, from, to } = view.state.selection.main;
|
|
1290
1286
|
if (from === to) {
|
|
1291
1287
|
return false;
|
|
1292
1288
|
}
|
|
@@ -1305,6 +1301,18 @@ var comments = (options = {}) => {
|
|
|
1305
1301
|
anchor: from
|
|
1306
1302
|
}
|
|
1307
1303
|
});
|
|
1304
|
+
if (options.footnote) {
|
|
1305
|
+
const tag = `[^${id}]`;
|
|
1306
|
+
view.dispatch({
|
|
1307
|
+
changes: {
|
|
1308
|
+
from: head,
|
|
1309
|
+
insert: tag
|
|
1310
|
+
},
|
|
1311
|
+
selection: {
|
|
1312
|
+
anchor: head + tag.length
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1308
1316
|
return true;
|
|
1309
1317
|
}
|
|
1310
1318
|
}
|
|
@@ -1366,7 +1374,14 @@ var comments = (options = {}) => {
|
|
|
1366
1374
|
if (from2 === to2) {
|
|
1367
1375
|
const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1368
1376
|
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1369
|
-
|
|
1377
|
+
log2.info("deleted comment", {
|
|
1378
|
+
thread: range.id
|
|
1379
|
+
}, {
|
|
1380
|
+
F: __dxlog_file3,
|
|
1381
|
+
L: 337,
|
|
1382
|
+
S: void 0,
|
|
1383
|
+
C: (f, a) => f(...a)
|
|
1384
|
+
});
|
|
1370
1385
|
}
|
|
1371
1386
|
}
|
|
1372
1387
|
if (from <= range.to) {
|
|
@@ -1417,7 +1432,7 @@ var comments = (options = {}) => {
|
|
|
1417
1432
|
}
|
|
1418
1433
|
}
|
|
1419
1434
|
}),
|
|
1420
|
-
options.
|
|
1435
|
+
options.onMove ? trackPastedComments(options.onMove) : []
|
|
1421
1436
|
];
|
|
1422
1437
|
};
|
|
1423
1438
|
|
|
@@ -2465,7 +2480,7 @@ var EditorModes = [
|
|
|
2465
2480
|
"default",
|
|
2466
2481
|
"vim"
|
|
2467
2482
|
];
|
|
2468
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2483
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
|
|
2469
2484
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2470
2485
|
tabBehavior: "limited"
|
|
2471
2486
|
});
|
|
@@ -2476,12 +2491,12 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2476
2491
|
view
|
|
2477
2492
|
]);
|
|
2478
2493
|
useEffect(() => {
|
|
2479
|
-
if (
|
|
2480
|
-
view
|
|
2494
|
+
if (view && focus) {
|
|
2495
|
+
view.focus();
|
|
2481
2496
|
}
|
|
2482
2497
|
}, [
|
|
2483
|
-
|
|
2484
|
-
|
|
2498
|
+
view,
|
|
2499
|
+
focus
|
|
2485
2500
|
]);
|
|
2486
2501
|
const { awareness: awareness2, peer } = model;
|
|
2487
2502
|
useEffect(() => {
|
|
@@ -2572,11 +2587,11 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2572
2587
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2573
2588
|
key: model.id,
|
|
2574
2589
|
role: "none",
|
|
2590
|
+
ref: rootRef,
|
|
2575
2591
|
tabIndex: 0,
|
|
2576
2592
|
onKeyUp: handleKeyUp,
|
|
2577
2593
|
...slots.root,
|
|
2578
|
-
...editorMode !== "vim" && tabsterDOMAttribute
|
|
2579
|
-
ref: rootRef
|
|
2594
|
+
...editorMode !== "vim" && tabsterDOMAttribute
|
|
2580
2595
|
});
|
|
2581
2596
|
});
|
|
2582
2597
|
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = textTheme, slots, ...props }, forwardedRef) => {
|
|
@@ -2619,7 +2634,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2619
2634
|
});
|
|
2620
2635
|
var defaultSlots = {
|
|
2621
2636
|
root: {
|
|
2622
|
-
className: mx3("
|
|
2637
|
+
className: mx3("p-2 overflow-y-auto", inputSurface)
|
|
2623
2638
|
}
|
|
2624
2639
|
};
|
|
2625
2640
|
var defaultTextSlots = {
|
|
@@ -2638,7 +2653,7 @@ import { isNotNullOrUndefined } from "@dxos/util";
|
|
|
2638
2653
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2639
2654
|
import { Context as Context2 } from "@dxos/context";
|
|
2640
2655
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2641
|
-
import { log as
|
|
2656
|
+
import { log as log3 } from "@dxos/log";
|
|
2642
2657
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2643
2658
|
var DEBOUNCE_INTERVAL = 100;
|
|
2644
2659
|
var SpaceAwarenessProvider = class {
|
|
@@ -2677,7 +2692,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2677
2692
|
void this._space.postMessage(this._channel, {
|
|
2678
2693
|
kind: "query"
|
|
2679
2694
|
}).catch((err) => {
|
|
2680
|
-
|
|
2695
|
+
log3.debug("failed to query awareness", {
|
|
2681
2696
|
err
|
|
2682
2697
|
}, {
|
|
2683
2698
|
F: __dxlog_file4,
|
|
@@ -2750,7 +2765,7 @@ import * as encoding from "lib0/encoding";
|
|
|
2750
2765
|
import { Observable } from "lib0/observable";
|
|
2751
2766
|
import * as YP from "y-protocols/awareness";
|
|
2752
2767
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2753
|
-
import { log as
|
|
2768
|
+
import { log as log4 } from "@dxos/log";
|
|
2754
2769
|
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2755
2770
|
var createYjsModel = ({ identity, space, text }) => {
|
|
2756
2771
|
invariant4(text?.doc && text?.content, void 0, {
|
|
@@ -2813,7 +2828,7 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2813
2828
|
return this._awareness;
|
|
2814
2829
|
}
|
|
2815
2830
|
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2816
|
-
|
|
2831
|
+
log4("awareness update", {
|
|
2817
2832
|
added,
|
|
2818
2833
|
updated,
|
|
2819
2834
|
removed,
|
|
@@ -2831,7 +2846,7 @@ var YAwarenessProvider = class extends Observable {
|
|
|
2831
2846
|
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2832
2847
|
}
|
|
2833
2848
|
_handleSpaceMessage({ payload }) {
|
|
2834
|
-
|
|
2849
|
+
log4("space message", payload, {
|
|
2835
2850
|
F: __dxlog_file5,
|
|
2836
2851
|
L: 109,
|
|
2837
2852
|
S: this,
|