@dxos/react-ui-editor 0.4.8-main.6d7437e → 0.4.8-main.6dbc1f1
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 +1927 -1747
- 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 +12 -11
- 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/dnd.d.ts +7 -1
- package/dist/types/src/extensions/dnd.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts +5 -1
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/action.d.ts +9 -0
- package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/bundle.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/markdown/index.d.ts +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/modes.d.ts +2 -1
- 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 +2 -2
- 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/themes/default.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 +26 -27
- package/src/components/TextEditor/TextEditor.stories.tsx +30 -6
- package/src/components/TextEditor/TextEditor.tsx +13 -12
- package/src/components/Toolbar/Toolbar.stories.tsx +23 -24
- package/src/components/Toolbar/Toolbar.tsx +102 -60
- package/src/extensions/automerge/automerge.ts +4 -4
- package/src/extensions/command/state.ts +2 -2
- package/src/extensions/comments.ts +2 -2
- package/src/extensions/dnd.ts +31 -9
- package/src/extensions/factories.ts +41 -18
- package/src/extensions/index.ts +1 -1
- package/src/extensions/markdown/action.ts +112 -0
- package/src/extensions/markdown/bundle.ts +8 -11
- package/src/extensions/markdown/decorate.ts +1 -1
- 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/markdown/index.ts +1 -0
- package/src/extensions/modes.ts +11 -2
- package/src/extensions/state.ts +90 -0
- package/src/hooks/useActionHandler.ts +4 -85
- package/src/hooks/useDocAccessor.ts +8 -2
- package/src/hooks/useTextEditor.stories.tsx +3 -3
- package/src/hooks/useTextEditor.ts +3 -0
- package/src/themes/default.ts +24 -8
- package/src/translations.ts +1 -0
- package/dist/types/src/extensions/cursor-line-margin.d.ts +0 -7
- package/dist/types/src/extensions/cursor-line-margin.d.ts.map +0 -1
- package/src/extensions/cursor-line-margin.ts +0 -94
|
@@ -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,7 +24,7 @@ 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 keymap11 } 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";
|
|
@@ -33,8 +34,8 @@ import { EditorState as EditorState2 } from "@codemirror/state";
|
|
|
33
34
|
import { EditorView as EditorView16 } 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
|
-
import { log as
|
|
37
|
-
import { isNotFalsy as
|
|
37
|
+
import { log as log7 } from "@dxos/log";
|
|
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 =
|
|
124
|
-
const decorations = annotations2.map((
|
|
125
|
-
const range = Cursor.getRangeFromCursor(
|
|
123
|
+
], (state2) => {
|
|
124
|
+
const annotations2 = state2.field(annotationsState);
|
|
125
|
+
const decorations = annotations2.map((annotation) => {
|
|
126
|
+
const range = Cursor.getRangeFromCursor(state2, annotation.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 {};
|
|
@@ -1195,7 +1196,7 @@ var commandState = StateField3.define({
|
|
|
1195
1196
|
}
|
|
1196
1197
|
});
|
|
1197
1198
|
}
|
|
1198
|
-
|
|
1199
|
+
requestAnimationFrame(() => view2.focus());
|
|
1199
1200
|
});
|
|
1200
1201
|
}
|
|
1201
1202
|
};
|
|
@@ -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
|
}
|
|
@@ -1850,76 +1851,14 @@ var useComments = (view, id, comments2 = []) => {
|
|
|
1850
1851
|
]);
|
|
1851
1852
|
};
|
|
1852
1853
|
|
|
1853
|
-
// packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
|
|
1854
|
-
import { Transaction } from "@codemirror/state";
|
|
1855
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1856
|
-
import { log as log5 } from "@dxos/log";
|
|
1857
|
-
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
|
|
1858
|
-
var annotation = "cursorLineMargin";
|
|
1859
|
-
var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
|
|
1860
|
-
var cursorLineMargin = (options = {
|
|
1861
|
-
lines: 3
|
|
1862
|
-
}) => {
|
|
1863
|
-
const { lines } = options;
|
|
1864
|
-
if (!lines || lines <= 0) {
|
|
1865
|
-
return [];
|
|
1866
|
-
}
|
|
1867
|
-
return EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
|
|
1868
|
-
if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
|
|
1869
|
-
return;
|
|
1870
|
-
}
|
|
1871
|
-
const s = state;
|
|
1872
|
-
const { main } = s.selection;
|
|
1873
|
-
const rect = view.dom.getBoundingClientRect();
|
|
1874
|
-
const viewportTop = rect.top - view.documentTop;
|
|
1875
|
-
const viewportBottom = rect.bottom - view.documentTop;
|
|
1876
|
-
const mainLine = lineAtPos(s, main.head);
|
|
1877
|
-
const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
|
|
1878
|
-
const botLineBlk = view.lineBlockAtHeight(viewportBottom);
|
|
1879
|
-
const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
|
|
1880
|
-
const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
|
|
1881
|
-
const needsScrollTop = false;
|
|
1882
|
-
const needsScrollBot = mainLine >= visBotLine - lines;
|
|
1883
|
-
if (needsScrollTop && needsScrollBot) {
|
|
1884
|
-
log5.warn("is cursorScrollMargin too large for the editor size?", void 0, {
|
|
1885
|
-
F: __dxlog_file6,
|
|
1886
|
-
L: 65,
|
|
1887
|
-
S: void 0,
|
|
1888
|
-
C: (f, a) => f(...a)
|
|
1889
|
-
});
|
|
1890
|
-
return;
|
|
1891
|
-
}
|
|
1892
|
-
if (!needsScrollTop && !needsScrollBot) {
|
|
1893
|
-
return;
|
|
1894
|
-
}
|
|
1895
|
-
if (selectionSet) {
|
|
1896
|
-
const { head } = startState.selection.main;
|
|
1897
|
-
const oldMainLine = lineAtPos(startState, head);
|
|
1898
|
-
if (needsScrollTop && oldMainLine < mainLine) {
|
|
1899
|
-
return;
|
|
1900
|
-
}
|
|
1901
|
-
if (needsScrollBot && oldMainLine > mainLine) {
|
|
1902
|
-
return;
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
view.dispatch({
|
|
1906
|
-
annotations: Transaction.userEvent.of(annotation),
|
|
1907
|
-
effects: EditorView8.scrollIntoView(s.selection.main.head, {
|
|
1908
|
-
y: needsScrollTop ? "start" : "end",
|
|
1909
|
-
yMargin: view.defaultLineHeight * lines
|
|
1910
|
-
})
|
|
1911
|
-
});
|
|
1912
|
-
});
|
|
1913
|
-
};
|
|
1914
|
-
|
|
1915
1854
|
// packages/ui/react-ui-editor/src/extensions/doc.ts
|
|
1916
1855
|
import { Facet as Facet5 } from "@codemirror/state";
|
|
1917
1856
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1918
|
-
var
|
|
1857
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
|
|
1919
1858
|
var documentId2 = Facet5.define({
|
|
1920
1859
|
combine: (providers) => {
|
|
1921
1860
|
invariant3(providers.length <= 1, void 0, {
|
|
1922
|
-
F:
|
|
1861
|
+
F: __dxlog_file6,
|
|
1923
1862
|
L: 11,
|
|
1924
1863
|
S: void 0,
|
|
1925
1864
|
A: [
|
|
@@ -1932,33 +1871,51 @@ var documentId2 = Facet5.define({
|
|
|
1932
1871
|
});
|
|
1933
1872
|
|
|
1934
1873
|
// packages/ui/react-ui-editor/src/extensions/dnd.ts
|
|
1935
|
-
import { EditorView as
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1874
|
+
import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
|
|
1875
|
+
var styles4 = EditorView8.baseTheme({
|
|
1876
|
+
".cm-dropCursor": {
|
|
1877
|
+
borderLeft: `2px solid ${getToken("extend.colors.primary.500")}`,
|
|
1878
|
+
color: getToken("extend.colors.primary.500"),
|
|
1879
|
+
padding: "0 4px"
|
|
1880
|
+
},
|
|
1881
|
+
".cm-dropCursor:after": {
|
|
1882
|
+
content: '"\u2190"'
|
|
1883
|
+
}
|
|
1884
|
+
});
|
|
1885
|
+
var dropFile = (options = {}) => {
|
|
1886
|
+
return [
|
|
1887
|
+
styles4,
|
|
1888
|
+
dropCursor(),
|
|
1889
|
+
EditorView8.domEventHandlers({
|
|
1890
|
+
drop: (event, view) => {
|
|
1891
|
+
event.preventDefault();
|
|
1892
|
+
const files = event.dataTransfer?.files;
|
|
1893
|
+
const pos = view.posAtCoords(event);
|
|
1894
|
+
if (files?.length && pos !== null) {
|
|
1895
|
+
view.dispatch({
|
|
1896
|
+
selection: {
|
|
1897
|
+
anchor: pos
|
|
1898
|
+
}
|
|
1899
|
+
});
|
|
1900
|
+
options.onDrop?.(view, {
|
|
1901
|
+
files
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
})
|
|
1906
|
+
];
|
|
1951
1907
|
};
|
|
1952
1908
|
|
|
1953
1909
|
// packages/ui/react-ui-editor/src/extensions/factories.ts
|
|
1954
|
-
import { closeBrackets } from "@codemirror/autocomplete";
|
|
1955
|
-
import { history } from "@codemirror/commands";
|
|
1910
|
+
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1911
|
+
import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1956
1912
|
import { bracketMatching } from "@codemirror/language";
|
|
1913
|
+
import { searchKeymap } from "@codemirror/search";
|
|
1957
1914
|
import { EditorState } from "@codemirror/state";
|
|
1958
|
-
import { EditorView as
|
|
1915
|
+
import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
|
|
1959
1916
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
1960
1917
|
import { generateName } from "@dxos/display-name";
|
|
1961
|
-
import { log as
|
|
1918
|
+
import { log as log5 } from "@dxos/log";
|
|
1962
1919
|
import { hueTokens } from "@dxos/react-ui-theme";
|
|
1963
1920
|
import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1964
1921
|
|
|
@@ -2163,50 +2120,75 @@ var defaultTheme = {
|
|
|
2163
2120
|
* </div>
|
|
2164
2121
|
* </div
|
|
2165
2122
|
*/
|
|
2166
|
-
".cm-panels": {
|
|
2167
|
-
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2168
|
-
},
|
|
2123
|
+
".cm-panels": {},
|
|
2169
2124
|
".cm-panel": {
|
|
2170
|
-
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2171
2125
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2172
2126
|
},
|
|
2127
|
+
".cm-panel input[type=checkbox]": {
|
|
2128
|
+
marginRight: "0.4rem !important"
|
|
2129
|
+
},
|
|
2130
|
+
"&light .cm-panel": {
|
|
2131
|
+
background: get3(tokens, "extend.colors.neutral.50")
|
|
2132
|
+
},
|
|
2133
|
+
"&dark .cm-panel": {
|
|
2134
|
+
background: get3(tokens, "extend.colors.neutral.850")
|
|
2135
|
+
},
|
|
2173
2136
|
".cm-button": {
|
|
2174
2137
|
margin: "4px",
|
|
2175
2138
|
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2176
|
-
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2177
2139
|
backgroundImage: "none",
|
|
2178
2140
|
border: "none",
|
|
2141
|
+
"&:active": {
|
|
2142
|
+
backgroundImage: "none"
|
|
2143
|
+
}
|
|
2144
|
+
},
|
|
2145
|
+
"&light .cm-button": {
|
|
2146
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2179
2147
|
"&:hover": {
|
|
2180
2148
|
background: get3(tokens, "extend.colors.neutral.200")
|
|
2181
2149
|
},
|
|
2182
2150
|
"&:active": {
|
|
2183
|
-
background: get3(tokens, "extend.colors.neutral.300")
|
|
2184
|
-
backgroundImage: "none"
|
|
2151
|
+
background: get3(tokens, "extend.colors.neutral.300")
|
|
2185
2152
|
}
|
|
2186
2153
|
},
|
|
2187
|
-
".cm-
|
|
2188
|
-
|
|
2154
|
+
"&dark .cm-button": {
|
|
2155
|
+
background: get3(tokens, "extend.colors.neutral.800"),
|
|
2156
|
+
"&:hover": {
|
|
2157
|
+
background: get3(tokens, "extend.colors.neutral.700")
|
|
2158
|
+
},
|
|
2159
|
+
"&:active": {
|
|
2160
|
+
background: get3(tokens, "extend.colors.neutral.600")
|
|
2161
|
+
}
|
|
2189
2162
|
}
|
|
2190
2163
|
};
|
|
2191
2164
|
|
|
2192
2165
|
// packages/ui/react-ui-editor/src/extensions/factories.ts
|
|
2193
|
-
var
|
|
2194
|
-
var
|
|
2166
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
|
|
2167
|
+
var defaultBasicOptions = {
|
|
2168
|
+
allowMultipleSelections: true,
|
|
2195
2169
|
bracketMatching: true,
|
|
2196
2170
|
closeBrackets: true,
|
|
2197
2171
|
drawSelection: true,
|
|
2198
2172
|
editable: true,
|
|
2199
2173
|
history: true,
|
|
2200
|
-
|
|
2174
|
+
keymap: "standard",
|
|
2175
|
+
lineWrapping: true,
|
|
2176
|
+
search: true
|
|
2177
|
+
};
|
|
2178
|
+
var keymaps = {
|
|
2179
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2180
|
+
standard: standardKeymap,
|
|
2181
|
+
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
|
2182
|
+
default: defaultKeymap
|
|
2201
2183
|
};
|
|
2202
2184
|
var createBasicExtensions = (_props) => {
|
|
2203
|
-
const props = defaultsDeep2({}, _props,
|
|
2185
|
+
const props = defaultsDeep2({}, _props, defaultBasicOptions);
|
|
2204
2186
|
return [
|
|
2205
|
-
//
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
F:
|
|
2209
|
-
L:
|
|
2187
|
+
// NOTE: Doesn't catch errors in keymap functions.
|
|
2188
|
+
EditorView9.exceptionSink.of((err) => {
|
|
2189
|
+
log5.catch(err, void 0, {
|
|
2190
|
+
F: __dxlog_file7,
|
|
2191
|
+
L: 91,
|
|
2210
2192
|
S: void 0,
|
|
2211
2193
|
C: (f, a) => f(...a)
|
|
2212
2194
|
});
|
|
@@ -2214,40 +2196,50 @@ var createBasicExtensions = (_props) => {
|
|
|
2214
2196
|
props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
|
|
2215
2197
|
props.bracketMatching && bracketMatching(),
|
|
2216
2198
|
props.closeBrackets && closeBrackets(),
|
|
2217
|
-
props.
|
|
2218
|
-
props.dropCursor && dropCursor(),
|
|
2199
|
+
props.dropCursor && dropCursor2(),
|
|
2219
2200
|
props.drawSelection && drawSelection(),
|
|
2220
2201
|
props.highlightActiveLine && highlightActiveLine(),
|
|
2221
2202
|
props.history && history(),
|
|
2222
2203
|
props.lineNumbers && lineNumbers(),
|
|
2223
|
-
props.lineWrapping &&
|
|
2204
|
+
props.lineWrapping && EditorView9.lineWrapping,
|
|
2224
2205
|
props.placeholder && placeholder(props.placeholder),
|
|
2225
2206
|
props.readonly && [
|
|
2226
2207
|
EditorState.readOnly.of(true),
|
|
2227
|
-
|
|
2208
|
+
EditorView9.editable.of(false)
|
|
2228
2209
|
],
|
|
2229
2210
|
props.scrollPastEnd && scrollPastEnd(),
|
|
2230
|
-
props.tabSize && EditorState.tabSize.of(props.tabSize)
|
|
2211
|
+
props.tabSize && EditorState.tabSize.of(props.tabSize),
|
|
2212
|
+
// https://codemirror.net/docs/ref/#view.KeyBinding
|
|
2213
|
+
keymap5.of([
|
|
2214
|
+
...(props.keymap && keymaps[props.keymap]) ?? [],
|
|
2215
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
2216
|
+
...props.indentWithTab ? [
|
|
2217
|
+
indentWithTab
|
|
2218
|
+
] : [],
|
|
2219
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
2220
|
+
...props.closeBrackets ? closeBracketsKeymap : [],
|
|
2221
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2222
|
+
...props.history ? historyKeymap : [],
|
|
2223
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2224
|
+
...props.search ? searchKeymap : []
|
|
2225
|
+
].filter(isNotFalsy2))
|
|
2231
2226
|
].filter(isNotFalsy2);
|
|
2232
2227
|
};
|
|
2233
|
-
var
|
|
2228
|
+
var defaultThemeSlots = {
|
|
2234
2229
|
editor: {
|
|
2235
2230
|
className: "w-full bs-full"
|
|
2236
|
-
},
|
|
2237
|
-
content: {
|
|
2238
|
-
className: "!p-2"
|
|
2239
2231
|
}
|
|
2240
2232
|
};
|
|
2241
2233
|
var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
|
|
2242
|
-
const slots = defaultsDeep2({}, _slots,
|
|
2234
|
+
const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
|
|
2243
2235
|
return [
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
theme &&
|
|
2247
|
-
slots.editor?.className &&
|
|
2236
|
+
EditorView9.baseTheme(defaultTheme),
|
|
2237
|
+
EditorView9.darkTheme.of(themeMode === "dark"),
|
|
2238
|
+
theme && EditorView9.theme(theme),
|
|
2239
|
+
slots.editor?.className && EditorView9.editorAttributes.of({
|
|
2248
2240
|
class: slots.editor.className
|
|
2249
2241
|
}),
|
|
2250
|
-
slots.content?.className &&
|
|
2242
|
+
slots.content?.className && EditorView9.contentAttributes.of({
|
|
2251
2243
|
class: slots.content.className
|
|
2252
2244
|
})
|
|
2253
2245
|
].filter(isNotFalsy2);
|
|
@@ -2275,1621 +2267,1671 @@ var createDataExtensions = ({ id, text, space, identity }) => {
|
|
|
2275
2267
|
};
|
|
2276
2268
|
|
|
2277
2269
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
2278
|
-
import { EditorView as
|
|
2270
|
+
import { EditorView as EditorView10 } from "@codemirror/view";
|
|
2279
2271
|
var listener = ({ onFocus, onChange }) => {
|
|
2280
2272
|
const extensions = [];
|
|
2281
|
-
onFocus && extensions.push(
|
|
2273
|
+
onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
|
|
2282
2274
|
onFocus(focusing);
|
|
2283
2275
|
return null;
|
|
2284
2276
|
}));
|
|
2285
|
-
onChange && extensions.push(
|
|
2277
|
+
onChange && extensions.push(EditorView10.updateListener.of((update2) => {
|
|
2286
2278
|
onChange(update2.state.doc.toString());
|
|
2287
2279
|
}));
|
|
2288
2280
|
return extensions;
|
|
2289
2281
|
};
|
|
2290
2282
|
|
|
2291
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/
|
|
2292
|
-
import {
|
|
2293
|
-
import {
|
|
2294
|
-
import {
|
|
2295
|
-
import {
|
|
2296
|
-
import {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2283
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
2284
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
2285
|
+
import { syntaxTree } from "@codemirror/language";
|
|
2286
|
+
import { EditorSelection } from "@codemirror/state";
|
|
2287
|
+
import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
|
|
2288
|
+
import { useMemo, useState } from "react";
|
|
2289
|
+
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;
|
|
2290
|
+
var Inline;
|
|
2291
|
+
(function(Inline2) {
|
|
2292
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
2293
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
2294
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
2295
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
2296
|
+
})(Inline || (Inline = {}));
|
|
2297
|
+
var List;
|
|
2298
|
+
(function(List2) {
|
|
2299
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
2300
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
2301
|
+
List2[List2["Task"] = 2] = "Task";
|
|
2302
|
+
})(List || (List = {}));
|
|
2303
|
+
var setHeading = (level) => ({ state: state2, dispatch }) => {
|
|
2304
|
+
const { selection: { ranges }, doc } = state2;
|
|
2305
|
+
const changes = [];
|
|
2306
|
+
let prevBlock = -1;
|
|
2307
|
+
for (const range of ranges) {
|
|
2308
|
+
let sawBlock = false;
|
|
2309
|
+
syntaxTree(state2).iterate({
|
|
2310
|
+
from: range.from,
|
|
2311
|
+
to: range.to,
|
|
2312
|
+
enter: (node) => {
|
|
2313
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
2314
|
+
return;
|
|
2315
|
+
}
|
|
2316
|
+
sawBlock = true;
|
|
2317
|
+
prevBlock = node.from;
|
|
2318
|
+
const blockType = Textblocks[node.name];
|
|
2319
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
2320
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
2321
|
+
if (curLevel < 0 || curLevel === level) {
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
if (curLevel === 0) {
|
|
2325
|
+
changes.push({
|
|
2326
|
+
from: node.from,
|
|
2327
|
+
insert: "#".repeat(level) + " "
|
|
2328
|
+
});
|
|
2329
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
2330
|
+
const nextLine = doc.lineAt(node.to);
|
|
2331
|
+
if (level) {
|
|
2332
|
+
changes.push({
|
|
2333
|
+
from: node.from,
|
|
2334
|
+
insert: "#".repeat(level) + " "
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
changes.push({
|
|
2338
|
+
from: nextLine.from - 1,
|
|
2339
|
+
to: nextLine.to
|
|
2340
|
+
});
|
|
2341
|
+
} else {
|
|
2342
|
+
if (level === 0) {
|
|
2343
|
+
changes.push({
|
|
2344
|
+
from: node.from,
|
|
2345
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
2346
|
+
});
|
|
2347
|
+
} else if (level < curLevel) {
|
|
2348
|
+
changes.push({
|
|
2349
|
+
from: node.from,
|
|
2350
|
+
to: node.from + (curLevel - level)
|
|
2351
|
+
});
|
|
2352
|
+
} else {
|
|
2353
|
+
changes.push({
|
|
2354
|
+
from: node.from,
|
|
2355
|
+
insert: "#".repeat(level - curLevel)
|
|
2356
|
+
});
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
});
|
|
2361
|
+
let line;
|
|
2362
|
+
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
|
|
2363
|
+
changes.push({
|
|
2364
|
+
from: line.from,
|
|
2365
|
+
to: line.to,
|
|
2366
|
+
insert: "#".repeat(level) + " "
|
|
2367
|
+
});
|
|
2326
2368
|
}
|
|
2327
2369
|
}
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
Table,
|
|
2331
|
-
{
|
|
2332
|
-
props: [
|
|
2333
|
-
styleTags(markdownTags)
|
|
2334
|
-
]
|
|
2370
|
+
if (!changes.length) {
|
|
2371
|
+
return false;
|
|
2335
2372
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
tags.string,
|
|
2372
|
-
tags.inserted,
|
|
2373
|
-
tags.invalid
|
|
2374
|
-
],
|
|
2375
|
-
color: "inherit !important"
|
|
2376
|
-
},
|
|
2377
|
-
// Markdown marks.
|
|
2378
|
-
{
|
|
2379
|
-
tag: [
|
|
2380
|
-
tags.meta,
|
|
2381
|
-
tags.processingInstruction,
|
|
2382
|
-
markdownTags.LinkLabel,
|
|
2383
|
-
markdownTags.LinkReference,
|
|
2384
|
-
markdownTags.ListMark
|
|
2385
|
-
],
|
|
2386
|
-
class: mark
|
|
2387
|
-
},
|
|
2388
|
-
// Markdown marks.
|
|
2389
|
-
{
|
|
2390
|
-
tag: [
|
|
2391
|
-
markdownTags.CodeMark,
|
|
2392
|
-
markdownTags.HeaderMark,
|
|
2393
|
-
markdownTags.QuoteMark,
|
|
2394
|
-
markdownTags.EmphasisMark
|
|
2395
|
-
],
|
|
2396
|
-
class: mark
|
|
2397
|
-
},
|
|
2398
|
-
// E.g., code block language (after ```).
|
|
2399
|
-
{
|
|
2400
|
-
tag: [
|
|
2401
|
-
tags.function(tags.variableName),
|
|
2402
|
-
tags.labelName
|
|
2403
|
-
],
|
|
2404
|
-
class: codeMark
|
|
2405
|
-
},
|
|
2406
|
-
{
|
|
2407
|
-
tag: [
|
|
2408
|
-
tags.monospace
|
|
2409
|
-
],
|
|
2410
|
-
class: "font-mono"
|
|
2411
|
-
},
|
|
2412
|
-
// Headings.
|
|
2413
|
-
{
|
|
2414
|
-
tag: tags.heading1,
|
|
2415
|
-
class: heading(1)
|
|
2416
|
-
},
|
|
2417
|
-
{
|
|
2418
|
-
tag: tags.heading2,
|
|
2419
|
-
class: heading(2)
|
|
2420
|
-
},
|
|
2421
|
-
{
|
|
2422
|
-
tag: tags.heading3,
|
|
2423
|
-
class: heading(3)
|
|
2424
|
-
},
|
|
2425
|
-
{
|
|
2426
|
-
tag: tags.heading4,
|
|
2427
|
-
class: heading(4)
|
|
2428
|
-
},
|
|
2429
|
-
{
|
|
2430
|
-
tag: tags.heading5,
|
|
2431
|
-
class: heading(5)
|
|
2432
|
-
},
|
|
2433
|
-
{
|
|
2434
|
-
tag: tags.heading6,
|
|
2435
|
-
class: heading(6)
|
|
2436
|
-
},
|
|
2437
|
-
// Emphasis.
|
|
2438
|
-
{
|
|
2439
|
-
tag: tags.emphasis,
|
|
2440
|
-
class: italic
|
|
2441
|
-
},
|
|
2442
|
-
{
|
|
2443
|
-
tag: tags.strong,
|
|
2444
|
-
class: bold
|
|
2445
|
-
},
|
|
2446
|
-
{
|
|
2447
|
-
tag: tags.strikethrough,
|
|
2448
|
-
class: strikethrough
|
|
2449
|
-
},
|
|
2450
|
-
// Naked URLs.
|
|
2451
|
-
{
|
|
2452
|
-
tag: [
|
|
2453
|
-
markdownTags.URL
|
|
2454
|
-
],
|
|
2455
|
-
class: inlineUrl
|
|
2456
|
-
},
|
|
2457
|
-
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
2458
|
-
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
2459
|
-
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
2460
|
-
// the code, but all other CSS properties will be inherited.
|
|
2461
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
2462
|
-
{
|
|
2463
|
-
tag: [
|
|
2464
|
-
markdownTags.CodeText,
|
|
2465
|
-
markdownTags.InlineCode
|
|
2466
|
-
],
|
|
2467
|
-
class: code
|
|
2468
|
-
},
|
|
2469
|
-
{
|
|
2470
|
-
tag: [
|
|
2471
|
-
markdownTags.QuoteMark
|
|
2472
|
-
],
|
|
2473
|
-
class: blockquote
|
|
2474
|
-
},
|
|
2475
|
-
{
|
|
2476
|
-
tag: [
|
|
2477
|
-
markdownTags.TableCell
|
|
2478
|
-
],
|
|
2479
|
-
class: "font-mono"
|
|
2373
|
+
const changeSet = state2.changes(changes);
|
|
2374
|
+
dispatch(state2.update({
|
|
2375
|
+
changes: changeSet,
|
|
2376
|
+
selection: state2.selection.map(changeSet, 1),
|
|
2377
|
+
userEvent: "format.setHeading",
|
|
2378
|
+
scrollIntoView: true
|
|
2379
|
+
}));
|
|
2380
|
+
return true;
|
|
2381
|
+
};
|
|
2382
|
+
var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
|
|
2383
|
+
const marker = inlineMarkerText(type);
|
|
2384
|
+
const changes = state2.changeByRange((range) => {
|
|
2385
|
+
if (!enable && range.empty) {
|
|
2386
|
+
const after = state2.doc.sliceString(range.head, range.head + 6);
|
|
2387
|
+
const found = after.indexOf(marker);
|
|
2388
|
+
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
2389
|
+
const before = state2.doc.sliceString(range.head - 6, range.head);
|
|
2390
|
+
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
2391
|
+
...before.slice(before.length - found)
|
|
2392
|
+
].reverse().join("") === after.slice(0, found)) {
|
|
2393
|
+
return {
|
|
2394
|
+
changes: [
|
|
2395
|
+
{
|
|
2396
|
+
from: range.head - marker.length - found,
|
|
2397
|
+
to: range.head - found
|
|
2398
|
+
},
|
|
2399
|
+
{
|
|
2400
|
+
from: range.head + found,
|
|
2401
|
+
to: range.head + found + marker.length
|
|
2402
|
+
}
|
|
2403
|
+
],
|
|
2404
|
+
range: EditorSelection.cursor(range.from - marker.length)
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2480
2408
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2409
|
+
const changes2 = [];
|
|
2410
|
+
const changesAtEnd = [];
|
|
2411
|
+
let blockStart = -1;
|
|
2412
|
+
let blockEnd = -1;
|
|
2413
|
+
let startCovered = false;
|
|
2414
|
+
let endCovered = false;
|
|
2415
|
+
let { from, to } = range;
|
|
2416
|
+
syntaxTree(state2).iterate({
|
|
2417
|
+
from,
|
|
2418
|
+
to,
|
|
2419
|
+
enter: (node) => {
|
|
2420
|
+
const { name } = node;
|
|
2421
|
+
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
2422
|
+
blockStart = blockContentStart(node);
|
|
2423
|
+
blockEnd = blockContentEnd(node, state2.doc);
|
|
2424
|
+
startCovered = endCovered = false;
|
|
2425
|
+
} else if (name === "Link" || name === "Image" && enable) {
|
|
2426
|
+
if (from < node.from && to > node.from && to <= node.to) {
|
|
2427
|
+
to = node.to;
|
|
2428
|
+
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
2429
|
+
from = node.from;
|
|
2430
|
+
}
|
|
2431
|
+
} else if (IgnoreInline.has(name) && enable) {
|
|
2432
|
+
if (node.from < from && node.to > from) {
|
|
2433
|
+
if (to === from) {
|
|
2434
|
+
to = node.to;
|
|
2435
|
+
}
|
|
2436
|
+
from = node.to;
|
|
2437
|
+
}
|
|
2438
|
+
if (node.from < to && node.to > to) {
|
|
2439
|
+
to = node.from;
|
|
2440
|
+
}
|
|
2441
|
+
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
2442
|
+
const markType = InlineMarker[name];
|
|
2443
|
+
const size = inlineMarkerText(markType).length;
|
|
2444
|
+
const openEnd = node.from + size;
|
|
2445
|
+
const closeStart = node.to - size;
|
|
2446
|
+
if (markType === type) {
|
|
2447
|
+
if (openEnd <= from && closeStart >= from) {
|
|
2448
|
+
startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
|
|
2449
|
+
from: node.from,
|
|
2450
|
+
to: openEnd
|
|
2451
|
+
} : true;
|
|
2452
|
+
}
|
|
2453
|
+
if (openEnd <= to && closeStart >= to) {
|
|
2454
|
+
endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
|
|
2455
|
+
from: closeStart,
|
|
2456
|
+
to: node.to
|
|
2457
|
+
} : true;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
if (markType === type || type === 3 && enable) {
|
|
2461
|
+
if (node.from >= from && openEnd <= to) {
|
|
2462
|
+
changes2.push({
|
|
2463
|
+
from: node.from,
|
|
2464
|
+
to: openEnd
|
|
2465
|
+
});
|
|
2466
|
+
if (markType !== type && closeStart >= to) {
|
|
2467
|
+
changesAtEnd.push({
|
|
2468
|
+
from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
|
|
2469
|
+
insert: inlineMarkerText(markType)
|
|
2470
|
+
});
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
if (closeStart >= from && node.to <= to) {
|
|
2474
|
+
changes2.push({
|
|
2475
|
+
from: closeStart,
|
|
2476
|
+
to: node.to
|
|
2477
|
+
});
|
|
2478
|
+
if (markType !== type && openEnd <= from) {
|
|
2479
|
+
changes2.push({
|
|
2480
|
+
from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
|
|
2481
|
+
insert: inlineMarkerText(markType)
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
},
|
|
2488
|
+
leave: (node) => {
|
|
2489
|
+
if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
|
|
2490
|
+
const rangeStart = Math.max(from, blockStart);
|
|
2491
|
+
const rangeEnd = Math.min(to, blockEnd);
|
|
2492
|
+
if (enable) {
|
|
2493
|
+
if (!startCovered) {
|
|
2494
|
+
changes2.push({
|
|
2495
|
+
from: rangeStart,
|
|
2496
|
+
insert: marker
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
if (!endCovered) {
|
|
2500
|
+
changes2.push({
|
|
2501
|
+
from: rangeEnd,
|
|
2502
|
+
insert: marker
|
|
2503
|
+
});
|
|
2504
|
+
}
|
|
2505
|
+
} else {
|
|
2506
|
+
if (typeof startCovered === "object") {
|
|
2507
|
+
changes2.push(startCovered);
|
|
2508
|
+
} else if (startCovered) {
|
|
2509
|
+
changes2.push({
|
|
2510
|
+
from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
|
|
2511
|
+
insert: marker
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
if (typeof endCovered === "object") {
|
|
2515
|
+
changes2.push(endCovered);
|
|
2516
|
+
} else if (endCovered) {
|
|
2517
|
+
changes2.push({
|
|
2518
|
+
from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
|
|
2519
|
+
insert: marker
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
});
|
|
2526
|
+
if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
|
|
2527
|
+
return {
|
|
2528
|
+
changes: {
|
|
2529
|
+
from: range.head,
|
|
2530
|
+
insert: marker + marker
|
|
2531
|
+
},
|
|
2532
|
+
range: EditorSelection.cursor(range.head + marker.length)
|
|
2533
|
+
};
|
|
2485
2534
|
}
|
|
2535
|
+
const changeSet = state2.changes(changes2.concat(changesAtEnd));
|
|
2536
|
+
return {
|
|
2537
|
+
changes: changeSet,
|
|
2538
|
+
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
2539
|
+
};
|
|
2486
2540
|
});
|
|
2541
|
+
dispatch(state2.update(changes, {
|
|
2542
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2543
|
+
scrollIntoView: true
|
|
2544
|
+
}));
|
|
2545
|
+
return true;
|
|
2487
2546
|
};
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
var
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
// https://github.com/codemirror/lang-markdown
|
|
2494
|
-
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
2495
|
-
markdown({
|
|
2496
|
-
// GRM by default (vs strict CommonMark):
|
|
2497
|
-
// Table, TaskList, Strikethrough, and Autolink.
|
|
2498
|
-
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
2499
|
-
// https://github.github.com/gfm
|
|
2500
|
-
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
2501
|
-
base: markdownLanguage3,
|
|
2502
|
-
// Languages for syntax highlighting fenced code blocks.
|
|
2503
|
-
codeLanguages: languages,
|
|
2504
|
-
// Parser extensions.
|
|
2505
|
-
extensions: [
|
|
2506
|
-
// GFM provided by default.
|
|
2507
|
-
markdownTagsExtensions
|
|
2508
|
-
]
|
|
2509
|
-
}),
|
|
2510
|
-
// https://github.com/codemirror/theme-one-dark
|
|
2511
|
-
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
2512
|
-
// Custom styles.
|
|
2513
|
-
syntaxHighlighting(markdownHighlightStyle()),
|
|
2514
|
-
keymap5.of([
|
|
2515
|
-
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
2516
|
-
indentWithTab,
|
|
2517
|
-
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
2518
|
-
...closeBracketsKeymap,
|
|
2519
|
-
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2520
|
-
...historyKeymap,
|
|
2521
|
-
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2522
|
-
...searchKeymap,
|
|
2523
|
-
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2524
|
-
...standardKeymap
|
|
2525
|
-
])
|
|
2526
|
-
];
|
|
2547
|
+
var addStyle = (style) => setStyle(style, true);
|
|
2548
|
+
var removeStyle = (style) => setStyle(style, false);
|
|
2549
|
+
var toggleStyle = (style) => (arg) => {
|
|
2550
|
+
const form = getFormatting(arg.state);
|
|
2551
|
+
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
2527
2552
|
};
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
el.className = "cm-hr";
|
|
2538
|
-
return el;
|
|
2553
|
+
var toggleStrong = toggleStyle(0);
|
|
2554
|
+
var toggleEmphasis = toggleStyle(1);
|
|
2555
|
+
var toggleStrikethrough = toggleStyle(2);
|
|
2556
|
+
var toggleInlineCode = toggleStyle(3);
|
|
2557
|
+
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
2558
|
+
var blockContentStart = (node) => {
|
|
2559
|
+
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
2560
|
+
if (atx) {
|
|
2561
|
+
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
2539
2562
|
}
|
|
2563
|
+
return node.from;
|
|
2540
2564
|
};
|
|
2541
|
-
var
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
}
|
|
2547
|
-
eq(other) {
|
|
2548
|
-
return this.url === other.url;
|
|
2549
|
-
}
|
|
2550
|
-
toDOM(view) {
|
|
2551
|
-
const el = document.createElement("span");
|
|
2552
|
-
this.render(el, this.url);
|
|
2553
|
-
return el;
|
|
2565
|
+
var blockContentEnd = (node, doc) => {
|
|
2566
|
+
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
2567
|
+
const lastLine = doc.lineAt(node.to);
|
|
2568
|
+
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
2569
|
+
return lastLine.from - 1;
|
|
2554
2570
|
}
|
|
2571
|
+
return node.to;
|
|
2555
2572
|
};
|
|
2556
|
-
var
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2573
|
+
var skipSpaces = (pos, doc, dir, limit) => {
|
|
2574
|
+
const line = doc.lineAt(pos);
|
|
2575
|
+
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
2576
|
+
pos += dir;
|
|
2560
2577
|
}
|
|
2561
|
-
|
|
2562
|
-
|
|
2578
|
+
return pos;
|
|
2579
|
+
};
|
|
2580
|
+
var skipMarkers = (pos, tree, dir, limit) => {
|
|
2581
|
+
for (; ; ) {
|
|
2582
|
+
const next = tree.resolve(pos, dir);
|
|
2583
|
+
if (!IgnoreInline.has(next.name)) {
|
|
2584
|
+
return pos;
|
|
2585
|
+
}
|
|
2586
|
+
const moveTo = dir < 0 ? next.from : next.to;
|
|
2587
|
+
if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
|
|
2588
|
+
return pos;
|
|
2589
|
+
}
|
|
2590
|
+
pos = moveTo;
|
|
2563
2591
|
}
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2592
|
+
};
|
|
2593
|
+
var snippets = {
|
|
2594
|
+
codeblock: snippet([
|
|
2595
|
+
//
|
|
2596
|
+
"```#{}",
|
|
2597
|
+
"",
|
|
2598
|
+
"```"
|
|
2599
|
+
].join("\n")),
|
|
2600
|
+
table: snippet([
|
|
2601
|
+
//
|
|
2602
|
+
"| #{col1} | #{col2} |",
|
|
2603
|
+
"| ---- | ---- |",
|
|
2604
|
+
"| #{val1} | #{val2} |",
|
|
2605
|
+
"| #{val3} | #{val4} |",
|
|
2606
|
+
""
|
|
2607
|
+
].join("\n"))
|
|
2608
|
+
};
|
|
2609
|
+
var insertTable = (view) => {
|
|
2610
|
+
const { selection: { main }, doc } = view.state;
|
|
2611
|
+
const { number } = doc.lineAt(main.anchor);
|
|
2612
|
+
const { from } = doc.line(number);
|
|
2613
|
+
snippets.table(view, null, from, from);
|
|
2614
|
+
};
|
|
2615
|
+
var removeLinkInner = (from, to, changes, state2) => {
|
|
2616
|
+
syntaxTree(state2).iterate({
|
|
2617
|
+
from,
|
|
2618
|
+
to,
|
|
2619
|
+
enter: (node) => {
|
|
2620
|
+
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
2621
|
+
node.node.cursor().iterate((node2) => {
|
|
2622
|
+
const { name } = node2;
|
|
2623
|
+
if (name === "LinkMark" || name === "LinkLabel") {
|
|
2624
|
+
changes.push({
|
|
2625
|
+
from: node2.from,
|
|
2626
|
+
to: node2.to
|
|
2627
|
+
});
|
|
2628
|
+
} else if (name === "LinkTitle" || name === "URL") {
|
|
2629
|
+
changes.push({
|
|
2630
|
+
from: skipSpaces(node2.from, state2.doc, -1),
|
|
2631
|
+
to: skipSpaces(node2.to, state2.doc, 1)
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
});
|
|
2635
|
+
return false;
|
|
2636
|
+
}
|
|
2586
2637
|
}
|
|
2587
|
-
|
|
2638
|
+
});
|
|
2639
|
+
};
|
|
2640
|
+
var removeLink = ({ state: state2, dispatch }) => {
|
|
2641
|
+
const changes = [];
|
|
2642
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
2643
|
+
removeLinkInner(from, to, changes, state2);
|
|
2588
2644
|
}
|
|
2589
|
-
|
|
2645
|
+
if (!changes) {
|
|
2590
2646
|
return false;
|
|
2591
2647
|
}
|
|
2648
|
+
dispatch(state2.update({
|
|
2649
|
+
changes,
|
|
2650
|
+
userEvent: "format.link.remove",
|
|
2651
|
+
scrollIntoView: true
|
|
2652
|
+
}));
|
|
2653
|
+
return true;
|
|
2592
2654
|
};
|
|
2593
|
-
var
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
});
|
|
2600
|
-
var fencedCodeLineLast = Decoration5.line({
|
|
2601
|
-
class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
|
|
2602
|
-
});
|
|
2603
|
-
var horizontalRule = Decoration5.replace({
|
|
2604
|
-
widget: new HorizontalRuleWidget()
|
|
2605
|
-
});
|
|
2606
|
-
var checkedTask = Decoration5.replace({
|
|
2607
|
-
widget: new CheckboxWidget(true)
|
|
2608
|
-
});
|
|
2609
|
-
var uncheckedTask = Decoration5.replace({
|
|
2610
|
-
widget: new CheckboxWidget(false)
|
|
2611
|
-
});
|
|
2612
|
-
var editingRange = (state, range, focus) => {
|
|
2613
|
-
const { readOnly, selection: { main: { head } } } = state;
|
|
2614
|
-
return focus && !readOnly && head >= range.from && head <= range.to;
|
|
2615
|
-
};
|
|
2616
|
-
var MarksByParent = /* @__PURE__ */ new Set([
|
|
2617
|
-
"CodeMark",
|
|
2618
|
-
"EmphasisMark",
|
|
2619
|
-
"StrikethroughMark",
|
|
2620
|
-
"SubscriptMark",
|
|
2621
|
-
"SuperscriptMark"
|
|
2622
|
-
]);
|
|
2623
|
-
var buildDecorations = (view, options, focus) => {
|
|
2624
|
-
const deco = new RangeSetBuilder2();
|
|
2625
|
-
const atomicDeco = new RangeSetBuilder2();
|
|
2626
|
-
const { state } = view;
|
|
2627
|
-
for (const { from, to } of view.visibleRanges) {
|
|
2628
|
-
syntaxTree(state).iterate({
|
|
2655
|
+
var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
|
|
2656
|
+
const changes = state2.changeByRange((range) => {
|
|
2657
|
+
let { from, to } = range;
|
|
2658
|
+
const cutStyles = [];
|
|
2659
|
+
let okay = null;
|
|
2660
|
+
syntaxTree(state2).iterate({
|
|
2629
2661
|
from,
|
|
2630
2662
|
to,
|
|
2631
2663
|
enter: (node) => {
|
|
2632
|
-
if (node.name
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
}
|
|
2648
|
-
return false;
|
|
2649
|
-
} else if (node.name === "Link") {
|
|
2650
|
-
const marks = node.node.getChildren("LinkMark");
|
|
2651
|
-
const urlNode = node.node.getChild("URL");
|
|
2652
|
-
const editing = editingRange(state, node, focus);
|
|
2653
|
-
if (urlNode && marks.length >= 2) {
|
|
2654
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2655
|
-
if (!editing) {
|
|
2656
|
-
atomicDeco.add(node.from, marks[0].to, hide);
|
|
2657
|
-
}
|
|
2658
|
-
deco.add(marks[0].to, marks[1].from, Decoration5.mark({
|
|
2659
|
-
tagName: "a",
|
|
2660
|
-
attributes: {
|
|
2661
|
-
class: "cm-link",
|
|
2662
|
-
href: url,
|
|
2663
|
-
rel: "noreferrer",
|
|
2664
|
-
target: "_blank"
|
|
2665
|
-
}
|
|
2666
|
-
}));
|
|
2667
|
-
if (!editing) {
|
|
2668
|
-
atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
|
|
2669
|
-
widget: new LinkButton(url, options.renderLinkButton)
|
|
2670
|
-
}) : hide);
|
|
2664
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2665
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
|
|
2666
|
+
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
2667
|
+
const sNode = node.node;
|
|
2668
|
+
if (node.from < from && node.to <= to) {
|
|
2669
|
+
if (sNode.firstChild.to === from) {
|
|
2670
|
+
from = node.from;
|
|
2671
|
+
} else {
|
|
2672
|
+
cutStyles.push(sNode);
|
|
2673
|
+
}
|
|
2674
|
+
} else if (node.from >= from && node.to > to) {
|
|
2675
|
+
if (sNode.lastChild.from === to) {
|
|
2676
|
+
to = node.to;
|
|
2677
|
+
} else {
|
|
2678
|
+
cutStyles.push(sNode);
|
|
2671
2679
|
}
|
|
2672
|
-
}
|
|
2673
|
-
} else if (node.name === "HeaderMark") {
|
|
2674
|
-
const parent = node.node.parent;
|
|
2675
|
-
if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from), focus)) {
|
|
2676
|
-
const next = state.doc.sliceString(node.to, node.to + 1);
|
|
2677
|
-
atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
|
|
2678
|
-
}
|
|
2679
|
-
} else if (node.name === "HorizontalRule") {
|
|
2680
|
-
if (!editingRange(state, node, focus)) {
|
|
2681
|
-
deco.add(node.from, node.to, horizontalRule);
|
|
2682
|
-
}
|
|
2683
|
-
} else if (node.name === "TaskMarker") {
|
|
2684
|
-
if (!editingRange(state, node, focus)) {
|
|
2685
|
-
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2686
|
-
atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
|
|
2687
|
-
class: "cm-task"
|
|
2688
|
-
}));
|
|
2689
|
-
atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
|
|
2690
|
-
}
|
|
2691
|
-
} else if (MarksByParent.has(node.name)) {
|
|
2692
|
-
if (!editingRange(state, node.node.parent, focus)) {
|
|
2693
|
-
atomicDeco.add(node.from, node.to, hide);
|
|
2694
2680
|
}
|
|
2695
2681
|
}
|
|
2696
2682
|
}
|
|
2697
2683
|
});
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
clearTimeout(this.pendingUpdate);
|
|
2732
|
-
this.pendingUpdate = void 0;
|
|
2684
|
+
if (okay === null) {
|
|
2685
|
+
const line = state2.doc.lineAt(from);
|
|
2686
|
+
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
2687
|
+
}
|
|
2688
|
+
if (!okay) {
|
|
2689
|
+
return {
|
|
2690
|
+
range
|
|
2691
|
+
};
|
|
2692
|
+
}
|
|
2693
|
+
const changes2 = [];
|
|
2694
|
+
const changesAfter = [];
|
|
2695
|
+
removeLinkInner(from, to, changesAfter, state2);
|
|
2696
|
+
let cursorOffset = 1;
|
|
2697
|
+
for (const style of cutStyles) {
|
|
2698
|
+
const type = InlineMarker[style.name];
|
|
2699
|
+
const mark2 = inlineMarkerText(type);
|
|
2700
|
+
if (style.from < from) {
|
|
2701
|
+
changes2.push({
|
|
2702
|
+
from: skipSpaces(from, state2.doc, -1),
|
|
2703
|
+
insert: mark2
|
|
2704
|
+
});
|
|
2705
|
+
changesAfter.push({
|
|
2706
|
+
from: skipSpaces(from, state2.doc, 1, to),
|
|
2707
|
+
insert: mark2
|
|
2708
|
+
});
|
|
2709
|
+
} else {
|
|
2710
|
+
changes2.push({
|
|
2711
|
+
from: skipSpaces(to, state2.doc, -1, from),
|
|
2712
|
+
insert: mark2
|
|
2713
|
+
});
|
|
2714
|
+
const after = skipSpaces(to, state2.doc, 1);
|
|
2715
|
+
if (after === to) {
|
|
2716
|
+
cursorOffset += mark2.length;
|
|
2733
2717
|
}
|
|
2718
|
+
changesAfter.push({
|
|
2719
|
+
from: after,
|
|
2720
|
+
insert: mark2
|
|
2721
|
+
});
|
|
2734
2722
|
}
|
|
2735
|
-
destroy() {
|
|
2736
|
-
this.clearUpdate();
|
|
2737
|
-
}
|
|
2738
|
-
}, {
|
|
2739
|
-
provide: (plugin) => [
|
|
2740
|
-
EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
2741
|
-
EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
2742
|
-
EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
|
|
2743
|
-
]
|
|
2744
|
-
}),
|
|
2745
|
-
formattingStyles
|
|
2746
|
-
];
|
|
2747
|
-
};
|
|
2748
|
-
var formattingStyles = EditorView12.baseTheme({
|
|
2749
|
-
"& .cm-code": {
|
|
2750
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
2751
|
-
},
|
|
2752
|
-
"& .cm-codeblock-line": {
|
|
2753
|
-
paddingInline: "1rem !important"
|
|
2754
|
-
},
|
|
2755
|
-
"& .cm-codeblock-end": {
|
|
2756
|
-
display: "inline-block",
|
|
2757
|
-
width: "100%",
|
|
2758
|
-
position: "relative",
|
|
2759
|
-
"&::after": {
|
|
2760
|
-
position: "absolute",
|
|
2761
|
-
inset: 0,
|
|
2762
|
-
content: '""'
|
|
2763
2723
|
}
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
mixBlendMode: "lighten"
|
|
2780
|
-
},
|
|
2781
|
-
"& .cm-hr": {
|
|
2782
|
-
display: "inline-block",
|
|
2783
|
-
width: "100%",
|
|
2784
|
-
height: "0",
|
|
2785
|
-
verticalAlign: "middle",
|
|
2786
|
-
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2787
|
-
},
|
|
2788
|
-
"& .cm-task": {
|
|
2789
|
-
color: getToken("extend.colors.blue.500")
|
|
2790
|
-
},
|
|
2791
|
-
"& .cm-task-checkbox": {
|
|
2792
|
-
marginLeft: "4px",
|
|
2793
|
-
marginRight: "4px"
|
|
2724
|
+
changes2.push({
|
|
2725
|
+
from,
|
|
2726
|
+
insert: image2 ? "`
|
|
2730
|
+
});
|
|
2731
|
+
const changeSet = state2.changes(changes2.concat(changesAfter));
|
|
2732
|
+
return {
|
|
2733
|
+
changes: changeSet,
|
|
2734
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
|
|
2735
|
+
};
|
|
2736
|
+
});
|
|
2737
|
+
if (changes.changes.empty) {
|
|
2738
|
+
return false;
|
|
2794
2739
|
}
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
var List;
|
|
2812
|
-
(function(List2) {
|
|
2813
|
-
List2[List2["Ordered"] = 0] = "Ordered";
|
|
2814
|
-
List2[List2["Bullet"] = 1] = "Bullet";
|
|
2815
|
-
List2[List2["Task"] = 2] = "Task";
|
|
2816
|
-
})(List || (List = {}));
|
|
2817
|
-
var setHeading = (level) => ({ state, dispatch }) => {
|
|
2818
|
-
const { selection: { ranges }, doc } = state;
|
|
2819
|
-
const changes = [];
|
|
2820
|
-
let prevBlock = -1;
|
|
2821
|
-
for (const range of ranges) {
|
|
2822
|
-
let sawBlock = false;
|
|
2823
|
-
syntaxTree2(state).iterate({
|
|
2824
|
-
from: range.from,
|
|
2825
|
-
to: range.to,
|
|
2740
|
+
dispatch(state2.update(changes, {
|
|
2741
|
+
userEvent: "format.link.add",
|
|
2742
|
+
scrollIntoView: true
|
|
2743
|
+
}));
|
|
2744
|
+
return true;
|
|
2745
|
+
};
|
|
2746
|
+
var addList = (type) => ({ state: state2, dispatch }) => {
|
|
2747
|
+
let lastBlock = -1;
|
|
2748
|
+
let counter = 1;
|
|
2749
|
+
let first = true;
|
|
2750
|
+
let parentColumn = null;
|
|
2751
|
+
const blocks = [];
|
|
2752
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
2753
|
+
syntaxTree(state2).iterate({
|
|
2754
|
+
from,
|
|
2755
|
+
to,
|
|
2826
2756
|
enter: (node) => {
|
|
2827
|
-
if (
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
}
|
|
2851
|
-
changes.push({
|
|
2852
|
-
from: nextLine.from - 1,
|
|
2853
|
-
to: nextLine.to
|
|
2854
|
-
});
|
|
2855
|
-
} else {
|
|
2856
|
-
if (level === 0) {
|
|
2857
|
-
changes.push({
|
|
2858
|
-
from: node.from,
|
|
2859
|
-
to: Math.min(node.to, node.from + curLevel + 1)
|
|
2860
|
-
});
|
|
2861
|
-
} else if (level < curLevel) {
|
|
2862
|
-
changes.push({
|
|
2863
|
-
from: node.from,
|
|
2864
|
-
to: node.from + (curLevel - level)
|
|
2865
|
-
});
|
|
2866
|
-
} else {
|
|
2867
|
-
changes.push({
|
|
2868
|
-
from: node.from,
|
|
2869
|
-
insert: "#".repeat(level - curLevel)
|
|
2870
|
-
});
|
|
2757
|
+
if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
|
|
2758
|
+
if (first) {
|
|
2759
|
+
let before = node.node.prevSibling;
|
|
2760
|
+
while (before && /Mark$/.test(before.name)) {
|
|
2761
|
+
before = before.prevSibling;
|
|
2762
|
+
}
|
|
2763
|
+
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
2764
|
+
const item = before.lastChild;
|
|
2765
|
+
const itemLine = state2.doc.lineAt(item.from);
|
|
2766
|
+
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
2767
|
+
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
2768
|
+
if (type === 0) {
|
|
2769
|
+
const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
|
|
2770
|
+
if (mark2) {
|
|
2771
|
+
parentColumn += mark2[1].length;
|
|
2772
|
+
counter = +mark2[1] + 1;
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
first = false;
|
|
2777
|
+
}
|
|
2778
|
+
if (node.from === lastBlock) {
|
|
2779
|
+
return;
|
|
2871
2780
|
}
|
|
2781
|
+
lastBlock = node.from;
|
|
2782
|
+
blocks.push({
|
|
2783
|
+
node: node.node,
|
|
2784
|
+
counter,
|
|
2785
|
+
parentColumn
|
|
2786
|
+
});
|
|
2787
|
+
counter++;
|
|
2788
|
+
return false;
|
|
2789
|
+
}
|
|
2790
|
+
},
|
|
2791
|
+
leave: (node) => {
|
|
2792
|
+
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
2793
|
+
counter = 1;
|
|
2794
|
+
parentColumn = null;
|
|
2872
2795
|
}
|
|
2873
2796
|
}
|
|
2874
2797
|
});
|
|
2875
|
-
|
|
2876
|
-
|
|
2798
|
+
}
|
|
2799
|
+
if (!blocks.length) {
|
|
2800
|
+
const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
|
|
2801
|
+
if (from === to) {
|
|
2802
|
+
const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
|
|
2803
|
+
dispatch(state2.update({
|
|
2804
|
+
changes: [
|
|
2805
|
+
{
|
|
2806
|
+
from,
|
|
2807
|
+
insert
|
|
2808
|
+
}
|
|
2809
|
+
],
|
|
2810
|
+
selection: {
|
|
2811
|
+
anchor: from + insert.length
|
|
2812
|
+
},
|
|
2813
|
+
userEvent: "format.list.add",
|
|
2814
|
+
scrollIntoView: true
|
|
2815
|
+
}));
|
|
2816
|
+
return true;
|
|
2817
|
+
}
|
|
2818
|
+
return false;
|
|
2819
|
+
}
|
|
2820
|
+
const changes = [];
|
|
2821
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
2822
|
+
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
2823
|
+
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
2824
|
+
let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
2825
|
+
if (type === 0) {
|
|
2826
|
+
padding += String(counter2).length;
|
|
2827
|
+
}
|
|
2828
|
+
let line = state2.doc.lineAt(nodeFrom);
|
|
2829
|
+
const column = nodeFrom - line.from;
|
|
2830
|
+
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
2831
|
+
padding = Math.max(padding, parentColumn2 - column);
|
|
2832
|
+
}
|
|
2833
|
+
let mark2;
|
|
2834
|
+
if (type === 0) {
|
|
2835
|
+
let max = counter2;
|
|
2836
|
+
for (let j = i + 1; j < blocks.length; j++) {
|
|
2837
|
+
if (blocks[j].counter !== max + 1) {
|
|
2838
|
+
break;
|
|
2839
|
+
}
|
|
2840
|
+
max++;
|
|
2841
|
+
}
|
|
2842
|
+
const num = String(counter2);
|
|
2843
|
+
padding = Math.max(String(max).length, padding);
|
|
2844
|
+
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
2845
|
+
} else {
|
|
2846
|
+
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
2847
|
+
}
|
|
2848
|
+
changes.push({
|
|
2849
|
+
from: nodeFrom,
|
|
2850
|
+
insert: mark2
|
|
2851
|
+
});
|
|
2852
|
+
while (line.to < node.to) {
|
|
2853
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
2854
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2877
2855
|
changes.push({
|
|
2878
|
-
from: line.from,
|
|
2879
|
-
|
|
2880
|
-
insert: "#".repeat(level) + " "
|
|
2856
|
+
from: line.from + Math.min(open, column),
|
|
2857
|
+
insert: " ".repeat(mark2.length)
|
|
2881
2858
|
});
|
|
2882
2859
|
}
|
|
2883
2860
|
}
|
|
2884
|
-
if (
|
|
2885
|
-
|
|
2861
|
+
if (type === 0) {
|
|
2862
|
+
const last = blocks[blocks.length - 1];
|
|
2863
|
+
let next = last.node.nextSibling;
|
|
2864
|
+
while (next && /Mark$/.test(next.name)) {
|
|
2865
|
+
next = next.nextSibling;
|
|
2866
|
+
}
|
|
2867
|
+
if (next?.name === "OrderedList") {
|
|
2868
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
|
|
2869
|
+
}
|
|
2886
2870
|
}
|
|
2887
|
-
const changeSet =
|
|
2888
|
-
dispatch(
|
|
2871
|
+
const changeSet = state2.changes(changes);
|
|
2872
|
+
dispatch(state2.update({
|
|
2889
2873
|
changes: changeSet,
|
|
2890
|
-
selection:
|
|
2891
|
-
userEvent: "format.
|
|
2874
|
+
selection: state2.selection.map(changeSet, 1),
|
|
2875
|
+
userEvent: "format.list.add",
|
|
2892
2876
|
scrollIntoView: true
|
|
2893
2877
|
}));
|
|
2894
2878
|
return true;
|
|
2895
2879
|
};
|
|
2896
|
-
var
|
|
2897
|
-
|
|
2898
|
-
const changes =
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
2904
|
-
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
2905
|
-
...before.slice(before.length - found)
|
|
2906
|
-
].reverse().join("") === after.slice(0, found)) {
|
|
2907
|
-
return {
|
|
2908
|
-
changes: [
|
|
2909
|
-
{
|
|
2910
|
-
from: range.head - marker.length - found,
|
|
2911
|
-
to: range.head - found
|
|
2912
|
-
},
|
|
2913
|
-
{
|
|
2914
|
-
from: range.head + found,
|
|
2915
|
-
to: range.head + found + marker.length
|
|
2916
|
-
}
|
|
2917
|
-
],
|
|
2918
|
-
range: EditorSelection.cursor(range.from - marker.length)
|
|
2919
|
-
};
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
const changes2 = [];
|
|
2924
|
-
const changesAtEnd = [];
|
|
2925
|
-
let blockStart = -1;
|
|
2926
|
-
let blockEnd = -1;
|
|
2927
|
-
let startCovered = false;
|
|
2928
|
-
let endCovered = false;
|
|
2929
|
-
let { from, to } = range;
|
|
2930
|
-
syntaxTree2(state).iterate({
|
|
2880
|
+
var removeList = (type) => ({ state: state2, dispatch }) => {
|
|
2881
|
+
let lastBlock = -1;
|
|
2882
|
+
const changes = [];
|
|
2883
|
+
const stack = [];
|
|
2884
|
+
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
2885
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
2886
|
+
syntaxTree(state2).iterate({
|
|
2931
2887
|
from,
|
|
2932
2888
|
to,
|
|
2933
2889
|
enter: (node) => {
|
|
2934
2890
|
const { name } = node;
|
|
2935
|
-
if (
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
} else if (name === "Link" || name === "Image" && enable) {
|
|
2940
|
-
if (from < node.from && to > node.from && to <= node.to) {
|
|
2941
|
-
to = node.to;
|
|
2942
|
-
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
2943
|
-
from = node.from;
|
|
2944
|
-
}
|
|
2945
|
-
} else if (IgnoreInline.has(name) && enable) {
|
|
2946
|
-
if (node.from < from && node.to > from) {
|
|
2947
|
-
if (to === from) {
|
|
2948
|
-
to = node.to;
|
|
2949
|
-
}
|
|
2950
|
-
from = node.to;
|
|
2951
|
-
}
|
|
2952
|
-
if (node.from < to && node.to > to) {
|
|
2953
|
-
to = node.from;
|
|
2954
|
-
}
|
|
2955
|
-
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
2956
|
-
const markType = InlineMarker[name];
|
|
2957
|
-
const size = inlineMarkerText(markType).length;
|
|
2958
|
-
const openEnd = node.from + size;
|
|
2959
|
-
const closeStart = node.to - size;
|
|
2960
|
-
if (markType === type) {
|
|
2961
|
-
if (openEnd <= from && closeStart >= from) {
|
|
2962
|
-
startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
|
|
2963
|
-
from: node.from,
|
|
2964
|
-
to: openEnd
|
|
2965
|
-
} : true;
|
|
2966
|
-
}
|
|
2967
|
-
if (openEnd <= to && closeStart >= to) {
|
|
2968
|
-
endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
|
|
2969
|
-
from: closeStart,
|
|
2970
|
-
to: node.to
|
|
2971
|
-
} : true;
|
|
2972
|
-
}
|
|
2973
|
-
}
|
|
2974
|
-
if (markType === type || type === 3 && enable) {
|
|
2975
|
-
if (node.from >= from && openEnd <= to) {
|
|
2976
|
-
changes2.push({
|
|
2977
|
-
from: node.from,
|
|
2978
|
-
to: openEnd
|
|
2979
|
-
});
|
|
2980
|
-
if (markType !== type && closeStart >= to) {
|
|
2981
|
-
changesAtEnd.push({
|
|
2982
|
-
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2983
|
-
insert: inlineMarkerText(markType)
|
|
2984
|
-
});
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
if (closeStart >= from && node.to <= to) {
|
|
2988
|
-
changes2.push({
|
|
2989
|
-
from: closeStart,
|
|
2990
|
-
to: node.to
|
|
2991
|
-
});
|
|
2992
|
-
if (markType !== type && openEnd <= from) {
|
|
2993
|
-
changes2.push({
|
|
2994
|
-
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2995
|
-
insert: inlineMarkerText(markType)
|
|
2996
|
-
});
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
2891
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2892
|
+
stack.push(name);
|
|
2893
|
+
} else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2894
|
+
stack[stack.length - 1] = "TaskList";
|
|
3000
2895
|
}
|
|
3001
2896
|
},
|
|
3002
2897
|
leave: (node) => {
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
insert: marker
|
|
3026
|
-
});
|
|
3027
|
-
}
|
|
3028
|
-
if (typeof endCovered === "object") {
|
|
3029
|
-
changes2.push(endCovered);
|
|
3030
|
-
} else if (endCovered) {
|
|
3031
|
-
changes2.push({
|
|
3032
|
-
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
3033
|
-
insert: marker
|
|
2898
|
+
const { name } = node;
|
|
2899
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2900
|
+
stack.pop();
|
|
2901
|
+
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
2902
|
+
lastBlock = node.from;
|
|
2903
|
+
let line = state2.doc.lineAt(node.from);
|
|
2904
|
+
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
2905
|
+
if (!mark2) {
|
|
2906
|
+
return false;
|
|
2907
|
+
}
|
|
2908
|
+
const column = node.from - line.from;
|
|
2909
|
+
changes.push({
|
|
2910
|
+
from: node.from,
|
|
2911
|
+
to: node.from + mark2[0].length
|
|
2912
|
+
});
|
|
2913
|
+
while (line.to < node.to) {
|
|
2914
|
+
line = state2.doc.lineAt(line.to + 1);
|
|
2915
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2916
|
+
if (open > column) {
|
|
2917
|
+
changes.push({
|
|
2918
|
+
from: line.from + column,
|
|
2919
|
+
to: line.from + Math.min(column + mark2[0].length, open)
|
|
3034
2920
|
});
|
|
3035
2921
|
}
|
|
3036
2922
|
}
|
|
2923
|
+
if (node.to >= to) {
|
|
2924
|
+
renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
|
|
2925
|
+
}
|
|
2926
|
+
return false;
|
|
3037
2927
|
}
|
|
3038
2928
|
}
|
|
3039
2929
|
});
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
};
|
|
3048
|
-
}
|
|
3049
|
-
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
3050
|
-
return {
|
|
3051
|
-
changes: changeSet,
|
|
3052
|
-
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
3053
|
-
};
|
|
3054
|
-
});
|
|
3055
|
-
dispatch(state.update(changes, {
|
|
3056
|
-
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2930
|
+
}
|
|
2931
|
+
if (!changes.length) {
|
|
2932
|
+
return false;
|
|
2933
|
+
}
|
|
2934
|
+
dispatch(state2.update({
|
|
2935
|
+
changes,
|
|
2936
|
+
userEvent: "format.list.remove",
|
|
3057
2937
|
scrollIntoView: true
|
|
3058
2938
|
}));
|
|
3059
2939
|
return true;
|
|
3060
2940
|
};
|
|
3061
|
-
var
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
3066
|
-
};
|
|
3067
|
-
var toggleStrong = toggleStyle(0);
|
|
3068
|
-
var toggleEmphasis = toggleStyle(1);
|
|
3069
|
-
var toggleStrikethrough = toggleStyle(2);
|
|
3070
|
-
var toggleInlineCode = toggleStyle(3);
|
|
3071
|
-
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
3072
|
-
var blockContentStart = (node) => {
|
|
3073
|
-
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
3074
|
-
if (atx) {
|
|
3075
|
-
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
3076
|
-
}
|
|
3077
|
-
return node.from;
|
|
3078
|
-
};
|
|
3079
|
-
var blockContentEnd = (node, doc) => {
|
|
3080
|
-
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
3081
|
-
const lastLine = doc.lineAt(node.to);
|
|
3082
|
-
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
3083
|
-
return lastLine.from - 1;
|
|
3084
|
-
}
|
|
3085
|
-
return node.to;
|
|
3086
|
-
};
|
|
3087
|
-
var skipSpaces = (pos, doc, dir, limit) => {
|
|
3088
|
-
const line = doc.lineAt(pos);
|
|
3089
|
-
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
3090
|
-
pos += dir;
|
|
3091
|
-
}
|
|
3092
|
-
return pos;
|
|
2941
|
+
var toggleList = (type) => (target) => {
|
|
2942
|
+
const formatting = getFormatting(target.state);
|
|
2943
|
+
const active = formatting.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
|
|
2944
|
+
return (active ? removeList(type) : addList(type))(target);
|
|
3093
2945
|
};
|
|
3094
|
-
var
|
|
3095
|
-
for (; ; ) {
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
2946
|
+
var renumberListItems = (item, counter, changes, doc) => {
|
|
2947
|
+
for (; item; item = item.nextSibling) {
|
|
2948
|
+
if (item.name === "ListItem") {
|
|
2949
|
+
const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
|
|
2950
|
+
if (!number || +number[2] === counter) {
|
|
2951
|
+
break;
|
|
2952
|
+
}
|
|
2953
|
+
const size = number[1].length + number[2].length;
|
|
2954
|
+
const newNum = String(counter);
|
|
2955
|
+
changes.push({
|
|
2956
|
+
from: item.from + Math.max(0, size - newNum.length),
|
|
2957
|
+
to: item.from + size,
|
|
2958
|
+
insert: newNum
|
|
2959
|
+
});
|
|
2960
|
+
counter++;
|
|
3103
2961
|
}
|
|
3104
|
-
pos = moveTo;
|
|
3105
2962
|
}
|
|
3106
2963
|
};
|
|
3107
|
-
var
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
"| #{val3} | #{val4} |",
|
|
3120
|
-
""
|
|
3121
|
-
].join("\n"))
|
|
3122
|
-
};
|
|
3123
|
-
var insertTable = (view) => {
|
|
3124
|
-
const { selection: { main }, doc } = view.state;
|
|
3125
|
-
const { number } = doc.lineAt(main.anchor);
|
|
3126
|
-
const { from } = doc.line(number);
|
|
3127
|
-
snippets.table(view, null, from, from);
|
|
3128
|
-
};
|
|
3129
|
-
var removeLinkInner = (from, to, changes, state) => {
|
|
3130
|
-
syntaxTree2(state).iterate({
|
|
3131
|
-
from,
|
|
3132
|
-
to,
|
|
3133
|
-
enter: (node) => {
|
|
3134
|
-
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
3135
|
-
node.node.cursor().iterate((node2) => {
|
|
3136
|
-
const { name } = node2;
|
|
3137
|
-
if (name === "LinkMark" || name === "LinkLabel") {
|
|
3138
|
-
changes.push({
|
|
3139
|
-
from: node2.from,
|
|
3140
|
-
to: node2.to
|
|
3141
|
-
});
|
|
3142
|
-
} else if (name === "LinkTitle" || name === "URL") {
|
|
3143
|
-
changes.push({
|
|
3144
|
-
from: skipSpaces(node2.from, state.doc, -1),
|
|
3145
|
-
to: skipSpaces(node2.to, state.doc, 1)
|
|
3146
|
-
});
|
|
2964
|
+
var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
|
|
2965
|
+
const lines = [];
|
|
2966
|
+
let lastBlock = -1;
|
|
2967
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
2968
|
+
const sawBlock = false;
|
|
2969
|
+
syntaxTree(state2).iterate({
|
|
2970
|
+
from,
|
|
2971
|
+
to,
|
|
2972
|
+
enter: (node) => {
|
|
2973
|
+
if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
|
|
2974
|
+
if (node.from === lastBlock) {
|
|
2975
|
+
return false;
|
|
3147
2976
|
}
|
|
3148
|
-
|
|
3149
|
-
|
|
2977
|
+
lastBlock = node.from;
|
|
2978
|
+
let line2 = state2.doc.lineAt(node.from);
|
|
2979
|
+
if (line2.number > 1) {
|
|
2980
|
+
const prevLine = state2.doc.line(line2.number - 1);
|
|
2981
|
+
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2982
|
+
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2983
|
+
lines.push(prevLine);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
for (; ; ) {
|
|
2988
|
+
lines.push(line2);
|
|
2989
|
+
if (line2.to >= node.to) {
|
|
2990
|
+
break;
|
|
2991
|
+
}
|
|
2992
|
+
line2 = state2.doc.line(line2.number + 1);
|
|
2993
|
+
}
|
|
2994
|
+
if (!enable && line2.number < state2.doc.lines) {
|
|
2995
|
+
const nextLine = state2.doc.line(line2.number + 1);
|
|
2996
|
+
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2997
|
+
lines.push(nextLine);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
return false;
|
|
3001
|
+
}
|
|
3150
3002
|
}
|
|
3003
|
+
});
|
|
3004
|
+
let line;
|
|
3005
|
+
if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
|
|
3006
|
+
lines.push(line);
|
|
3151
3007
|
}
|
|
3152
|
-
}
|
|
3153
|
-
};
|
|
3154
|
-
var removeLink = ({ state, dispatch }) => {
|
|
3008
|
+
}
|
|
3155
3009
|
const changes = [];
|
|
3156
|
-
for (const
|
|
3157
|
-
|
|
3010
|
+
for (const line of lines) {
|
|
3011
|
+
if (enable) {
|
|
3012
|
+
changes.push({
|
|
3013
|
+
from: line.from,
|
|
3014
|
+
insert: /\S/.test(line.text) ? "> " : ">"
|
|
3015
|
+
});
|
|
3016
|
+
} else {
|
|
3017
|
+
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
3018
|
+
if (quote) {
|
|
3019
|
+
changes.push({
|
|
3020
|
+
from: line.from + quote[1].length,
|
|
3021
|
+
to: line.from + quote[0].length
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3158
3025
|
}
|
|
3159
|
-
if (!changes) {
|
|
3026
|
+
if (!changes.length) {
|
|
3160
3027
|
return false;
|
|
3161
3028
|
}
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3029
|
+
const changeSet = state2.changes(changes);
|
|
3030
|
+
dispatch(state2.update({
|
|
3031
|
+
changes: changeSet,
|
|
3032
|
+
selection: state2.selection.map(changeSet, 1),
|
|
3033
|
+
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
3165
3034
|
scrollIntoView: true
|
|
3166
3035
|
}));
|
|
3167
3036
|
return true;
|
|
3168
3037
|
};
|
|
3169
|
-
var
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3038
|
+
var addBlockquote = setBlockquote(true);
|
|
3039
|
+
var removeBlockquote = setBlockquote(false);
|
|
3040
|
+
var toggleBlockquote = (target) => {
|
|
3041
|
+
return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
|
|
3042
|
+
};
|
|
3043
|
+
var addCodeblock = (target) => {
|
|
3044
|
+
const { state: state2, dispatch } = target;
|
|
3045
|
+
const { selection } = state2;
|
|
3046
|
+
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
3047
|
+
const { head } = selection.main;
|
|
3048
|
+
const line = state2.doc.lineAt(head);
|
|
3049
|
+
if (!/\S/.test(line.text) && head === line.from) {
|
|
3050
|
+
snippets.codeblock(target, null, line.from, line.to);
|
|
3051
|
+
return true;
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
const ranges = [];
|
|
3055
|
+
for (const { from, to } of selection.ranges) {
|
|
3056
|
+
let blockFrom = from;
|
|
3057
|
+
let blockTo = to;
|
|
3058
|
+
syntaxTree(state2).iterate({
|
|
3175
3059
|
from,
|
|
3176
3060
|
to,
|
|
3177
3061
|
enter: (node) => {
|
|
3178
3062
|
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
} else {
|
|
3186
|
-
cutStyles.push(sNode);
|
|
3187
|
-
}
|
|
3188
|
-
} else if (node.from >= from && node.to > to) {
|
|
3189
|
-
if (sNode.lastChild.from === to) {
|
|
3190
|
-
to = node.to;
|
|
3191
|
-
} else {
|
|
3192
|
-
cutStyles.push(sNode);
|
|
3193
|
-
}
|
|
3063
|
+
if (from >= node.from && to <= node.to) {
|
|
3064
|
+
blockFrom = node.from;
|
|
3065
|
+
blockTo = node.to;
|
|
3066
|
+
} else {
|
|
3067
|
+
blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
|
|
3068
|
+
blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
|
|
3194
3069
|
}
|
|
3195
3070
|
}
|
|
3196
3071
|
}
|
|
3197
3072
|
});
|
|
3198
|
-
if (
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
};
|
|
3206
|
-
}
|
|
3207
|
-
const changes2 = [];
|
|
3208
|
-
const changesAfter = [];
|
|
3209
|
-
removeLinkInner(from, to, changesAfter, state);
|
|
3210
|
-
let cursorOffset = 1;
|
|
3211
|
-
for (const style of cutStyles) {
|
|
3212
|
-
const type = InlineMarker[style.name];
|
|
3213
|
-
const mark2 = inlineMarkerText(type);
|
|
3214
|
-
if (style.from < from) {
|
|
3215
|
-
changes2.push({
|
|
3216
|
-
from: skipSpaces(from, state.doc, -1),
|
|
3217
|
-
insert: mark2
|
|
3218
|
-
});
|
|
3219
|
-
changesAfter.push({
|
|
3220
|
-
from: skipSpaces(from, state.doc, 1, to),
|
|
3221
|
-
insert: mark2
|
|
3222
|
-
});
|
|
3223
|
-
} else {
|
|
3224
|
-
changes2.push({
|
|
3225
|
-
from: skipSpaces(to, state.doc, -1, from),
|
|
3226
|
-
insert: mark2
|
|
3227
|
-
});
|
|
3228
|
-
const after = skipSpaces(to, state.doc, 1);
|
|
3229
|
-
if (after === to) {
|
|
3230
|
-
cursorOffset += mark2.length;
|
|
3231
|
-
}
|
|
3232
|
-
changesAfter.push({
|
|
3233
|
-
from: after,
|
|
3234
|
-
insert: mark2
|
|
3235
|
-
});
|
|
3236
|
-
}
|
|
3073
|
+
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
3074
|
+
ranges[ranges.length - 1].to = blockTo;
|
|
3075
|
+
} else {
|
|
3076
|
+
ranges.push({
|
|
3077
|
+
from: blockFrom,
|
|
3078
|
+
to: blockTo
|
|
3079
|
+
});
|
|
3237
3080
|
}
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3081
|
+
}
|
|
3082
|
+
if (!ranges.length) {
|
|
3083
|
+
return false;
|
|
3084
|
+
}
|
|
3085
|
+
const changes = ranges.map(({ from, to }) => {
|
|
3086
|
+
const column = from - state2.doc.lineAt(from).from;
|
|
3087
|
+
return [
|
|
3088
|
+
{
|
|
3089
|
+
from,
|
|
3090
|
+
insert: "```\n" + " ".repeat(column)
|
|
3091
|
+
},
|
|
3092
|
+
{
|
|
3093
|
+
from: to,
|
|
3094
|
+
insert: "\n" + " ".repeat(column) + "```"
|
|
3095
|
+
}
|
|
3096
|
+
];
|
|
3250
3097
|
});
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
dispatch(state.update(changes, {
|
|
3255
|
-
userEvent: "format.link.add",
|
|
3098
|
+
dispatch(state2.update({
|
|
3099
|
+
changes,
|
|
3100
|
+
userEvent: "format.codeblock.add",
|
|
3256
3101
|
scrollIntoView: true
|
|
3257
3102
|
}));
|
|
3258
3103
|
return true;
|
|
3259
3104
|
};
|
|
3260
|
-
var
|
|
3105
|
+
var removeCodeblock = ({ state: state2, dispatch }) => {
|
|
3106
|
+
const changes = [];
|
|
3261
3107
|
let lastBlock = -1;
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
let parentColumn = null;
|
|
3265
|
-
const blocks = [];
|
|
3266
|
-
for (const { from, to } of state.selection.ranges) {
|
|
3267
|
-
syntaxTree2(state).iterate({
|
|
3108
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3109
|
+
syntaxTree(state2).iterate({
|
|
3268
3110
|
from,
|
|
3269
3111
|
to,
|
|
3270
3112
|
enter: (node) => {
|
|
3271
|
-
if (
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3113
|
+
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
3114
|
+
lastBlock = node.from;
|
|
3115
|
+
const firstLine = state2.doc.lineAt(node.from);
|
|
3116
|
+
if (node.name === "FencedCode") {
|
|
3117
|
+
changes.push({
|
|
3118
|
+
from: node.from,
|
|
3119
|
+
to: firstLine.to + 1 + node.from - firstLine.from
|
|
3120
|
+
});
|
|
3121
|
+
const lastLine = state2.doc.lineAt(node.to);
|
|
3122
|
+
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
3123
|
+
changes.push({
|
|
3124
|
+
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
3125
|
+
to: lastLine.to
|
|
3126
|
+
});
|
|
3276
3127
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
counter = +mark2[1] + 1;
|
|
3287
|
-
}
|
|
3128
|
+
} else {
|
|
3129
|
+
const column = node.from - firstLine.from;
|
|
3130
|
+
for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
|
|
3131
|
+
changes.push({
|
|
3132
|
+
from: line.from + column - 4,
|
|
3133
|
+
to: line.from + column
|
|
3134
|
+
});
|
|
3135
|
+
if (line.to >= node.to) {
|
|
3136
|
+
break;
|
|
3288
3137
|
}
|
|
3289
3138
|
}
|
|
3290
|
-
first = false;
|
|
3291
|
-
}
|
|
3292
|
-
if (node.from === lastBlock) {
|
|
3293
|
-
return;
|
|
3294
3139
|
}
|
|
3295
|
-
lastBlock = node.from;
|
|
3296
|
-
blocks.push({
|
|
3297
|
-
node: node.node,
|
|
3298
|
-
counter,
|
|
3299
|
-
parentColumn
|
|
3300
|
-
});
|
|
3301
|
-
counter++;
|
|
3302
|
-
return false;
|
|
3303
|
-
}
|
|
3304
|
-
},
|
|
3305
|
-
leave: (node) => {
|
|
3306
|
-
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
3307
|
-
counter = 1;
|
|
3308
|
-
parentColumn = null;
|
|
3309
3140
|
}
|
|
3310
3141
|
}
|
|
3311
3142
|
});
|
|
3312
3143
|
}
|
|
3313
|
-
if (!
|
|
3314
|
-
const { from, to } = state.doc.lineAt(state.selection.main.anchor);
|
|
3315
|
-
if (from === to) {
|
|
3316
|
-
const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
|
|
3317
|
-
dispatch(state.update({
|
|
3318
|
-
changes: [
|
|
3319
|
-
{
|
|
3320
|
-
from,
|
|
3321
|
-
insert
|
|
3322
|
-
}
|
|
3323
|
-
],
|
|
3324
|
-
selection: {
|
|
3325
|
-
anchor: from + insert.length
|
|
3326
|
-
},
|
|
3327
|
-
userEvent: "format.list.add",
|
|
3328
|
-
scrollIntoView: true
|
|
3329
|
-
}));
|
|
3330
|
-
return true;
|
|
3331
|
-
}
|
|
3144
|
+
if (!changes.length) {
|
|
3332
3145
|
return false;
|
|
3333
3146
|
}
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3147
|
+
dispatch(state2.update({
|
|
3148
|
+
changes,
|
|
3149
|
+
userEvent: "format.codeblock.remove",
|
|
3150
|
+
scrollIntoView: true
|
|
3151
|
+
}));
|
|
3152
|
+
return true;
|
|
3153
|
+
};
|
|
3154
|
+
var toggleCodeblock = (target) => {
|
|
3155
|
+
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
3156
|
+
};
|
|
3157
|
+
var formattingKeymap = (options = {}) => {
|
|
3158
|
+
return [
|
|
3159
|
+
keymap6.of([
|
|
3160
|
+
{
|
|
3161
|
+
key: "meta-b",
|
|
3162
|
+
run: toggleStrong
|
|
3163
|
+
}
|
|
3164
|
+
])
|
|
3165
|
+
];
|
|
3166
|
+
};
|
|
3167
|
+
var InlineMarker = {
|
|
3168
|
+
Emphasis: 1,
|
|
3169
|
+
StrongEmphasis: 0,
|
|
3170
|
+
InlineCode: 3,
|
|
3171
|
+
Strikethrough: 2
|
|
3172
|
+
};
|
|
3173
|
+
var IgnoreInline = /* @__PURE__ */ new Set([
|
|
3174
|
+
"Autolink",
|
|
3175
|
+
"CodeMark",
|
|
3176
|
+
"CodeText",
|
|
3177
|
+
"Comment",
|
|
3178
|
+
"EmphasisMark",
|
|
3179
|
+
"Hardbreak",
|
|
3180
|
+
"HeaderMark",
|
|
3181
|
+
"HTMLTag",
|
|
3182
|
+
"LinkMark",
|
|
3183
|
+
"ListMark",
|
|
3184
|
+
"ProcessingInstruction",
|
|
3185
|
+
"QuoteMark",
|
|
3186
|
+
"StrikethroughMark",
|
|
3187
|
+
"SubscriptMark",
|
|
3188
|
+
"SuperscriptMark",
|
|
3189
|
+
"TaskMarker"
|
|
3190
|
+
]);
|
|
3191
|
+
var Textblocks = {
|
|
3192
|
+
ATXHeading1: "heading1",
|
|
3193
|
+
ATXHeading2: "heading2",
|
|
3194
|
+
ATXHeading3: "heading3",
|
|
3195
|
+
ATXHeading4: "heading4",
|
|
3196
|
+
ATXHeading5: "heading5",
|
|
3197
|
+
ATXHeading6: "heading6",
|
|
3198
|
+
CodeBlock: "codeblock",
|
|
3199
|
+
FencedCode: "codeblock",
|
|
3200
|
+
Paragraph: "paragraph",
|
|
3201
|
+
SetextHeading1: "heading1",
|
|
3202
|
+
SetextHeading2: "heading2",
|
|
3203
|
+
TableCell: "tablecell",
|
|
3204
|
+
Task: "paragraph"
|
|
3205
|
+
};
|
|
3206
|
+
var getFormatting = (state2) => {
|
|
3207
|
+
let blockType = null;
|
|
3208
|
+
const inline = [
|
|
3209
|
+
null,
|
|
3210
|
+
null,
|
|
3211
|
+
null,
|
|
3212
|
+
null
|
|
3213
|
+
];
|
|
3214
|
+
let link = false;
|
|
3215
|
+
let blockQuote = null;
|
|
3216
|
+
let listStyle = null;
|
|
3217
|
+
const stack = [];
|
|
3218
|
+
let currentBlock = null;
|
|
3219
|
+
const advanceInline = (upto) => {
|
|
3220
|
+
if (!currentBlock) {
|
|
3221
|
+
return;
|
|
3341
3222
|
}
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
padding = Math.max(padding, parentColumn2 - column);
|
|
3223
|
+
upto = Math.min(upto, currentBlock.end);
|
|
3224
|
+
if (upto <= currentBlock.pos) {
|
|
3225
|
+
return;
|
|
3346
3226
|
}
|
|
3347
|
-
let
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
max++;
|
|
3227
|
+
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
3228
|
+
if (inline[i] === false) {
|
|
3229
|
+
continue;
|
|
3230
|
+
} else if (currentBlock.active[i]) {
|
|
3231
|
+
inline[i] = true;
|
|
3232
|
+
} else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
|
|
3233
|
+
inline[i] = false;
|
|
3355
3234
|
}
|
|
3356
|
-
const num = String(counter2);
|
|
3357
|
-
padding = Math.max(String(max).length, padding);
|
|
3358
|
-
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
3359
|
-
} else {
|
|
3360
|
-
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
3361
|
-
}
|
|
3362
|
-
changes.push({
|
|
3363
|
-
from: nodeFrom,
|
|
3364
|
-
insert: mark2
|
|
3365
|
-
});
|
|
3366
|
-
while (line.to < node.to) {
|
|
3367
|
-
line = state.doc.lineAt(line.to + 1);
|
|
3368
|
-
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3369
|
-
changes.push({
|
|
3370
|
-
from: line.from + Math.min(open, column),
|
|
3371
|
-
insert: " ".repeat(mark2.length)
|
|
3372
|
-
});
|
|
3373
3235
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
next = next.nextSibling;
|
|
3236
|
+
currentBlock.pos = upto;
|
|
3237
|
+
};
|
|
3238
|
+
const skipInline = (upto) => {
|
|
3239
|
+
if (currentBlock && upto > currentBlock.pos) {
|
|
3240
|
+
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
3380
3241
|
}
|
|
3381
|
-
|
|
3382
|
-
|
|
3242
|
+
};
|
|
3243
|
+
const { selection } = state2;
|
|
3244
|
+
for (const range of selection.ranges) {
|
|
3245
|
+
if (range.empty && inline.some((v) => v === null)) {
|
|
3246
|
+
const contextSize = Math.min(range.head, 6);
|
|
3247
|
+
const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
|
|
3248
|
+
let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
|
|
3249
|
+
for (let i = 0; i < contextSize; i++) {
|
|
3250
|
+
const ch = contextAfter[i];
|
|
3251
|
+
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
3252
|
+
contextAfter = contextAfter.slice(0, i);
|
|
3253
|
+
break;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
for (let i = 0; i < inline.length; i++) {
|
|
3257
|
+
const mark2 = inlineMarkerText(i);
|
|
3258
|
+
const found = contextAfter.indexOf(mark2);
|
|
3259
|
+
if (found > -1) {
|
|
3260
|
+
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
3261
|
+
if (inline[i] === null) {
|
|
3262
|
+
inline[i] = true;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3383
3266
|
}
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
changes: changeSet,
|
|
3388
|
-
selection: state.selection.map(changeSet, 1),
|
|
3389
|
-
userEvent: "format.list.add",
|
|
3390
|
-
scrollIntoView: true
|
|
3391
|
-
}));
|
|
3392
|
-
return true;
|
|
3393
|
-
};
|
|
3394
|
-
var removeList = (type) => ({ state, dispatch }) => {
|
|
3395
|
-
let lastBlock = -1;
|
|
3396
|
-
const changes = [];
|
|
3397
|
-
const stack = [];
|
|
3398
|
-
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
3399
|
-
for (const { from, to } of state.selection.ranges) {
|
|
3400
|
-
syntaxTree2(state).iterate({
|
|
3401
|
-
from,
|
|
3402
|
-
to,
|
|
3267
|
+
syntaxTree(state2).iterate({
|
|
3268
|
+
from: range.from,
|
|
3269
|
+
to: range.to,
|
|
3403
3270
|
enter: (node) => {
|
|
3271
|
+
advanceInline(node.from);
|
|
3404
3272
|
const { name } = node;
|
|
3405
3273
|
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
3406
3274
|
stack.push(name);
|
|
3407
|
-
} else if (name === "
|
|
3408
|
-
|
|
3275
|
+
} else if (name === "Link") {
|
|
3276
|
+
link = true;
|
|
3277
|
+
} else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
|
|
3278
|
+
if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
3279
|
+
stack[stack.length - 1] = "TaskList";
|
|
3280
|
+
}
|
|
3281
|
+
const blockCode = Textblocks[name];
|
|
3282
|
+
if (blockType === null) {
|
|
3283
|
+
blockType = blockCode;
|
|
3284
|
+
} else if (blockType !== blockCode) {
|
|
3285
|
+
blockType = false;
|
|
3286
|
+
}
|
|
3287
|
+
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
3288
|
+
currentBlock = {
|
|
3289
|
+
pos: Math.max(range.from, node.from),
|
|
3290
|
+
end: Math.min(range.to, node.to),
|
|
3291
|
+
active: [
|
|
3292
|
+
false,
|
|
3293
|
+
false,
|
|
3294
|
+
false,
|
|
3295
|
+
false
|
|
3296
|
+
]
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3300
|
+
const index = InlineMarker[name];
|
|
3301
|
+
if (range.empty && inline[index] === null) {
|
|
3302
|
+
inline[index] = true;
|
|
3303
|
+
}
|
|
3304
|
+
currentBlock.active[index] = true;
|
|
3305
|
+
} else if (IgnoreInline.has(name)) {
|
|
3306
|
+
skipInline(node.to);
|
|
3409
3307
|
}
|
|
3410
3308
|
},
|
|
3411
3309
|
leave: (node) => {
|
|
3310
|
+
advanceInline(node.to);
|
|
3412
3311
|
const { name } = node;
|
|
3413
3312
|
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
3414
3313
|
stack.pop();
|
|
3415
|
-
} else if (
|
|
3416
|
-
|
|
3417
|
-
let
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
changes.push({
|
|
3424
|
-
from: node.from,
|
|
3425
|
-
to: node.from + mark2[0].length
|
|
3426
|
-
});
|
|
3427
|
-
while (line.to < node.to) {
|
|
3428
|
-
line = state.doc.lineAt(line.to + 1);
|
|
3429
|
-
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3430
|
-
if (open > column) {
|
|
3431
|
-
changes.push({
|
|
3432
|
-
from: line.from + column,
|
|
3433
|
-
to: line.from + Math.min(column + mark2[0].length, open)
|
|
3434
|
-
});
|
|
3314
|
+
} else if (Object.hasOwn(Textblocks, name)) {
|
|
3315
|
+
let hasList = false;
|
|
3316
|
+
let hasQuote = false;
|
|
3317
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
3318
|
+
if (stack[i] === "Blockquote") {
|
|
3319
|
+
hasQuote = true;
|
|
3320
|
+
} else if (!hasList) {
|
|
3321
|
+
hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
|
|
3435
3322
|
}
|
|
3436
3323
|
}
|
|
3437
|
-
if (
|
|
3438
|
-
|
|
3324
|
+
if (blockQuote === null) {
|
|
3325
|
+
blockQuote = hasQuote;
|
|
3326
|
+
} else if (!hasQuote && blockQuote) {
|
|
3327
|
+
blockQuote = false;
|
|
3439
3328
|
}
|
|
3440
|
-
|
|
3329
|
+
if (listStyle === null) {
|
|
3330
|
+
listStyle = hasList;
|
|
3331
|
+
} else if (listStyle !== hasList) {
|
|
3332
|
+
listStyle = false;
|
|
3333
|
+
}
|
|
3334
|
+
currentBlock = null;
|
|
3335
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3336
|
+
currentBlock.active[InlineMarker[name]] = false;
|
|
3441
3337
|
}
|
|
3442
3338
|
}
|
|
3443
3339
|
});
|
|
3444
3340
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
return (active ? removeList(type) : addList(type))(target);
|
|
3341
|
+
const { from, to } = state2.doc.lineAt(selection.main.anchor);
|
|
3342
|
+
const blankLine = from === to;
|
|
3343
|
+
return {
|
|
3344
|
+
blankLine,
|
|
3345
|
+
blockType: blockType || null,
|
|
3346
|
+
blockQuote: blockQuote ?? false,
|
|
3347
|
+
code: inline[3] ?? false,
|
|
3348
|
+
emphasis: inline[1] ?? false,
|
|
3349
|
+
strong: inline[0] ?? false,
|
|
3350
|
+
strikethrough: inline[2] ?? false,
|
|
3351
|
+
link,
|
|
3352
|
+
listStyle: listStyle || null
|
|
3353
|
+
};
|
|
3459
3354
|
};
|
|
3460
|
-
var
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
from: item.from + Math.max(0, size - newNum.length),
|
|
3471
|
-
to: item.from + size,
|
|
3472
|
-
insert: newNum
|
|
3355
|
+
var useFormattingState = () => {
|
|
3356
|
+
const [state2, setState] = useState();
|
|
3357
|
+
const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
|
|
3358
|
+
if (update2.docChanged || update2.selectionSet) {
|
|
3359
|
+
setState((prevState) => {
|
|
3360
|
+
const newState = getFormatting(update2.state);
|
|
3361
|
+
if (!prevState || !formattingEquals(prevState, newState)) {
|
|
3362
|
+
return newState;
|
|
3363
|
+
}
|
|
3364
|
+
return prevState;
|
|
3473
3365
|
});
|
|
3474
|
-
counter++;
|
|
3475
3366
|
}
|
|
3367
|
+
}), [
|
|
3368
|
+
setState
|
|
3369
|
+
]);
|
|
3370
|
+
return [
|
|
3371
|
+
state2,
|
|
3372
|
+
observer
|
|
3373
|
+
];
|
|
3374
|
+
};
|
|
3375
|
+
|
|
3376
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/action.ts
|
|
3377
|
+
var processAction = (view, action) => {
|
|
3378
|
+
let inlineType, listType;
|
|
3379
|
+
switch (action.type) {
|
|
3380
|
+
case "heading":
|
|
3381
|
+
setHeading(parseInt(action.data))(view);
|
|
3382
|
+
break;
|
|
3383
|
+
case "strong":
|
|
3384
|
+
case "emphasis":
|
|
3385
|
+
case "strikethrough":
|
|
3386
|
+
case "code":
|
|
3387
|
+
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
3388
|
+
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
3389
|
+
break;
|
|
3390
|
+
case "list-ordered":
|
|
3391
|
+
case "list-bullet":
|
|
3392
|
+
case "list-task":
|
|
3393
|
+
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
3394
|
+
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
3395
|
+
break;
|
|
3396
|
+
case "blockquote":
|
|
3397
|
+
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
3398
|
+
break;
|
|
3399
|
+
case "codeblock":
|
|
3400
|
+
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
3401
|
+
break;
|
|
3402
|
+
case "table":
|
|
3403
|
+
insertTable(view);
|
|
3404
|
+
break;
|
|
3405
|
+
case "link":
|
|
3406
|
+
(action.data === false ? removeLink : addLink())(view);
|
|
3407
|
+
break;
|
|
3408
|
+
case "image":
|
|
3409
|
+
addLink({
|
|
3410
|
+
url: action.data,
|
|
3411
|
+
image: true
|
|
3412
|
+
})(view);
|
|
3413
|
+
break;
|
|
3414
|
+
case "comment":
|
|
3415
|
+
createComment(view);
|
|
3416
|
+
break;
|
|
3476
3417
|
}
|
|
3418
|
+
requestAnimationFrame(() => {
|
|
3419
|
+
if (!view.hasFocus) {
|
|
3420
|
+
view.focus();
|
|
3421
|
+
}
|
|
3422
|
+
});
|
|
3477
3423
|
};
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3424
|
+
|
|
3425
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
3426
|
+
import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
|
|
3427
|
+
import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
|
|
3428
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
3429
|
+
import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
3430
|
+
import { languages } from "@codemirror/language-data";
|
|
3431
|
+
import { lintKeymap } from "@codemirror/lint";
|
|
3432
|
+
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
3433
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
3434
|
+
|
|
3435
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
3436
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
3437
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
3438
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
3439
|
+
import { Table } from "@lezer/markdown";
|
|
3440
|
+
var markdownTags = {
|
|
3441
|
+
Blockquote: Tag.define(),
|
|
3442
|
+
CodeMark: Tag.define(),
|
|
3443
|
+
CodeText: Tag.define(),
|
|
3444
|
+
EmphasisMark: Tag.define(),
|
|
3445
|
+
HeaderMark: Tag.define(),
|
|
3446
|
+
InlineCode: Tag.define(),
|
|
3447
|
+
LinkLabel: Tag.define(),
|
|
3448
|
+
LinkReference: Tag.define(),
|
|
3449
|
+
ListMark: Tag.define(),
|
|
3450
|
+
QuoteMark: Tag.define(),
|
|
3451
|
+
URL: Tag.define(),
|
|
3452
|
+
// Custom.
|
|
3453
|
+
TableCell: Tag.define()
|
|
3454
|
+
};
|
|
3455
|
+
Table.defineNodes?.forEach((node) => {
|
|
3456
|
+
switch (node?.name) {
|
|
3457
|
+
case "TableCell": {
|
|
3458
|
+
node.style = markdownTags.TableCell;
|
|
3459
|
+
break;
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
});
|
|
3463
|
+
var markdownTagsExtensions = [
|
|
3464
|
+
Table,
|
|
3465
|
+
{
|
|
3466
|
+
props: [
|
|
3467
|
+
styleTags(markdownTags)
|
|
3468
|
+
]
|
|
3469
|
+
}
|
|
3470
|
+
];
|
|
3471
|
+
var markdownHighlightStyle = (readonly) => {
|
|
3472
|
+
return HighlightStyle.define([
|
|
3473
|
+
{
|
|
3474
|
+
tag: [
|
|
3475
|
+
tags.keyword,
|
|
3476
|
+
tags.name,
|
|
3477
|
+
tags.deleted,
|
|
3478
|
+
tags.character,
|
|
3479
|
+
tags.propertyName,
|
|
3480
|
+
tags.macroName,
|
|
3481
|
+
tags.color,
|
|
3482
|
+
tags.constant(tags.name),
|
|
3483
|
+
tags.standard(tags.name),
|
|
3484
|
+
tags.definition(tags.name),
|
|
3485
|
+
tags.separator,
|
|
3486
|
+
tags.typeName,
|
|
3487
|
+
tags.className,
|
|
3488
|
+
tags.number,
|
|
3489
|
+
tags.changed,
|
|
3490
|
+
tags.annotation,
|
|
3491
|
+
tags.modifier,
|
|
3492
|
+
tags.self,
|
|
3493
|
+
tags.namespace,
|
|
3494
|
+
tags.operator,
|
|
3495
|
+
tags.operatorKeyword,
|
|
3496
|
+
tags.escape,
|
|
3497
|
+
tags.regexp,
|
|
3498
|
+
tags.special(tags.string),
|
|
3499
|
+
tags.meta,
|
|
3500
|
+
tags.comment,
|
|
3501
|
+
tags.atom,
|
|
3502
|
+
tags.bool,
|
|
3503
|
+
tags.special(tags.variableName),
|
|
3504
|
+
tags.processingInstruction,
|
|
3505
|
+
tags.string,
|
|
3506
|
+
tags.inserted,
|
|
3507
|
+
tags.invalid
|
|
3508
|
+
],
|
|
3509
|
+
color: "inherit !important"
|
|
3510
|
+
},
|
|
3511
|
+
// Markdown marks.
|
|
3512
|
+
{
|
|
3513
|
+
tag: [
|
|
3514
|
+
tags.meta,
|
|
3515
|
+
tags.processingInstruction,
|
|
3516
|
+
markdownTags.LinkLabel,
|
|
3517
|
+
markdownTags.LinkReference,
|
|
3518
|
+
markdownTags.ListMark
|
|
3519
|
+
],
|
|
3520
|
+
class: mark
|
|
3521
|
+
},
|
|
3522
|
+
// Markdown marks.
|
|
3523
|
+
{
|
|
3524
|
+
tag: [
|
|
3525
|
+
markdownTags.CodeMark,
|
|
3526
|
+
markdownTags.HeaderMark,
|
|
3527
|
+
markdownTags.QuoteMark,
|
|
3528
|
+
markdownTags.EmphasisMark
|
|
3529
|
+
],
|
|
3530
|
+
class: mark
|
|
3531
|
+
},
|
|
3532
|
+
// E.g., code block language (after ```).
|
|
3533
|
+
{
|
|
3534
|
+
tag: [
|
|
3535
|
+
tags.function(tags.variableName),
|
|
3536
|
+
tags.labelName
|
|
3537
|
+
],
|
|
3538
|
+
class: codeMark
|
|
3539
|
+
},
|
|
3540
|
+
{
|
|
3541
|
+
tag: [
|
|
3542
|
+
tags.monospace
|
|
3543
|
+
],
|
|
3544
|
+
class: "font-mono"
|
|
3545
|
+
},
|
|
3546
|
+
// Headings.
|
|
3547
|
+
{
|
|
3548
|
+
tag: tags.heading1,
|
|
3549
|
+
class: heading(1)
|
|
3550
|
+
},
|
|
3551
|
+
{
|
|
3552
|
+
tag: tags.heading2,
|
|
3553
|
+
class: heading(2)
|
|
3554
|
+
},
|
|
3555
|
+
{
|
|
3556
|
+
tag: tags.heading3,
|
|
3557
|
+
class: heading(3)
|
|
3558
|
+
},
|
|
3559
|
+
{
|
|
3560
|
+
tag: tags.heading4,
|
|
3561
|
+
class: heading(4)
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
tag: tags.heading5,
|
|
3565
|
+
class: heading(5)
|
|
3566
|
+
},
|
|
3567
|
+
{
|
|
3568
|
+
tag: tags.heading6,
|
|
3569
|
+
class: heading(6)
|
|
3570
|
+
},
|
|
3571
|
+
// Emphasis.
|
|
3572
|
+
{
|
|
3573
|
+
tag: tags.emphasis,
|
|
3574
|
+
class: italic
|
|
3575
|
+
},
|
|
3576
|
+
{
|
|
3577
|
+
tag: tags.strong,
|
|
3578
|
+
class: bold
|
|
3579
|
+
},
|
|
3580
|
+
{
|
|
3581
|
+
tag: tags.strikethrough,
|
|
3582
|
+
class: strikethrough
|
|
3583
|
+
},
|
|
3584
|
+
// Naked URLs.
|
|
3585
|
+
{
|
|
3586
|
+
tag: [
|
|
3587
|
+
markdownTags.URL
|
|
3588
|
+
],
|
|
3589
|
+
class: inlineUrl
|
|
3590
|
+
},
|
|
3591
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
3592
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
3593
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
3594
|
+
// the code, but all other CSS properties will be inherited.
|
|
3595
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
3596
|
+
{
|
|
3597
|
+
tag: [
|
|
3598
|
+
markdownTags.CodeText,
|
|
3599
|
+
markdownTags.InlineCode
|
|
3600
|
+
],
|
|
3601
|
+
class: code
|
|
3602
|
+
},
|
|
3603
|
+
{
|
|
3604
|
+
tag: [
|
|
3605
|
+
markdownTags.QuoteMark
|
|
3606
|
+
],
|
|
3607
|
+
class: blockquote
|
|
3608
|
+
},
|
|
3609
|
+
{
|
|
3610
|
+
tag: [
|
|
3611
|
+
markdownTags.TableCell
|
|
3612
|
+
],
|
|
3613
|
+
class: "font-mono"
|
|
3521
3614
|
}
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
changes.push({
|
|
3527
|
-
from: line.from,
|
|
3528
|
-
insert: /\S/.test(line.text) ? "> " : ">"
|
|
3529
|
-
});
|
|
3530
|
-
} else {
|
|
3531
|
-
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
3532
|
-
if (quote) {
|
|
3533
|
-
changes.push({
|
|
3534
|
-
from: line.from + quote[1].length,
|
|
3535
|
-
to: line.from + quote[0].length
|
|
3536
|
-
});
|
|
3537
|
-
}
|
|
3615
|
+
], {
|
|
3616
|
+
scope: markdownLanguage2,
|
|
3617
|
+
all: {
|
|
3618
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
3538
3619
|
}
|
|
3539
|
-
}
|
|
3540
|
-
if (!changes.length) {
|
|
3541
|
-
return false;
|
|
3542
|
-
}
|
|
3543
|
-
const changeSet = state.changes(changes);
|
|
3544
|
-
dispatch(state.update({
|
|
3545
|
-
changes: changeSet,
|
|
3546
|
-
selection: state.selection.map(changeSet, 1),
|
|
3547
|
-
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
3548
|
-
scrollIntoView: true
|
|
3549
|
-
}));
|
|
3550
|
-
return true;
|
|
3620
|
+
});
|
|
3551
3621
|
};
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
var
|
|
3555
|
-
return
|
|
3622
|
+
|
|
3623
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
3624
|
+
var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
3625
|
+
return [
|
|
3626
|
+
// Main extension.
|
|
3627
|
+
// https://github.com/codemirror/lang-markdown
|
|
3628
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
3629
|
+
markdown({
|
|
3630
|
+
// GRM by default (vs strict CommonMark):
|
|
3631
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
3632
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
3633
|
+
// https://github.github.com/gfm
|
|
3634
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
3635
|
+
base: markdownLanguage3,
|
|
3636
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
3637
|
+
codeLanguages: languages,
|
|
3638
|
+
// Parser extensions.
|
|
3639
|
+
extensions: [
|
|
3640
|
+
// GFM provided by default.
|
|
3641
|
+
markdownTagsExtensions
|
|
3642
|
+
]
|
|
3643
|
+
}),
|
|
3644
|
+
// https://github.com/codemirror/theme-one-dark
|
|
3645
|
+
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
3646
|
+
// Custom styles.
|
|
3647
|
+
syntaxHighlighting(markdownHighlightStyle()),
|
|
3648
|
+
keymap7.of([
|
|
3649
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
3650
|
+
indentWithTab2,
|
|
3651
|
+
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
|
3652
|
+
...defaultKeymap2,
|
|
3653
|
+
...completionKeymap2,
|
|
3654
|
+
...lintKeymap
|
|
3655
|
+
])
|
|
3656
|
+
];
|
|
3556
3657
|
};
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3658
|
+
|
|
3659
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
|
|
3660
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
3661
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
|
|
3662
|
+
import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
3663
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
3664
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
3665
|
+
toDOM() {
|
|
3666
|
+
const el = document.createElement("span");
|
|
3667
|
+
el.className = "cm-hr";
|
|
3668
|
+
return el;
|
|
3567
3669
|
}
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
to,
|
|
3575
|
-
enter: (node) => {
|
|
3576
|
-
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3577
|
-
if (from >= node.from && to <= node.to) {
|
|
3578
|
-
blockFrom = node.from;
|
|
3579
|
-
blockTo = node.to;
|
|
3580
|
-
} else {
|
|
3581
|
-
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
3582
|
-
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
|
-
}
|
|
3586
|
-
});
|
|
3587
|
-
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
3588
|
-
ranges[ranges.length - 1].to = blockTo;
|
|
3589
|
-
} else {
|
|
3590
|
-
ranges.push({
|
|
3591
|
-
from: blockFrom,
|
|
3592
|
-
to: blockTo
|
|
3593
|
-
});
|
|
3594
|
-
}
|
|
3670
|
+
};
|
|
3671
|
+
var LinkButton = class extends WidgetType3 {
|
|
3672
|
+
constructor(url, render) {
|
|
3673
|
+
super();
|
|
3674
|
+
this.url = url;
|
|
3675
|
+
this.render = render;
|
|
3595
3676
|
}
|
|
3596
|
-
|
|
3597
|
-
return
|
|
3677
|
+
eq(other) {
|
|
3678
|
+
return this.url === other.url;
|
|
3598
3679
|
}
|
|
3599
|
-
|
|
3600
|
-
const
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
if (node.name === "FencedCode") {
|
|
3631
|
-
changes.push({
|
|
3632
|
-
from: node.from,
|
|
3633
|
-
to: firstLine.to + 1 + node.from - firstLine.from
|
|
3634
|
-
});
|
|
3635
|
-
const lastLine = state.doc.lineAt(node.to);
|
|
3636
|
-
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
3637
|
-
changes.push({
|
|
3638
|
-
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
3639
|
-
to: lastLine.to
|
|
3640
|
-
});
|
|
3641
|
-
}
|
|
3642
|
-
} else {
|
|
3643
|
-
const column = node.from - firstLine.from;
|
|
3644
|
-
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
3645
|
-
changes.push({
|
|
3646
|
-
from: line.from + column - 4,
|
|
3647
|
-
to: line.from + column
|
|
3648
|
-
});
|
|
3649
|
-
if (line.to >= node.to) {
|
|
3650
|
-
break;
|
|
3651
|
-
}
|
|
3680
|
+
toDOM(view) {
|
|
3681
|
+
const el = document.createElement("span");
|
|
3682
|
+
this.render(el, this.url);
|
|
3683
|
+
return el;
|
|
3684
|
+
}
|
|
3685
|
+
};
|
|
3686
|
+
var CheckboxWidget = class extends WidgetType3 {
|
|
3687
|
+
constructor(_checked) {
|
|
3688
|
+
super();
|
|
3689
|
+
this._checked = _checked;
|
|
3690
|
+
}
|
|
3691
|
+
eq(other) {
|
|
3692
|
+
return this._checked === other._checked;
|
|
3693
|
+
}
|
|
3694
|
+
toDOM(view) {
|
|
3695
|
+
const input = document.createElement("input");
|
|
3696
|
+
input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
|
|
3697
|
+
input.type = "checkbox";
|
|
3698
|
+
input.checked = this._checked;
|
|
3699
|
+
if (view.state.readOnly) {
|
|
3700
|
+
input.setAttribute("disabled", "true");
|
|
3701
|
+
} else {
|
|
3702
|
+
input.onmousedown = (event) => {
|
|
3703
|
+
const pos = view.posAtDOM(input);
|
|
3704
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
3705
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
3706
|
+
view.dispatch({
|
|
3707
|
+
changes: {
|
|
3708
|
+
from: pos + 1,
|
|
3709
|
+
to: pos + 2,
|
|
3710
|
+
insert: this._checked ? " " : "x"
|
|
3652
3711
|
}
|
|
3653
|
-
}
|
|
3712
|
+
});
|
|
3713
|
+
event.preventDefault();
|
|
3654
3714
|
}
|
|
3655
|
-
}
|
|
3656
|
-
}
|
|
3715
|
+
};
|
|
3716
|
+
}
|
|
3717
|
+
return input;
|
|
3657
3718
|
}
|
|
3658
|
-
|
|
3719
|
+
ignoreEvent() {
|
|
3659
3720
|
return false;
|
|
3660
3721
|
}
|
|
3661
|
-
dispatch(state.update({
|
|
3662
|
-
changes,
|
|
3663
|
-
userEvent: "format.codeblock.remove",
|
|
3664
|
-
scrollIntoView: true
|
|
3665
|
-
}));
|
|
3666
|
-
return true;
|
|
3667
|
-
};
|
|
3668
|
-
var toggleCodeblock = (target) => {
|
|
3669
|
-
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
3670
|
-
};
|
|
3671
|
-
var formattingKeymap = (options = {}) => {
|
|
3672
|
-
return [
|
|
3673
|
-
keymap6.of([
|
|
3674
|
-
{
|
|
3675
|
-
key: "meta-b",
|
|
3676
|
-
run: toggleStrong
|
|
3677
|
-
}
|
|
3678
|
-
])
|
|
3679
|
-
];
|
|
3680
3722
|
};
|
|
3681
|
-
var
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3723
|
+
var hide = Decoration5.replace({});
|
|
3724
|
+
var fencedCodeLine = Decoration5.line({
|
|
3725
|
+
class: mx2("cm-code cm-codeblock-line")
|
|
3726
|
+
});
|
|
3727
|
+
var fencedCodeLineFirst = Decoration5.line({
|
|
3728
|
+
class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
|
|
3729
|
+
});
|
|
3730
|
+
var fencedCodeLineLast = Decoration5.line({
|
|
3731
|
+
class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
|
|
3732
|
+
});
|
|
3733
|
+
var horizontalRule = Decoration5.replace({
|
|
3734
|
+
widget: new HorizontalRuleWidget()
|
|
3735
|
+
});
|
|
3736
|
+
var checkedTask = Decoration5.replace({
|
|
3737
|
+
widget: new CheckboxWidget(true)
|
|
3738
|
+
});
|
|
3739
|
+
var uncheckedTask = Decoration5.replace({
|
|
3740
|
+
widget: new CheckboxWidget(false)
|
|
3741
|
+
});
|
|
3742
|
+
var editingRange = (state2, range, focus) => {
|
|
3743
|
+
const { readOnly, selection: { main: { head } } } = state2;
|
|
3744
|
+
return focus && !readOnly && head >= range.from && head <= range.to;
|
|
3686
3745
|
};
|
|
3687
|
-
var
|
|
3688
|
-
"Autolink",
|
|
3746
|
+
var MarksByParent = /* @__PURE__ */ new Set([
|
|
3689
3747
|
"CodeMark",
|
|
3690
|
-
"CodeText",
|
|
3691
|
-
"Comment",
|
|
3692
3748
|
"EmphasisMark",
|
|
3693
|
-
"Hardbreak",
|
|
3694
|
-
"HeaderMark",
|
|
3695
|
-
"HTMLTag",
|
|
3696
|
-
"LinkMark",
|
|
3697
|
-
"ListMark",
|
|
3698
|
-
"ProcessingInstruction",
|
|
3699
|
-
"QuoteMark",
|
|
3700
3749
|
"StrikethroughMark",
|
|
3701
3750
|
"SubscriptMark",
|
|
3702
|
-
"SuperscriptMark"
|
|
3703
|
-
"TaskMarker"
|
|
3751
|
+
"SuperscriptMark"
|
|
3704
3752
|
]);
|
|
3705
|
-
var
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
FencedCode: "codeblock",
|
|
3714
|
-
Paragraph: "paragraph",
|
|
3715
|
-
SetextHeading1: "heading1",
|
|
3716
|
-
SetextHeading2: "heading2",
|
|
3717
|
-
TableCell: "tablecell",
|
|
3718
|
-
Task: "paragraph"
|
|
3719
|
-
};
|
|
3720
|
-
var getFormatting = (state) => {
|
|
3721
|
-
let blockType = null;
|
|
3722
|
-
const inline = [
|
|
3723
|
-
null,
|
|
3724
|
-
null,
|
|
3725
|
-
null,
|
|
3726
|
-
null
|
|
3727
|
-
];
|
|
3728
|
-
let link = false;
|
|
3729
|
-
let blockQuote = null;
|
|
3730
|
-
let listStyle = null;
|
|
3731
|
-
const stack = [];
|
|
3732
|
-
let currentBlock = null;
|
|
3733
|
-
const advanceInline = (upto) => {
|
|
3734
|
-
if (!currentBlock) {
|
|
3735
|
-
return;
|
|
3736
|
-
}
|
|
3737
|
-
upto = Math.min(upto, currentBlock.end);
|
|
3738
|
-
if (upto <= currentBlock.pos) {
|
|
3739
|
-
return;
|
|
3740
|
-
}
|
|
3741
|
-
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
3742
|
-
if (inline[i] === false) {
|
|
3743
|
-
continue;
|
|
3744
|
-
} else if (currentBlock.active[i]) {
|
|
3745
|
-
inline[i] = true;
|
|
3746
|
-
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
3747
|
-
inline[i] = false;
|
|
3748
|
-
}
|
|
3749
|
-
}
|
|
3750
|
-
currentBlock.pos = upto;
|
|
3751
|
-
};
|
|
3752
|
-
const skipInline = (upto) => {
|
|
3753
|
-
if (currentBlock && upto > currentBlock.pos) {
|
|
3754
|
-
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
3755
|
-
}
|
|
3756
|
-
};
|
|
3757
|
-
const { selection } = state;
|
|
3758
|
-
for (const range of selection.ranges) {
|
|
3759
|
-
if (range.empty && inline.some((v) => v === null)) {
|
|
3760
|
-
const contextSize = Math.min(range.head, 6);
|
|
3761
|
-
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
3762
|
-
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
3763
|
-
for (let i = 0; i < contextSize; i++) {
|
|
3764
|
-
const ch = contextAfter[i];
|
|
3765
|
-
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
3766
|
-
contextAfter = contextAfter.slice(0, i);
|
|
3767
|
-
break;
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
for (let i = 0; i < inline.length; i++) {
|
|
3771
|
-
const mark2 = inlineMarkerText(i);
|
|
3772
|
-
const found = contextAfter.indexOf(mark2);
|
|
3773
|
-
if (found > -1) {
|
|
3774
|
-
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
3775
|
-
if (inline[i] === null) {
|
|
3776
|
-
inline[i] = true;
|
|
3777
|
-
}
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
}
|
|
3781
|
-
syntaxTree2(state).iterate({
|
|
3782
|
-
from: range.from,
|
|
3783
|
-
to: range.to,
|
|
3753
|
+
var buildDecorations = (view, options, focus) => {
|
|
3754
|
+
const deco = new RangeSetBuilder2();
|
|
3755
|
+
const atomicDeco = new RangeSetBuilder2();
|
|
3756
|
+
const { state: state2 } = view;
|
|
3757
|
+
for (const { from, to } of view.visibleRanges) {
|
|
3758
|
+
syntaxTree2(state2).iterate({
|
|
3759
|
+
from,
|
|
3760
|
+
to,
|
|
3784
3761
|
enter: (node) => {
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
}
|
|
3801
|
-
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
3802
|
-
currentBlock = {
|
|
3803
|
-
pos: Math.max(range.from, node.from),
|
|
3804
|
-
end: Math.min(range.to, node.to),
|
|
3805
|
-
active: [
|
|
3806
|
-
false,
|
|
3807
|
-
false,
|
|
3808
|
-
false,
|
|
3809
|
-
false
|
|
3810
|
-
]
|
|
3811
|
-
};
|
|
3812
|
-
}
|
|
3813
|
-
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3814
|
-
const index = InlineMarker[name];
|
|
3815
|
-
if (range.empty && inline[index] === null) {
|
|
3816
|
-
inline[index] = true;
|
|
3762
|
+
if (node.name === "FencedCode") {
|
|
3763
|
+
const editing = editingRange(state2, node, focus);
|
|
3764
|
+
for (const block of view.viewportLineBlocks) {
|
|
3765
|
+
if (block.to < node.from) {
|
|
3766
|
+
continue;
|
|
3767
|
+
}
|
|
3768
|
+
if (block.from > node.to) {
|
|
3769
|
+
break;
|
|
3770
|
+
}
|
|
3771
|
+
const first = block.from <= node.from;
|
|
3772
|
+
const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
|
|
3773
|
+
deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
|
|
3774
|
+
if (!editing && (first || last)) {
|
|
3775
|
+
atomicDeco.add(block.from, block.to, hide);
|
|
3776
|
+
}
|
|
3817
3777
|
}
|
|
3818
|
-
|
|
3819
|
-
} else if (
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3778
|
+
return false;
|
|
3779
|
+
} else if (node.name === "Link") {
|
|
3780
|
+
const marks = node.node.getChildren("LinkMark");
|
|
3781
|
+
const urlNode = node.node.getChild("URL");
|
|
3782
|
+
const editing = editingRange(state2, node, focus);
|
|
3783
|
+
if (urlNode && marks.length >= 2) {
|
|
3784
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
3785
|
+
if (!editing) {
|
|
3786
|
+
atomicDeco.add(node.from, marks[0].to, hide);
|
|
3787
|
+
}
|
|
3788
|
+
deco.add(marks[0].to, marks[1].from, Decoration5.mark({
|
|
3789
|
+
tagName: "a",
|
|
3790
|
+
attributes: {
|
|
3791
|
+
class: "cm-link",
|
|
3792
|
+
href: url,
|
|
3793
|
+
rel: "noreferrer",
|
|
3794
|
+
target: "_blank"
|
|
3795
|
+
}
|
|
3796
|
+
}));
|
|
3797
|
+
if (!editing) {
|
|
3798
|
+
atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
|
|
3799
|
+
widget: new LinkButton(url, options.renderLinkButton)
|
|
3800
|
+
}) : hide);
|
|
3836
3801
|
}
|
|
3837
3802
|
}
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3803
|
+
} else if (node.name === "HeaderMark") {
|
|
3804
|
+
const parent = node.node.parent;
|
|
3805
|
+
if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
|
|
3806
|
+
const next = state2.doc.sliceString(node.to, node.to + 1);
|
|
3807
|
+
atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
|
|
3842
3808
|
}
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3809
|
+
} else if (node.name === "HorizontalRule") {
|
|
3810
|
+
if (!editingRange(state2, node, focus)) {
|
|
3811
|
+
deco.add(node.from, node.to, horizontalRule);
|
|
3812
|
+
}
|
|
3813
|
+
} else if (node.name === "TaskMarker") {
|
|
3814
|
+
if (!editingRange(state2, node, focus)) {
|
|
3815
|
+
const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
3816
|
+
atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
|
|
3817
|
+
class: "cm-task"
|
|
3818
|
+
}));
|
|
3819
|
+
atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
|
|
3820
|
+
}
|
|
3821
|
+
} else if (MarksByParent.has(node.name)) {
|
|
3822
|
+
if (!editingRange(state2, node.node.parent, focus)) {
|
|
3823
|
+
atomicDeco.add(node.from, node.to, hide);
|
|
3847
3824
|
}
|
|
3848
|
-
currentBlock = null;
|
|
3849
|
-
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3850
|
-
currentBlock.active[InlineMarker[name]] = false;
|
|
3851
3825
|
}
|
|
3852
3826
|
}
|
|
3853
3827
|
});
|
|
3854
3828
|
}
|
|
3855
|
-
const { from, to } = state.doc.lineAt(selection.main.anchor);
|
|
3856
|
-
const blankLine = from === to;
|
|
3857
3829
|
return {
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
blockQuote: blockQuote ?? false,
|
|
3861
|
-
code: inline[3] ?? false,
|
|
3862
|
-
emphasis: inline[1] ?? false,
|
|
3863
|
-
strong: inline[0] ?? false,
|
|
3864
|
-
strikethrough: inline[2] ?? false,
|
|
3865
|
-
link,
|
|
3866
|
-
listStyle: listStyle || null
|
|
3830
|
+
deco: deco.finish(),
|
|
3831
|
+
atomicDeco: atomicDeco.finish()
|
|
3867
3832
|
};
|
|
3868
3833
|
};
|
|
3869
|
-
var
|
|
3870
|
-
|
|
3871
|
-
const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
|
|
3872
|
-
if (update2.docChanged || update2.selectionSet) {
|
|
3873
|
-
const newState = getFormatting(update2.state);
|
|
3874
|
-
if (!state || !compareFormatting(state, newState)) {
|
|
3875
|
-
setState(newState);
|
|
3876
|
-
}
|
|
3877
|
-
}
|
|
3878
|
-
}), []);
|
|
3834
|
+
var forceUpdate = StateEffect4.define();
|
|
3835
|
+
var decorateMarkdown = (options = {}) => {
|
|
3879
3836
|
return [
|
|
3880
|
-
|
|
3881
|
-
|
|
3837
|
+
ViewPlugin4.fromClass(class {
|
|
3838
|
+
constructor(view) {
|
|
3839
|
+
({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
|
|
3840
|
+
}
|
|
3841
|
+
update(update2) {
|
|
3842
|
+
if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
|
|
3843
|
+
({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
|
|
3844
|
+
this.clearUpdate();
|
|
3845
|
+
} else if (update2.selectionSet) {
|
|
3846
|
+
this.scheduleUpdate(update2.view);
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
// TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
|
|
3850
|
+
// the cursor will float in space or be in the wrong position after the decoration is applied.
|
|
3851
|
+
scheduleUpdate(view) {
|
|
3852
|
+
this.clearUpdate();
|
|
3853
|
+
this.pendingUpdate = setTimeout(() => {
|
|
3854
|
+
view.dispatch({
|
|
3855
|
+
effects: forceUpdate.of(null)
|
|
3856
|
+
});
|
|
3857
|
+
}, options.selectionChangeDelay);
|
|
3858
|
+
}
|
|
3859
|
+
clearUpdate() {
|
|
3860
|
+
if (this.pendingUpdate) {
|
|
3861
|
+
clearTimeout(this.pendingUpdate);
|
|
3862
|
+
this.pendingUpdate = void 0;
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
destroy() {
|
|
3866
|
+
this.clearUpdate();
|
|
3867
|
+
}
|
|
3868
|
+
}, {
|
|
3869
|
+
provide: (plugin) => [
|
|
3870
|
+
EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
3871
|
+
EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
3872
|
+
EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
|
|
3873
|
+
]
|
|
3874
|
+
}),
|
|
3875
|
+
formattingStyles
|
|
3882
3876
|
];
|
|
3883
3877
|
};
|
|
3878
|
+
var formattingStyles = EditorView12.baseTheme({
|
|
3879
|
+
"& .cm-code": {
|
|
3880
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
3881
|
+
},
|
|
3882
|
+
"& .cm-codeblock-line": {
|
|
3883
|
+
paddingInline: "1rem !important"
|
|
3884
|
+
},
|
|
3885
|
+
"& .cm-codeblock-end": {
|
|
3886
|
+
display: "inline-block",
|
|
3887
|
+
width: "100%",
|
|
3888
|
+
position: "relative",
|
|
3889
|
+
"&::after": {
|
|
3890
|
+
position: "absolute",
|
|
3891
|
+
inset: 0,
|
|
3892
|
+
content: '""'
|
|
3893
|
+
}
|
|
3894
|
+
},
|
|
3895
|
+
"& .cm-codeblock-first": {
|
|
3896
|
+
borderTopLeftRadius: ".5rem",
|
|
3897
|
+
borderTopRightRadius: ".5rem"
|
|
3898
|
+
},
|
|
3899
|
+
"& .cm-codeblock-last": {
|
|
3900
|
+
borderBottomLeftRadius: ".5rem",
|
|
3901
|
+
borderBottomRightRadius: ".5rem"
|
|
3902
|
+
},
|
|
3903
|
+
"&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
|
|
3904
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
3905
|
+
mixBlendMode: "darken"
|
|
3906
|
+
},
|
|
3907
|
+
"&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
|
|
3908
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
3909
|
+
mixBlendMode: "lighten"
|
|
3910
|
+
},
|
|
3911
|
+
"& .cm-hr": {
|
|
3912
|
+
display: "inline-block",
|
|
3913
|
+
width: "100%",
|
|
3914
|
+
height: "0",
|
|
3915
|
+
verticalAlign: "middle",
|
|
3916
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
3917
|
+
},
|
|
3918
|
+
"& .cm-task": {
|
|
3919
|
+
color: getToken("extend.colors.blue.500")
|
|
3920
|
+
},
|
|
3921
|
+
"& .cm-task-checkbox": {
|
|
3922
|
+
marginLeft: "4px",
|
|
3923
|
+
marginRight: "4px"
|
|
3924
|
+
}
|
|
3925
|
+
});
|
|
3884
3926
|
|
|
3885
3927
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3886
3928
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
3887
3929
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
3888
|
-
import { Decoration as Decoration6, EditorView as
|
|
3930
|
+
import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3889
3931
|
var image = (options = {}) => {
|
|
3890
3932
|
return StateField5.define({
|
|
3891
|
-
create: (
|
|
3892
|
-
return Decoration6.set(buildDecorations2(0,
|
|
3933
|
+
create: (state2) => {
|
|
3934
|
+
return Decoration6.set(buildDecorations2(0, state2.doc.length, state2));
|
|
3893
3935
|
},
|
|
3894
3936
|
update: (value, tr) => {
|
|
3895
3937
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -3912,7 +3954,7 @@ var image = (options = {}) => {
|
|
|
3912
3954
|
add: buildDecorations2(from, to, tr.state)
|
|
3913
3955
|
});
|
|
3914
3956
|
},
|
|
3915
|
-
provide: (field) =>
|
|
3957
|
+
provide: (field) => EditorView13.decorations.from(field)
|
|
3916
3958
|
});
|
|
3917
3959
|
};
|
|
3918
3960
|
var preloaded = /* @__PURE__ */ new Set();
|
|
@@ -3923,16 +3965,16 @@ var preloadImage = (url) => {
|
|
|
3923
3965
|
preloaded.add(url);
|
|
3924
3966
|
}
|
|
3925
3967
|
};
|
|
3926
|
-
var buildDecorations2 = (from, to,
|
|
3968
|
+
var buildDecorations2 = (from, to, state2) => {
|
|
3927
3969
|
const decorations = [];
|
|
3928
|
-
const cursor =
|
|
3929
|
-
syntaxTree3(
|
|
3970
|
+
const cursor = state2.selection.main.head;
|
|
3971
|
+
syntaxTree3(state2).iterate({
|
|
3930
3972
|
enter: (node) => {
|
|
3931
3973
|
if (node.name === "Image") {
|
|
3932
3974
|
const urlNode = node.node.getChild("URL");
|
|
3933
3975
|
if (urlNode) {
|
|
3934
|
-
const hide2 =
|
|
3935
|
-
const url =
|
|
3976
|
+
const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
|
|
3977
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
3936
3978
|
preloadImage(url);
|
|
3937
3979
|
decorations.push(Decoration6.replace({
|
|
3938
3980
|
block: true,
|
|
@@ -3962,6 +4004,8 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
3962
4004
|
return img;
|
|
3963
4005
|
}
|
|
3964
4006
|
};
|
|
4007
|
+
var imageUpload = (options = {}) => {
|
|
4008
|
+
};
|
|
3965
4009
|
|
|
3966
4010
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
3967
4011
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
@@ -4000,24 +4044,24 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
|
4000
4044
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
4001
4045
|
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
4002
4046
|
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
|
|
4003
|
-
import { Decoration as Decoration7, EditorView as
|
|
4047
|
+
import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4004
4048
|
var table = (options = {}) => {
|
|
4005
4049
|
return StateField6.define({
|
|
4006
|
-
create: (
|
|
4050
|
+
create: (state2) => update(state2, options),
|
|
4007
4051
|
update: (_, tr) => update(tr.state, options),
|
|
4008
|
-
provide: (field) =>
|
|
4052
|
+
provide: (field) => EditorView14.decorations.from(field)
|
|
4009
4053
|
});
|
|
4010
4054
|
};
|
|
4011
|
-
var update = (
|
|
4055
|
+
var update = (state2, options) => {
|
|
4012
4056
|
const builder = new RangeSetBuilder3();
|
|
4013
|
-
const cursor =
|
|
4057
|
+
const cursor = state2.selection.main.head;
|
|
4014
4058
|
const tables = [];
|
|
4015
4059
|
const getTable = () => tables[tables.length - 1];
|
|
4016
4060
|
const getRow = () => {
|
|
4017
4061
|
const table2 = getTable();
|
|
4018
4062
|
return table2.rows?.[table2.rows.length - 1];
|
|
4019
4063
|
};
|
|
4020
|
-
syntaxTree5(
|
|
4064
|
+
syntaxTree5(state2).iterate({
|
|
4021
4065
|
enter: (node) => {
|
|
4022
4066
|
switch (node.name) {
|
|
4023
4067
|
case "Table": {
|
|
@@ -4038,9 +4082,9 @@ var update = (state, options) => {
|
|
|
4038
4082
|
case "TableCell": {
|
|
4039
4083
|
const row = getRow();
|
|
4040
4084
|
if (row) {
|
|
4041
|
-
row.push(
|
|
4085
|
+
row.push(state2.sliceDoc(node.from, node.to));
|
|
4042
4086
|
} else {
|
|
4043
|
-
getTable().header?.push(
|
|
4087
|
+
getTable().header?.push(state2.sliceDoc(node.from, node.to));
|
|
4044
4088
|
}
|
|
4045
4089
|
break;
|
|
4046
4090
|
}
|
|
@@ -4048,7 +4092,7 @@ var update = (state, options) => {
|
|
|
4048
4092
|
}
|
|
4049
4093
|
});
|
|
4050
4094
|
tables.forEach((table2) => {
|
|
4051
|
-
const hide2 =
|
|
4095
|
+
const hide2 = state2.readOnly || cursor < table2.from || cursor > table2.to;
|
|
4052
4096
|
if (hide2) {
|
|
4053
4097
|
builder.add(table2.from, table2.to, Decoration7.replace({
|
|
4054
4098
|
widget: new TableWidget(table2)
|
|
@@ -4099,8 +4143,8 @@ var TableWidget = class extends WidgetType5 {
|
|
|
4099
4143
|
|
|
4100
4144
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
4101
4145
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
4102
|
-
import { log as
|
|
4103
|
-
var
|
|
4146
|
+
import { log as log6 } from "@dxos/log";
|
|
4147
|
+
var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
|
|
4104
4148
|
var mention = ({ onSearch }) => {
|
|
4105
4149
|
return autocompletion2({
|
|
4106
4150
|
// TODO(burdon): Not working.
|
|
@@ -4112,10 +4156,10 @@ var mention = ({ onSearch }) => {
|
|
|
4112
4156
|
icons: false,
|
|
4113
4157
|
override: [
|
|
4114
4158
|
(context) => {
|
|
4115
|
-
|
|
4159
|
+
log6.info("completion context", {
|
|
4116
4160
|
context
|
|
4117
4161
|
}, {
|
|
4118
|
-
F:
|
|
4162
|
+
F: __dxlog_file8,
|
|
4119
4163
|
L: 26,
|
|
4120
4164
|
S: void 0,
|
|
4121
4165
|
C: (f, a) => f(...a)
|
|
@@ -4137,25 +4181,35 @@ var mention = ({ onSearch }) => {
|
|
|
4137
4181
|
|
|
4138
4182
|
// packages/ui/react-ui-editor/src/extensions/modes.ts
|
|
4139
4183
|
import { Facet as Facet6 } from "@codemirror/state";
|
|
4140
|
-
import { keymap as
|
|
4184
|
+
import { keymap as keymap8 } from "@codemirror/view";
|
|
4141
4185
|
import { vim } from "@replit/codemirror-vim";
|
|
4186
|
+
import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
|
|
4187
|
+
var focusEvent = "focus.container";
|
|
4142
4188
|
var editorMode = Facet6.define({
|
|
4143
4189
|
combine: (modes) => modes[0] ?? {}
|
|
4144
4190
|
});
|
|
4145
4191
|
var EditorModes = {
|
|
4146
4192
|
default: [],
|
|
4193
|
+
vscode: [
|
|
4194
|
+
// https://github.com/replit/codemirror-vscode-keymap
|
|
4195
|
+
editorMode.of({
|
|
4196
|
+
type: "vscode"
|
|
4197
|
+
}),
|
|
4198
|
+
keymap8.of(vscodeKeymap)
|
|
4199
|
+
],
|
|
4147
4200
|
vim: [
|
|
4201
|
+
// https://github.com/replit/codemirror-vim
|
|
4148
4202
|
vim(),
|
|
4149
4203
|
editorMode.of({
|
|
4150
4204
|
type: "vim",
|
|
4151
4205
|
noTabster: true
|
|
4152
4206
|
}),
|
|
4153
|
-
|
|
4207
|
+
keymap8.of([
|
|
4154
4208
|
{
|
|
4155
4209
|
key: "Alt-Escape",
|
|
4156
4210
|
run: (view) => {
|
|
4157
4211
|
view.dispatch({
|
|
4158
|
-
userEvent:
|
|
4212
|
+
userEvent: focusEvent
|
|
4159
4213
|
});
|
|
4160
4214
|
return true;
|
|
4161
4215
|
}
|
|
@@ -4164,8 +4218,95 @@ var EditorModes = {
|
|
|
4164
4218
|
]
|
|
4165
4219
|
};
|
|
4166
4220
|
|
|
4221
|
+
// packages/ui/react-ui-editor/src/extensions/state.ts
|
|
4222
|
+
import { Transaction } from "@codemirror/state";
|
|
4223
|
+
import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
|
|
4224
|
+
import { debounce as debounce2 } from "@dxos/async";
|
|
4225
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
4226
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
4227
|
+
var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
|
|
4228
|
+
var scrollAnnotation = "dxos.org/cm/scrolling";
|
|
4229
|
+
var keyPrefix = "dxos.org/react-ui-editor/state";
|
|
4230
|
+
var localStorageStateStoreAdapter = {
|
|
4231
|
+
setState: (id, state2) => {
|
|
4232
|
+
invariant4(id, void 0, {
|
|
4233
|
+
F: __dxlog_file9,
|
|
4234
|
+
L: 35,
|
|
4235
|
+
S: void 0,
|
|
4236
|
+
A: [
|
|
4237
|
+
"id",
|
|
4238
|
+
""
|
|
4239
|
+
]
|
|
4240
|
+
});
|
|
4241
|
+
localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state2));
|
|
4242
|
+
},
|
|
4243
|
+
getState: (id) => {
|
|
4244
|
+
invariant4(id, void 0, {
|
|
4245
|
+
F: __dxlog_file9,
|
|
4246
|
+
L: 39,
|
|
4247
|
+
S: void 0,
|
|
4248
|
+
A: [
|
|
4249
|
+
"id",
|
|
4250
|
+
""
|
|
4251
|
+
]
|
|
4252
|
+
});
|
|
4253
|
+
const state2 = localStorage.getItem(`${keyPrefix}/${id}`);
|
|
4254
|
+
return state2 ? JSON.parse(state2) : void 0;
|
|
4255
|
+
}
|
|
4256
|
+
};
|
|
4257
|
+
var state = ({ getState, setState } = {}) => {
|
|
4258
|
+
const setStateDebounced = debounce2(setState, 1e3);
|
|
4259
|
+
return [
|
|
4260
|
+
// TODO(burdon): Track scrolling (currently only updates when cursor moves).
|
|
4261
|
+
EditorView15.updateListener.of(({ view, changes, transactions }) => {
|
|
4262
|
+
const id = view.state.facet(documentId2);
|
|
4263
|
+
if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
|
|
4264
|
+
return;
|
|
4265
|
+
}
|
|
4266
|
+
if (setState) {
|
|
4267
|
+
const { top } = view.dom.getBoundingClientRect();
|
|
4268
|
+
const pos = view.posAtCoords({
|
|
4269
|
+
x: 0,
|
|
4270
|
+
y: top
|
|
4271
|
+
});
|
|
4272
|
+
if (pos !== null) {
|
|
4273
|
+
const { anchor, head } = view.state.selection.main;
|
|
4274
|
+
setStateDebounced(id, {
|
|
4275
|
+
scrollTo: {
|
|
4276
|
+
from: pos,
|
|
4277
|
+
yMargin: 0
|
|
4278
|
+
},
|
|
4279
|
+
selection: {
|
|
4280
|
+
anchor,
|
|
4281
|
+
head
|
|
4282
|
+
}
|
|
4283
|
+
});
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
}),
|
|
4287
|
+
getState && keymap9.of([
|
|
4288
|
+
{
|
|
4289
|
+
key: "ctrl-r",
|
|
4290
|
+
run: (view) => {
|
|
4291
|
+
const state2 = getState(view.state.facet(documentId2));
|
|
4292
|
+
if (state2) {
|
|
4293
|
+
view.dispatch({
|
|
4294
|
+
effects: EditorView15.scrollIntoView(state2.scrollTo.from, {
|
|
4295
|
+
yMargin: 0
|
|
4296
|
+
}),
|
|
4297
|
+
selection: state2.selection,
|
|
4298
|
+
annotations: Transaction.userEvent.of(scrollAnnotation)
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
4301
|
+
return true;
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
])
|
|
4305
|
+
].filter(isNotFalsy3);
|
|
4306
|
+
};
|
|
4307
|
+
|
|
4167
4308
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
4168
|
-
import { keymap as
|
|
4309
|
+
import { keymap as keymap10 } from "@codemirror/view";
|
|
4169
4310
|
var defaultItems = [
|
|
4170
4311
|
"hello world!",
|
|
4171
4312
|
"this is a test.",
|
|
@@ -4175,7 +4316,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4175
4316
|
let t;
|
|
4176
4317
|
let idx = 0;
|
|
4177
4318
|
return [
|
|
4178
|
-
|
|
4319
|
+
keymap10.of([
|
|
4179
4320
|
{
|
|
4180
4321
|
// Reset.
|
|
4181
4322
|
key: "alt-meta-'",
|
|
@@ -4222,9 +4363,11 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4222
4363
|
};
|
|
4223
4364
|
|
|
4224
4365
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
4225
|
-
var
|
|
4366
|
+
var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
4226
4367
|
var instanceCount = 0;
|
|
4227
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0
|
|
4368
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0, {
|
|
4369
|
+
yMargin: 0
|
|
4370
|
+
}), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
|
|
4228
4371
|
const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
|
|
4229
4372
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
4230
4373
|
tabBehavior: "limited"
|
|
@@ -4243,24 +4386,24 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4243
4386
|
autoFocus
|
|
4244
4387
|
]);
|
|
4245
4388
|
useEffect2(() => {
|
|
4246
|
-
|
|
4389
|
+
log7("create", {
|
|
4247
4390
|
id,
|
|
4248
4391
|
instanceId
|
|
4249
4392
|
}, {
|
|
4250
|
-
F:
|
|
4393
|
+
F: __dxlog_file10,
|
|
4251
4394
|
L: 88,
|
|
4252
4395
|
S: void 0,
|
|
4253
4396
|
C: (f, a) => f(...a)
|
|
4254
4397
|
});
|
|
4255
|
-
const
|
|
4398
|
+
const state2 = EditorState2.create({
|
|
4256
4399
|
doc,
|
|
4257
4400
|
selection,
|
|
4258
4401
|
extensions: [
|
|
4259
4402
|
id && documentId2.of(id),
|
|
4260
4403
|
// TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
|
|
4261
4404
|
EditorView16.exceptionSink.of((err) => {
|
|
4262
|
-
|
|
4263
|
-
F:
|
|
4405
|
+
log7.catch(err, void 0, {
|
|
4406
|
+
F: __dxlog_file10,
|
|
4264
4407
|
L: 101,
|
|
4265
4408
|
S: void 0,
|
|
4266
4409
|
C: (f, a) => f(...a)
|
|
@@ -4269,16 +4412,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4269
4412
|
// Focus.
|
|
4270
4413
|
EditorView16.updateListener.of((update2) => {
|
|
4271
4414
|
update2.transactions.forEach((transaction) => {
|
|
4272
|
-
if (transaction.isUserEvent(
|
|
4415
|
+
if (transaction.isUserEvent(focusEvent)) {
|
|
4273
4416
|
rootRef.current?.focus();
|
|
4274
4417
|
}
|
|
4275
4418
|
});
|
|
4276
4419
|
}),
|
|
4277
4420
|
extensions
|
|
4278
|
-
].filter(
|
|
4421
|
+
].filter(isNotFalsy4)
|
|
4279
4422
|
});
|
|
4280
4423
|
const view2 = new EditorView16({
|
|
4281
|
-
state,
|
|
4424
|
+
state: state2,
|
|
4282
4425
|
parent: rootRef.current,
|
|
4283
4426
|
scrollTo,
|
|
4284
4427
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
@@ -4290,21 +4433,29 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4290
4433
|
view3.update(trs);
|
|
4291
4434
|
}
|
|
4292
4435
|
});
|
|
4293
|
-
|
|
4294
|
-
if (moveToEndOfLine) {
|
|
4436
|
+
if (moveToEndOfLine && !(scrollTo || selection)) {
|
|
4295
4437
|
const { to } = view2.state.doc.lineAt(0);
|
|
4296
|
-
view2
|
|
4438
|
+
view2.dispatch({
|
|
4297
4439
|
selection: {
|
|
4298
4440
|
anchor: to
|
|
4299
4441
|
}
|
|
4300
4442
|
});
|
|
4301
4443
|
}
|
|
4302
|
-
if (
|
|
4444
|
+
if (state2.facet(editorMode).noTabster) {
|
|
4303
4445
|
rootRef.current?.removeAttribute("data-tabster");
|
|
4304
4446
|
}
|
|
4447
|
+
setView(view2);
|
|
4305
4448
|
return () => {
|
|
4449
|
+
log7("destroy", {
|
|
4450
|
+
id,
|
|
4451
|
+
instanceId
|
|
4452
|
+
}, {
|
|
4453
|
+
F: __dxlog_file10,
|
|
4454
|
+
L: 150,
|
|
4455
|
+
S: void 0,
|
|
4456
|
+
C: (f, a) => f(...a)
|
|
4457
|
+
});
|
|
4306
4458
|
view2?.destroy();
|
|
4307
|
-
setView(null);
|
|
4308
4459
|
};
|
|
4309
4460
|
}, [
|
|
4310
4461
|
doc,
|
|
@@ -4334,9 +4485,10 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4334
4485
|
});
|
|
4335
4486
|
|
|
4336
4487
|
// 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
|
|
4488
|
+
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
4489
|
import { createContext } from "@radix-ui/react-context";
|
|
4339
|
-
import React2, { useRef as useRef2, useState as useState3 } from "react";
|
|
4490
|
+
import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
4491
|
+
import { useDropzone } from "react-dropzone";
|
|
4340
4492
|
import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
|
|
4341
4493
|
import { getSize } from "@dxos/react-ui-theme";
|
|
4342
4494
|
var tooltipProps = {
|
|
@@ -4353,10 +4505,10 @@ var HeadingIcons = {
|
|
|
4353
4505
|
"6": TextHSix
|
|
4354
4506
|
};
|
|
4355
4507
|
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
4356
|
-
var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
4508
|
+
var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
|
|
4357
4509
|
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
4358
4510
|
onAction,
|
|
4359
|
-
state
|
|
4511
|
+
state: state2
|
|
4360
4512
|
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
4361
4513
|
density: "fine"
|
|
4362
4514
|
}, /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
@@ -4370,7 +4522,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
|
4370
4522
|
};
|
|
4371
4523
|
var buttonStyles = "min-bs-0 p-2";
|
|
4372
4524
|
var iconStyles = getSize(5);
|
|
4373
|
-
var
|
|
4525
|
+
var ToolbarToggleButton = ({ Icon, children, ...props }) => {
|
|
4374
4526
|
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4375
4527
|
asChild: true
|
|
4376
4528
|
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
|
|
@@ -4383,14 +4535,27 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
|
4383
4535
|
className: "sr-only"
|
|
4384
4536
|
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4385
4537
|
};
|
|
4538
|
+
var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
4539
|
+
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4540
|
+
asChild: true
|
|
4541
|
+
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
|
|
4542
|
+
variant: "ghost",
|
|
4543
|
+
...props,
|
|
4544
|
+
classNames: buttonStyles
|
|
4545
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
4546
|
+
className: iconStyles
|
|
4547
|
+
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4548
|
+
className: "sr-only"
|
|
4549
|
+
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4550
|
+
};
|
|
4386
4551
|
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4387
4552
|
role: "separator",
|
|
4388
4553
|
className: "grow"
|
|
4389
4554
|
});
|
|
4390
4555
|
var MarkdownHeading = () => {
|
|
4391
4556
|
const { t } = useTranslation(translationKey);
|
|
4392
|
-
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
4393
|
-
const blockType =
|
|
4557
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
|
|
4558
|
+
const blockType = state2 ? state2.blockType : "paragraph";
|
|
4394
4559
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
4395
4560
|
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
|
|
4396
4561
|
const HeadingIcon = HeadingIcons[value ?? "0"];
|
|
@@ -4464,43 +4629,43 @@ var markdownStyles = [
|
|
|
4464
4629
|
{
|
|
4465
4630
|
type: "strong",
|
|
4466
4631
|
Icon: TextB,
|
|
4467
|
-
getState: (
|
|
4632
|
+
getState: (state2) => state2.strong
|
|
4468
4633
|
},
|
|
4469
4634
|
{
|
|
4470
4635
|
type: "emphasis",
|
|
4471
4636
|
Icon: TextItalic,
|
|
4472
|
-
getState: (
|
|
4637
|
+
getState: (state2) => state2.emphasis
|
|
4473
4638
|
},
|
|
4474
4639
|
{
|
|
4475
4640
|
type: "strikethrough",
|
|
4476
4641
|
Icon: TextStrikethrough,
|
|
4477
|
-
getState: (
|
|
4642
|
+
getState: (state2) => state2.strikethrough
|
|
4478
4643
|
},
|
|
4479
4644
|
{
|
|
4480
4645
|
type: "code",
|
|
4481
4646
|
Icon: Code,
|
|
4482
|
-
getState: (
|
|
4647
|
+
getState: (state2) => state2.code
|
|
4483
4648
|
},
|
|
4484
4649
|
{
|
|
4485
4650
|
type: "link",
|
|
4486
4651
|
Icon: Link,
|
|
4487
|
-
getState: (
|
|
4652
|
+
getState: (state2) => state2.link
|
|
4488
4653
|
}
|
|
4489
4654
|
];
|
|
4490
4655
|
var MarkdownStyles = () => {
|
|
4491
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4656
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4492
4657
|
const { t } = useTranslation(translationKey);
|
|
4493
4658
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4494
4659
|
type: "multiple",
|
|
4495
|
-
value: markdownStyles.filter(({ getState }) =>
|
|
4496
|
-
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4660
|
+
value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
|
|
4661
|
+
}, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4497
4662
|
key: type,
|
|
4498
4663
|
value: type,
|
|
4499
4664
|
Icon,
|
|
4500
|
-
disabled:
|
|
4501
|
-
onClick:
|
|
4665
|
+
disabled: state2?.blockType === "codeblock",
|
|
4666
|
+
onClick: state2 ? () => onAction?.({
|
|
4502
4667
|
type,
|
|
4503
|
-
data: !getState(
|
|
4668
|
+
data: !getState(state2)
|
|
4504
4669
|
}) : void 0
|
|
4505
4670
|
}, t(`${type} label`))));
|
|
4506
4671
|
};
|
|
@@ -4508,32 +4673,32 @@ var markdownLists = [
|
|
|
4508
4673
|
{
|
|
4509
4674
|
type: "list-bullet",
|
|
4510
4675
|
Icon: ListBullets,
|
|
4511
|
-
getState: (
|
|
4676
|
+
getState: (state2) => state2.listStyle === "bullet"
|
|
4512
4677
|
},
|
|
4513
4678
|
{
|
|
4514
4679
|
type: "list-ordered",
|
|
4515
4680
|
Icon: ListNumbers,
|
|
4516
|
-
getState: (
|
|
4681
|
+
getState: (state2) => state2.listStyle === "ordered"
|
|
4517
4682
|
},
|
|
4518
4683
|
{
|
|
4519
4684
|
type: "list-task",
|
|
4520
4685
|
Icon: ListChecks,
|
|
4521
|
-
getState: (
|
|
4686
|
+
getState: (state2) => state2.listStyle === "task"
|
|
4522
4687
|
}
|
|
4523
4688
|
];
|
|
4524
4689
|
var MarkdownLists = () => {
|
|
4525
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4690
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4526
4691
|
const { t } = useTranslation(translationKey);
|
|
4527
4692
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4528
4693
|
type: "single",
|
|
4529
|
-
value:
|
|
4530
|
-
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4694
|
+
value: state2?.listStyle ? `list-${state2.listStyle}` : ""
|
|
4695
|
+
}, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4531
4696
|
key: type,
|
|
4532
4697
|
value: type,
|
|
4533
4698
|
Icon,
|
|
4534
|
-
onClick:
|
|
4699
|
+
onClick: state2 ? () => onAction?.({
|
|
4535
4700
|
type,
|
|
4536
|
-
data: !getState(
|
|
4701
|
+
data: !getState(state2)
|
|
4537
4702
|
}) : void 0
|
|
4538
4703
|
}, t(`${type} label`))));
|
|
4539
4704
|
};
|
|
@@ -4541,111 +4706,106 @@ var markdownBlocks = [
|
|
|
4541
4706
|
{
|
|
4542
4707
|
type: "blockquote",
|
|
4543
4708
|
Icon: Quotes,
|
|
4544
|
-
getState: (
|
|
4709
|
+
getState: (state2) => state2.blockQuote
|
|
4545
4710
|
},
|
|
4546
4711
|
{
|
|
4547
4712
|
type: "codeblock",
|
|
4548
4713
|
Icon: CodeBlock,
|
|
4549
|
-
getState: (
|
|
4714
|
+
getState: (state2) => state2.blockType === "codeblock"
|
|
4550
4715
|
},
|
|
4551
4716
|
{
|
|
4552
4717
|
type: "table",
|
|
4553
4718
|
Icon: Table2,
|
|
4554
|
-
getState: (
|
|
4555
|
-
disabled: (
|
|
4719
|
+
getState: (state2) => state2.blockType === "tablecell",
|
|
4720
|
+
disabled: (state2) => !state2.blankLine
|
|
4556
4721
|
}
|
|
4557
4722
|
];
|
|
4558
4723
|
var MarkdownBlocks = () => {
|
|
4559
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4724
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4560
4725
|
const { t } = useTranslation(translationKey);
|
|
4561
|
-
const value = markdownBlocks.find(({ getState }) =>
|
|
4726
|
+
const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
|
|
4562
4727
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4563
4728
|
type: "single",
|
|
4564
4729
|
value: value?.type ?? ""
|
|
4565
|
-
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4730
|
+
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4566
4731
|
key: type,
|
|
4567
4732
|
value: type,
|
|
4568
4733
|
Icon,
|
|
4569
|
-
disabled: !
|
|
4570
|
-
onClick:
|
|
4734
|
+
disabled: !state2 || disabled?.(state2),
|
|
4735
|
+
onClick: state2 ? () => onAction?.({
|
|
4571
4736
|
type,
|
|
4572
|
-
data: !getState(
|
|
4737
|
+
data: !getState(state2)
|
|
4573
4738
|
}) : void 0
|
|
4574
4739
|
}, t(`${type} label`))));
|
|
4575
4740
|
};
|
|
4576
4741
|
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
|
|
4742
|
+
var MarkdownCustom = ({ onUpload } = {}) => {
|
|
4578
4743
|
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4579
4744
|
const { t } = useTranslation(translationKey);
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4745
|
+
const { acceptedFiles, getInputProps, open } = useDropzone({
|
|
4746
|
+
multiple: false,
|
|
4747
|
+
noDrag: true,
|
|
4748
|
+
accept: {
|
|
4749
|
+
"image/*": [
|
|
4750
|
+
".jpg",
|
|
4751
|
+
".jpeg",
|
|
4752
|
+
".png",
|
|
4753
|
+
".gif"
|
|
4754
|
+
]
|
|
4755
|
+
}
|
|
4756
|
+
});
|
|
4757
|
+
useEffect3(() => {
|
|
4758
|
+
if (onUpload && acceptedFiles.length) {
|
|
4759
|
+
requestAnimationFrame(async () => {
|
|
4760
|
+
const f = acceptedFiles[0];
|
|
4761
|
+
const file = new File([
|
|
4762
|
+
f
|
|
4763
|
+
], f.name, {
|
|
4764
|
+
type: f.type,
|
|
4765
|
+
lastModified: f.lastModified
|
|
4766
|
+
});
|
|
4767
|
+
const { url } = await onUpload(file);
|
|
4768
|
+
if (url) {
|
|
4769
|
+
onAction?.({
|
|
4770
|
+
type: "image",
|
|
4771
|
+
data: url
|
|
4772
|
+
});
|
|
4773
|
+
}
|
|
4774
|
+
});
|
|
4775
|
+
}
|
|
4776
|
+
}, [
|
|
4777
|
+
acceptedFiles
|
|
4778
|
+
]);
|
|
4779
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("input", getInputProps()), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4780
|
+
value: "image",
|
|
4781
|
+
Icon: Image,
|
|
4782
|
+
onClick: () => open()
|
|
4783
|
+
}, t("image label")));
|
|
4784
|
+
};
|
|
4785
|
+
var MarkdownActions = () => {
|
|
4786
|
+
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4787
|
+
const { t } = useTranslation(translationKey);
|
|
4788
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4789
|
+
value: "comment",
|
|
4790
|
+
Icon: ChatText,
|
|
4584
4791
|
"data-testid": "editor.toolbar.comment",
|
|
4585
4792
|
onClick: () => onAction?.({
|
|
4586
4793
|
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))));
|
|
4794
|
+
})
|
|
4795
|
+
}, t("comment label")));
|
|
4594
4796
|
};
|
|
4595
4797
|
var Toolbar = {
|
|
4596
4798
|
Root: ToolbarRoot,
|
|
4597
|
-
Button:
|
|
4799
|
+
Button: ToolbarToggleButton,
|
|
4598
4800
|
Separator: ToolbarSeparator,
|
|
4599
4801
|
Markdown: MarkdownStandard,
|
|
4600
|
-
|
|
4802
|
+
Custom: MarkdownCustom,
|
|
4803
|
+
Actions: MarkdownActions
|
|
4601
4804
|
};
|
|
4602
4805
|
|
|
4603
4806
|
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
4604
4807
|
var useActionHandler = (view) => {
|
|
4605
|
-
return (action) =>
|
|
4606
|
-
if (!view) {
|
|
4607
|
-
return;
|
|
4608
|
-
}
|
|
4609
|
-
let inlineType, listType;
|
|
4610
|
-
switch (action.type) {
|
|
4611
|
-
case "heading":
|
|
4612
|
-
setHeading(parseInt(action.data))(view);
|
|
4613
|
-
break;
|
|
4614
|
-
case "strong":
|
|
4615
|
-
case "emphasis":
|
|
4616
|
-
case "strikethrough":
|
|
4617
|
-
case "code":
|
|
4618
|
-
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4619
|
-
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
4620
|
-
break;
|
|
4621
|
-
case "list-ordered":
|
|
4622
|
-
case "list-bullet":
|
|
4623
|
-
case "list-task":
|
|
4624
|
-
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4625
|
-
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
4626
|
-
break;
|
|
4627
|
-
case "blockquote":
|
|
4628
|
-
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
4629
|
-
break;
|
|
4630
|
-
case "codeblock":
|
|
4631
|
-
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
4632
|
-
break;
|
|
4633
|
-
case "table":
|
|
4634
|
-
insertTable(view);
|
|
4635
|
-
break;
|
|
4636
|
-
case "link":
|
|
4637
|
-
(action.data === false ? removeLink : addLink)(view);
|
|
4638
|
-
break;
|
|
4639
|
-
case "comment":
|
|
4640
|
-
createComment(view);
|
|
4641
|
-
break;
|
|
4642
|
-
}
|
|
4643
|
-
setTimeout(() => {
|
|
4644
|
-
if (!view.hasFocus) {
|
|
4645
|
-
view.focus();
|
|
4646
|
-
}
|
|
4647
|
-
});
|
|
4648
|
-
};
|
|
4808
|
+
return (action) => view && processAction(view, action);
|
|
4649
4809
|
};
|
|
4650
4810
|
|
|
4651
4811
|
// packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
|
|
@@ -4664,28 +4824,36 @@ var useDocAccessor = (text) => {
|
|
|
4664
4824
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4665
4825
|
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4666
4826
|
import { EditorView as EditorView17 } from "@codemirror/view";
|
|
4667
|
-
import { useEffect as
|
|
4668
|
-
import { log as
|
|
4669
|
-
import { isNotFalsy as
|
|
4670
|
-
var
|
|
4827
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
|
|
4828
|
+
import { log as log8 } from "@dxos/log";
|
|
4829
|
+
import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
|
|
4830
|
+
var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4671
4831
|
var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
4672
4832
|
let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
|
|
4673
4833
|
const onUpdate = useRef3();
|
|
4674
4834
|
const [view, setView] = useState4();
|
|
4675
4835
|
const parentRef = useRef3(null);
|
|
4676
|
-
|
|
4836
|
+
useEffect4(() => {
|
|
4677
4837
|
let view2;
|
|
4678
4838
|
if (parentRef.current) {
|
|
4679
|
-
|
|
4839
|
+
log8("create", {
|
|
4840
|
+
id
|
|
4841
|
+
}, {
|
|
4842
|
+
F: __dxlog_file11,
|
|
4843
|
+
L: 36,
|
|
4844
|
+
S: void 0,
|
|
4845
|
+
C: (f, a) => f(...a)
|
|
4846
|
+
});
|
|
4847
|
+
const state2 = EditorState3.create({
|
|
4680
4848
|
doc,
|
|
4681
4849
|
selection,
|
|
4682
4850
|
extensions: [
|
|
4683
4851
|
id && documentId2.of(id),
|
|
4684
4852
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4685
4853
|
EditorView17.exceptionSink.of((err) => {
|
|
4686
|
-
|
|
4687
|
-
F:
|
|
4688
|
-
L:
|
|
4854
|
+
log8.catch(err, void 0, {
|
|
4855
|
+
F: __dxlog_file11,
|
|
4856
|
+
L: 46,
|
|
4689
4857
|
S: void 0,
|
|
4690
4858
|
C: (f, a) => f(...a)
|
|
4691
4859
|
});
|
|
@@ -4694,12 +4862,12 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4694
4862
|
EditorView17.updateListener.of(() => {
|
|
4695
4863
|
onUpdate.current?.();
|
|
4696
4864
|
})
|
|
4697
|
-
].filter(
|
|
4865
|
+
].filter(isNotFalsy5)
|
|
4698
4866
|
});
|
|
4699
4867
|
view2 = new EditorView17({
|
|
4700
4868
|
parent: parentRef.current,
|
|
4701
4869
|
scrollTo,
|
|
4702
|
-
state,
|
|
4870
|
+
state: state2,
|
|
4703
4871
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4704
4872
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4705
4873
|
dispatchTransactions: (trs, view3) => {
|
|
@@ -4712,10 +4880,18 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4712
4880
|
setView(view2);
|
|
4713
4881
|
}
|
|
4714
4882
|
return () => {
|
|
4883
|
+
log8("destroy", {
|
|
4884
|
+
id
|
|
4885
|
+
}, {
|
|
4886
|
+
F: __dxlog_file11,
|
|
4887
|
+
L: 74,
|
|
4888
|
+
S: void 0,
|
|
4889
|
+
C: (f, a) => f(...a)
|
|
4890
|
+
});
|
|
4715
4891
|
view2?.destroy();
|
|
4716
4892
|
};
|
|
4717
4893
|
}, deps);
|
|
4718
|
-
|
|
4894
|
+
useEffect4(() => {
|
|
4719
4895
|
if (view) {
|
|
4720
4896
|
if (!selection && !view.state.selection.main.anchor) {
|
|
4721
4897
|
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
@@ -4774,36 +4950,39 @@ export {
|
|
|
4774
4950
|
callbackWrapper,
|
|
4775
4951
|
command,
|
|
4776
4952
|
comments,
|
|
4777
|
-
compareFormatting,
|
|
4778
4953
|
createBasicExtensions,
|
|
4779
4954
|
createComment,
|
|
4780
4955
|
createDataExtensions,
|
|
4781
4956
|
createMarkdownExtensions,
|
|
4782
4957
|
createThemeExtensions,
|
|
4783
|
-
cursorLineMargin,
|
|
4784
4958
|
decorateMarkdown,
|
|
4785
4959
|
defaultOptions,
|
|
4786
4960
|
defaultTheme,
|
|
4787
|
-
dnd,
|
|
4788
4961
|
documentId2 as documentId,
|
|
4962
|
+
dropFile,
|
|
4789
4963
|
editorFillLayoutEditor,
|
|
4790
4964
|
editorFillLayoutRoot,
|
|
4791
4965
|
editorMode,
|
|
4792
4966
|
editorWithToolbarLayout,
|
|
4793
4967
|
focusComment,
|
|
4968
|
+
focusEvent,
|
|
4969
|
+
formattingEquals,
|
|
4794
4970
|
formattingKeymap,
|
|
4795
4971
|
getFormatting,
|
|
4796
4972
|
getToken,
|
|
4797
4973
|
image,
|
|
4974
|
+
imageUpload,
|
|
4798
4975
|
insertTable,
|
|
4799
|
-
|
|
4976
|
+
keymap11 as keymap,
|
|
4800
4977
|
linkTooltip,
|
|
4801
4978
|
listener,
|
|
4979
|
+
localStorageStateStoreAdapter,
|
|
4802
4980
|
logChanges,
|
|
4803
4981
|
markdownHighlightStyle,
|
|
4804
4982
|
markdownTags,
|
|
4805
4983
|
markdownTagsExtensions,
|
|
4806
4984
|
mention,
|
|
4985
|
+
processAction,
|
|
4807
4986
|
removeBlockquote,
|
|
4808
4987
|
removeCodeblock,
|
|
4809
4988
|
removeLink,
|
|
@@ -4814,6 +4993,7 @@ export {
|
|
|
4814
4993
|
setHeading,
|
|
4815
4994
|
setSelection,
|
|
4816
4995
|
setStyle,
|
|
4996
|
+
state,
|
|
4817
4997
|
table,
|
|
4818
4998
|
tags2 as tags,
|
|
4819
4999
|
toggleBlockquote,
|