@dxos/react-ui-editor 0.4.8-main.de30065 → 0.4.8-main.e23f3c5
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 +456 -272
- 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/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/useDocAccessor.d.ts +4 -2
- package/dist/types/src/hooks/useDocAccessor.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 -24
- 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/index.ts +1 -0
- package/src/extensions/markdown/formatting.test.ts +13 -13
- package/src/extensions/markdown/formatting.ts +95 -87
- 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/useDocAccessor.ts +8 -2
- 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
36
|
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } 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;
|
|
@@ -2606,8 +2607,8 @@ var checkedTask = Decoration5.replace({
|
|
|
2606
2607
|
var uncheckedTask = Decoration5.replace({
|
|
2607
2608
|
widget: new CheckboxWidget(false)
|
|
2608
2609
|
});
|
|
2609
|
-
var editingRange = (
|
|
2610
|
-
const { readOnly, selection: { main: { head } } } =
|
|
2610
|
+
var editingRange = (state2, range, focus) => {
|
|
2611
|
+
const { readOnly, selection: { main: { head } } } = state2;
|
|
2611
2612
|
return focus && !readOnly && head >= range.from && head <= range.to;
|
|
2612
2613
|
};
|
|
2613
2614
|
var MarksByParent = /* @__PURE__ */ new Set([
|
|
@@ -2620,14 +2621,14 @@ var MarksByParent = /* @__PURE__ */ new Set([
|
|
|
2620
2621
|
var buildDecorations = (view, options, focus) => {
|
|
2621
2622
|
const deco = new RangeSetBuilder2();
|
|
2622
2623
|
const atomicDeco = new RangeSetBuilder2();
|
|
2623
|
-
const { state } = view;
|
|
2624
|
+
const { state: state2 } = view;
|
|
2624
2625
|
for (const { from, to } of view.visibleRanges) {
|
|
2625
|
-
syntaxTree(
|
|
2626
|
+
syntaxTree(state2).iterate({
|
|
2626
2627
|
from,
|
|
2627
2628
|
to,
|
|
2628
2629
|
enter: (node) => {
|
|
2629
2630
|
if (node.name === "FencedCode") {
|
|
2630
|
-
const editing = editingRange(
|
|
2631
|
+
const editing = editingRange(state2, node, focus);
|
|
2631
2632
|
for (const block of view.viewportLineBlocks) {
|
|
2632
2633
|
if (block.to < node.from) {
|
|
2633
2634
|
continue;
|
|
@@ -2636,7 +2637,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2636
2637
|
break;
|
|
2637
2638
|
}
|
|
2638
2639
|
const first = block.from <= node.from;
|
|
2639
|
-
const last = block.to >= node.to && /^(\s>)*```$/.test(
|
|
2640
|
+
const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
|
|
2640
2641
|
deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
|
|
2641
2642
|
if (!editing && (first || last)) {
|
|
2642
2643
|
atomicDeco.add(block.from, block.to, hide);
|
|
@@ -2646,9 +2647,9 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2646
2647
|
} else if (node.name === "Link") {
|
|
2647
2648
|
const marks = node.node.getChildren("LinkMark");
|
|
2648
2649
|
const urlNode = node.node.getChild("URL");
|
|
2649
|
-
const editing = editingRange(
|
|
2650
|
+
const editing = editingRange(state2, node, focus);
|
|
2650
2651
|
if (urlNode && marks.length >= 2) {
|
|
2651
|
-
const url =
|
|
2652
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
2652
2653
|
if (!editing) {
|
|
2653
2654
|
atomicDeco.add(node.from, marks[0].to, hide);
|
|
2654
2655
|
}
|
|
@@ -2669,24 +2670,24 @@ var buildDecorations = (view, options, focus) => {
|
|
|
2669
2670
|
}
|
|
2670
2671
|
} else if (node.name === "HeaderMark") {
|
|
2671
2672
|
const parent = node.node.parent;
|
|
2672
|
-
if (/^ATX/.test(parent.name) && !editingRange(
|
|
2673
|
-
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);
|
|
2674
2675
|
atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
|
|
2675
2676
|
}
|
|
2676
2677
|
} else if (node.name === "HorizontalRule") {
|
|
2677
|
-
if (!editingRange(
|
|
2678
|
+
if (!editingRange(state2, node, focus)) {
|
|
2678
2679
|
deco.add(node.from, node.to, horizontalRule);
|
|
2679
2680
|
}
|
|
2680
2681
|
} else if (node.name === "TaskMarker") {
|
|
2681
|
-
if (!editingRange(
|
|
2682
|
-
const checked =
|
|
2682
|
+
if (!editingRange(state2, node, focus)) {
|
|
2683
|
+
const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2683
2684
|
atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
|
|
2684
2685
|
class: "cm-task"
|
|
2685
2686
|
}));
|
|
2686
2687
|
atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
|
|
2687
2688
|
}
|
|
2688
2689
|
} else if (MarksByParent.has(node.name)) {
|
|
2689
|
-
if (!editingRange(
|
|
2690
|
+
if (!editingRange(state2, node.node.parent, focus)) {
|
|
2690
2691
|
atomicDeco.add(node.from, node.to, hide);
|
|
2691
2692
|
}
|
|
2692
2693
|
}
|
|
@@ -2796,8 +2797,8 @@ import { snippet } from "@codemirror/autocomplete";
|
|
|
2796
2797
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
2797
2798
|
import { EditorSelection } from "@codemirror/state";
|
|
2798
2799
|
import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
|
|
2799
|
-
import {
|
|
2800
|
-
var
|
|
2800
|
+
import { useMemo, useState } from "react";
|
|
2801
|
+
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;
|
|
2801
2802
|
var Inline;
|
|
2802
2803
|
(function(Inline2) {
|
|
2803
2804
|
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
@@ -2811,13 +2812,13 @@ var List;
|
|
|
2811
2812
|
List2[List2["Bullet"] = 1] = "Bullet";
|
|
2812
2813
|
List2[List2["Task"] = 2] = "Task";
|
|
2813
2814
|
})(List || (List = {}));
|
|
2814
|
-
var setHeading = (level) => ({ state, dispatch }) => {
|
|
2815
|
-
const { selection: { ranges }, doc } =
|
|
2815
|
+
var setHeading = (level) => ({ state: state2, dispatch }) => {
|
|
2816
|
+
const { selection: { ranges }, doc } = state2;
|
|
2816
2817
|
const changes = [];
|
|
2817
2818
|
let prevBlock = -1;
|
|
2818
2819
|
for (const range of ranges) {
|
|
2819
2820
|
let sawBlock = false;
|
|
2820
|
-
syntaxTree2(
|
|
2821
|
+
syntaxTree2(state2).iterate({
|
|
2821
2822
|
from: range.from,
|
|
2822
2823
|
to: range.to,
|
|
2823
2824
|
enter: (node) => {
|
|
@@ -2870,7 +2871,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
2870
2871
|
}
|
|
2871
2872
|
});
|
|
2872
2873
|
let line;
|
|
2873
|
-
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line =
|
|
2874
|
+
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
|
|
2874
2875
|
changes.push({
|
|
2875
2876
|
from: line.from,
|
|
2876
2877
|
to: line.to,
|
|
@@ -2881,23 +2882,23 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
2881
2882
|
if (!changes.length) {
|
|
2882
2883
|
return false;
|
|
2883
2884
|
}
|
|
2884
|
-
const changeSet =
|
|
2885
|
-
dispatch(
|
|
2885
|
+
const changeSet = state2.changes(changes);
|
|
2886
|
+
dispatch(state2.update({
|
|
2886
2887
|
changes: changeSet,
|
|
2887
|
-
selection:
|
|
2888
|
+
selection: state2.selection.map(changeSet, 1),
|
|
2888
2889
|
userEvent: "format.setHeading",
|
|
2889
2890
|
scrollIntoView: true
|
|
2890
2891
|
}));
|
|
2891
2892
|
return true;
|
|
2892
2893
|
};
|
|
2893
|
-
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
2894
|
+
var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
|
|
2894
2895
|
const marker = inlineMarkerText(type);
|
|
2895
|
-
const changes =
|
|
2896
|
+
const changes = state2.changeByRange((range) => {
|
|
2896
2897
|
if (!enable && range.empty) {
|
|
2897
|
-
const after =
|
|
2898
|
+
const after = state2.doc.sliceString(range.head, range.head + 6);
|
|
2898
2899
|
const found = after.indexOf(marker);
|
|
2899
2900
|
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
2900
|
-
const before =
|
|
2901
|
+
const before = state2.doc.sliceString(range.head - 6, range.head);
|
|
2901
2902
|
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
2902
2903
|
...before.slice(before.length - found)
|
|
2903
2904
|
].reverse().join("") === after.slice(0, found)) {
|
|
@@ -2924,14 +2925,14 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2924
2925
|
let startCovered = false;
|
|
2925
2926
|
let endCovered = false;
|
|
2926
2927
|
let { from, to } = range;
|
|
2927
|
-
syntaxTree2(
|
|
2928
|
+
syntaxTree2(state2).iterate({
|
|
2928
2929
|
from,
|
|
2929
2930
|
to,
|
|
2930
2931
|
enter: (node) => {
|
|
2931
2932
|
const { name } = node;
|
|
2932
2933
|
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
2933
2934
|
blockStart = blockContentStart(node);
|
|
2934
|
-
blockEnd = blockContentEnd(node,
|
|
2935
|
+
blockEnd = blockContentEnd(node, state2.doc);
|
|
2935
2936
|
startCovered = endCovered = false;
|
|
2936
2937
|
} else if (name === "Link" || name === "Image" && enable) {
|
|
2937
2938
|
if (from < node.from && to > node.from && to <= node.to) {
|
|
@@ -2976,7 +2977,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2976
2977
|
});
|
|
2977
2978
|
if (markType !== type && closeStart >= to) {
|
|
2978
2979
|
changesAtEnd.push({
|
|
2979
|
-
from: skipSpaces(Math.min(to, blockEnd),
|
|
2980
|
+
from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
|
|
2980
2981
|
insert: inlineMarkerText(markType)
|
|
2981
2982
|
});
|
|
2982
2983
|
}
|
|
@@ -2988,7 +2989,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2988
2989
|
});
|
|
2989
2990
|
if (markType !== type && openEnd <= from) {
|
|
2990
2991
|
changes2.push({
|
|
2991
|
-
from: skipSpaces(Math.max(from, blockStart),
|
|
2992
|
+
from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
|
|
2992
2993
|
insert: inlineMarkerText(markType)
|
|
2993
2994
|
});
|
|
2994
2995
|
}
|
|
@@ -3018,7 +3019,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3018
3019
|
changes2.push(startCovered);
|
|
3019
3020
|
} else if (startCovered) {
|
|
3020
3021
|
changes2.push({
|
|
3021
|
-
from: skipSpaces(rangeStart,
|
|
3022
|
+
from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
|
|
3022
3023
|
insert: marker
|
|
3023
3024
|
});
|
|
3024
3025
|
}
|
|
@@ -3026,7 +3027,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3026
3027
|
changes2.push(endCovered);
|
|
3027
3028
|
} else if (endCovered) {
|
|
3028
3029
|
changes2.push({
|
|
3029
|
-
from: skipSpaces(rangeEnd,
|
|
3030
|
+
from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
|
|
3030
3031
|
insert: marker
|
|
3031
3032
|
});
|
|
3032
3033
|
}
|
|
@@ -3034,7 +3035,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3034
3035
|
}
|
|
3035
3036
|
}
|
|
3036
3037
|
});
|
|
3037
|
-
if (blockStart < 0 && range.empty && enable && !/\S/.test(
|
|
3038
|
+
if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
|
|
3038
3039
|
return {
|
|
3039
3040
|
changes: {
|
|
3040
3041
|
from: range.head,
|
|
@@ -3043,13 +3044,13 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
3043
3044
|
range: EditorSelection.cursor(range.head + marker.length)
|
|
3044
3045
|
};
|
|
3045
3046
|
}
|
|
3046
|
-
const changeSet =
|
|
3047
|
+
const changeSet = state2.changes(changes2.concat(changesAtEnd));
|
|
3047
3048
|
return {
|
|
3048
3049
|
changes: changeSet,
|
|
3049
3050
|
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
3050
3051
|
};
|
|
3051
3052
|
});
|
|
3052
|
-
dispatch(
|
|
3053
|
+
dispatch(state2.update(changes, {
|
|
3053
3054
|
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
3054
3055
|
scrollIntoView: true
|
|
3055
3056
|
}));
|
|
@@ -3123,8 +3124,8 @@ var insertTable = (view) => {
|
|
|
3123
3124
|
const { from } = doc.line(number);
|
|
3124
3125
|
snippets.table(view, null, from, from);
|
|
3125
3126
|
};
|
|
3126
|
-
var removeLinkInner = (from, to, changes,
|
|
3127
|
-
syntaxTree2(
|
|
3127
|
+
var removeLinkInner = (from, to, changes, state2) => {
|
|
3128
|
+
syntaxTree2(state2).iterate({
|
|
3128
3129
|
from,
|
|
3129
3130
|
to,
|
|
3130
3131
|
enter: (node) => {
|
|
@@ -3138,8 +3139,8 @@ var removeLinkInner = (from, to, changes, state) => {
|
|
|
3138
3139
|
});
|
|
3139
3140
|
} else if (name === "LinkTitle" || name === "URL") {
|
|
3140
3141
|
changes.push({
|
|
3141
|
-
from: skipSpaces(node2.from,
|
|
3142
|
-
to: skipSpaces(node2.to,
|
|
3142
|
+
from: skipSpaces(node2.from, state2.doc, -1),
|
|
3143
|
+
to: skipSpaces(node2.to, state2.doc, 1)
|
|
3143
3144
|
});
|
|
3144
3145
|
}
|
|
3145
3146
|
});
|
|
@@ -3148,32 +3149,32 @@ var removeLinkInner = (from, to, changes, state) => {
|
|
|
3148
3149
|
}
|
|
3149
3150
|
});
|
|
3150
3151
|
};
|
|
3151
|
-
var removeLink = ({ state, dispatch }) => {
|
|
3152
|
+
var removeLink = ({ state: state2, dispatch }) => {
|
|
3152
3153
|
const changes = [];
|
|
3153
|
-
for (const { from, to } of
|
|
3154
|
-
removeLinkInner(from, to, changes,
|
|
3154
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3155
|
+
removeLinkInner(from, to, changes, state2);
|
|
3155
3156
|
}
|
|
3156
3157
|
if (!changes) {
|
|
3157
3158
|
return false;
|
|
3158
3159
|
}
|
|
3159
|
-
dispatch(
|
|
3160
|
+
dispatch(state2.update({
|
|
3160
3161
|
changes,
|
|
3161
3162
|
userEvent: "format.link.remove",
|
|
3162
3163
|
scrollIntoView: true
|
|
3163
3164
|
}));
|
|
3164
3165
|
return true;
|
|
3165
3166
|
};
|
|
3166
|
-
var addLink = ({ state, dispatch }) => {
|
|
3167
|
-
const changes =
|
|
3167
|
+
var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
|
|
3168
|
+
const changes = state2.changeByRange((range) => {
|
|
3168
3169
|
let { from, to } = range;
|
|
3169
3170
|
const cutStyles = [];
|
|
3170
3171
|
let okay = null;
|
|
3171
|
-
syntaxTree2(
|
|
3172
|
+
syntaxTree2(state2).iterate({
|
|
3172
3173
|
from,
|
|
3173
3174
|
to,
|
|
3174
3175
|
enter: (node) => {
|
|
3175
3176
|
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3176
|
-
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node,
|
|
3177
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
|
|
3177
3178
|
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
3178
3179
|
const sNode = node.node;
|
|
3179
3180
|
if (node.from < from && node.to <= to) {
|
|
@@ -3193,7 +3194,7 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3193
3194
|
}
|
|
3194
3195
|
});
|
|
3195
3196
|
if (okay === null) {
|
|
3196
|
-
const line =
|
|
3197
|
+
const line = state2.doc.lineAt(from);
|
|
3197
3198
|
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
3198
3199
|
}
|
|
3199
3200
|
if (!okay) {
|
|
@@ -3203,26 +3204,26 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3203
3204
|
}
|
|
3204
3205
|
const changes2 = [];
|
|
3205
3206
|
const changesAfter = [];
|
|
3206
|
-
removeLinkInner(from, to, changesAfter,
|
|
3207
|
+
removeLinkInner(from, to, changesAfter, state2);
|
|
3207
3208
|
let cursorOffset = 1;
|
|
3208
3209
|
for (const style of cutStyles) {
|
|
3209
3210
|
const type = InlineMarker[style.name];
|
|
3210
3211
|
const mark2 = inlineMarkerText(type);
|
|
3211
3212
|
if (style.from < from) {
|
|
3212
3213
|
changes2.push({
|
|
3213
|
-
from: skipSpaces(from,
|
|
3214
|
+
from: skipSpaces(from, state2.doc, -1),
|
|
3214
3215
|
insert: mark2
|
|
3215
3216
|
});
|
|
3216
3217
|
changesAfter.push({
|
|
3217
|
-
from: skipSpaces(from,
|
|
3218
|
+
from: skipSpaces(from, state2.doc, 1, to),
|
|
3218
3219
|
insert: mark2
|
|
3219
3220
|
});
|
|
3220
3221
|
} else {
|
|
3221
3222
|
changes2.push({
|
|
3222
|
-
from: skipSpaces(to,
|
|
3223
|
+
from: skipSpaces(to, state2.doc, -1, from),
|
|
3223
3224
|
insert: mark2
|
|
3224
3225
|
});
|
|
3225
|
-
const after = skipSpaces(to,
|
|
3226
|
+
const after = skipSpaces(to, state2.doc, 1);
|
|
3226
3227
|
if (after === to) {
|
|
3227
3228
|
cursorOffset += mark2.length;
|
|
3228
3229
|
}
|
|
@@ -3234,34 +3235,34 @@ var addLink = ({ state, dispatch }) => {
|
|
|
3234
3235
|
}
|
|
3235
3236
|
changes2.push({
|
|
3236
3237
|
from,
|
|
3237
|
-
insert: "["
|
|
3238
|
+
insert: image2 ? "`
|
|
3241
3242
|
});
|
|
3242
|
-
const changeSet =
|
|
3243
|
+
const changeSet = state2.changes(changes2.concat(changesAfter));
|
|
3243
3244
|
return {
|
|
3244
3245
|
changes: changeSet,
|
|
3245
|
-
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
3246
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
|
|
3246
3247
|
};
|
|
3247
3248
|
});
|
|
3248
3249
|
if (changes.changes.empty) {
|
|
3249
3250
|
return false;
|
|
3250
3251
|
}
|
|
3251
|
-
dispatch(
|
|
3252
|
+
dispatch(state2.update(changes, {
|
|
3252
3253
|
userEvent: "format.link.add",
|
|
3253
3254
|
scrollIntoView: true
|
|
3254
3255
|
}));
|
|
3255
3256
|
return true;
|
|
3256
3257
|
};
|
|
3257
|
-
var addList = (type) => ({ state, dispatch }) => {
|
|
3258
|
+
var addList = (type) => ({ state: state2, dispatch }) => {
|
|
3258
3259
|
let lastBlock = -1;
|
|
3259
3260
|
let counter = 1;
|
|
3260
3261
|
let first = true;
|
|
3261
3262
|
let parentColumn = null;
|
|
3262
3263
|
const blocks = [];
|
|
3263
|
-
for (const { from, to } of
|
|
3264
|
-
syntaxTree2(
|
|
3264
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3265
|
+
syntaxTree2(state2).iterate({
|
|
3265
3266
|
from,
|
|
3266
3267
|
to,
|
|
3267
3268
|
enter: (node) => {
|
|
@@ -3273,7 +3274,7 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3273
3274
|
}
|
|
3274
3275
|
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
3275
3276
|
const item = before.lastChild;
|
|
3276
|
-
const itemLine =
|
|
3277
|
+
const itemLine = state2.doc.lineAt(item.from);
|
|
3277
3278
|
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
3278
3279
|
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
3279
3280
|
if (type === 0) {
|
|
@@ -3308,10 +3309,10 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3308
3309
|
});
|
|
3309
3310
|
}
|
|
3310
3311
|
if (!blocks.length) {
|
|
3311
|
-
const { from, to } =
|
|
3312
|
+
const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
|
|
3312
3313
|
if (from === to) {
|
|
3313
3314
|
const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
|
|
3314
|
-
dispatch(
|
|
3315
|
+
dispatch(state2.update({
|
|
3315
3316
|
changes: [
|
|
3316
3317
|
{
|
|
3317
3318
|
from,
|
|
@@ -3332,11 +3333,11 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3332
3333
|
for (let i = 0; i < blocks.length; i++) {
|
|
3333
3334
|
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
3334
3335
|
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
3335
|
-
let padding = nodeFrom > 0 && !/\s/.test(
|
|
3336
|
+
let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
3336
3337
|
if (type === 0) {
|
|
3337
3338
|
padding += String(counter2).length;
|
|
3338
3339
|
}
|
|
3339
|
-
let line =
|
|
3340
|
+
let line = state2.doc.lineAt(nodeFrom);
|
|
3340
3341
|
const column = nodeFrom - line.from;
|
|
3341
3342
|
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
3342
3343
|
padding = Math.max(padding, parentColumn2 - column);
|
|
@@ -3361,7 +3362,7 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3361
3362
|
insert: mark2
|
|
3362
3363
|
});
|
|
3363
3364
|
while (line.to < node.to) {
|
|
3364
|
-
line =
|
|
3365
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
3365
3366
|
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3366
3367
|
changes.push({
|
|
3367
3368
|
from: line.from + Math.min(open, column),
|
|
@@ -3376,25 +3377,25 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
3376
3377
|
next = next.nextSibling;
|
|
3377
3378
|
}
|
|
3378
3379
|
if (next?.name === "OrderedList") {
|
|
3379
|
-
renumberListItems(next.firstChild, last.counter + 1, changes,
|
|
3380
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
|
|
3380
3381
|
}
|
|
3381
3382
|
}
|
|
3382
|
-
const changeSet =
|
|
3383
|
-
dispatch(
|
|
3383
|
+
const changeSet = state2.changes(changes);
|
|
3384
|
+
dispatch(state2.update({
|
|
3384
3385
|
changes: changeSet,
|
|
3385
|
-
selection:
|
|
3386
|
+
selection: state2.selection.map(changeSet, 1),
|
|
3386
3387
|
userEvent: "format.list.add",
|
|
3387
3388
|
scrollIntoView: true
|
|
3388
3389
|
}));
|
|
3389
3390
|
return true;
|
|
3390
3391
|
};
|
|
3391
|
-
var removeList = (type) => ({ state, dispatch }) => {
|
|
3392
|
+
var removeList = (type) => ({ state: state2, dispatch }) => {
|
|
3392
3393
|
let lastBlock = -1;
|
|
3393
3394
|
const changes = [];
|
|
3394
3395
|
const stack = [];
|
|
3395
3396
|
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
3396
|
-
for (const { from, to } of
|
|
3397
|
-
syntaxTree2(
|
|
3397
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3398
|
+
syntaxTree2(state2).iterate({
|
|
3398
3399
|
from,
|
|
3399
3400
|
to,
|
|
3400
3401
|
enter: (node) => {
|
|
@@ -3411,7 +3412,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3411
3412
|
stack.pop();
|
|
3412
3413
|
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
3413
3414
|
lastBlock = node.from;
|
|
3414
|
-
let line =
|
|
3415
|
+
let line = state2.doc.lineAt(node.from);
|
|
3415
3416
|
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
3416
3417
|
if (!mark2) {
|
|
3417
3418
|
return false;
|
|
@@ -3422,7 +3423,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3422
3423
|
to: node.from + mark2[0].length
|
|
3423
3424
|
});
|
|
3424
3425
|
while (line.to < node.to) {
|
|
3425
|
-
line =
|
|
3426
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
3426
3427
|
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3427
3428
|
if (open > column) {
|
|
3428
3429
|
changes.push({
|
|
@@ -3432,7 +3433,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3432
3433
|
}
|
|
3433
3434
|
}
|
|
3434
3435
|
if (node.to >= to) {
|
|
3435
|
-
renumberListItems(node.node.nextSibling, 1, changes,
|
|
3436
|
+
renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
|
|
3436
3437
|
}
|
|
3437
3438
|
return false;
|
|
3438
3439
|
}
|
|
@@ -3442,7 +3443,7 @@ var removeList = (type) => ({ state, dispatch }) => {
|
|
|
3442
3443
|
if (!changes.length) {
|
|
3443
3444
|
return false;
|
|
3444
3445
|
}
|
|
3445
|
-
dispatch(
|
|
3446
|
+
dispatch(state2.update({
|
|
3446
3447
|
changes,
|
|
3447
3448
|
userEvent: "format.list.remove",
|
|
3448
3449
|
scrollIntoView: true
|
|
@@ -3472,12 +3473,12 @@ var renumberListItems = (item, counter, changes, doc) => {
|
|
|
3472
3473
|
}
|
|
3473
3474
|
}
|
|
3474
3475
|
};
|
|
3475
|
-
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
3476
|
+
var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
|
|
3476
3477
|
const lines = [];
|
|
3477
3478
|
let lastBlock = -1;
|
|
3478
|
-
for (const { from, to } of
|
|
3479
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3479
3480
|
const sawBlock = false;
|
|
3480
|
-
syntaxTree2(
|
|
3481
|
+
syntaxTree2(state2).iterate({
|
|
3481
3482
|
from,
|
|
3482
3483
|
to,
|
|
3483
3484
|
enter: (node) => {
|
|
@@ -3486,9 +3487,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3486
3487
|
return false;
|
|
3487
3488
|
}
|
|
3488
3489
|
lastBlock = node.from;
|
|
3489
|
-
let line2 =
|
|
3490
|
+
let line2 = state2.doc.lineAt(node.from);
|
|
3490
3491
|
if (line2.number > 1) {
|
|
3491
|
-
const prevLine =
|
|
3492
|
+
const prevLine = state2.doc.line(line2.number - 1);
|
|
3492
3493
|
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
3493
3494
|
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
3494
3495
|
lines.push(prevLine);
|
|
@@ -3500,10 +3501,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3500
3501
|
if (line2.to >= node.to) {
|
|
3501
3502
|
break;
|
|
3502
3503
|
}
|
|
3503
|
-
line2 =
|
|
3504
|
+
line2 = state2.doc.line(line2.number + 1);
|
|
3504
3505
|
}
|
|
3505
|
-
if (!enable && line2.number <
|
|
3506
|
-
const nextLine =
|
|
3506
|
+
if (!enable && line2.number < state2.doc.lines) {
|
|
3507
|
+
const nextLine = state2.doc.line(line2.number + 1);
|
|
3507
3508
|
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
3508
3509
|
lines.push(nextLine);
|
|
3509
3510
|
}
|
|
@@ -3513,7 +3514,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3513
3514
|
}
|
|
3514
3515
|
});
|
|
3515
3516
|
let line;
|
|
3516
|
-
if (!sawBlock && enable && from === to && !/\S/.test((line =
|
|
3517
|
+
if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
|
|
3517
3518
|
lines.push(line);
|
|
3518
3519
|
}
|
|
3519
3520
|
}
|
|
@@ -3537,10 +3538,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
3537
3538
|
if (!changes.length) {
|
|
3538
3539
|
return false;
|
|
3539
3540
|
}
|
|
3540
|
-
const changeSet =
|
|
3541
|
-
dispatch(
|
|
3541
|
+
const changeSet = state2.changes(changes);
|
|
3542
|
+
dispatch(state2.update({
|
|
3542
3543
|
changes: changeSet,
|
|
3543
|
-
selection:
|
|
3544
|
+
selection: state2.selection.map(changeSet, 1),
|
|
3544
3545
|
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
3545
3546
|
scrollIntoView: true
|
|
3546
3547
|
}));
|
|
@@ -3552,11 +3553,11 @@ var toggleBlockquote = (target) => {
|
|
|
3552
3553
|
return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
|
|
3553
3554
|
};
|
|
3554
3555
|
var addCodeblock = (target) => {
|
|
3555
|
-
const { state, dispatch } = target;
|
|
3556
|
-
const { selection } =
|
|
3556
|
+
const { state: state2, dispatch } = target;
|
|
3557
|
+
const { selection } = state2;
|
|
3557
3558
|
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
3558
3559
|
const { head } = selection.main;
|
|
3559
|
-
const line =
|
|
3560
|
+
const line = state2.doc.lineAt(head);
|
|
3560
3561
|
if (!/\S/.test(line.text) && head === line.from) {
|
|
3561
3562
|
snippets.codeblock(target, null, line.from, line.to);
|
|
3562
3563
|
return true;
|
|
@@ -3566,7 +3567,7 @@ var addCodeblock = (target) => {
|
|
|
3566
3567
|
for (const { from, to } of selection.ranges) {
|
|
3567
3568
|
let blockFrom = from;
|
|
3568
3569
|
let blockTo = to;
|
|
3569
|
-
syntaxTree2(
|
|
3570
|
+
syntaxTree2(state2).iterate({
|
|
3570
3571
|
from,
|
|
3571
3572
|
to,
|
|
3572
3573
|
enter: (node) => {
|
|
@@ -3575,8 +3576,8 @@ var addCodeblock = (target) => {
|
|
|
3575
3576
|
blockFrom = node.from;
|
|
3576
3577
|
blockTo = node.to;
|
|
3577
3578
|
} else {
|
|
3578
|
-
blockFrom = Math.min(blockFrom,
|
|
3579
|
-
blockTo = Math.max(blockTo,
|
|
3579
|
+
blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
|
|
3580
|
+
blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
|
|
3580
3581
|
}
|
|
3581
3582
|
}
|
|
3582
3583
|
}
|
|
@@ -3594,7 +3595,7 @@ var addCodeblock = (target) => {
|
|
|
3594
3595
|
return false;
|
|
3595
3596
|
}
|
|
3596
3597
|
const changes = ranges.map(({ from, to }) => {
|
|
3597
|
-
const column = from -
|
|
3598
|
+
const column = from - state2.doc.lineAt(from).from;
|
|
3598
3599
|
return [
|
|
3599
3600
|
{
|
|
3600
3601
|
from,
|
|
@@ -3606,30 +3607,30 @@ var addCodeblock = (target) => {
|
|
|
3606
3607
|
}
|
|
3607
3608
|
];
|
|
3608
3609
|
});
|
|
3609
|
-
dispatch(
|
|
3610
|
+
dispatch(state2.update({
|
|
3610
3611
|
changes,
|
|
3611
3612
|
userEvent: "format.codeblock.add",
|
|
3612
3613
|
scrollIntoView: true
|
|
3613
3614
|
}));
|
|
3614
3615
|
return true;
|
|
3615
3616
|
};
|
|
3616
|
-
var removeCodeblock = ({ state, dispatch }) => {
|
|
3617
|
+
var removeCodeblock = ({ state: state2, dispatch }) => {
|
|
3617
3618
|
const changes = [];
|
|
3618
3619
|
let lastBlock = -1;
|
|
3619
|
-
for (const { from, to } of
|
|
3620
|
-
syntaxTree2(
|
|
3620
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3621
|
+
syntaxTree2(state2).iterate({
|
|
3621
3622
|
from,
|
|
3622
3623
|
to,
|
|
3623
3624
|
enter: (node) => {
|
|
3624
3625
|
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
3625
3626
|
lastBlock = node.from;
|
|
3626
|
-
const firstLine =
|
|
3627
|
+
const firstLine = state2.doc.lineAt(node.from);
|
|
3627
3628
|
if (node.name === "FencedCode") {
|
|
3628
3629
|
changes.push({
|
|
3629
3630
|
from: node.from,
|
|
3630
3631
|
to: firstLine.to + 1 + node.from - firstLine.from
|
|
3631
3632
|
});
|
|
3632
|
-
const lastLine =
|
|
3633
|
+
const lastLine = state2.doc.lineAt(node.to);
|
|
3633
3634
|
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
3634
3635
|
changes.push({
|
|
3635
3636
|
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
@@ -3638,7 +3639,7 @@ var removeCodeblock = ({ state, dispatch }) => {
|
|
|
3638
3639
|
}
|
|
3639
3640
|
} else {
|
|
3640
3641
|
const column = node.from - firstLine.from;
|
|
3641
|
-
for (let line = firstLine; ; line =
|
|
3642
|
+
for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
|
|
3642
3643
|
changes.push({
|
|
3643
3644
|
from: line.from + column - 4,
|
|
3644
3645
|
to: line.from + column
|
|
@@ -3655,7 +3656,7 @@ var removeCodeblock = ({ state, dispatch }) => {
|
|
|
3655
3656
|
if (!changes.length) {
|
|
3656
3657
|
return false;
|
|
3657
3658
|
}
|
|
3658
|
-
dispatch(
|
|
3659
|
+
dispatch(state2.update({
|
|
3659
3660
|
changes,
|
|
3660
3661
|
userEvent: "format.codeblock.remove",
|
|
3661
3662
|
scrollIntoView: true
|
|
@@ -3714,7 +3715,7 @@ var Textblocks = {
|
|
|
3714
3715
|
TableCell: "tablecell",
|
|
3715
3716
|
Task: "paragraph"
|
|
3716
3717
|
};
|
|
3717
|
-
var getFormatting = (
|
|
3718
|
+
var getFormatting = (state2) => {
|
|
3718
3719
|
let blockType = null;
|
|
3719
3720
|
const inline = [
|
|
3720
3721
|
null,
|
|
@@ -3740,7 +3741,7 @@ var getFormatting = (state) => {
|
|
|
3740
3741
|
continue;
|
|
3741
3742
|
} else if (currentBlock.active[i]) {
|
|
3742
3743
|
inline[i] = true;
|
|
3743
|
-
} else if (/\S/.test(
|
|
3744
|
+
} else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
|
|
3744
3745
|
inline[i] = false;
|
|
3745
3746
|
}
|
|
3746
3747
|
}
|
|
@@ -3751,12 +3752,12 @@ var getFormatting = (state) => {
|
|
|
3751
3752
|
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
3752
3753
|
}
|
|
3753
3754
|
};
|
|
3754
|
-
const { selection } =
|
|
3755
|
+
const { selection } = state2;
|
|
3755
3756
|
for (const range of selection.ranges) {
|
|
3756
3757
|
if (range.empty && inline.some((v) => v === null)) {
|
|
3757
3758
|
const contextSize = Math.min(range.head, 6);
|
|
3758
|
-
const contextBefore =
|
|
3759
|
-
let contextAfter =
|
|
3759
|
+
const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
|
|
3760
|
+
let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
|
|
3760
3761
|
for (let i = 0; i < contextSize; i++) {
|
|
3761
3762
|
const ch = contextAfter[i];
|
|
3762
3763
|
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
@@ -3775,7 +3776,7 @@ var getFormatting = (state) => {
|
|
|
3775
3776
|
}
|
|
3776
3777
|
}
|
|
3777
3778
|
}
|
|
3778
|
-
syntaxTree2(
|
|
3779
|
+
syntaxTree2(state2).iterate({
|
|
3779
3780
|
from: range.from,
|
|
3780
3781
|
to: range.to,
|
|
3781
3782
|
enter: (node) => {
|
|
@@ -3849,7 +3850,7 @@ var getFormatting = (state) => {
|
|
|
3849
3850
|
}
|
|
3850
3851
|
});
|
|
3851
3852
|
}
|
|
3852
|
-
const { from, to } =
|
|
3853
|
+
const { from, to } = state2.doc.lineAt(selection.main.anchor);
|
|
3853
3854
|
const blankLine = from === to;
|
|
3854
3855
|
return {
|
|
3855
3856
|
blankLine,
|
|
@@ -3864,17 +3865,22 @@ var getFormatting = (state) => {
|
|
|
3864
3865
|
};
|
|
3865
3866
|
};
|
|
3866
3867
|
var useFormattingState = () => {
|
|
3867
|
-
const [
|
|
3868
|
+
const [state2, setState] = useState();
|
|
3868
3869
|
const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
|
|
3869
3870
|
if (update2.docChanged || update2.selectionSet) {
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3871
|
+
setState((prevState) => {
|
|
3872
|
+
const newState = getFormatting(update2.state);
|
|
3873
|
+
if (!prevState || !formattingEquals(prevState, newState)) {
|
|
3874
|
+
return newState;
|
|
3875
|
+
}
|
|
3876
|
+
return prevState;
|
|
3877
|
+
});
|
|
3874
3878
|
}
|
|
3875
|
-
}), [
|
|
3879
|
+
}), [
|
|
3880
|
+
setState
|
|
3881
|
+
]);
|
|
3876
3882
|
return [
|
|
3877
|
-
|
|
3883
|
+
state2,
|
|
3878
3884
|
observer
|
|
3879
3885
|
];
|
|
3880
3886
|
};
|
|
@@ -3885,8 +3891,8 @@ import { StateField as StateField5 } from "@codemirror/state";
|
|
|
3885
3891
|
import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3886
3892
|
var image = (options = {}) => {
|
|
3887
3893
|
return StateField5.define({
|
|
3888
|
-
create: (
|
|
3889
|
-
return Decoration6.set(buildDecorations2(0,
|
|
3894
|
+
create: (state2) => {
|
|
3895
|
+
return Decoration6.set(buildDecorations2(0, state2.doc.length, state2));
|
|
3890
3896
|
},
|
|
3891
3897
|
update: (value, tr) => {
|
|
3892
3898
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -3920,16 +3926,16 @@ var preloadImage = (url) => {
|
|
|
3920
3926
|
preloaded.add(url);
|
|
3921
3927
|
}
|
|
3922
3928
|
};
|
|
3923
|
-
var buildDecorations2 = (from, to,
|
|
3929
|
+
var buildDecorations2 = (from, to, state2) => {
|
|
3924
3930
|
const decorations = [];
|
|
3925
|
-
const cursor =
|
|
3926
|
-
syntaxTree3(
|
|
3931
|
+
const cursor = state2.selection.main.head;
|
|
3932
|
+
syntaxTree3(state2).iterate({
|
|
3927
3933
|
enter: (node) => {
|
|
3928
3934
|
if (node.name === "Image") {
|
|
3929
3935
|
const urlNode = node.node.getChild("URL");
|
|
3930
3936
|
if (urlNode) {
|
|
3931
|
-
const hide2 =
|
|
3932
|
-
const url =
|
|
3937
|
+
const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
|
|
3938
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
3933
3939
|
preloadImage(url);
|
|
3934
3940
|
decorations.push(Decoration6.replace({
|
|
3935
3941
|
block: true,
|
|
@@ -3959,6 +3965,8 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
3959
3965
|
return img;
|
|
3960
3966
|
}
|
|
3961
3967
|
};
|
|
3968
|
+
var imageUpload = (options = {}) => {
|
|
3969
|
+
};
|
|
3962
3970
|
|
|
3963
3971
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
3964
3972
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
@@ -4000,21 +4008,21 @@ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "
|
|
|
4000
4008
|
import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4001
4009
|
var table = (options = {}) => {
|
|
4002
4010
|
return StateField6.define({
|
|
4003
|
-
create: (
|
|
4011
|
+
create: (state2) => update(state2, options),
|
|
4004
4012
|
update: (_, tr) => update(tr.state, options),
|
|
4005
4013
|
provide: (field) => EditorView15.decorations.from(field)
|
|
4006
4014
|
});
|
|
4007
4015
|
};
|
|
4008
|
-
var update = (
|
|
4016
|
+
var update = (state2, options) => {
|
|
4009
4017
|
const builder = new RangeSetBuilder3();
|
|
4010
|
-
const cursor =
|
|
4018
|
+
const cursor = state2.selection.main.head;
|
|
4011
4019
|
const tables = [];
|
|
4012
4020
|
const getTable = () => tables[tables.length - 1];
|
|
4013
4021
|
const getRow = () => {
|
|
4014
4022
|
const table2 = getTable();
|
|
4015
4023
|
return table2.rows?.[table2.rows.length - 1];
|
|
4016
4024
|
};
|
|
4017
|
-
syntaxTree5(
|
|
4025
|
+
syntaxTree5(state2).iterate({
|
|
4018
4026
|
enter: (node) => {
|
|
4019
4027
|
switch (node.name) {
|
|
4020
4028
|
case "Table": {
|
|
@@ -4035,9 +4043,9 @@ var update = (state, options) => {
|
|
|
4035
4043
|
case "TableCell": {
|
|
4036
4044
|
const row = getRow();
|
|
4037
4045
|
if (row) {
|
|
4038
|
-
row.push(
|
|
4046
|
+
row.push(state2.sliceDoc(node.from, node.to));
|
|
4039
4047
|
} else {
|
|
4040
|
-
getTable().header?.push(
|
|
4048
|
+
getTable().header?.push(state2.sliceDoc(node.from, node.to));
|
|
4041
4049
|
}
|
|
4042
4050
|
break;
|
|
4043
4051
|
}
|
|
@@ -4045,7 +4053,7 @@ var update = (state, options) => {
|
|
|
4045
4053
|
}
|
|
4046
4054
|
});
|
|
4047
4055
|
tables.forEach((table2) => {
|
|
4048
|
-
const hide2 =
|
|
4056
|
+
const hide2 = state2.readOnly || cursor < table2.from || cursor > table2.to;
|
|
4049
4057
|
if (hide2) {
|
|
4050
4058
|
builder.add(table2.from, table2.to, Decoration7.replace({
|
|
4051
4059
|
widget: new TableWidget(table2)
|
|
@@ -4136,6 +4144,7 @@ var mention = ({ onSearch }) => {
|
|
|
4136
4144
|
import { Facet as Facet6 } from "@codemirror/state";
|
|
4137
4145
|
import { keymap as keymap7 } from "@codemirror/view";
|
|
4138
4146
|
import { vim } from "@replit/codemirror-vim";
|
|
4147
|
+
var focusEvent = "focus.container";
|
|
4139
4148
|
var editorMode = Facet6.define({
|
|
4140
4149
|
combine: (modes) => modes[0] ?? {}
|
|
4141
4150
|
});
|
|
@@ -4152,7 +4161,7 @@ var EditorModes = {
|
|
|
4152
4161
|
key: "Alt-Escape",
|
|
4153
4162
|
run: (view) => {
|
|
4154
4163
|
view.dispatch({
|
|
4155
|
-
userEvent:
|
|
4164
|
+
userEvent: focusEvent
|
|
4156
4165
|
});
|
|
4157
4166
|
return true;
|
|
4158
4167
|
}
|
|
@@ -4161,8 +4170,95 @@ var EditorModes = {
|
|
|
4161
4170
|
]
|
|
4162
4171
|
};
|
|
4163
4172
|
|
|
4173
|
+
// packages/ui/react-ui-editor/src/extensions/state.ts
|
|
4174
|
+
import { Transaction as Transaction2 } from "@codemirror/state";
|
|
4175
|
+
import { EditorView as EditorView16, keymap as keymap8 } from "@codemirror/view";
|
|
4176
|
+
import { debounce as debounce2 } from "@dxos/async";
|
|
4177
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
4178
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
4179
|
+
var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
|
|
4180
|
+
var scrollAnnotation = "dxos.org/cm/scrolling";
|
|
4181
|
+
var keyPrefix = "dxos.org/react-ui-editor/state";
|
|
4182
|
+
var localStorageStateStoreAdapter = {
|
|
4183
|
+
setState: (id, state2) => {
|
|
4184
|
+
invariant4(id, void 0, {
|
|
4185
|
+
F: __dxlog_file11,
|
|
4186
|
+
L: 35,
|
|
4187
|
+
S: void 0,
|
|
4188
|
+
A: [
|
|
4189
|
+
"id",
|
|
4190
|
+
""
|
|
4191
|
+
]
|
|
4192
|
+
});
|
|
4193
|
+
localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state2));
|
|
4194
|
+
},
|
|
4195
|
+
getState: (id) => {
|
|
4196
|
+
invariant4(id, void 0, {
|
|
4197
|
+
F: __dxlog_file11,
|
|
4198
|
+
L: 39,
|
|
4199
|
+
S: void 0,
|
|
4200
|
+
A: [
|
|
4201
|
+
"id",
|
|
4202
|
+
""
|
|
4203
|
+
]
|
|
4204
|
+
});
|
|
4205
|
+
const state2 = localStorage.getItem(`${keyPrefix}/${id}`);
|
|
4206
|
+
return state2 ? JSON.parse(state2) : void 0;
|
|
4207
|
+
}
|
|
4208
|
+
};
|
|
4209
|
+
var state = ({ getState, setState } = {}) => {
|
|
4210
|
+
const setStateDebounced = debounce2(setState, 1e3);
|
|
4211
|
+
return [
|
|
4212
|
+
// TODO(burdon): Track scrolling (currently only updates when cursor moves).
|
|
4213
|
+
EditorView16.updateListener.of(({ view, changes, transactions }) => {
|
|
4214
|
+
const id = view.state.facet(documentId2);
|
|
4215
|
+
if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
if (setState) {
|
|
4219
|
+
const { top } = view.dom.getBoundingClientRect();
|
|
4220
|
+
const pos = view.posAtCoords({
|
|
4221
|
+
x: 0,
|
|
4222
|
+
y: top
|
|
4223
|
+
});
|
|
4224
|
+
if (pos !== null) {
|
|
4225
|
+
const { anchor, head } = view.state.selection.main;
|
|
4226
|
+
setStateDebounced(id, {
|
|
4227
|
+
scrollTo: {
|
|
4228
|
+
from: pos,
|
|
4229
|
+
yMargin: 0
|
|
4230
|
+
},
|
|
4231
|
+
selection: {
|
|
4232
|
+
anchor,
|
|
4233
|
+
head
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
}),
|
|
4239
|
+
getState && keymap8.of([
|
|
4240
|
+
{
|
|
4241
|
+
key: "ctrl-r",
|
|
4242
|
+
run: (view) => {
|
|
4243
|
+
const state2 = getState(view.state.facet(documentId2));
|
|
4244
|
+
if (state2) {
|
|
4245
|
+
view.dispatch({
|
|
4246
|
+
effects: EditorView16.scrollIntoView(state2.scrollTo.from, {
|
|
4247
|
+
yMargin: 0
|
|
4248
|
+
}),
|
|
4249
|
+
selection: state2.selection,
|
|
4250
|
+
annotations: Transaction2.userEvent.of(scrollAnnotation)
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
return true;
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
])
|
|
4257
|
+
].filter(isNotFalsy3);
|
|
4258
|
+
};
|
|
4259
|
+
|
|
4164
4260
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
4165
|
-
import { keymap as
|
|
4261
|
+
import { keymap as keymap9 } from "@codemirror/view";
|
|
4166
4262
|
var defaultItems = [
|
|
4167
4263
|
"hello world!",
|
|
4168
4264
|
"this is a test.",
|
|
@@ -4172,7 +4268,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4172
4268
|
let t;
|
|
4173
4269
|
let idx = 0;
|
|
4174
4270
|
return [
|
|
4175
|
-
|
|
4271
|
+
keymap9.of([
|
|
4176
4272
|
{
|
|
4177
4273
|
// Reset.
|
|
4178
4274
|
key: "alt-meta-'",
|
|
@@ -4219,9 +4315,11 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4219
4315
|
};
|
|
4220
4316
|
|
|
4221
4317
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
4222
|
-
var
|
|
4318
|
+
var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
4223
4319
|
var instanceCount = 0;
|
|
4224
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo =
|
|
4320
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView17.scrollIntoView(0, {
|
|
4321
|
+
yMargin: 0
|
|
4322
|
+
}), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
|
|
4225
4323
|
const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
|
|
4226
4324
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
4227
4325
|
tabBehavior: "limited"
|
|
@@ -4240,42 +4338,42 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4240
4338
|
autoFocus
|
|
4241
4339
|
]);
|
|
4242
4340
|
useEffect2(() => {
|
|
4243
|
-
log9("
|
|
4341
|
+
log9("create", {
|
|
4244
4342
|
id,
|
|
4245
4343
|
instanceId
|
|
4246
4344
|
}, {
|
|
4247
|
-
F:
|
|
4345
|
+
F: __dxlog_file12,
|
|
4248
4346
|
L: 88,
|
|
4249
4347
|
S: void 0,
|
|
4250
4348
|
C: (f, a) => f(...a)
|
|
4251
4349
|
});
|
|
4252
|
-
const
|
|
4350
|
+
const state2 = EditorState2.create({
|
|
4253
4351
|
doc,
|
|
4254
4352
|
selection,
|
|
4255
4353
|
extensions: [
|
|
4256
4354
|
id && documentId2.of(id),
|
|
4257
4355
|
// TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
|
|
4258
|
-
|
|
4356
|
+
EditorView17.exceptionSink.of((err) => {
|
|
4259
4357
|
log9.catch(err, void 0, {
|
|
4260
|
-
F:
|
|
4358
|
+
F: __dxlog_file12,
|
|
4261
4359
|
L: 101,
|
|
4262
4360
|
S: void 0,
|
|
4263
4361
|
C: (f, a) => f(...a)
|
|
4264
4362
|
});
|
|
4265
4363
|
}),
|
|
4266
4364
|
// Focus.
|
|
4267
|
-
|
|
4365
|
+
EditorView17.updateListener.of((update2) => {
|
|
4268
4366
|
update2.transactions.forEach((transaction) => {
|
|
4269
|
-
if (transaction.isUserEvent(
|
|
4367
|
+
if (transaction.isUserEvent(focusEvent)) {
|
|
4270
4368
|
rootRef.current?.focus();
|
|
4271
4369
|
}
|
|
4272
4370
|
});
|
|
4273
4371
|
}),
|
|
4274
4372
|
extensions
|
|
4275
|
-
].filter(
|
|
4373
|
+
].filter(isNotFalsy4)
|
|
4276
4374
|
});
|
|
4277
|
-
const view2 = new
|
|
4278
|
-
state,
|
|
4375
|
+
const view2 = new EditorView17({
|
|
4376
|
+
state: state2,
|
|
4279
4377
|
parent: rootRef.current,
|
|
4280
4378
|
scrollTo,
|
|
4281
4379
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
@@ -4287,21 +4385,29 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4287
4385
|
view3.update(trs);
|
|
4288
4386
|
}
|
|
4289
4387
|
});
|
|
4290
|
-
|
|
4291
|
-
if (moveToEndOfLine) {
|
|
4388
|
+
if (moveToEndOfLine && !(scrollTo || selection)) {
|
|
4292
4389
|
const { to } = view2.state.doc.lineAt(0);
|
|
4293
|
-
view2
|
|
4390
|
+
view2.dispatch({
|
|
4294
4391
|
selection: {
|
|
4295
4392
|
anchor: to
|
|
4296
4393
|
}
|
|
4297
4394
|
});
|
|
4298
4395
|
}
|
|
4299
|
-
if (
|
|
4396
|
+
if (state2.facet(editorMode).noTabster) {
|
|
4300
4397
|
rootRef.current?.removeAttribute("data-tabster");
|
|
4301
4398
|
}
|
|
4399
|
+
setView(view2);
|
|
4302
4400
|
return () => {
|
|
4401
|
+
log9("destroy", {
|
|
4402
|
+
id,
|
|
4403
|
+
instanceId
|
|
4404
|
+
}, {
|
|
4405
|
+
F: __dxlog_file12,
|
|
4406
|
+
L: 150,
|
|
4407
|
+
S: void 0,
|
|
4408
|
+
C: (f, a) => f(...a)
|
|
4409
|
+
});
|
|
4303
4410
|
view2?.destroy();
|
|
4304
|
-
setView(null);
|
|
4305
4411
|
};
|
|
4306
4412
|
}, [
|
|
4307
4413
|
doc,
|
|
@@ -4331,9 +4437,10 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4331
4437
|
});
|
|
4332
4438
|
|
|
4333
4439
|
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
4334
|
-
import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic
|
|
4440
|
+
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";
|
|
4335
4441
|
import { createContext } from "@radix-ui/react-context";
|
|
4336
|
-
import React2, { useRef as useRef2, useState as useState3 } from "react";
|
|
4442
|
+
import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
4443
|
+
import { useDropzone } from "react-dropzone";
|
|
4337
4444
|
import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
|
|
4338
4445
|
import { getSize } from "@dxos/react-ui-theme";
|
|
4339
4446
|
var tooltipProps = {
|
|
@@ -4350,10 +4457,10 @@ var HeadingIcons = {
|
|
|
4350
4457
|
"6": TextHSix
|
|
4351
4458
|
};
|
|
4352
4459
|
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
4353
|
-
var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
4460
|
+
var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
|
|
4354
4461
|
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
4355
4462
|
onAction,
|
|
4356
|
-
state
|
|
4463
|
+
state: state2
|
|
4357
4464
|
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
4358
4465
|
density: "fine"
|
|
4359
4466
|
}, /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
@@ -4367,7 +4474,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
|
4367
4474
|
};
|
|
4368
4475
|
var buttonStyles = "min-bs-0 p-2";
|
|
4369
4476
|
var iconStyles = getSize(5);
|
|
4370
|
-
var
|
|
4477
|
+
var ToolbarToggleButton = ({ Icon, children, ...props }) => {
|
|
4371
4478
|
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4372
4479
|
asChild: true
|
|
4373
4480
|
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
|
|
@@ -4380,14 +4487,27 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
|
4380
4487
|
className: "sr-only"
|
|
4381
4488
|
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4382
4489
|
};
|
|
4490
|
+
var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
4491
|
+
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4492
|
+
asChild: true
|
|
4493
|
+
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
|
|
4494
|
+
variant: "ghost",
|
|
4495
|
+
...props,
|
|
4496
|
+
classNames: buttonStyles
|
|
4497
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
4498
|
+
className: iconStyles
|
|
4499
|
+
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4500
|
+
className: "sr-only"
|
|
4501
|
+
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4502
|
+
};
|
|
4383
4503
|
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4384
4504
|
role: "separator",
|
|
4385
4505
|
className: "grow"
|
|
4386
4506
|
});
|
|
4387
4507
|
var MarkdownHeading = () => {
|
|
4388
4508
|
const { t } = useTranslation(translationKey);
|
|
4389
|
-
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
4390
|
-
const blockType =
|
|
4509
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
|
|
4510
|
+
const blockType = state2 ? state2.blockType : "paragraph";
|
|
4391
4511
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
4392
4512
|
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
|
|
4393
4513
|
const HeadingIcon = HeadingIcons[value ?? "0"];
|
|
@@ -4461,43 +4581,43 @@ var markdownStyles = [
|
|
|
4461
4581
|
{
|
|
4462
4582
|
type: "strong",
|
|
4463
4583
|
Icon: TextB,
|
|
4464
|
-
getState: (
|
|
4584
|
+
getState: (state2) => state2.strong
|
|
4465
4585
|
},
|
|
4466
4586
|
{
|
|
4467
4587
|
type: "emphasis",
|
|
4468
4588
|
Icon: TextItalic,
|
|
4469
|
-
getState: (
|
|
4589
|
+
getState: (state2) => state2.emphasis
|
|
4470
4590
|
},
|
|
4471
4591
|
{
|
|
4472
4592
|
type: "strikethrough",
|
|
4473
4593
|
Icon: TextStrikethrough,
|
|
4474
|
-
getState: (
|
|
4594
|
+
getState: (state2) => state2.strikethrough
|
|
4475
4595
|
},
|
|
4476
4596
|
{
|
|
4477
4597
|
type: "code",
|
|
4478
4598
|
Icon: Code,
|
|
4479
|
-
getState: (
|
|
4599
|
+
getState: (state2) => state2.code
|
|
4480
4600
|
},
|
|
4481
4601
|
{
|
|
4482
4602
|
type: "link",
|
|
4483
4603
|
Icon: Link,
|
|
4484
|
-
getState: (
|
|
4604
|
+
getState: (state2) => state2.link
|
|
4485
4605
|
}
|
|
4486
4606
|
];
|
|
4487
4607
|
var MarkdownStyles = () => {
|
|
4488
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4608
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4489
4609
|
const { t } = useTranslation(translationKey);
|
|
4490
4610
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4491
4611
|
type: "multiple",
|
|
4492
|
-
value: markdownStyles.filter(({ getState }) =>
|
|
4493
|
-
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4612
|
+
value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
|
|
4613
|
+
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4494
4614
|
key: type,
|
|
4495
4615
|
value: type,
|
|
4496
4616
|
Icon,
|
|
4497
|
-
disabled:
|
|
4498
|
-
onClick:
|
|
4617
|
+
disabled: state2?.blockType === "codeblock",
|
|
4618
|
+
onClick: state2 ? () => onAction?.({
|
|
4499
4619
|
type,
|
|
4500
|
-
data: !getState(
|
|
4620
|
+
data: !getState(state2)
|
|
4501
4621
|
}) : void 0
|
|
4502
4622
|
}, t(`${type} label`))));
|
|
4503
4623
|
};
|
|
@@ -4505,32 +4625,32 @@ var markdownLists = [
|
|
|
4505
4625
|
{
|
|
4506
4626
|
type: "list-bullet",
|
|
4507
4627
|
Icon: ListBullets,
|
|
4508
|
-
getState: (
|
|
4628
|
+
getState: (state2) => state2.listStyle === "bullet"
|
|
4509
4629
|
},
|
|
4510
4630
|
{
|
|
4511
4631
|
type: "list-ordered",
|
|
4512
4632
|
Icon: ListNumbers,
|
|
4513
|
-
getState: (
|
|
4633
|
+
getState: (state2) => state2.listStyle === "ordered"
|
|
4514
4634
|
},
|
|
4515
4635
|
{
|
|
4516
4636
|
type: "list-task",
|
|
4517
4637
|
Icon: ListChecks,
|
|
4518
|
-
getState: (
|
|
4638
|
+
getState: (state2) => state2.listStyle === "task"
|
|
4519
4639
|
}
|
|
4520
4640
|
];
|
|
4521
4641
|
var MarkdownLists = () => {
|
|
4522
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4642
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4523
4643
|
const { t } = useTranslation(translationKey);
|
|
4524
4644
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4525
4645
|
type: "single",
|
|
4526
|
-
value:
|
|
4527
|
-
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4646
|
+
value: state2?.listStyle ? `list-${state2.listStyle}` : ""
|
|
4647
|
+
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4528
4648
|
key: type,
|
|
4529
4649
|
value: type,
|
|
4530
4650
|
Icon,
|
|
4531
|
-
onClick:
|
|
4651
|
+
onClick: state2 ? () => onAction?.({
|
|
4532
4652
|
type,
|
|
4533
|
-
data: !getState(
|
|
4653
|
+
data: !getState(state2)
|
|
4534
4654
|
}) : void 0
|
|
4535
4655
|
}, t(`${type} label`))));
|
|
4536
4656
|
};
|
|
@@ -4538,63 +4658,101 @@ var markdownBlocks = [
|
|
|
4538
4658
|
{
|
|
4539
4659
|
type: "blockquote",
|
|
4540
4660
|
Icon: Quotes,
|
|
4541
|
-
getState: (
|
|
4661
|
+
getState: (state2) => state2.blockQuote
|
|
4542
4662
|
},
|
|
4543
4663
|
{
|
|
4544
4664
|
type: "codeblock",
|
|
4545
4665
|
Icon: CodeBlock,
|
|
4546
|
-
getState: (
|
|
4666
|
+
getState: (state2) => state2.blockType === "codeblock"
|
|
4547
4667
|
},
|
|
4548
4668
|
{
|
|
4549
4669
|
type: "table",
|
|
4550
4670
|
Icon: Table2,
|
|
4551
|
-
getState: (
|
|
4552
|
-
disabled: (
|
|
4671
|
+
getState: (state2) => state2.blockType === "tablecell",
|
|
4672
|
+
disabled: (state2) => !state2.blankLine
|
|
4553
4673
|
}
|
|
4554
4674
|
];
|
|
4555
4675
|
var MarkdownBlocks = () => {
|
|
4556
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4676
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4557
4677
|
const { t } = useTranslation(translationKey);
|
|
4558
|
-
const value = markdownBlocks.find(({ getState }) =>
|
|
4678
|
+
const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
|
|
4559
4679
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4560
4680
|
type: "single",
|
|
4561
4681
|
value: value?.type ?? ""
|
|
4562
|
-
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4682
|
+
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4563
4683
|
key: type,
|
|
4564
4684
|
value: type,
|
|
4565
4685
|
Icon,
|
|
4566
|
-
disabled: !
|
|
4567
|
-
onClick:
|
|
4686
|
+
disabled: !state2 || disabled?.(state2),
|
|
4687
|
+
onClick: state2 ? () => onAction?.({
|
|
4568
4688
|
type,
|
|
4569
|
-
data: !getState(
|
|
4689
|
+
data: !getState(state2)
|
|
4570
4690
|
}) : void 0
|
|
4571
4691
|
}, t(`${type} label`))));
|
|
4572
4692
|
};
|
|
4573
4693
|
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));
|
|
4574
|
-
var
|
|
4694
|
+
var MarkdownCustom = ({ onUpload } = {}) => {
|
|
4575
4695
|
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4576
4696
|
const { t } = useTranslation(translationKey);
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4697
|
+
const { acceptedFiles, getInputProps, open } = useDropzone({
|
|
4698
|
+
multiple: false,
|
|
4699
|
+
noDrag: true,
|
|
4700
|
+
accept: {
|
|
4701
|
+
"image/*": [
|
|
4702
|
+
".jpg",
|
|
4703
|
+
".jpeg",
|
|
4704
|
+
".png",
|
|
4705
|
+
".gif"
|
|
4706
|
+
]
|
|
4707
|
+
}
|
|
4708
|
+
});
|
|
4709
|
+
useEffect3(() => {
|
|
4710
|
+
if (onUpload && acceptedFiles.length) {
|
|
4711
|
+
setTimeout(async () => {
|
|
4712
|
+
const f = acceptedFiles[0];
|
|
4713
|
+
const file = new File([
|
|
4714
|
+
f
|
|
4715
|
+
], f.name, {
|
|
4716
|
+
type: f.type,
|
|
4717
|
+
lastModified: f.lastModified
|
|
4718
|
+
});
|
|
4719
|
+
const { url } = await onUpload(file);
|
|
4720
|
+
if (url) {
|
|
4721
|
+
onAction?.({
|
|
4722
|
+
type: "image",
|
|
4723
|
+
data: url
|
|
4724
|
+
});
|
|
4725
|
+
}
|
|
4726
|
+
});
|
|
4727
|
+
}
|
|
4728
|
+
}, [
|
|
4729
|
+
acceptedFiles
|
|
4730
|
+
]);
|
|
4731
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("input", getInputProps()), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4732
|
+
value: "image",
|
|
4733
|
+
Icon: Image,
|
|
4734
|
+
onClick: () => open()
|
|
4735
|
+
}, t("image label")));
|
|
4736
|
+
};
|
|
4737
|
+
var MarkdownActions = () => {
|
|
4738
|
+
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4739
|
+
const { t } = useTranslation(translationKey);
|
|
4740
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4741
|
+
value: "comment",
|
|
4742
|
+
Icon: ChatText,
|
|
4581
4743
|
"data-testid": "editor.toolbar.comment",
|
|
4582
4744
|
onClick: () => onAction?.({
|
|
4583
4745
|
type: "comment"
|
|
4584
|
-
})
|
|
4585
|
-
|
|
4586
|
-
}, /* @__PURE__ */ React2.createElement(ChatText, {
|
|
4587
|
-
className: iconStyles
|
|
4588
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4589
|
-
className: "sr-only"
|
|
4590
|
-
}, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4746
|
+
})
|
|
4747
|
+
}, t("comment label")));
|
|
4591
4748
|
};
|
|
4592
4749
|
var Toolbar = {
|
|
4593
4750
|
Root: ToolbarRoot,
|
|
4594
|
-
Button:
|
|
4751
|
+
Button: ToolbarToggleButton,
|
|
4595
4752
|
Separator: ToolbarSeparator,
|
|
4596
4753
|
Markdown: MarkdownStandard,
|
|
4597
|
-
|
|
4754
|
+
Custom: MarkdownCustom,
|
|
4755
|
+
Actions: MarkdownActions
|
|
4598
4756
|
};
|
|
4599
4757
|
|
|
4600
4758
|
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
@@ -4631,7 +4789,13 @@ var useActionHandler = (view) => {
|
|
|
4631
4789
|
insertTable(view);
|
|
4632
4790
|
break;
|
|
4633
4791
|
case "link":
|
|
4634
|
-
(action.data === false ? removeLink : addLink)(view);
|
|
4792
|
+
(action.data === false ? removeLink : addLink())(view);
|
|
4793
|
+
break;
|
|
4794
|
+
case "image":
|
|
4795
|
+
addLink({
|
|
4796
|
+
url: action.data,
|
|
4797
|
+
image: true
|
|
4798
|
+
})(view);
|
|
4635
4799
|
break;
|
|
4636
4800
|
case "comment":
|
|
4637
4801
|
createComment(view);
|
|
@@ -4660,43 +4824,51 @@ var useDocAccessor = (text) => {
|
|
|
4660
4824
|
|
|
4661
4825
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4662
4826
|
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4663
|
-
import { EditorView as
|
|
4664
|
-
import { useEffect as
|
|
4827
|
+
import { EditorView as EditorView18 } from "@codemirror/view";
|
|
4828
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
|
|
4665
4829
|
import { log as log10 } from "@dxos/log";
|
|
4666
|
-
import { isNotFalsy as
|
|
4667
|
-
var
|
|
4830
|
+
import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
|
|
4831
|
+
var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4668
4832
|
var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
4669
4833
|
let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
|
|
4670
4834
|
const onUpdate = useRef3();
|
|
4671
4835
|
const [view, setView] = useState4();
|
|
4672
4836
|
const parentRef = useRef3(null);
|
|
4673
|
-
|
|
4837
|
+
useEffect4(() => {
|
|
4674
4838
|
let view2;
|
|
4675
4839
|
if (parentRef.current) {
|
|
4676
|
-
|
|
4840
|
+
log10("create", {
|
|
4841
|
+
id
|
|
4842
|
+
}, {
|
|
4843
|
+
F: __dxlog_file13,
|
|
4844
|
+
L: 36,
|
|
4845
|
+
S: void 0,
|
|
4846
|
+
C: (f, a) => f(...a)
|
|
4847
|
+
});
|
|
4848
|
+
const state2 = EditorState3.create({
|
|
4677
4849
|
doc,
|
|
4678
4850
|
selection,
|
|
4679
4851
|
extensions: [
|
|
4680
4852
|
id && documentId2.of(id),
|
|
4681
4853
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4682
|
-
|
|
4854
|
+
EditorView18.exceptionSink.of((err) => {
|
|
4683
4855
|
log10.catch(err, void 0, {
|
|
4684
|
-
F:
|
|
4685
|
-
L:
|
|
4856
|
+
F: __dxlog_file13,
|
|
4857
|
+
L: 46,
|
|
4686
4858
|
S: void 0,
|
|
4687
4859
|
C: (f, a) => f(...a)
|
|
4688
4860
|
});
|
|
4689
4861
|
}),
|
|
4690
4862
|
extensions,
|
|
4691
|
-
|
|
4863
|
+
EditorView18.updateListener.of(() => {
|
|
4692
4864
|
onUpdate.current?.();
|
|
4693
4865
|
})
|
|
4694
|
-
].filter(
|
|
4866
|
+
].filter(isNotFalsy5)
|
|
4695
4867
|
});
|
|
4696
|
-
view2 = new
|
|
4868
|
+
view2 = new EditorView18({
|
|
4697
4869
|
parent: parentRef.current,
|
|
4698
4870
|
scrollTo,
|
|
4699
|
-
state,
|
|
4871
|
+
state: state2,
|
|
4700
4872
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4701
4873
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4702
4874
|
dispatchTransactions: (trs, view3) => {
|
|
@@ -4709,10 +4881,18 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4709
4881
|
setView(view2);
|
|
4710
4882
|
}
|
|
4711
4883
|
return () => {
|
|
4884
|
+
log10("destroy", {
|
|
4885
|
+
id
|
|
4886
|
+
}, {
|
|
4887
|
+
F: __dxlog_file13,
|
|
4888
|
+
L: 74,
|
|
4889
|
+
S: void 0,
|
|
4890
|
+
C: (f, a) => f(...a)
|
|
4891
|
+
});
|
|
4712
4892
|
view2?.destroy();
|
|
4713
4893
|
};
|
|
4714
4894
|
}, deps);
|
|
4715
|
-
|
|
4895
|
+
useEffect4(() => {
|
|
4716
4896
|
if (view) {
|
|
4717
4897
|
if (!selection && !view.state.selection.main.anchor) {
|
|
4718
4898
|
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
@@ -4771,7 +4951,6 @@ export {
|
|
|
4771
4951
|
callbackWrapper,
|
|
4772
4952
|
command,
|
|
4773
4953
|
comments,
|
|
4774
|
-
compareFormatting,
|
|
4775
4954
|
createBasicExtensions,
|
|
4776
4955
|
createComment,
|
|
4777
4956
|
createDataExtensions,
|
|
@@ -4788,14 +4967,18 @@ export {
|
|
|
4788
4967
|
editorMode,
|
|
4789
4968
|
editorWithToolbarLayout,
|
|
4790
4969
|
focusComment,
|
|
4970
|
+
focusEvent,
|
|
4971
|
+
formattingEquals,
|
|
4791
4972
|
formattingKeymap,
|
|
4792
4973
|
getFormatting,
|
|
4793
4974
|
getToken,
|
|
4794
4975
|
image,
|
|
4976
|
+
imageUpload,
|
|
4795
4977
|
insertTable,
|
|
4796
|
-
|
|
4978
|
+
keymap10 as keymap,
|
|
4797
4979
|
linkTooltip,
|
|
4798
4980
|
listener,
|
|
4981
|
+
localStorageStateStoreAdapter,
|
|
4799
4982
|
logChanges,
|
|
4800
4983
|
markdownHighlightStyle,
|
|
4801
4984
|
markdownTags,
|
|
@@ -4811,6 +4994,7 @@ export {
|
|
|
4811
4994
|
setHeading,
|
|
4812
4995
|
setSelection,
|
|
4813
4996
|
setStyle,
|
|
4997
|
+
state,
|
|
4814
4998
|
table,
|
|
4815
4999
|
tags2 as tags,
|
|
4816
5000
|
toggleBlockquote,
|