@dxos/react-ui-editor 0.4.8-main.ec0899a → 0.4.8-main.f253994
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 +454 -277
- package/dist/lib/browser/index.mjs.map +4 -4
- 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/TextEditor.stories.d.ts +2 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +11 -5
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +4 -2
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts +1 -0
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +7 -4
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/image.d.ts +6 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
- package/dist/types/src/extensions/modes.d.ts +1 -0
- package/dist/types/src/extensions/modes.d.ts.map +1 -1
- package/dist/types/src/extensions/state.d.ts +20 -0
- package/dist/types/src/extensions/state.d.ts.map +1 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.stories.d.ts +1 -0
- package/dist/types/src/hooks/useTextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/package.json +25 -27
- package/src/components/TextEditor/TextEditor.stories.tsx +16 -4
- package/src/components/TextEditor/TextEditor.tsx +13 -12
- package/src/components/Toolbar/Toolbar.stories.tsx +23 -24
- package/src/components/Toolbar/Toolbar.tsx +101 -35
- package/src/extensions/automerge/automerge.ts +4 -4
- package/src/extensions/comments.ts +2 -2
- package/src/extensions/factories.ts +0 -3
- package/src/extensions/index.ts +1 -0
- package/src/extensions/markdown/formatting.test.ts +13 -13
- package/src/extensions/markdown/formatting.ts +91 -83
- package/src/extensions/markdown/image.ts +6 -0
- package/src/extensions/modes.ts +3 -1
- package/src/extensions/state.ts +90 -0
- package/src/hooks/useActionHandler.ts +5 -1
- package/src/hooks/useTextEditor.stories.tsx +3 -3
- package/src/hooks/useTextEditor.ts +3 -0
- package/src/translations.ts +1 -0
|
@@ -15,6 +15,7 @@ var translations_default = [
|
|
|
15
15
|
"blockquote label": "Block quote",
|
|
16
16
|
"codeblock label": "Code block",
|
|
17
17
|
"comment label": "Create comment",
|
|
18
|
+
"image label": "Insert image",
|
|
18
19
|
"heading label": "Heading level",
|
|
19
20
|
"table label": "Create table"
|
|
20
21
|
}
|
|
@@ -23,18 +24,18 @@ var translations_default = [
|
|
|
23
24
|
];
|
|
24
25
|
|
|
25
26
|
// packages/ui/react-ui-editor/src/index.ts
|
|
26
|
-
import { keymap as
|
|
27
|
+
import { keymap as keymap10 } from "@codemirror/view";
|
|
27
28
|
import { tags as tags2 } from "@lezer/highlight";
|
|
28
29
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
29
30
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
30
31
|
|
|
31
32
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
32
33
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
33
|
-
import { EditorView as
|
|
34
|
+
import { EditorView as EditorView17 } from "@codemirror/view";
|
|
34
35
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
35
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState
|
|
36
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
36
37
|
import { log as log9 } from "@dxos/log";
|
|
37
|
-
import { isNotFalsy as
|
|
38
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
38
39
|
|
|
39
40
|
// packages/ui/react-ui-editor/src/extensions/annotations.ts
|
|
40
41
|
import { StateField } from "@codemirror/state";
|
|
@@ -56,8 +57,8 @@ var Cursor = class _Cursor {
|
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
static {
|
|
59
|
-
this.getCursorFromRange = (
|
|
60
|
-
const cursorConverter2 =
|
|
60
|
+
this.getCursorFromRange = (state2, range) => {
|
|
61
|
+
const cursorConverter2 = state2.facet(_Cursor.converter);
|
|
61
62
|
const from = cursorConverter2.toCursor(range.from);
|
|
62
63
|
const to = cursorConverter2.toCursor(range.to, -1);
|
|
63
64
|
return [
|
|
@@ -67,8 +68,8 @@ var Cursor = class _Cursor {
|
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
static {
|
|
70
|
-
this.getRangeFromCursor = (
|
|
71
|
-
const cursorConverter2 =
|
|
71
|
+
this.getRangeFromCursor = (state2, cursor) => {
|
|
72
|
+
const cursorConverter2 = state2.facet(_Cursor.converter);
|
|
72
73
|
const parts = cursor.split(":");
|
|
73
74
|
const from = cursorConverter2.fromCursor(parts[0]);
|
|
74
75
|
const to = cursorConverter2.fromCursor(parts[1]);
|
|
@@ -85,15 +86,15 @@ var annotationMark = Decoration.mark({
|
|
|
85
86
|
class: "cm-annotation"
|
|
86
87
|
});
|
|
87
88
|
var annotations = (options = {}) => {
|
|
88
|
-
const match = (
|
|
89
|
+
const match = (state2) => {
|
|
89
90
|
const annotations2 = [];
|
|
90
|
-
const text =
|
|
91
|
+
const text = state2.doc.toString();
|
|
91
92
|
if (options.match) {
|
|
92
93
|
const matches = text.matchAll(options.match);
|
|
93
94
|
for (const match2 of matches) {
|
|
94
95
|
const from = match2.index;
|
|
95
96
|
const to = from + match2[0].length;
|
|
96
|
-
const cursor = Cursor.getCursorFromRange(
|
|
97
|
+
const cursor = Cursor.getCursorFromRange(state2, {
|
|
97
98
|
from,
|
|
98
99
|
to
|
|
99
100
|
});
|
|
@@ -105,8 +106,8 @@ var annotations = (options = {}) => {
|
|
|
105
106
|
return annotations2;
|
|
106
107
|
};
|
|
107
108
|
const annotationsState = StateField.define({
|
|
108
|
-
create: (
|
|
109
|
-
return match(
|
|
109
|
+
create: (state2) => {
|
|
110
|
+
return match(state2);
|
|
110
111
|
},
|
|
111
112
|
update: (value, tr) => {
|
|
112
113
|
if (!tr.changes.empty) {
|
|
@@ -119,10 +120,10 @@ var annotations = (options = {}) => {
|
|
|
119
120
|
annotationsState,
|
|
120
121
|
EditorView.decorations.compute([
|
|
121
122
|
annotationsState
|
|
122
|
-
], (
|
|
123
|
-
const annotations2 =
|
|
123
|
+
], (state2) => {
|
|
124
|
+
const annotations2 = state2.field(annotationsState);
|
|
124
125
|
const decorations = annotations2.map((annotation2) => {
|
|
125
|
-
const range = Cursor.getRangeFromCursor(
|
|
126
|
+
const range = Cursor.getRangeFromCursor(state2, annotation2.cursor);
|
|
126
127
|
return range && annotationMark.range(range.from, range.to);
|
|
127
128
|
}).filter(isNotFalsy);
|
|
128
129
|
return Decoration.set(decorations);
|
|
@@ -239,8 +240,8 @@ var cursorConverter = ({ handle, path }) => ({
|
|
|
239
240
|
|
|
240
241
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
241
242
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
242
|
-
var getPath = (
|
|
243
|
-
var getLastHeads = (
|
|
243
|
+
var getPath = (state2, field) => state2.field(field).path;
|
|
244
|
+
var getLastHeads = (state2, field) => state2.field(field).lastHeads;
|
|
244
245
|
var updateHeadsEffect = StateEffect.define({});
|
|
245
246
|
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
246
247
|
newHeads
|
|
@@ -255,8 +256,8 @@ import { next as A3 } from "@dxos/automerge/automerge";
|
|
|
255
256
|
|
|
256
257
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
257
258
|
import { next as A2 } from "@dxos/automerge/automerge";
|
|
258
|
-
var updateAutomerge = (field, handle, transactions,
|
|
259
|
-
const { lastHeads, path } =
|
|
259
|
+
var updateAutomerge = (field, handle, transactions, state2) => {
|
|
260
|
+
const { lastHeads, path } = state2.field(field);
|
|
260
261
|
let hasChanges = false;
|
|
261
262
|
for (const tr of transactions) {
|
|
262
263
|
tr.changes.iterChanges(() => {
|
|
@@ -303,7 +304,7 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
303
304
|
annotations: reconcileAnnotation.of(false)
|
|
304
305
|
});
|
|
305
306
|
};
|
|
306
|
-
var handlePatch = (patch, target,
|
|
307
|
+
var handlePatch = (patch, target, state2) => {
|
|
307
308
|
if (patch.action === "insert") {
|
|
308
309
|
return handleInsert(target, patch);
|
|
309
310
|
} else if (patch.action === "splice") {
|
|
@@ -311,7 +312,7 @@ var handlePatch = (patch, target, state) => {
|
|
|
311
312
|
} else if (patch.action === "del") {
|
|
312
313
|
return handleDel(target, patch);
|
|
313
314
|
} else if (patch.action === "put") {
|
|
314
|
-
return handlePut(target, patch,
|
|
315
|
+
return handlePut(target, patch, state2);
|
|
315
316
|
} else {
|
|
316
317
|
return null;
|
|
317
318
|
}
|
|
@@ -355,7 +356,7 @@ var handleDel = (target, patch) => {
|
|
|
355
356
|
}
|
|
356
357
|
];
|
|
357
358
|
};
|
|
358
|
-
var handlePut = (target, patch,
|
|
359
|
+
var handlePut = (target, patch, state2) => {
|
|
359
360
|
const index = charPath(target, [
|
|
360
361
|
...patch.path,
|
|
361
362
|
0
|
|
@@ -363,7 +364,7 @@ var handlePut = (target, patch, state) => {
|
|
|
363
364
|
if (index == null) {
|
|
364
365
|
return [];
|
|
365
366
|
}
|
|
366
|
-
const length =
|
|
367
|
+
const length = state2.doc.length;
|
|
367
368
|
if (typeof patch.value !== "string") {
|
|
368
369
|
return [];
|
|
369
370
|
}
|
|
@@ -474,13 +475,13 @@ var automerge = (accessor) => {
|
|
|
474
475
|
ViewPlugin.fromClass(class {
|
|
475
476
|
constructor(_view) {
|
|
476
477
|
this._view = _view;
|
|
477
|
-
|
|
478
|
+
this._handleChange = () => {
|
|
479
|
+
syncer.reconcile(this._view, false);
|
|
480
|
+
};
|
|
481
|
+
accessor.handle.addListener("change", this._handleChange);
|
|
478
482
|
}
|
|
479
483
|
destroy() {
|
|
480
|
-
accessor.handle.removeListener("change", this._handleChange
|
|
481
|
-
}
|
|
482
|
-
_handleChange() {
|
|
483
|
-
syncer.reconcile(this._view, false);
|
|
484
|
+
accessor.handle.removeListener("change", this._handleChange);
|
|
484
485
|
}
|
|
485
486
|
}),
|
|
486
487
|
// Reconcile local updates.
|
|
@@ -561,9 +562,9 @@ var RemoteSelectionsDecorator = class {
|
|
|
561
562
|
_updateRemoteSelections(update2) {
|
|
562
563
|
const decorations = [];
|
|
563
564
|
const awarenessStates = this._provider.getRemoteStates();
|
|
564
|
-
for (const
|
|
565
|
-
const anchor =
|
|
566
|
-
const head =
|
|
565
|
+
for (const state2 of awarenessStates) {
|
|
566
|
+
const anchor = state2.position?.anchor ? this._cursorConverter.fromCursor(state2.position.anchor) : null;
|
|
567
|
+
const head = state2.position?.head ? this._cursorConverter.fromCursor(state2.position.head) : null;
|
|
567
568
|
if (anchor == null || head == null) {
|
|
568
569
|
continue;
|
|
569
570
|
}
|
|
@@ -571,8 +572,8 @@ var RemoteSelectionsDecorator = class {
|
|
|
571
572
|
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
572
573
|
const startLine = update2.view.state.doc.lineAt(start);
|
|
573
574
|
const endLine = update2.view.state.doc.lineAt(end);
|
|
574
|
-
const color =
|
|
575
|
-
const lightColor =
|
|
575
|
+
const color = state2.info.color ?? "#30bced";
|
|
576
|
+
const lightColor = state2.info.lightColor ?? color + "33";
|
|
576
577
|
if (startLine.number === endLine.number) {
|
|
577
578
|
decorations.push({
|
|
578
579
|
from: start,
|
|
@@ -625,7 +626,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
625
626
|
value: Decoration2.widget({
|
|
626
627
|
side: head - anchor > 0 ? -1 : 1,
|
|
627
628
|
block: false,
|
|
628
|
-
widget: new RemoteCaretWidget(
|
|
629
|
+
widget: new RemoteCaretWidget(state2.info.displayName ?? "Anonymous", color)
|
|
629
630
|
})
|
|
630
631
|
});
|
|
631
632
|
}
|
|
@@ -1156,7 +1157,7 @@ var commandConfig = Facet3.define({
|
|
|
1156
1157
|
});
|
|
1157
1158
|
var commandState = StateField3.define({
|
|
1158
1159
|
create: () => ({}),
|
|
1159
|
-
update: (
|
|
1160
|
+
update: (state2, tr) => {
|
|
1160
1161
|
for (const effect of tr.effects) {
|
|
1161
1162
|
if (effect.is(closeEffect)) {
|
|
1162
1163
|
return {};
|
|
@@ -1207,7 +1208,7 @@ var commandState = StateField3.define({
|
|
|
1207
1208
|
};
|
|
1208
1209
|
}
|
|
1209
1210
|
}
|
|
1210
|
-
return
|
|
1211
|
+
return state2;
|
|
1211
1212
|
},
|
|
1212
1213
|
provide: (field) => [
|
|
1213
1214
|
showTooltip.from(field, (value) => value.tooltip ?? null)
|
|
@@ -1453,8 +1454,8 @@ var setComments = StateEffect3.define();
|
|
|
1453
1454
|
var setSelection = StateEffect3.define();
|
|
1454
1455
|
var setCommentState = StateEffect3.define();
|
|
1455
1456
|
var commentsState = StateField4.define({
|
|
1456
|
-
create: (
|
|
1457
|
-
id:
|
|
1457
|
+
create: (state2) => ({
|
|
1458
|
+
id: state2.facet(documentId),
|
|
1458
1459
|
comments: [],
|
|
1459
1460
|
selection: {}
|
|
1460
1461
|
}),
|
|
@@ -1526,8 +1527,8 @@ var commentCurrentMark = Decoration4.mark({
|
|
|
1526
1527
|
});
|
|
1527
1528
|
var commentsDecorations = EditorView7.decorations.compute([
|
|
1528
1529
|
commentsState
|
|
1529
|
-
], (
|
|
1530
|
-
const { selection: { current }, comments: comments2 } =
|
|
1530
|
+
], (state2) => {
|
|
1531
|
+
const { selection: { current }, comments: comments2 } = state2.field(commentsState);
|
|
1531
1532
|
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1532
1533
|
const range = comment.range;
|
|
1533
1534
|
if (!range || range.from === range.to) {
|
|
@@ -1691,7 +1692,7 @@ var optionsFacet = Facet4.define({
|
|
|
1691
1692
|
});
|
|
1692
1693
|
var comments = (options = {}) => {
|
|
1693
1694
|
const { key: shortcut = "meta-'" } = options;
|
|
1694
|
-
const handleSelect = debounce((
|
|
1695
|
+
const handleSelect = debounce((state2) => options.onSelect?.(state2), 200);
|
|
1695
1696
|
return [
|
|
1696
1697
|
optionsFacet.of(options),
|
|
1697
1698
|
documentId.of(options.id),
|
|
@@ -1740,9 +1741,9 @@ var comments = (options = {}) => {
|
|
|
1740
1741
|
//
|
|
1741
1742
|
// Track deleted ranges and update ranges for decorations.
|
|
1742
1743
|
//
|
|
1743
|
-
EditorView7.updateListener.of(({ view, state, changes }) => {
|
|
1744
|
+
EditorView7.updateListener.of(({ view, state: state2, changes }) => {
|
|
1744
1745
|
let mod = false;
|
|
1745
|
-
const { comments: comments2, ...value } =
|
|
1746
|
+
const { comments: comments2, ...value } = state2.field(commentsState);
|
|
1746
1747
|
changes.iterChanges((from, to, from2, to2) => {
|
|
1747
1748
|
comments2.forEach(({ comment, range }) => {
|
|
1748
1749
|
if (from2 === to2) {
|
|
@@ -1772,10 +1773,10 @@ var comments = (options = {}) => {
|
|
|
1772
1773
|
//
|
|
1773
1774
|
// Track selection/proximity.
|
|
1774
1775
|
//
|
|
1775
|
-
EditorView7.updateListener.of(({ view, state }) => {
|
|
1776
|
+
EditorView7.updateListener.of(({ view, state: state2 }) => {
|
|
1776
1777
|
let min = Infinity;
|
|
1777
|
-
const { selection: { current, closest }, comments: comments2 } =
|
|
1778
|
-
const { head } =
|
|
1778
|
+
const { selection: { current, closest }, comments: comments2 } = state2.field(commentsState);
|
|
1779
|
+
const { head } = state2.selection.main;
|
|
1779
1780
|
const selection = {};
|
|
1780
1781
|
comments2.forEach(({ comment, range }) => {
|
|
1781
1782
|
if (head >= range.from && head <= range.to) {
|
|
@@ -1796,7 +1797,7 @@ var comments = (options = {}) => {
|
|
|
1796
1797
|
});
|
|
1797
1798
|
handleSelect({
|
|
1798
1799
|
selection,
|
|
1799
|
-
id:
|
|
1800
|
+
id: state2.facet(documentId),
|
|
1800
1801
|
comments: comments2.map(({ comment, range }) => ({
|
|
1801
1802
|
comment,
|
|
1802
1803
|
range,
|
|
@@ -1831,14 +1832,14 @@ var focusComment = (view, id, center = true) => {
|
|
|
1831
1832
|
});
|
|
1832
1833
|
}
|
|
1833
1834
|
};
|
|
1834
|
-
var useComments = (view, id, comments2
|
|
1835
|
+
var useComments = (view, id, comments2) => {
|
|
1835
1836
|
useEffect(() => {
|
|
1836
1837
|
if (view) {
|
|
1837
1838
|
if (id === view.state.facet(documentId)) {
|
|
1838
1839
|
view.dispatch({
|
|
1839
1840
|
effects: setComments.of({
|
|
1840
1841
|
id,
|
|
1841
|
-
comments: comments2
|
|
1842
|
+
comments: comments2 ?? []
|
|
1842
1843
|
})
|
|
1843
1844
|
});
|
|
1844
1845
|
}
|
|
@@ -1864,11 +1865,11 @@ var cursorLineMargin = (options = {
|
|
|
1864
1865
|
if (!lines || lines <= 0) {
|
|
1865
1866
|
return [];
|
|
1866
1867
|
}
|
|
1867
|
-
return EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
|
|
1868
|
+
return EditorView8.updateListener.of(({ transactions, state: state2, selectionSet, startState, view }) => {
|
|
1868
1869
|
if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
|
|
1869
1870
|
return;
|
|
1870
1871
|
}
|
|
1871
|
-
const s =
|
|
1872
|
+
const s = state2;
|
|
1872
1873
|
const { main } = s.selection;
|
|
1873
1874
|
const rect = view.dom.getBoundingClientRect();
|
|
1874
1875
|
const viewportTop = rect.top - view.documentTop;
|
|
@@ -2233,9 +2234,6 @@ var createBasicExtensions = (_props) => {
|
|
|
2233
2234
|
var defaultSlots = {
|
|
2234
2235
|
editor: {
|
|
2235
2236
|
className: "w-full bs-full"
|
|
2236
|
-
},
|
|
2237
|
-
content: {
|
|
2238
|
-
className: "!p-2"
|
|
2239
2237
|
}
|
|
2240
2238
|
};
|
|
2241
2239
|
var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
|
|
@@ -2609,8 +2607,8 @@ var checkedTask = Decoration5.replace({
|
|
|
2609
2607
|
var uncheckedTask = Decoration5.replace({
|
|
2610
2608
|
widget: new CheckboxWidget(false)
|
|
2611
2609
|
});
|
|
2612
|
-
var editingRange = (
|
|
2613
|
-
const { readOnly, selection: { main: { head } } } =
|
|
2610
|
+
var editingRange = (state2, range, focus) => {
|
|
2611
|
+
const { readOnly, selection: { main: { head } } } = state2;
|
|
2614
2612
|
return focus && !readOnly && head >= range.from && head <= range.to;
|
|
2615
2613
|
};
|
|
2616
2614
|
var MarksByParent = /* @__PURE__ */ new Set([
|
|
@@ -2623,14 +2621,14 @@ var MarksByParent = /* @__PURE__ */ new Set([
|
|
|
2623
2621
|
var buildDecorations = (view, options, focus) => {
|
|
2624
2622
|
const deco = new RangeSetBuilder2();
|
|
2625
2623
|
const atomicDeco = new RangeSetBuilder2();
|
|
2626
|
-
const { state } = view;
|
|
2624
|
+
const { state: state2 } = view;
|
|
2627
2625
|
for (const { from, to } of view.visibleRanges) {
|
|
2628
|
-
syntaxTree(
|
|
2626
|
+
syntaxTree(state2).iterate({
|
|
2629
2627
|
from,
|
|
2630
2628
|
to,
|
|
2631
2629
|
enter: (node) => {
|
|
2632
2630
|
if (node.name === "FencedCode") {
|
|
2633
|
-
const editing = editingRange(
|
|
2631
|
+
const editing = editingRange(state2, node, focus);
|
|
2634
2632
|
for (const block of view.viewportLineBlocks) {
|
|
2635
2633
|
if (block.to < node.from) {
|
|
2636
2634
|
continue;
|
|
@@ -2639,7 +2637,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2639
2637
|
break;
|
|
2640
2638
|
}
|
|
2641
2639
|
const first = block.from <= node.from;
|
|
2642
|
-
const last = block.to >= node.to && /^(\s>)*```$/.test(
|
|
2640
|
+
const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
|
|
2643
2641
|
deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
|
|
2644
2642
|
if (!editing && (first || last)) {
|
|
2645
2643
|
atomicDeco.add(block.from, block.to, hide);
|
|
@@ -2649,9 +2647,9 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2649
2647
|
} else if (node.name === "Link") {
|
|
2650
2648
|
const marks = node.node.getChildren("LinkMark");
|
|
2651
2649
|
const urlNode = node.node.getChild("URL");
|
|
2652
|
-
const editing = editingRange(
|
|
2650
|
+
const editing = editingRange(state2, node, focus);
|
|
2653
2651
|
if (urlNode && marks.length >= 2) {
|
|
2654
|
-
const url =
|
|
2652
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
2655
2653
|
if (!editing) {
|
|
2656
2654
|
atomicDeco.add(node.from, marks[0].to, hide);
|
|
2657
2655
|
}
|
|
@@ -2672,24 +2670,24 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2672
2670
|
}
|
|
2673
2671
|
} else if (node.name === "HeaderMark") {
|
|
2674
2672
|
const parent = node.node.parent;
|
|
2675
|
-
if (/^ATX/.test(parent.name) && !editingRange(
|
|
2676
|
-
const next =
|
|
2673
|
+
if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
|
|
2674
|
+
const next = state2.doc.sliceString(node.to, node.to + 1);
|
|
2677
2675
|
atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
|
|
2678
2676
|
}
|
|
2679
2677
|
} else if (node.name === "HorizontalRule") {
|
|
2680
|
-
if (!editingRange(
|
|
2678
|
+
if (!editingRange(state2, node, focus)) {
|
|
2681
2679
|
deco.add(node.from, node.to, horizontalRule);
|
|
2682
2680
|
}
|
|
2683
2681
|
} else if (node.name === "TaskMarker") {
|
|
2684
|
-
if (!editingRange(
|
|
2685
|
-
const checked =
|
|
2682
|
+
if (!editingRange(state2, node, focus)) {
|
|
2683
|
+
const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2686
2684
|
atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
|
|
2687
2685
|
class: "cm-task"
|
|
2688
2686
|
}));
|
|
2689
2687
|
atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
|
|
2690
2688
|
}
|
|
2691
2689
|
} else if (MarksByParent.has(node.name)) {
|
|
2692
|
-
if (!editingRange(
|
|
2690
|
+
if (!editingRange(state2, node.node.parent, focus)) {
|
|
2693
2691
|
atomicDeco.add(node.from, node.to, hide);
|
|
2694
2692
|
}
|
|
2695
2693
|
}
|
|
@@ -2799,8 +2797,9 @@ import { snippet } from "@codemirror/autocomplete";
|
|
|
2799
2797
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
2800
2798
|
import { EditorSelection } from "@codemirror/state";
|
|
2801
2799
|
import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
|
|
2802
|
-
import {
|
|
2803
|
-
|
|
2800
|
+
import { useMemo } from "react";
|
|
2801
|
+
import { useStateRef } from "@dxos/react-async";
|
|
2802
|
+
var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
|
|
2804
2803
|
var Inline;
|
|
2805
2804
|
(function(Inline2) {
|
|
2806
2805
|
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
@@ -2814,13 +2813,13 @@ var List;
|
|
|
2814
2813
|
List2[List2["Bullet"] = 1] = "Bullet";
|
|
2815
2814
|
List2[List2["Task"] = 2] = "Task";
|
|
2816
2815
|
})(List || (List = {}));
|
|
2817
|
-
var setHeading = (level) => ({ state, dispatch }) => {
|
|
2818
|
-
const { selection: { ranges }, doc } =
|
|
2816
|
+
var setHeading = (level) => ({ state: state2, dispatch }) => {
|
|
2817
|
+
const { selection: { ranges }, doc } = state2;
|
|
2819
2818
|
const changes = [];
|
|
2820
2819
|
let prevBlock = -1;
|
|
2821
2820
|
for (const range of ranges) {
|
|
2822
2821
|
let sawBlock = false;
|
|
2823
|
-
syntaxTree2(
|
|
2822
|
+
syntaxTree2(state2).iterate({
|
|
2824
2823
|
from: range.from,
|
|
2825
2824
|
to: range.to,
|
|
2826
2825
|
enter: (node) => {
|
|
@@ -2873,7 +2872,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
2873
2872
|
}
|
|
2874
2873
|
});
|
|
2875
2874
|
let line;
|
|
2876
|
-
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line =
|
|
2875
|
+
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
|
|
2877
2876
|
changes.push({
|
|
2878
2877
|
from: line.from,
|
|
2879
2878
|
to: line.to,
|
|
@@ -2884,23 +2883,23 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
2884
2883
|
if (!changes.length) {
|
|
2885
2884
|
return false;
|
|
2886
2885
|
}
|
|
2887
|
-
const changeSet =
|
|
2888
|
-
dispatch(
|
|
2886
|
+
const changeSet = state2.changes(changes);
|
|
2887
|
+
dispatch(state2.update({
|
|
2889
2888
|
changes: changeSet,
|
|
2890
|
-
selection:
|
|
2889
|
+
selection: state2.selection.map(changeSet, 1),
|
|
2891
2890
|
userEvent: "format.setHeading",
|
|
2892
2891
|
scrollIntoView: true
|
|
2893
2892
|
}));
|
|
2894
2893
|
return true;
|
|
2895
2894
|
};
|
|
2896
|
-
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
2895
|
+
var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
|
|
2897
2896
|
const marker = inlineMarkerText(type);
|
|
2898
|
-
const changes =
|
|
2897
|
+
const changes = state2.changeByRange((range) => {
|
|
2899
2898
|
if (!enable && range.empty) {
|
|
2900
|
-
const after =
|
|
2899
|
+
const after = state2.doc.sliceString(range.head, range.head + 6);
|
|
2901
2900
|
const found = after.indexOf(marker);
|
|
2902
2901
|
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
2903
|
-
const before =
|
|
2902
|
+
const before = state2.doc.sliceString(range.head - 6, range.head);
|
|
2904
2903
|
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
2905
2904
|
...before.slice(before.length - found)
|
|
2906
2905
|
].reverse().join("") === after.slice(0, found)) {
|
|
@@ -2927,14 +2926,14 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2927
2926
|
let startCovered = false;
|
|
2928
2927
|
let endCovered = false;
|
|
2929
2928
|
let { from, to } = range;
|
|
2930
|
-
syntaxTree2(
|
|
2929
|
+
syntaxTree2(state2).iterate({
|
|
2931
2930
|
from,
|
|
2932
2931
|
to,
|
|
2933
2932
|
enter: (node) => {
|
|
2934
2933
|
const { name } = node;
|
|
2935
2934
|
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
2936
2935
|
blockStart = blockContentStart(node);
|
|
2937
|
-
blockEnd = blockContentEnd(node,
|
|
2936
|
+
blockEnd = blockContentEnd(node, state2.doc);
|
|
2938
2937
|
startCovered = endCovered = false;
|
|
2939
2938
|
} else if (name === "Link" || name === "Image" && enable) {
|
|
2940
2939
|
if (from < node.from && to > node.from && to <= node.to) {
|
|
@@ -2979,7 +2978,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2979
2978
|
});
|
|
2980
2979
|
if (markType !== type && closeStart >= to) {
|
|
2981
2980
|
changesAtEnd.push({
|
|
2982
|
-
from: skipSpaces(Math.min(to, blockEnd),
|
|
2981
|
+
from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
|
|
2983
2982
|
insert: inlineMarkerText(markType)
|
|
2984
2983
|
});
|
|
2985
2984
|
}
|
|
@@ -2991,7 +2990,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2991
2990
|
});
|
|
2992
2991
|
if (markType !== type && openEnd <= from) {
|
|
2993
2992
|
changes2.push({
|
|
2994
|
-
from: skipSpaces(Math.max(from, blockStart),
|
|
2993
|
+
from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
|
|
2995
2994
|
insert: inlineMarkerText(markType)
|
|
2996
2995
|
});
|
|
2997
2996
|
}
|
|
@@ -3021,7 +3020,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3021
3020
|
changes2.push(startCovered);
|
|
3022
3021
|
} else if (startCovered) {
|
|
3023
3022
|
changes2.push({
|
|
3024
|
-
from: skipSpaces(rangeStart,
|
|
3023
|
+
from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
|
|
3025
3024
|
insert: marker
|
|
3026
3025
|
});
|
|
3027
3026
|
}
|
|
@@ -3029,7 +3028,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3029
3028
|
changes2.push(endCovered);
|
|
3030
3029
|
} else if (endCovered) {
|
|
3031
3030
|
changes2.push({
|
|
3032
|
-
from: skipSpaces(rangeEnd,
|
|
3031
|
+
from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
|
|
3033
3032
|
insert: marker
|
|
3034
3033
|
});
|
|
3035
3034
|
}
|
|
@@ -3037,7 +3036,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3037
3036
|
}
|
|
3038
3037
|
}
|
|
3039
3038
|
});
|
|
3040
|
-
if (blockStart < 0 && range.empty && enable && !/\S/.test(
|
|
3039
|
+
if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
|
|
3041
3040
|
return {
|
|
3042
3041
|
changes: {
|
|
3043
3042
|
from: range.head,
|
|
@@ -3046,13 +3045,13 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3046
3045
|
range: EditorSelection.cursor(range.head + marker.length)
|
|
3047
3046
|
};
|
|
3048
3047
|
}
|
|
3049
|
-
const changeSet =
|
|
3048
|
+
const changeSet = state2.changes(changes2.concat(changesAtEnd));
|
|
3050
3049
|
return {
|
|
3051
3050
|
changes: changeSet,
|
|
3052
3051
|
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
3053
3052
|
};
|
|
3054
3053
|
});
|
|
3055
|
-
dispatch(
|
|
3054
|
+
dispatch(state2.update(changes, {
|
|
3056
3055
|
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
3057
3056
|
scrollIntoView: true
|
|
3058
3057
|
}));
|
|
@@ -3126,8 +3125,8 @@ var insertTable = (view) => {
|
|
|
3126
3125
|
const { from } = doc.line(number);
|
|
3127
3126
|
snippets.table(view, null, from, from);
|
|
3128
3127
|
};
|
|
3129
|
-
var removeLinkInner = (from, to, changes,
|
|
3130
|
-
syntaxTree2(
|
|
3128
|
+
var removeLinkInner = (from, to, changes, state2) => {
|
|
3129
|
+
syntaxTree2(state2).iterate({
|
|
3131
3130
|
from,
|
|
3132
3131
|
to,
|
|
3133
3132
|
enter: (node) => {
|
|
@@ -3141,8 +3140,8 @@ var removeLinkInner = (from, to, changes, state) => {
|
|
|
3141
3140
|
});
|
|
3142
3141
|
} else if (name === "LinkTitle" || name === "URL") {
|
|
3143
3142
|
changes.push({
|
|
3144
|
-
from: skipSpaces(node2.from,
|
|
3145
|
-
to: skipSpaces(node2.to,
|
|
3143
|
+
from: skipSpaces(node2.from, state2.doc, -1),
|
|
3144
|
+
to: skipSpaces(node2.to, state2.doc, 1)
|
|
3146
3145
|
});
|
|
3147
3146
|
}
|
|
3148
3147
|
});
|
|
@@ -3151,32 +3150,32 @@ var removeLinkInner = (from, to, changes, state) => {
|
|
|
3151
3150
|
}
|
|
3152
3151
|
});
|
|
3153
3152
|
};
|
|
3154
|
-
var removeLink = ({ state, dispatch }) => {
|
|
3153
|
+
var removeLink = ({ state: state2, dispatch }) => {
|
|
3155
3154
|
const changes = [];
|
|
3156
|
-
for (const { from, to } of
|
|
3157
|
-
removeLinkInner(from, to, changes,
|
|
3155
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3156
|
+
removeLinkInner(from, to, changes, state2);
|
|
3158
3157
|
}
|
|
3159
3158
|
if (!changes) {
|
|
3160
3159
|
return false;
|
|
3161
3160
|
}
|
|
3162
|
-
dispatch(
|
|
3161
|
+
dispatch(state2.update({
|
|
3163
3162
|
changes,
|
|
3164
3163
|
userEvent: "format.link.remove",
|
|
3165
3164
|
scrollIntoView: true
|
|
3166
3165
|
}));
|
|
3167
3166
|
return true;
|
|
3168
3167
|
};
|
|
3169
|
-
var addLink = ({ state, dispatch }) => {
|
|
3170
|
-
const changes =
|
|
3168
|
+
var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
|
|
3169
|
+
const changes = state2.changeByRange((range) => {
|
|
3171
3170
|
let { from, to } = range;
|
|
3172
3171
|
const cutStyles = [];
|
|
3173
3172
|
let okay = null;
|
|
3174
|
-
syntaxTree2(
|
|
3173
|
+
syntaxTree2(state2).iterate({
|
|
3175
3174
|
from,
|
|
3176
3175
|
to,
|
|
3177
3176
|
enter: (node) => {
|
|
3178
3177
|
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3179
|
-
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node,
|
|
3178
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
|
|
3180
3179
|
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
3181
3180
|
const sNode = node.node;
|
|
3182
3181
|
if (node.from < from && node.to <= to) {
|
|
@@ -3196,7 +3195,7 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3196
3195
|
}
|
|
3197
3196
|
});
|
|
3198
3197
|
if (okay === null) {
|
|
3199
|
-
const line =
|
|
3198
|
+
const line = state2.doc.lineAt(from);
|
|
3200
3199
|
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
3201
3200
|
}
|
|
3202
3201
|
if (!okay) {
|
|
@@ -3206,26 +3205,26 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3206
3205
|
}
|
|
3207
3206
|
const changes2 = [];
|
|
3208
3207
|
const changesAfter = [];
|
|
3209
|
-
removeLinkInner(from, to, changesAfter,
|
|
3208
|
+
removeLinkInner(from, to, changesAfter, state2);
|
|
3210
3209
|
let cursorOffset = 1;
|
|
3211
3210
|
for (const style of cutStyles) {
|
|
3212
3211
|
const type = InlineMarker[style.name];
|
|
3213
3212
|
const mark2 = inlineMarkerText(type);
|
|
3214
3213
|
if (style.from < from) {
|
|
3215
3214
|
changes2.push({
|
|
3216
|
-
from: skipSpaces(from,
|
|
3215
|
+
from: skipSpaces(from, state2.doc, -1),
|
|
3217
3216
|
insert: mark2
|
|
3218
3217
|
});
|
|
3219
3218
|
changesAfter.push({
|
|
3220
|
-
from: skipSpaces(from,
|
|
3219
|
+
from: skipSpaces(from, state2.doc, 1, to),
|
|
3221
3220
|
insert: mark2
|
|
3222
3221
|
});
|
|
3223
3222
|
} else {
|
|
3224
3223
|
changes2.push({
|
|
3225
|
-
from: skipSpaces(to,
|
|
3224
|
+
from: skipSpaces(to, state2.doc, -1, from),
|
|
3226
3225
|
insert: mark2
|
|
3227
3226
|
});
|
|
3228
|
-
const after = skipSpaces(to,
|
|
3227
|
+
const after = skipSpaces(to, state2.doc, 1);
|
|
3229
3228
|
if (after === to) {
|
|
3230
3229
|
cursorOffset += mark2.length;
|
|
3231
3230
|
}
|
|
@@ -3237,34 +3236,34 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3237
3236
|
}
|
|
3238
3237
|
changes2.push({
|
|
3239
3238
|
from,
|
|
3240
|
-
insert: "["
|
|
3239
|
+
insert: image2 ? "`
|
|
3244
3243
|
});
|
|
3245
|
-
const changeSet =
|
|
3244
|
+
const changeSet = state2.changes(changes2.concat(changesAfter));
|
|
3246
3245
|
return {
|
|
3247
3246
|
changes: changeSet,
|
|
3248
|
-
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
3247
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
|
|
3249
3248
|
};
|
|
3250
3249
|
});
|
|
3251
3250
|
if (changes.changes.empty) {
|
|
3252
3251
|
return false;
|
|
3253
3252
|
}
|
|
3254
|
-
dispatch(
|
|
3253
|
+
dispatch(state2.update(changes, {
|
|
3255
3254
|
userEvent: "format.link.add",
|
|
3256
3255
|
scrollIntoView: true
|
|
3257
3256
|
}));
|
|
3258
3257
|
return true;
|
|
3259
3258
|
};
|
|
3260
|
-
var addList = (type) => ({ state, dispatch }) => {
|
|
3259
|
+
var addList = (type) => ({ state: state2, dispatch }) => {
|
|
3261
3260
|
let lastBlock = -1;
|
|
3262
3261
|
let counter = 1;
|
|
3263
3262
|
let first = true;
|
|
3264
3263
|
let parentColumn = null;
|
|
3265
3264
|
const blocks = [];
|
|
3266
|
-
for (const { from, to } of
|
|
3267
|
-
syntaxTree2(
|
|
3265
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3266
|
+
syntaxTree2(state2).iterate({
|
|
3268
3267
|
from,
|
|
3269
3268
|
to,
|
|
3270
3269
|
enter: (node) => {
|
|
@@ -3276,7 +3275,7 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3276
3275
|
}
|
|
3277
3276
|
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
3278
3277
|
const item = before.lastChild;
|
|
3279
|
-
const itemLine =
|
|
3278
|
+
const itemLine = state2.doc.lineAt(item.from);
|
|
3280
3279
|
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
3281
3280
|
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
3282
3281
|
if (type === 0) {
|
|
@@ -3311,10 +3310,10 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3311
3310
|
});
|
|
3312
3311
|
}
|
|
3313
3312
|
if (!blocks.length) {
|
|
3314
|
-
const { from, to } =
|
|
3313
|
+
const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
|
|
3315
3314
|
if (from === to) {
|
|
3316
3315
|
const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
|
|
3317
|
-
dispatch(
|
|
3316
|
+
dispatch(state2.update({
|
|
3318
3317
|
changes: [
|
|
3319
3318
|
{
|
|
3320
3319
|
from,
|
|
@@ -3335,11 +3334,11 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3335
3334
|
for (let i = 0; i < blocks.length; i++) {
|
|
3336
3335
|
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
3337
3336
|
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
3338
|
-
let padding = nodeFrom > 0 && !/\s/.test(
|
|
3337
|
+
let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
3339
3338
|
if (type === 0) {
|
|
3340
3339
|
padding += String(counter2).length;
|
|
3341
3340
|
}
|
|
3342
|
-
let line =
|
|
3341
|
+
let line = state2.doc.lineAt(nodeFrom);
|
|
3343
3342
|
const column = nodeFrom - line.from;
|
|
3344
3343
|
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
3345
3344
|
padding = Math.max(padding, parentColumn2 - column);
|
|
@@ -3364,7 +3363,7 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3364
3363
|
insert: mark2
|
|
3365
3364
|
});
|
|
3366
3365
|
while (line.to < node.to) {
|
|
3367
|
-
line =
|
|
3366
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
3368
3367
|
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3369
3368
|
changes.push({
|
|
3370
3369
|
from: line.from + Math.min(open, column),
|
|
@@ -3379,25 +3378,25 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3379
3378
|
next = next.nextSibling;
|
|
3380
3379
|
}
|
|
3381
3380
|
if (next?.name === "OrderedList") {
|
|
3382
|
-
renumberListItems(next.firstChild, last.counter + 1, changes,
|
|
3381
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
|
|
3383
3382
|
}
|
|
3384
3383
|
}
|
|
3385
|
-
const changeSet =
|
|
3386
|
-
dispatch(
|
|
3384
|
+
const changeSet = state2.changes(changes);
|
|
3385
|
+
dispatch(state2.update({
|
|
3387
3386
|
changes: changeSet,
|
|
3388
|
-
selection:
|
|
3387
|
+
selection: state2.selection.map(changeSet, 1),
|
|
3389
3388
|
userEvent: "format.list.add",
|
|
3390
3389
|
scrollIntoView: true
|
|
3391
3390
|
}));
|
|
3392
3391
|
return true;
|
|
3393
3392
|
};
|
|
3394
|
-
var removeList = (type) => ({ state, dispatch }) => {
|
|
3393
|
+
var removeList = (type) => ({ state: state2, dispatch }) => {
|
|
3395
3394
|
let lastBlock = -1;
|
|
3396
3395
|
const changes = [];
|
|
3397
3396
|
const stack = [];
|
|
3398
3397
|
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
3399
|
-
for (const { from, to } of
|
|
3400
|
-
syntaxTree2(
|
|
3398
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3399
|
+
syntaxTree2(state2).iterate({
|
|
3401
3400
|
from,
|
|
3402
3401
|
to,
|
|
3403
3402
|
enter: (node) => {
|
|
@@ -3414,7 +3413,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3414
3413
|
stack.pop();
|
|
3415
3414
|
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
3416
3415
|
lastBlock = node.from;
|
|
3417
|
-
let line =
|
|
3416
|
+
let line = state2.doc.lineAt(node.from);
|
|
3418
3417
|
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
3419
3418
|
if (!mark2) {
|
|
3420
3419
|
return false;
|
|
@@ -3425,7 +3424,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3425
3424
|
to: node.from + mark2[0].length
|
|
3426
3425
|
});
|
|
3427
3426
|
while (line.to < node.to) {
|
|
3428
|
-
line =
|
|
3427
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
3429
3428
|
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3430
3429
|
if (open > column) {
|
|
3431
3430
|
changes.push({
|
|
@@ -3435,7 +3434,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3435
3434
|
}
|
|
3436
3435
|
}
|
|
3437
3436
|
if (node.to >= to) {
|
|
3438
|
-
renumberListItems(node.node.nextSibling, 1, changes,
|
|
3437
|
+
renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
|
|
3439
3438
|
}
|
|
3440
3439
|
return false;
|
|
3441
3440
|
}
|
|
@@ -3445,7 +3444,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3445
3444
|
if (!changes.length) {
|
|
3446
3445
|
return false;
|
|
3447
3446
|
}
|
|
3448
|
-
dispatch(
|
|
3447
|
+
dispatch(state2.update({
|
|
3449
3448
|
changes,
|
|
3450
3449
|
userEvent: "format.list.remove",
|
|
3451
3450
|
scrollIntoView: true
|
|
@@ -3475,12 +3474,12 @@ var renumberListItems = (item, counter, changes, doc) => {
|
|
|
3475
3474
|
}
|
|
3476
3475
|
}
|
|
3477
3476
|
};
|
|
3478
|
-
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
3477
|
+
var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
|
|
3479
3478
|
const lines = [];
|
|
3480
3479
|
let lastBlock = -1;
|
|
3481
|
-
for (const { from, to } of
|
|
3480
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3482
3481
|
const sawBlock = false;
|
|
3483
|
-
syntaxTree2(
|
|
3482
|
+
syntaxTree2(state2).iterate({
|
|
3484
3483
|
from,
|
|
3485
3484
|
to,
|
|
3486
3485
|
enter: (node) => {
|
|
@@ -3489,9 +3488,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3489
3488
|
return false;
|
|
3490
3489
|
}
|
|
3491
3490
|
lastBlock = node.from;
|
|
3492
|
-
let line2 =
|
|
3491
|
+
let line2 = state2.doc.lineAt(node.from);
|
|
3493
3492
|
if (line2.number > 1) {
|
|
3494
|
-
const prevLine =
|
|
3493
|
+
const prevLine = state2.doc.line(line2.number - 1);
|
|
3495
3494
|
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
3496
3495
|
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
3497
3496
|
lines.push(prevLine);
|
|
@@ -3503,10 +3502,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3503
3502
|
if (line2.to >= node.to) {
|
|
3504
3503
|
break;
|
|
3505
3504
|
}
|
|
3506
|
-
line2 =
|
|
3505
|
+
line2 = state2.doc.line(line2.number + 1);
|
|
3507
3506
|
}
|
|
3508
|
-
if (!enable && line2.number <
|
|
3509
|
-
const nextLine =
|
|
3507
|
+
if (!enable && line2.number < state2.doc.lines) {
|
|
3508
|
+
const nextLine = state2.doc.line(line2.number + 1);
|
|
3510
3509
|
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
3511
3510
|
lines.push(nextLine);
|
|
3512
3511
|
}
|
|
@@ -3516,7 +3515,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3516
3515
|
}
|
|
3517
3516
|
});
|
|
3518
3517
|
let line;
|
|
3519
|
-
if (!sawBlock && enable && from === to && !/\S/.test((line =
|
|
3518
|
+
if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
|
|
3520
3519
|
lines.push(line);
|
|
3521
3520
|
}
|
|
3522
3521
|
}
|
|
@@ -3540,10 +3539,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3540
3539
|
if (!changes.length) {
|
|
3541
3540
|
return false;
|
|
3542
3541
|
}
|
|
3543
|
-
const changeSet =
|
|
3544
|
-
dispatch(
|
|
3542
|
+
const changeSet = state2.changes(changes);
|
|
3543
|
+
dispatch(state2.update({
|
|
3545
3544
|
changes: changeSet,
|
|
3546
|
-
selection:
|
|
3545
|
+
selection: state2.selection.map(changeSet, 1),
|
|
3547
3546
|
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
3548
3547
|
scrollIntoView: true
|
|
3549
3548
|
}));
|
|
@@ -3555,11 +3554,11 @@ var toggleBlockquote = (target) => {
|
|
|
3555
3554
|
return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
|
|
3556
3555
|
};
|
|
3557
3556
|
var addCodeblock = (target) => {
|
|
3558
|
-
const { state, dispatch } = target;
|
|
3559
|
-
const { selection } =
|
|
3557
|
+
const { state: state2, dispatch } = target;
|
|
3558
|
+
const { selection } = state2;
|
|
3560
3559
|
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
3561
3560
|
const { head } = selection.main;
|
|
3562
|
-
const line =
|
|
3561
|
+
const line = state2.doc.lineAt(head);
|
|
3563
3562
|
if (!/\S/.test(line.text) && head === line.from) {
|
|
3564
3563
|
snippets.codeblock(target, null, line.from, line.to);
|
|
3565
3564
|
return true;
|
|
@@ -3569,7 +3568,7 @@ var addCodeblock = (target) => {
|
|
|
3569
3568
|
for (const { from, to } of selection.ranges) {
|
|
3570
3569
|
let blockFrom = from;
|
|
3571
3570
|
let blockTo = to;
|
|
3572
|
-
syntaxTree2(
|
|
3571
|
+
syntaxTree2(state2).iterate({
|
|
3573
3572
|
from,
|
|
3574
3573
|
to,
|
|
3575
3574
|
enter: (node) => {
|
|
@@ -3578,8 +3577,8 @@ var addCodeblock = (target) => {
|
|
|
3578
3577
|
blockFrom = node.from;
|
|
3579
3578
|
blockTo = node.to;
|
|
3580
3579
|
} else {
|
|
3581
|
-
blockFrom = Math.min(blockFrom,
|
|
3582
|
-
blockTo = Math.max(blockTo,
|
|
3580
|
+
blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
|
|
3581
|
+
blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
|
|
3583
3582
|
}
|
|
3584
3583
|
}
|
|
3585
3584
|
}
|
|
@@ -3597,7 +3596,7 @@ var addCodeblock = (target) => {
|
|
|
3597
3596
|
return false;
|
|
3598
3597
|
}
|
|
3599
3598
|
const changes = ranges.map(({ from, to }) => {
|
|
3600
|
-
const column = from -
|
|
3599
|
+
const column = from - state2.doc.lineAt(from).from;
|
|
3601
3600
|
return [
|
|
3602
3601
|
{
|
|
3603
3602
|
from,
|
|
@@ -3609,30 +3608,30 @@ var addCodeblock = (target) => {
|
|
|
3609
3608
|
}
|
|
3610
3609
|
];
|
|
3611
3610
|
});
|
|
3612
|
-
dispatch(
|
|
3611
|
+
dispatch(state2.update({
|
|
3613
3612
|
changes,
|
|
3614
3613
|
userEvent: "format.codeblock.add",
|
|
3615
3614
|
scrollIntoView: true
|
|
3616
3615
|
}));
|
|
3617
3616
|
return true;
|
|
3618
3617
|
};
|
|
3619
|
-
var removeCodeblock = ({ state, dispatch }) => {
|
|
3618
|
+
var removeCodeblock = ({ state: state2, dispatch }) => {
|
|
3620
3619
|
const changes = [];
|
|
3621
3620
|
let lastBlock = -1;
|
|
3622
|
-
for (const { from, to } of
|
|
3623
|
-
syntaxTree2(
|
|
3621
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3622
|
+
syntaxTree2(state2).iterate({
|
|
3624
3623
|
from,
|
|
3625
3624
|
to,
|
|
3626
3625
|
enter: (node) => {
|
|
3627
3626
|
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
3628
3627
|
lastBlock = node.from;
|
|
3629
|
-
const firstLine =
|
|
3628
|
+
const firstLine = state2.doc.lineAt(node.from);
|
|
3630
3629
|
if (node.name === "FencedCode") {
|
|
3631
3630
|
changes.push({
|
|
3632
3631
|
from: node.from,
|
|
3633
3632
|
to: firstLine.to + 1 + node.from - firstLine.from
|
|
3634
3633
|
});
|
|
3635
|
-
const lastLine =
|
|
3634
|
+
const lastLine = state2.doc.lineAt(node.to);
|
|
3636
3635
|
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
3637
3636
|
changes.push({
|
|
3638
3637
|
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
@@ -3641,7 +3640,7 @@ var removeCodeblock = ({ state, dispatch }) => {
|
|
|
3641
3640
|
}
|
|
3642
3641
|
} else {
|
|
3643
3642
|
const column = node.from - firstLine.from;
|
|
3644
|
-
for (let line = firstLine; ; line =
|
|
3643
|
+
for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
|
|
3645
3644
|
changes.push({
|
|
3646
3645
|
from: line.from + column - 4,
|
|
3647
3646
|
to: line.from + column
|
|
@@ -3658,7 +3657,7 @@ var removeCodeblock = ({ state, dispatch }) => {
|
|
|
3658
3657
|
if (!changes.length) {
|
|
3659
3658
|
return false;
|
|
3660
3659
|
}
|
|
3661
|
-
dispatch(
|
|
3660
|
+
dispatch(state2.update({
|
|
3662
3661
|
changes,
|
|
3663
3662
|
userEvent: "format.codeblock.remove",
|
|
3664
3663
|
scrollIntoView: true
|
|
@@ -3717,7 +3716,7 @@ var Textblocks = {
|
|
|
3717
3716
|
TableCell: "tablecell",
|
|
3718
3717
|
Task: "paragraph"
|
|
3719
3718
|
};
|
|
3720
|
-
var getFormatting = (
|
|
3719
|
+
var getFormatting = (state2) => {
|
|
3721
3720
|
let blockType = null;
|
|
3722
3721
|
const inline = [
|
|
3723
3722
|
null,
|
|
@@ -3743,7 +3742,7 @@ var getFormatting = (state) => {
|
|
|
3743
3742
|
continue;
|
|
3744
3743
|
} else if (currentBlock.active[i]) {
|
|
3745
3744
|
inline[i] = true;
|
|
3746
|
-
} else if (/\S/.test(
|
|
3745
|
+
} else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
|
|
3747
3746
|
inline[i] = false;
|
|
3748
3747
|
}
|
|
3749
3748
|
}
|
|
@@ -3754,12 +3753,12 @@ var getFormatting = (state) => {
|
|
|
3754
3753
|
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
3755
3754
|
}
|
|
3756
3755
|
};
|
|
3757
|
-
const { selection } =
|
|
3756
|
+
const { selection } = state2;
|
|
3758
3757
|
for (const range of selection.ranges) {
|
|
3759
3758
|
if (range.empty && inline.some((v) => v === null)) {
|
|
3760
3759
|
const contextSize = Math.min(range.head, 6);
|
|
3761
|
-
const contextBefore =
|
|
3762
|
-
let contextAfter =
|
|
3760
|
+
const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
|
|
3761
|
+
let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
|
|
3763
3762
|
for (let i = 0; i < contextSize; i++) {
|
|
3764
3763
|
const ch = contextAfter[i];
|
|
3765
3764
|
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
@@ -3778,7 +3777,7 @@ var getFormatting = (state) => {
|
|
|
3778
3777
|
}
|
|
3779
3778
|
}
|
|
3780
3779
|
}
|
|
3781
|
-
syntaxTree2(
|
|
3780
|
+
syntaxTree2(state2).iterate({
|
|
3782
3781
|
from: range.from,
|
|
3783
3782
|
to: range.to,
|
|
3784
3783
|
enter: (node) => {
|
|
@@ -3852,7 +3851,7 @@ var getFormatting = (state) => {
|
|
|
3852
3851
|
}
|
|
3853
3852
|
});
|
|
3854
3853
|
}
|
|
3855
|
-
const { from, to } =
|
|
3854
|
+
const { from, to } = state2.doc.lineAt(selection.main.anchor);
|
|
3856
3855
|
const blankLine = from === to;
|
|
3857
3856
|
return {
|
|
3858
3857
|
blankLine,
|
|
@@ -3867,17 +3866,17 @@ var getFormatting = (state) => {
|
|
|
3867
3866
|
};
|
|
3868
3867
|
};
|
|
3869
3868
|
var useFormattingState = () => {
|
|
3870
|
-
const [
|
|
3869
|
+
const [state2, setState, stateRef] = useStateRef();
|
|
3871
3870
|
const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
|
|
3872
3871
|
if (update2.docChanged || update2.selectionSet) {
|
|
3873
3872
|
const newState = getFormatting(update2.state);
|
|
3874
|
-
if (!
|
|
3873
|
+
if (!stateRef.current || !formattingEquals(stateRef.current, newState)) {
|
|
3875
3874
|
setState(newState);
|
|
3876
3875
|
}
|
|
3877
3876
|
}
|
|
3878
3877
|
}), []);
|
|
3879
3878
|
return [
|
|
3880
|
-
|
|
3879
|
+
state2,
|
|
3881
3880
|
observer
|
|
3882
3881
|
];
|
|
3883
3882
|
};
|
|
@@ -3888,8 +3887,8 @@ import { StateField as StateField5 } from "@codemirror/state";
|
|
|
3888
3887
|
import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3889
3888
|
var image = (options = {}) => {
|
|
3890
3889
|
return StateField5.define({
|
|
3891
|
-
create: (
|
|
3892
|
-
return Decoration6.set(buildDecorations2(0,
|
|
3890
|
+
create: (state2) => {
|
|
3891
|
+
return Decoration6.set(buildDecorations2(0, state2.doc.length, state2));
|
|
3893
3892
|
},
|
|
3894
3893
|
update: (value, tr) => {
|
|
3895
3894
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -3923,16 +3922,16 @@ var preloadImage = (url) => {
|
|
|
3923
3922
|
preloaded.add(url);
|
|
3924
3923
|
}
|
|
3925
3924
|
};
|
|
3926
|
-
var buildDecorations2 = (from, to,
|
|
3925
|
+
var buildDecorations2 = (from, to, state2) => {
|
|
3927
3926
|
const decorations = [];
|
|
3928
|
-
const cursor =
|
|
3929
|
-
syntaxTree3(
|
|
3927
|
+
const cursor = state2.selection.main.head;
|
|
3928
|
+
syntaxTree3(state2).iterate({
|
|
3930
3929
|
enter: (node) => {
|
|
3931
3930
|
if (node.name === "Image") {
|
|
3932
3931
|
const urlNode = node.node.getChild("URL");
|
|
3933
3932
|
if (urlNode) {
|
|
3934
|
-
const hide2 =
|
|
3935
|
-
const url =
|
|
3933
|
+
const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
|
|
3934
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
3936
3935
|
preloadImage(url);
|
|
3937
3936
|
decorations.push(Decoration6.replace({
|
|
3938
3937
|
block: true,
|
|
@@ -3962,6 +3961,8 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
3962
3961
|
return img;
|
|
3963
3962
|
}
|
|
3964
3963
|
};
|
|
3964
|
+
var imageUpload = (options = {}) => {
|
|
3965
|
+
};
|
|
3965
3966
|
|
|
3966
3967
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
3967
3968
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
@@ -4003,21 +4004,21 @@ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "
|
|
|
4003
4004
|
import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4004
4005
|
var table = (options = {}) => {
|
|
4005
4006
|
return StateField6.define({
|
|
4006
|
-
create: (
|
|
4007
|
+
create: (state2) => update(state2, options),
|
|
4007
4008
|
update: (_, tr) => update(tr.state, options),
|
|
4008
4009
|
provide: (field) => EditorView15.decorations.from(field)
|
|
4009
4010
|
});
|
|
4010
4011
|
};
|
|
4011
|
-
var update = (
|
|
4012
|
+
var update = (state2, options) => {
|
|
4012
4013
|
const builder = new RangeSetBuilder3();
|
|
4013
|
-
const cursor =
|
|
4014
|
+
const cursor = state2.selection.main.head;
|
|
4014
4015
|
const tables = [];
|
|
4015
4016
|
const getTable = () => tables[tables.length - 1];
|
|
4016
4017
|
const getRow = () => {
|
|
4017
4018
|
const table2 = getTable();
|
|
4018
4019
|
return table2.rows?.[table2.rows.length - 1];
|
|
4019
4020
|
};
|
|
4020
|
-
syntaxTree5(
|
|
4021
|
+
syntaxTree5(state2).iterate({
|
|
4021
4022
|
enter: (node) => {
|
|
4022
4023
|
switch (node.name) {
|
|
4023
4024
|
case "Table": {
|
|
@@ -4038,9 +4039,9 @@ var update = (state, options) => {
|
|
|
4038
4039
|
case "TableCell": {
|
|
4039
4040
|
const row = getRow();
|
|
4040
4041
|
if (row) {
|
|
4041
|
-
row.push(
|
|
4042
|
+
row.push(state2.sliceDoc(node.from, node.to));
|
|
4042
4043
|
} else {
|
|
4043
|
-
getTable().header?.push(
|
|
4044
|
+
getTable().header?.push(state2.sliceDoc(node.from, node.to));
|
|
4044
4045
|
}
|
|
4045
4046
|
break;
|
|
4046
4047
|
}
|
|
@@ -4048,7 +4049,7 @@ var update = (state, options) => {
|
|
|
4048
4049
|
}
|
|
4049
4050
|
});
|
|
4050
4051
|
tables.forEach((table2) => {
|
|
4051
|
-
const hide2 =
|
|
4052
|
+
const hide2 = state2.readOnly || cursor < table2.from || cursor > table2.to;
|
|
4052
4053
|
if (hide2) {
|
|
4053
4054
|
builder.add(table2.from, table2.to, Decoration7.replace({
|
|
4054
4055
|
widget: new TableWidget(table2)
|
|
@@ -4139,6 +4140,7 @@ var mention = ({ onSearch }) => {
|
|
|
4139
4140
|
import { Facet as Facet6 } from "@codemirror/state";
|
|
4140
4141
|
import { keymap as keymap7 } from "@codemirror/view";
|
|
4141
4142
|
import { vim } from "@replit/codemirror-vim";
|
|
4143
|
+
var focusEvent = "focus.container";
|
|
4142
4144
|
var editorMode = Facet6.define({
|
|
4143
4145
|
combine: (modes) => modes[0] ?? {}
|
|
4144
4146
|
});
|
|
@@ -4155,7 +4157,7 @@ var EditorModes = {
|
|
|
4155
4157
|
key: "Alt-Escape",
|
|
4156
4158
|
run: (view) => {
|
|
4157
4159
|
view.dispatch({
|
|
4158
|
-
userEvent:
|
|
4160
|
+
userEvent: focusEvent
|
|
4159
4161
|
});
|
|
4160
4162
|
return true;
|
|
4161
4163
|
}
|
|
@@ -4164,8 +4166,95 @@ var EditorModes = {
|
|
|
4164
4166
|
]
|
|
4165
4167
|
};
|
|
4166
4168
|
|
|
4169
|
+
// packages/ui/react-ui-editor/src/extensions/state.ts
|
|
4170
|
+
import { Transaction as Transaction2 } from "@codemirror/state";
|
|
4171
|
+
import { EditorView as EditorView16, keymap as keymap8 } from "@codemirror/view";
|
|
4172
|
+
import { debounce as debounce2 } from "@dxos/async";
|
|
4173
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
4174
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
4175
|
+
var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
|
|
4176
|
+
var scrollAnnotation = "dxos.org/cm/scrolling";
|
|
4177
|
+
var keyPrefix = "dxos.org/react-ui-editor/state";
|
|
4178
|
+
var localStorageStateStoreAdapter = {
|
|
4179
|
+
setState: (id, state2) => {
|
|
4180
|
+
invariant4(id, void 0, {
|
|
4181
|
+
F: __dxlog_file11,
|
|
4182
|
+
L: 35,
|
|
4183
|
+
S: void 0,
|
|
4184
|
+
A: [
|
|
4185
|
+
"id",
|
|
4186
|
+
""
|
|
4187
|
+
]
|
|
4188
|
+
});
|
|
4189
|
+
localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state2));
|
|
4190
|
+
},
|
|
4191
|
+
getState: (id) => {
|
|
4192
|
+
invariant4(id, void 0, {
|
|
4193
|
+
F: __dxlog_file11,
|
|
4194
|
+
L: 39,
|
|
4195
|
+
S: void 0,
|
|
4196
|
+
A: [
|
|
4197
|
+
"id",
|
|
4198
|
+
""
|
|
4199
|
+
]
|
|
4200
|
+
});
|
|
4201
|
+
const state2 = localStorage.getItem(`${keyPrefix}/${id}`);
|
|
4202
|
+
return state2 ? JSON.parse(state2) : void 0;
|
|
4203
|
+
}
|
|
4204
|
+
};
|
|
4205
|
+
var state = ({ getState, setState } = {}) => {
|
|
4206
|
+
const setStateDebounced = debounce2(setState, 1e3);
|
|
4207
|
+
return [
|
|
4208
|
+
// TODO(burdon): Track scrolling (currently only updates when cursor moves).
|
|
4209
|
+
EditorView16.updateListener.of(({ view, changes, transactions }) => {
|
|
4210
|
+
const id = view.state.facet(documentId2);
|
|
4211
|
+
if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
if (setState) {
|
|
4215
|
+
const { top } = view.dom.getBoundingClientRect();
|
|
4216
|
+
const pos = view.posAtCoords({
|
|
4217
|
+
x: 0,
|
|
4218
|
+
y: top
|
|
4219
|
+
});
|
|
4220
|
+
if (pos !== null) {
|
|
4221
|
+
const { anchor, head } = view.state.selection.main;
|
|
4222
|
+
setStateDebounced(id, {
|
|
4223
|
+
scrollTo: {
|
|
4224
|
+
from: pos,
|
|
4225
|
+
yMargin: 0
|
|
4226
|
+
},
|
|
4227
|
+
selection: {
|
|
4228
|
+
anchor,
|
|
4229
|
+
head
|
|
4230
|
+
}
|
|
4231
|
+
});
|
|
4232
|
+
}
|
|
4233
|
+
}
|
|
4234
|
+
}),
|
|
4235
|
+
getState && keymap8.of([
|
|
4236
|
+
{
|
|
4237
|
+
key: "ctrl-r",
|
|
4238
|
+
run: (view) => {
|
|
4239
|
+
const state2 = getState(view.state.facet(documentId2));
|
|
4240
|
+
if (state2) {
|
|
4241
|
+
view.dispatch({
|
|
4242
|
+
effects: EditorView16.scrollIntoView(state2.scrollTo.from, {
|
|
4243
|
+
yMargin: 0
|
|
4244
|
+
}),
|
|
4245
|
+
selection: state2.selection,
|
|
4246
|
+
annotations: Transaction2.userEvent.of(scrollAnnotation)
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
return true;
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
])
|
|
4253
|
+
].filter(isNotFalsy3);
|
|
4254
|
+
};
|
|
4255
|
+
|
|
4167
4256
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
4168
|
-
import { keymap as
|
|
4257
|
+
import { keymap as keymap9 } from "@codemirror/view";
|
|
4169
4258
|
var defaultItems = [
|
|
4170
4259
|
"hello world!",
|
|
4171
4260
|
"this is a test.",
|
|
@@ -4175,7 +4264,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4175
4264
|
let t;
|
|
4176
4265
|
let idx = 0;
|
|
4177
4266
|
return [
|
|
4178
|
-
|
|
4267
|
+
keymap9.of([
|
|
4179
4268
|
{
|
|
4180
4269
|
// Reset.
|
|
4181
4270
|
key: "alt-meta-'",
|
|
@@ -4222,15 +4311,17 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4222
4311
|
};
|
|
4223
4312
|
|
|
4224
4313
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
4225
|
-
var
|
|
4314
|
+
var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
4226
4315
|
var instanceCount = 0;
|
|
4227
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo =
|
|
4228
|
-
|
|
4316
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView17.scrollIntoView(0, {
|
|
4317
|
+
yMargin: 0
|
|
4318
|
+
}), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
|
|
4319
|
+
const [instanceId] = useState(() => `text-editor-${++instanceCount}`);
|
|
4229
4320
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
4230
4321
|
tabBehavior: "limited"
|
|
4231
4322
|
});
|
|
4232
4323
|
const rootRef = useRef(null);
|
|
4233
|
-
const [view, setView] =
|
|
4324
|
+
const [view, setView] = useState(null);
|
|
4234
4325
|
useImperativeHandle(forwardedRef, () => view, [
|
|
4235
4326
|
view
|
|
4236
4327
|
]);
|
|
@@ -4243,42 +4334,42 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4243
4334
|
autoFocus
|
|
4244
4335
|
]);
|
|
4245
4336
|
useEffect2(() => {
|
|
4246
|
-
log9("
|
|
4337
|
+
log9("create", {
|
|
4247
4338
|
id,
|
|
4248
4339
|
instanceId
|
|
4249
4340
|
}, {
|
|
4250
|
-
F:
|
|
4341
|
+
F: __dxlog_file12,
|
|
4251
4342
|
L: 88,
|
|
4252
4343
|
S: void 0,
|
|
4253
4344
|
C: (f, a) => f(...a)
|
|
4254
4345
|
});
|
|
4255
|
-
const
|
|
4346
|
+
const state2 = EditorState2.create({
|
|
4256
4347
|
doc,
|
|
4257
4348
|
selection,
|
|
4258
4349
|
extensions: [
|
|
4259
4350
|
id && documentId2.of(id),
|
|
4260
4351
|
// TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
|
|
4261
|
-
|
|
4352
|
+
EditorView17.exceptionSink.of((err) => {
|
|
4262
4353
|
log9.catch(err, void 0, {
|
|
4263
|
-
F:
|
|
4354
|
+
F: __dxlog_file12,
|
|
4264
4355
|
L: 101,
|
|
4265
4356
|
S: void 0,
|
|
4266
4357
|
C: (f, a) => f(...a)
|
|
4267
4358
|
});
|
|
4268
4359
|
}),
|
|
4269
4360
|
// Focus.
|
|
4270
|
-
|
|
4361
|
+
EditorView17.updateListener.of((update2) => {
|
|
4271
4362
|
update2.transactions.forEach((transaction) => {
|
|
4272
|
-
if (transaction.isUserEvent(
|
|
4363
|
+
if (transaction.isUserEvent(focusEvent)) {
|
|
4273
4364
|
rootRef.current?.focus();
|
|
4274
4365
|
}
|
|
4275
4366
|
});
|
|
4276
4367
|
}),
|
|
4277
4368
|
extensions
|
|
4278
|
-
].filter(
|
|
4369
|
+
].filter(isNotFalsy4)
|
|
4279
4370
|
});
|
|
4280
|
-
const view2 = new
|
|
4281
|
-
state,
|
|
4371
|
+
const view2 = new EditorView17({
|
|
4372
|
+
state: state2,
|
|
4282
4373
|
parent: rootRef.current,
|
|
4283
4374
|
scrollTo,
|
|
4284
4375
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
@@ -4290,21 +4381,29 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4290
4381
|
view3.update(trs);
|
|
4291
4382
|
}
|
|
4292
4383
|
});
|
|
4293
|
-
|
|
4294
|
-
if (moveToEndOfLine) {
|
|
4384
|
+
if (moveToEndOfLine && !(scrollTo || selection)) {
|
|
4295
4385
|
const { to } = view2.state.doc.lineAt(0);
|
|
4296
|
-
view2
|
|
4386
|
+
view2.dispatch({
|
|
4297
4387
|
selection: {
|
|
4298
4388
|
anchor: to
|
|
4299
4389
|
}
|
|
4300
4390
|
});
|
|
4301
4391
|
}
|
|
4302
|
-
if (
|
|
4392
|
+
if (state2.facet(editorMode).noTabster) {
|
|
4303
4393
|
rootRef.current?.removeAttribute("data-tabster");
|
|
4304
4394
|
}
|
|
4395
|
+
setView(view2);
|
|
4305
4396
|
return () => {
|
|
4397
|
+
log9("destroy", {
|
|
4398
|
+
id,
|
|
4399
|
+
instanceId
|
|
4400
|
+
}, {
|
|
4401
|
+
F: __dxlog_file12,
|
|
4402
|
+
L: 150,
|
|
4403
|
+
S: void 0,
|
|
4404
|
+
C: (f, a) => f(...a)
|
|
4405
|
+
});
|
|
4306
4406
|
view2?.destroy();
|
|
4307
|
-
setView(null);
|
|
4308
4407
|
};
|
|
4309
4408
|
}, [
|
|
4310
4409
|
doc,
|
|
@@ -4334,9 +4433,10 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4334
4433
|
});
|
|
4335
4434
|
|
|
4336
4435
|
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
4337
|
-
import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic
|
|
4436
|
+
import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic } from "@phosphor-icons/react";
|
|
4338
4437
|
import { createContext } from "@radix-ui/react-context";
|
|
4339
|
-
import React2, { useRef as useRef2, useState as
|
|
4438
|
+
import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
|
|
4439
|
+
import { useDropzone } from "react-dropzone";
|
|
4340
4440
|
import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
|
|
4341
4441
|
import { getSize } from "@dxos/react-ui-theme";
|
|
4342
4442
|
var tooltipProps = {
|
|
@@ -4353,10 +4453,10 @@ var HeadingIcons = {
|
|
|
4353
4453
|
"6": TextHSix
|
|
4354
4454
|
};
|
|
4355
4455
|
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
4356
|
-
var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
4456
|
+
var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
|
|
4357
4457
|
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
4358
4458
|
onAction,
|
|
4359
|
-
state
|
|
4459
|
+
state: state2
|
|
4360
4460
|
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
4361
4461
|
density: "fine"
|
|
4362
4462
|
}, /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
@@ -4370,7 +4470,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
|
4370
4470
|
};
|
|
4371
4471
|
var buttonStyles = "min-bs-0 p-2";
|
|
4372
4472
|
var iconStyles = getSize(5);
|
|
4373
|
-
var
|
|
4473
|
+
var ToolbarToggleButton = ({ Icon, children, ...props }) => {
|
|
4374
4474
|
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4375
4475
|
asChild: true
|
|
4376
4476
|
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
|
|
@@ -4383,20 +4483,33 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
|
4383
4483
|
className: "sr-only"
|
|
4384
4484
|
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4385
4485
|
};
|
|
4486
|
+
var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
4487
|
+
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4488
|
+
asChild: true
|
|
4489
|
+
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
|
|
4490
|
+
variant: "ghost",
|
|
4491
|
+
...props,
|
|
4492
|
+
classNames: buttonStyles
|
|
4493
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
4494
|
+
className: iconStyles
|
|
4495
|
+
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4496
|
+
className: "sr-only"
|
|
4497
|
+
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4498
|
+
};
|
|
4386
4499
|
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4387
4500
|
role: "separator",
|
|
4388
4501
|
className: "grow"
|
|
4389
4502
|
});
|
|
4390
4503
|
var MarkdownHeading = () => {
|
|
4391
4504
|
const { t } = useTranslation(translationKey);
|
|
4392
|
-
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
4393
|
-
const blockType =
|
|
4505
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
|
|
4506
|
+
const blockType = state2 ? state2.blockType : "paragraph";
|
|
4394
4507
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
4395
4508
|
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
|
|
4396
4509
|
const HeadingIcon = HeadingIcons[value ?? "0"];
|
|
4397
4510
|
const suppressNextTooltip = useRef2(false);
|
|
4398
|
-
const [tooltipOpen, setTooltipOpen] =
|
|
4399
|
-
const [selectOpen, setSelectOpen] =
|
|
4511
|
+
const [tooltipOpen, setTooltipOpen] = useState2(false);
|
|
4512
|
+
const [selectOpen, setSelectOpen] = useState2(false);
|
|
4400
4513
|
return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
|
|
4401
4514
|
open: tooltipOpen,
|
|
4402
4515
|
onOpenChange: (nextOpen) => {
|
|
@@ -4464,43 +4577,43 @@ var markdownStyles = [
|
|
|
4464
4577
|
{
|
|
4465
4578
|
type: "strong",
|
|
4466
4579
|
Icon: TextB,
|
|
4467
|
-
getState: (
|
|
4580
|
+
getState: (state2) => state2.strong
|
|
4468
4581
|
},
|
|
4469
4582
|
{
|
|
4470
4583
|
type: "emphasis",
|
|
4471
4584
|
Icon: TextItalic,
|
|
4472
|
-
getState: (
|
|
4585
|
+
getState: (state2) => state2.emphasis
|
|
4473
4586
|
},
|
|
4474
4587
|
{
|
|
4475
4588
|
type: "strikethrough",
|
|
4476
4589
|
Icon: TextStrikethrough,
|
|
4477
|
-
getState: (
|
|
4590
|
+
getState: (state2) => state2.strikethrough
|
|
4478
4591
|
},
|
|
4479
4592
|
{
|
|
4480
4593
|
type: "code",
|
|
4481
4594
|
Icon: Code,
|
|
4482
|
-
getState: (
|
|
4595
|
+
getState: (state2) => state2.code
|
|
4483
4596
|
},
|
|
4484
4597
|
{
|
|
4485
4598
|
type: "link",
|
|
4486
4599
|
Icon: Link,
|
|
4487
|
-
getState: (
|
|
4600
|
+
getState: (state2) => state2.link
|
|
4488
4601
|
}
|
|
4489
4602
|
];
|
|
4490
4603
|
var MarkdownStyles = () => {
|
|
4491
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4604
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4492
4605
|
const { t } = useTranslation(translationKey);
|
|
4493
4606
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4494
4607
|
type: "multiple",
|
|
4495
|
-
value: markdownStyles.filter(({ getState }) =>
|
|
4496
|
-
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4608
|
+
value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
|
|
4609
|
+
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4497
4610
|
key: type,
|
|
4498
4611
|
value: type,
|
|
4499
4612
|
Icon,
|
|
4500
|
-
disabled:
|
|
4501
|
-
onClick:
|
|
4613
|
+
disabled: state2?.blockType === "codeblock",
|
|
4614
|
+
onClick: state2 ? () => onAction?.({
|
|
4502
4615
|
type,
|
|
4503
|
-
data: !getState(
|
|
4616
|
+
data: !getState(state2)
|
|
4504
4617
|
}) : void 0
|
|
4505
4618
|
}, t(`${type} label`))));
|
|
4506
4619
|
};
|
|
@@ -4508,32 +4621,32 @@ var markdownLists = [
|
|
|
4508
4621
|
{
|
|
4509
4622
|
type: "list-bullet",
|
|
4510
4623
|
Icon: ListBullets,
|
|
4511
|
-
getState: (
|
|
4624
|
+
getState: (state2) => state2.listStyle === "bullet"
|
|
4512
4625
|
},
|
|
4513
4626
|
{
|
|
4514
4627
|
type: "list-ordered",
|
|
4515
4628
|
Icon: ListNumbers,
|
|
4516
|
-
getState: (
|
|
4629
|
+
getState: (state2) => state2.listStyle === "ordered"
|
|
4517
4630
|
},
|
|
4518
4631
|
{
|
|
4519
4632
|
type: "list-task",
|
|
4520
4633
|
Icon: ListChecks,
|
|
4521
|
-
getState: (
|
|
4634
|
+
getState: (state2) => state2.listStyle === "task"
|
|
4522
4635
|
}
|
|
4523
4636
|
];
|
|
4524
4637
|
var MarkdownLists = () => {
|
|
4525
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4638
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4526
4639
|
const { t } = useTranslation(translationKey);
|
|
4527
4640
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4528
4641
|
type: "single",
|
|
4529
|
-
value:
|
|
4530
|
-
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4642
|
+
value: state2?.listStyle ? `list-${state2.listStyle}` : ""
|
|
4643
|
+
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4531
4644
|
key: type,
|
|
4532
4645
|
value: type,
|
|
4533
4646
|
Icon,
|
|
4534
|
-
onClick:
|
|
4647
|
+
onClick: state2 ? () => onAction?.({
|
|
4535
4648
|
type,
|
|
4536
|
-
data: !getState(
|
|
4649
|
+
data: !getState(state2)
|
|
4537
4650
|
}) : void 0
|
|
4538
4651
|
}, t(`${type} label`))));
|
|
4539
4652
|
};
|
|
@@ -4541,63 +4654,101 @@ var markdownBlocks = [
|
|
|
4541
4654
|
{
|
|
4542
4655
|
type: "blockquote",
|
|
4543
4656
|
Icon: Quotes,
|
|
4544
|
-
getState: (
|
|
4657
|
+
getState: (state2) => state2.blockQuote
|
|
4545
4658
|
},
|
|
4546
4659
|
{
|
|
4547
4660
|
type: "codeblock",
|
|
4548
4661
|
Icon: CodeBlock,
|
|
4549
|
-
getState: (
|
|
4662
|
+
getState: (state2) => state2.blockType === "codeblock"
|
|
4550
4663
|
},
|
|
4551
4664
|
{
|
|
4552
4665
|
type: "table",
|
|
4553
4666
|
Icon: Table2,
|
|
4554
|
-
getState: (
|
|
4555
|
-
disabled: (
|
|
4667
|
+
getState: (state2) => state2.blockType === "tablecell",
|
|
4668
|
+
disabled: (state2) => !state2.blankLine
|
|
4556
4669
|
}
|
|
4557
4670
|
];
|
|
4558
4671
|
var MarkdownBlocks = () => {
|
|
4559
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4672
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4560
4673
|
const { t } = useTranslation(translationKey);
|
|
4561
|
-
const value = markdownBlocks.find(({ getState }) =>
|
|
4674
|
+
const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
|
|
4562
4675
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4563
4676
|
type: "single",
|
|
4564
4677
|
value: value?.type ?? ""
|
|
4565
|
-
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4678
|
+
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4566
4679
|
key: type,
|
|
4567
4680
|
value: type,
|
|
4568
4681
|
Icon,
|
|
4569
|
-
disabled: !
|
|
4570
|
-
onClick:
|
|
4682
|
+
disabled: !state2 || disabled?.(state2),
|
|
4683
|
+
onClick: state2 ? () => onAction?.({
|
|
4571
4684
|
type,
|
|
4572
|
-
data: !getState(
|
|
4685
|
+
data: !getState(state2)
|
|
4573
4686
|
}) : void 0
|
|
4574
4687
|
}, t(`${type} label`))));
|
|
4575
4688
|
};
|
|
4576
4689
|
var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null));
|
|
4577
|
-
var
|
|
4690
|
+
var MarkdownCustom = ({ onUpload } = {}) => {
|
|
4578
4691
|
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4579
4692
|
const { t } = useTranslation(translationKey);
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4693
|
+
const { acceptedFiles, getInputProps, open } = useDropzone({
|
|
4694
|
+
multiple: false,
|
|
4695
|
+
noDrag: true,
|
|
4696
|
+
accept: {
|
|
4697
|
+
"image/*": [
|
|
4698
|
+
".jpg",
|
|
4699
|
+
".jpeg",
|
|
4700
|
+
".png",
|
|
4701
|
+
".gif"
|
|
4702
|
+
]
|
|
4703
|
+
}
|
|
4704
|
+
});
|
|
4705
|
+
useEffect3(() => {
|
|
4706
|
+
if (onUpload && acceptedFiles.length) {
|
|
4707
|
+
setTimeout(async () => {
|
|
4708
|
+
const f = acceptedFiles[0];
|
|
4709
|
+
const file = new File([
|
|
4710
|
+
f
|
|
4711
|
+
], f.name, {
|
|
4712
|
+
type: f.type,
|
|
4713
|
+
lastModified: f.lastModified
|
|
4714
|
+
});
|
|
4715
|
+
const { url } = await onUpload(file);
|
|
4716
|
+
if (url) {
|
|
4717
|
+
onAction?.({
|
|
4718
|
+
type: "image",
|
|
4719
|
+
data: url
|
|
4720
|
+
});
|
|
4721
|
+
}
|
|
4722
|
+
});
|
|
4723
|
+
}
|
|
4724
|
+
}, [
|
|
4725
|
+
acceptedFiles
|
|
4726
|
+
]);
|
|
4727
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("input", getInputProps()), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4728
|
+
value: "image",
|
|
4729
|
+
Icon: Image,
|
|
4730
|
+
onClick: () => open()
|
|
4731
|
+
}, t("image label")));
|
|
4732
|
+
};
|
|
4733
|
+
var MarkdownActions = () => {
|
|
4734
|
+
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4735
|
+
const { t } = useTranslation(translationKey);
|
|
4736
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4737
|
+
value: "comment",
|
|
4738
|
+
Icon: ChatText,
|
|
4584
4739
|
"data-testid": "editor.toolbar.comment",
|
|
4585
4740
|
onClick: () => onAction?.({
|
|
4586
4741
|
type: "comment"
|
|
4587
|
-
})
|
|
4588
|
-
|
|
4589
|
-
}, /* @__PURE__ */ React2.createElement(ChatText, {
|
|
4590
|
-
className: iconStyles
|
|
4591
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4592
|
-
className: "sr-only"
|
|
4593
|
-
}, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4742
|
+
})
|
|
4743
|
+
}, t("comment label")));
|
|
4594
4744
|
};
|
|
4595
4745
|
var Toolbar = {
|
|
4596
4746
|
Root: ToolbarRoot,
|
|
4597
|
-
Button:
|
|
4747
|
+
Button: ToolbarToggleButton,
|
|
4598
4748
|
Separator: ToolbarSeparator,
|
|
4599
4749
|
Markdown: MarkdownStandard,
|
|
4600
|
-
|
|
4750
|
+
Custom: MarkdownCustom,
|
|
4751
|
+
Actions: MarkdownActions
|
|
4601
4752
|
};
|
|
4602
4753
|
|
|
4603
4754
|
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
@@ -4634,7 +4785,13 @@ var useActionHandler = (view) => {
|
|
|
4634
4785
|
insertTable(view);
|
|
4635
4786
|
break;
|
|
4636
4787
|
case "link":
|
|
4637
|
-
(action.data === false ? removeLink : addLink)(view);
|
|
4788
|
+
(action.data === false ? removeLink : addLink())(view);
|
|
4789
|
+
break;
|
|
4790
|
+
case "image":
|
|
4791
|
+
addLink({
|
|
4792
|
+
url: action.data,
|
|
4793
|
+
image: true
|
|
4794
|
+
})(view);
|
|
4638
4795
|
break;
|
|
4639
4796
|
case "comment":
|
|
4640
4797
|
createComment(view);
|
|
@@ -4663,43 +4820,51 @@ var useDocAccessor = (text) => {
|
|
|
4663
4820
|
|
|
4664
4821
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4665
4822
|
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4666
|
-
import { EditorView as
|
|
4667
|
-
import { useEffect as
|
|
4823
|
+
import { EditorView as EditorView18 } from "@codemirror/view";
|
|
4824
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
4668
4825
|
import { log as log10 } from "@dxos/log";
|
|
4669
|
-
import { isNotFalsy as
|
|
4670
|
-
var
|
|
4826
|
+
import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
|
|
4827
|
+
var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4671
4828
|
var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
4672
4829
|
let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
|
|
4673
4830
|
const onUpdate = useRef3();
|
|
4674
|
-
const [view, setView] =
|
|
4831
|
+
const [view, setView] = useState3();
|
|
4675
4832
|
const parentRef = useRef3(null);
|
|
4676
|
-
|
|
4833
|
+
useEffect4(() => {
|
|
4677
4834
|
let view2;
|
|
4678
4835
|
if (parentRef.current) {
|
|
4679
|
-
|
|
4836
|
+
log10("create", {
|
|
4837
|
+
id
|
|
4838
|
+
}, {
|
|
4839
|
+
F: __dxlog_file13,
|
|
4840
|
+
L: 36,
|
|
4841
|
+
S: void 0,
|
|
4842
|
+
C: (f, a) => f(...a)
|
|
4843
|
+
});
|
|
4844
|
+
const state2 = EditorState3.create({
|
|
4680
4845
|
doc,
|
|
4681
4846
|
selection,
|
|
4682
4847
|
extensions: [
|
|
4683
4848
|
id && documentId2.of(id),
|
|
4684
4849
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4685
|
-
|
|
4850
|
+
EditorView18.exceptionSink.of((err) => {
|
|
4686
4851
|
log10.catch(err, void 0, {
|
|
4687
|
-
F:
|
|
4688
|
-
L:
|
|
4852
|
+
F: __dxlog_file13,
|
|
4853
|
+
L: 46,
|
|
4689
4854
|
S: void 0,
|
|
4690
4855
|
C: (f, a) => f(...a)
|
|
4691
4856
|
});
|
|
4692
4857
|
}),
|
|
4693
4858
|
extensions,
|
|
4694
|
-
|
|
4859
|
+
EditorView18.updateListener.of(() => {
|
|
4695
4860
|
onUpdate.current?.();
|
|
4696
4861
|
})
|
|
4697
|
-
].filter(
|
|
4862
|
+
].filter(isNotFalsy5)
|
|
4698
4863
|
});
|
|
4699
|
-
view2 = new
|
|
4864
|
+
view2 = new EditorView18({
|
|
4700
4865
|
parent: parentRef.current,
|
|
4701
4866
|
scrollTo,
|
|
4702
|
-
state,
|
|
4867
|
+
state: state2,
|
|
4703
4868
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4704
4869
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4705
4870
|
dispatchTransactions: (trs, view3) => {
|
|
@@ -4712,10 +4877,18 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4712
4877
|
setView(view2);
|
|
4713
4878
|
}
|
|
4714
4879
|
return () => {
|
|
4880
|
+
log10("destroy", {
|
|
4881
|
+
id
|
|
4882
|
+
}, {
|
|
4883
|
+
F: __dxlog_file13,
|
|
4884
|
+
L: 74,
|
|
4885
|
+
S: void 0,
|
|
4886
|
+
C: (f, a) => f(...a)
|
|
4887
|
+
});
|
|
4715
4888
|
view2?.destroy();
|
|
4716
4889
|
};
|
|
4717
4890
|
}, deps);
|
|
4718
|
-
|
|
4891
|
+
useEffect4(() => {
|
|
4719
4892
|
if (view) {
|
|
4720
4893
|
if (!selection && !view.state.selection.main.anchor) {
|
|
4721
4894
|
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
@@ -4774,7 +4947,6 @@ export {
|
|
|
4774
4947
|
callbackWrapper,
|
|
4775
4948
|
command,
|
|
4776
4949
|
comments,
|
|
4777
|
-
compareFormatting,
|
|
4778
4950
|
createBasicExtensions,
|
|
4779
4951
|
createComment,
|
|
4780
4952
|
createDataExtensions,
|
|
@@ -4791,14 +4963,18 @@ export {
|
|
|
4791
4963
|
editorMode,
|
|
4792
4964
|
editorWithToolbarLayout,
|
|
4793
4965
|
focusComment,
|
|
4966
|
+
focusEvent,
|
|
4967
|
+
formattingEquals,
|
|
4794
4968
|
formattingKeymap,
|
|
4795
4969
|
getFormatting,
|
|
4796
4970
|
getToken,
|
|
4797
4971
|
image,
|
|
4972
|
+
imageUpload,
|
|
4798
4973
|
insertTable,
|
|
4799
|
-
|
|
4974
|
+
keymap10 as keymap,
|
|
4800
4975
|
linkTooltip,
|
|
4801
4976
|
listener,
|
|
4977
|
+
localStorageStateStoreAdapter,
|
|
4802
4978
|
logChanges,
|
|
4803
4979
|
markdownHighlightStyle,
|
|
4804
4980
|
markdownTags,
|
|
@@ -4814,6 +4990,7 @@ export {
|
|
|
4814
4990
|
setHeading,
|
|
4815
4991
|
setSelection,
|
|
4816
4992
|
setStyle,
|
|
4993
|
+
state,
|
|
4817
4994
|
table,
|
|
4818
4995
|
tags2 as tags,
|
|
4819
4996
|
toggleBlockquote,
|