@dxos/react-ui-editor 0.4.8-main.c67d72c → 0.4.8-main.cd60bd2
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 +1926 -1743
- 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 -24
- 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 -15
- 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/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,37 +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
2231
|
}
|
|
2237
2232
|
};
|
|
2238
2233
|
var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
|
|
2239
|
-
const slots = defaultsDeep2({}, _slots,
|
|
2234
|
+
const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
|
|
2240
2235
|
return [
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
theme &&
|
|
2244
|
-
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({
|
|
2245
2240
|
class: slots.editor.className
|
|
2246
2241
|
}),
|
|
2247
|
-
slots.content?.className &&
|
|
2242
|
+
slots.content?.className && EditorView9.contentAttributes.of({
|
|
2248
2243
|
class: slots.content.className
|
|
2249
2244
|
})
|
|
2250
2245
|
].filter(isNotFalsy2);
|
|
@@ -2272,1621 +2267,1671 @@ var createDataExtensions = ({ id, text, space, identity }) => {
|
|
|
2272
2267
|
};
|
|
2273
2268
|
|
|
2274
2269
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
2275
|
-
import { EditorView as
|
|
2270
|
+
import { EditorView as EditorView10 } from "@codemirror/view";
|
|
2276
2271
|
var listener = ({ onFocus, onChange }) => {
|
|
2277
2272
|
const extensions = [];
|
|
2278
|
-
onFocus && extensions.push(
|
|
2273
|
+
onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
|
|
2279
2274
|
onFocus(focusing);
|
|
2280
2275
|
return null;
|
|
2281
2276
|
}));
|
|
2282
|
-
onChange && extensions.push(
|
|
2277
|
+
onChange && extensions.push(EditorView10.updateListener.of((update2) => {
|
|
2283
2278
|
onChange(update2.state.doc.toString());
|
|
2284
2279
|
}));
|
|
2285
2280
|
return extensions;
|
|
2286
2281
|
};
|
|
2287
2282
|
|
|
2288
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/
|
|
2289
|
-
import {
|
|
2290
|
-
import {
|
|
2291
|
-
import {
|
|
2292
|
-
import {
|
|
2293
|
-
import {
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
2323
2368
|
}
|
|
2324
2369
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
Table,
|
|
2328
|
-
{
|
|
2329
|
-
props: [
|
|
2330
|
-
styleTags(markdownTags)
|
|
2331
|
-
]
|
|
2370
|
+
if (!changes.length) {
|
|
2371
|
+
return false;
|
|
2332
2372
|
}
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
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
|
-
tags.string,
|
|
2369
|
-
tags.inserted,
|
|
2370
|
-
tags.invalid
|
|
2371
|
-
],
|
|
2372
|
-
color: "inherit !important"
|
|
2373
|
-
},
|
|
2374
|
-
// Markdown marks.
|
|
2375
|
-
{
|
|
2376
|
-
tag: [
|
|
2377
|
-
tags.meta,
|
|
2378
|
-
tags.processingInstruction,
|
|
2379
|
-
markdownTags.LinkLabel,
|
|
2380
|
-
markdownTags.LinkReference,
|
|
2381
|
-
markdownTags.ListMark
|
|
2382
|
-
],
|
|
2383
|
-
class: mark
|
|
2384
|
-
},
|
|
2385
|
-
// Markdown marks.
|
|
2386
|
-
{
|
|
2387
|
-
tag: [
|
|
2388
|
-
markdownTags.CodeMark,
|
|
2389
|
-
markdownTags.HeaderMark,
|
|
2390
|
-
markdownTags.QuoteMark,
|
|
2391
|
-
markdownTags.EmphasisMark
|
|
2392
|
-
],
|
|
2393
|
-
class: mark
|
|
2394
|
-
},
|
|
2395
|
-
// E.g., code block language (after ```).
|
|
2396
|
-
{
|
|
2397
|
-
tag: [
|
|
2398
|
-
tags.function(tags.variableName),
|
|
2399
|
-
tags.labelName
|
|
2400
|
-
],
|
|
2401
|
-
class: codeMark
|
|
2402
|
-
},
|
|
2403
|
-
{
|
|
2404
|
-
tag: [
|
|
2405
|
-
tags.monospace
|
|
2406
|
-
],
|
|
2407
|
-
class: "font-mono"
|
|
2408
|
-
},
|
|
2409
|
-
// Headings.
|
|
2410
|
-
{
|
|
2411
|
-
tag: tags.heading1,
|
|
2412
|
-
class: heading(1)
|
|
2413
|
-
},
|
|
2414
|
-
{
|
|
2415
|
-
tag: tags.heading2,
|
|
2416
|
-
class: heading(2)
|
|
2417
|
-
},
|
|
2418
|
-
{
|
|
2419
|
-
tag: tags.heading3,
|
|
2420
|
-
class: heading(3)
|
|
2421
|
-
},
|
|
2422
|
-
{
|
|
2423
|
-
tag: tags.heading4,
|
|
2424
|
-
class: heading(4)
|
|
2425
|
-
},
|
|
2426
|
-
{
|
|
2427
|
-
tag: tags.heading5,
|
|
2428
|
-
class: heading(5)
|
|
2429
|
-
},
|
|
2430
|
-
{
|
|
2431
|
-
tag: tags.heading6,
|
|
2432
|
-
class: heading(6)
|
|
2433
|
-
},
|
|
2434
|
-
// Emphasis.
|
|
2435
|
-
{
|
|
2436
|
-
tag: tags.emphasis,
|
|
2437
|
-
class: italic
|
|
2438
|
-
},
|
|
2439
|
-
{
|
|
2440
|
-
tag: tags.strong,
|
|
2441
|
-
class: bold
|
|
2442
|
-
},
|
|
2443
|
-
{
|
|
2444
|
-
tag: tags.strikethrough,
|
|
2445
|
-
class: strikethrough
|
|
2446
|
-
},
|
|
2447
|
-
// Naked URLs.
|
|
2448
|
-
{
|
|
2449
|
-
tag: [
|
|
2450
|
-
markdownTags.URL
|
|
2451
|
-
],
|
|
2452
|
-
class: inlineUrl
|
|
2453
|
-
},
|
|
2454
|
-
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
2455
|
-
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
2456
|
-
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
2457
|
-
// the code, but all other CSS properties will be inherited.
|
|
2458
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
2459
|
-
{
|
|
2460
|
-
tag: [
|
|
2461
|
-
markdownTags.CodeText,
|
|
2462
|
-
markdownTags.InlineCode
|
|
2463
|
-
],
|
|
2464
|
-
class: code
|
|
2465
|
-
},
|
|
2466
|
-
{
|
|
2467
|
-
tag: [
|
|
2468
|
-
markdownTags.QuoteMark
|
|
2469
|
-
],
|
|
2470
|
-
class: blockquote
|
|
2471
|
-
},
|
|
2472
|
-
{
|
|
2473
|
-
tag: [
|
|
2474
|
-
markdownTags.TableCell
|
|
2475
|
-
],
|
|
2476
|
-
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
|
+
}
|
|
2477
2408
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
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
|
+
};
|
|
2482
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
|
+
};
|
|
2483
2540
|
});
|
|
2541
|
+
dispatch(state2.update(changes, {
|
|
2542
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2543
|
+
scrollIntoView: true
|
|
2544
|
+
}));
|
|
2545
|
+
return true;
|
|
2484
2546
|
};
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
var
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
// https://github.com/codemirror/lang-markdown
|
|
2491
|
-
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
2492
|
-
markdown({
|
|
2493
|
-
// GRM by default (vs strict CommonMark):
|
|
2494
|
-
// Table, TaskList, Strikethrough, and Autolink.
|
|
2495
|
-
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
2496
|
-
// https://github.github.com/gfm
|
|
2497
|
-
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
2498
|
-
base: markdownLanguage3,
|
|
2499
|
-
// Languages for syntax highlighting fenced code blocks.
|
|
2500
|
-
codeLanguages: languages,
|
|
2501
|
-
// Parser extensions.
|
|
2502
|
-
extensions: [
|
|
2503
|
-
// GFM provided by default.
|
|
2504
|
-
markdownTagsExtensions
|
|
2505
|
-
]
|
|
2506
|
-
}),
|
|
2507
|
-
// https://github.com/codemirror/theme-one-dark
|
|
2508
|
-
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
2509
|
-
// Custom styles.
|
|
2510
|
-
syntaxHighlighting(markdownHighlightStyle()),
|
|
2511
|
-
keymap5.of([
|
|
2512
|
-
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
2513
|
-
indentWithTab,
|
|
2514
|
-
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
2515
|
-
...closeBracketsKeymap,
|
|
2516
|
-
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2517
|
-
...historyKeymap,
|
|
2518
|
-
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2519
|
-
...searchKeymap,
|
|
2520
|
-
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2521
|
-
...standardKeymap
|
|
2522
|
-
])
|
|
2523
|
-
];
|
|
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);
|
|
2524
2552
|
};
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
el.className = "cm-hr";
|
|
2535
|
-
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);
|
|
2536
2562
|
}
|
|
2563
|
+
return node.from;
|
|
2537
2564
|
};
|
|
2538
|
-
var
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
}
|
|
2544
|
-
eq(other) {
|
|
2545
|
-
return this.url === other.url;
|
|
2546
|
-
}
|
|
2547
|
-
toDOM(view) {
|
|
2548
|
-
const el = document.createElement("span");
|
|
2549
|
-
this.render(el, this.url);
|
|
2550
|
-
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;
|
|
2551
2570
|
}
|
|
2571
|
+
return node.to;
|
|
2552
2572
|
};
|
|
2553
|
-
var
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
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;
|
|
2557
2577
|
}
|
|
2558
|
-
|
|
2559
|
-
|
|
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;
|
|
2560
2591
|
}
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
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
|
+
}
|
|
2583
2637
|
}
|
|
2584
|
-
|
|
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);
|
|
2585
2644
|
}
|
|
2586
|
-
|
|
2645
|
+
if (!changes) {
|
|
2587
2646
|
return false;
|
|
2588
2647
|
}
|
|
2648
|
+
dispatch(state2.update({
|
|
2649
|
+
changes,
|
|
2650
|
+
userEvent: "format.link.remove",
|
|
2651
|
+
scrollIntoView: true
|
|
2652
|
+
}));
|
|
2653
|
+
return true;
|
|
2589
2654
|
};
|
|
2590
|
-
var
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
});
|
|
2597
|
-
var fencedCodeLineLast = Decoration5.line({
|
|
2598
|
-
class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
|
|
2599
|
-
});
|
|
2600
|
-
var horizontalRule = Decoration5.replace({
|
|
2601
|
-
widget: new HorizontalRuleWidget()
|
|
2602
|
-
});
|
|
2603
|
-
var checkedTask = Decoration5.replace({
|
|
2604
|
-
widget: new CheckboxWidget(true)
|
|
2605
|
-
});
|
|
2606
|
-
var uncheckedTask = Decoration5.replace({
|
|
2607
|
-
widget: new CheckboxWidget(false)
|
|
2608
|
-
});
|
|
2609
|
-
var editingRange = (state, range, focus) => {
|
|
2610
|
-
const { readOnly, selection: { main: { head } } } = state;
|
|
2611
|
-
return focus && !readOnly && head >= range.from && head <= range.to;
|
|
2612
|
-
};
|
|
2613
|
-
var MarksByParent = /* @__PURE__ */ new Set([
|
|
2614
|
-
"CodeMark",
|
|
2615
|
-
"EmphasisMark",
|
|
2616
|
-
"StrikethroughMark",
|
|
2617
|
-
"SubscriptMark",
|
|
2618
|
-
"SuperscriptMark"
|
|
2619
|
-
]);
|
|
2620
|
-
var buildDecorations = (view, options, focus) => {
|
|
2621
|
-
const deco = new RangeSetBuilder2();
|
|
2622
|
-
const atomicDeco = new RangeSetBuilder2();
|
|
2623
|
-
const { state } = view;
|
|
2624
|
-
for (const { from, to } of view.visibleRanges) {
|
|
2625
|
-
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({
|
|
2626
2661
|
from,
|
|
2627
2662
|
to,
|
|
2628
2663
|
enter: (node) => {
|
|
2629
|
-
if (node.name
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
const first = block.from <= node.from;
|
|
2639
|
-
const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
|
|
2640
|
-
deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
|
|
2641
|
-
if (!editing && (first || last)) {
|
|
2642
|
-
atomicDeco.add(block.from, block.to, hide);
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
return false;
|
|
2646
|
-
} else if (node.name === "Link") {
|
|
2647
|
-
const marks = node.node.getChildren("LinkMark");
|
|
2648
|
-
const urlNode = node.node.getChild("URL");
|
|
2649
|
-
const editing = editingRange(state, node, focus);
|
|
2650
|
-
if (urlNode && marks.length >= 2) {
|
|
2651
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2652
|
-
if (!editing) {
|
|
2653
|
-
atomicDeco.add(node.from, marks[0].to, 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);
|
|
2654
2673
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
rel: "noreferrer",
|
|
2661
|
-
target: "_blank"
|
|
2662
|
-
}
|
|
2663
|
-
}));
|
|
2664
|
-
if (!editing) {
|
|
2665
|
-
atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
|
|
2666
|
-
widget: new LinkButton(url, options.renderLinkButton)
|
|
2667
|
-
}) : hide);
|
|
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);
|
|
2668
2679
|
}
|
|
2669
2680
|
}
|
|
2670
|
-
} else if (node.name === "HeaderMark") {
|
|
2671
|
-
const parent = node.node.parent;
|
|
2672
|
-
if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from), focus)) {
|
|
2673
|
-
const next = state.doc.sliceString(node.to, node.to + 1);
|
|
2674
|
-
atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
|
|
2675
|
-
}
|
|
2676
|
-
} else if (node.name === "HorizontalRule") {
|
|
2677
|
-
if (!editingRange(state, node, focus)) {
|
|
2678
|
-
deco.add(node.from, node.to, horizontalRule);
|
|
2679
|
-
}
|
|
2680
|
-
} else if (node.name === "TaskMarker") {
|
|
2681
|
-
if (!editingRange(state, node, focus)) {
|
|
2682
|
-
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2683
|
-
atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
|
|
2684
|
-
class: "cm-task"
|
|
2685
|
-
}));
|
|
2686
|
-
atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
|
|
2687
|
-
}
|
|
2688
|
-
} else if (MarksByParent.has(node.name)) {
|
|
2689
|
-
if (!editingRange(state, node.node.parent, focus)) {
|
|
2690
|
-
atomicDeco.add(node.from, node.to, hide);
|
|
2691
|
-
}
|
|
2692
2681
|
}
|
|
2693
2682
|
}
|
|
2694
2683
|
});
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
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
|
-
clearTimeout(this.pendingUpdate);
|
|
2729
|
-
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;
|
|
2730
2717
|
}
|
|
2718
|
+
changesAfter.push({
|
|
2719
|
+
from: after,
|
|
2720
|
+
insert: mark2
|
|
2721
|
+
});
|
|
2731
2722
|
}
|
|
2732
|
-
destroy() {
|
|
2733
|
-
this.clearUpdate();
|
|
2734
|
-
}
|
|
2735
|
-
}, {
|
|
2736
|
-
provide: (plugin) => [
|
|
2737
|
-
EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
2738
|
-
EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
|
|
2739
|
-
EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
|
|
2740
|
-
]
|
|
2741
|
-
}),
|
|
2742
|
-
formattingStyles
|
|
2743
|
-
];
|
|
2744
|
-
};
|
|
2745
|
-
var formattingStyles = EditorView12.baseTheme({
|
|
2746
|
-
"& .cm-code": {
|
|
2747
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
2748
|
-
},
|
|
2749
|
-
"& .cm-codeblock-line": {
|
|
2750
|
-
paddingInline: "1rem !important"
|
|
2751
|
-
},
|
|
2752
|
-
"& .cm-codeblock-end": {
|
|
2753
|
-
display: "inline-block",
|
|
2754
|
-
width: "100%",
|
|
2755
|
-
position: "relative",
|
|
2756
|
-
"&::after": {
|
|
2757
|
-
position: "absolute",
|
|
2758
|
-
inset: 0,
|
|
2759
|
-
content: '""'
|
|
2760
2723
|
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
mixBlendMode: "lighten"
|
|
2777
|
-
},
|
|
2778
|
-
"& .cm-hr": {
|
|
2779
|
-
display: "inline-block",
|
|
2780
|
-
width: "100%",
|
|
2781
|
-
height: "0",
|
|
2782
|
-
verticalAlign: "middle",
|
|
2783
|
-
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2784
|
-
},
|
|
2785
|
-
"& .cm-task": {
|
|
2786
|
-
color: getToken("extend.colors.blue.500")
|
|
2787
|
-
},
|
|
2788
|
-
"& .cm-task-checkbox": {
|
|
2789
|
-
marginLeft: "4px",
|
|
2790
|
-
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;
|
|
2791
2739
|
}
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
var List;
|
|
2809
|
-
(function(List2) {
|
|
2810
|
-
List2[List2["Ordered"] = 0] = "Ordered";
|
|
2811
|
-
List2[List2["Bullet"] = 1] = "Bullet";
|
|
2812
|
-
List2[List2["Task"] = 2] = "Task";
|
|
2813
|
-
})(List || (List = {}));
|
|
2814
|
-
var setHeading = (level) => ({ state, dispatch }) => {
|
|
2815
|
-
const { selection: { ranges }, doc } = state;
|
|
2816
|
-
const changes = [];
|
|
2817
|
-
let prevBlock = -1;
|
|
2818
|
-
for (const range of ranges) {
|
|
2819
|
-
let sawBlock = false;
|
|
2820
|
-
syntaxTree2(state).iterate({
|
|
2821
|
-
from: range.from,
|
|
2822
|
-
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,
|
|
2823
2756
|
enter: (node) => {
|
|
2824
|
-
if (
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
from: node.from,
|
|
2845
|
-
insert: "#".repeat(level) + " "
|
|
2846
|
-
});
|
|
2847
|
-
}
|
|
2848
|
-
changes.push({
|
|
2849
|
-
from: nextLine.from - 1,
|
|
2850
|
-
to: nextLine.to
|
|
2851
|
-
});
|
|
2852
|
-
} else {
|
|
2853
|
-
if (level === 0) {
|
|
2854
|
-
changes.push({
|
|
2855
|
-
from: node.from,
|
|
2856
|
-
to: Math.min(node.to, node.from + curLevel + 1)
|
|
2857
|
-
});
|
|
2858
|
-
} else if (level < curLevel) {
|
|
2859
|
-
changes.push({
|
|
2860
|
-
from: node.from,
|
|
2861
|
-
to: node.from + (curLevel - level)
|
|
2862
|
-
});
|
|
2863
|
-
} else {
|
|
2864
|
-
changes.push({
|
|
2865
|
-
from: node.from,
|
|
2866
|
-
insert: "#".repeat(level - curLevel)
|
|
2867
|
-
});
|
|
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;
|
|
2868
2777
|
}
|
|
2778
|
+
if (node.from === lastBlock) {
|
|
2779
|
+
return;
|
|
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;
|
|
2869
2795
|
}
|
|
2870
2796
|
}
|
|
2871
2797
|
});
|
|
2872
|
-
|
|
2873
|
-
|
|
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;
|
|
2874
2855
|
changes.push({
|
|
2875
|
-
from: line.from,
|
|
2876
|
-
|
|
2877
|
-
insert: "#".repeat(level) + " "
|
|
2856
|
+
from: line.from + Math.min(open, column),
|
|
2857
|
+
insert: " ".repeat(mark2.length)
|
|
2878
2858
|
});
|
|
2879
2859
|
}
|
|
2880
2860
|
}
|
|
2881
|
-
if (
|
|
2882
|
-
|
|
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
|
+
}
|
|
2883
2870
|
}
|
|
2884
|
-
const changeSet =
|
|
2885
|
-
dispatch(
|
|
2871
|
+
const changeSet = state2.changes(changes);
|
|
2872
|
+
dispatch(state2.update({
|
|
2886
2873
|
changes: changeSet,
|
|
2887
|
-
selection:
|
|
2888
|
-
userEvent: "format.
|
|
2874
|
+
selection: state2.selection.map(changeSet, 1),
|
|
2875
|
+
userEvent: "format.list.add",
|
|
2889
2876
|
scrollIntoView: true
|
|
2890
2877
|
}));
|
|
2891
2878
|
return true;
|
|
2892
2879
|
};
|
|
2893
|
-
var
|
|
2894
|
-
|
|
2895
|
-
const changes =
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
2901
|
-
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
2902
|
-
...before.slice(before.length - found)
|
|
2903
|
-
].reverse().join("") === after.slice(0, found)) {
|
|
2904
|
-
return {
|
|
2905
|
-
changes: [
|
|
2906
|
-
{
|
|
2907
|
-
from: range.head - marker.length - found,
|
|
2908
|
-
to: range.head - found
|
|
2909
|
-
},
|
|
2910
|
-
{
|
|
2911
|
-
from: range.head + found,
|
|
2912
|
-
to: range.head + found + marker.length
|
|
2913
|
-
}
|
|
2914
|
-
],
|
|
2915
|
-
range: EditorSelection.cursor(range.from - marker.length)
|
|
2916
|
-
};
|
|
2917
|
-
}
|
|
2918
|
-
}
|
|
2919
|
-
}
|
|
2920
|
-
const changes2 = [];
|
|
2921
|
-
const changesAtEnd = [];
|
|
2922
|
-
let blockStart = -1;
|
|
2923
|
-
let blockEnd = -1;
|
|
2924
|
-
let startCovered = false;
|
|
2925
|
-
let endCovered = false;
|
|
2926
|
-
let { from, to } = range;
|
|
2927
|
-
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({
|
|
2928
2887
|
from,
|
|
2929
2888
|
to,
|
|
2930
2889
|
enter: (node) => {
|
|
2931
2890
|
const { name } = node;
|
|
2932
|
-
if (
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
} else if (name === "Link" || name === "Image" && enable) {
|
|
2937
|
-
if (from < node.from && to > node.from && to <= node.to) {
|
|
2938
|
-
to = node.to;
|
|
2939
|
-
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
2940
|
-
from = node.from;
|
|
2941
|
-
}
|
|
2942
|
-
} else if (IgnoreInline.has(name) && enable) {
|
|
2943
|
-
if (node.from < from && node.to > from) {
|
|
2944
|
-
if (to === from) {
|
|
2945
|
-
to = node.to;
|
|
2946
|
-
}
|
|
2947
|
-
from = node.to;
|
|
2948
|
-
}
|
|
2949
|
-
if (node.from < to && node.to > to) {
|
|
2950
|
-
to = node.from;
|
|
2951
|
-
}
|
|
2952
|
-
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
2953
|
-
const markType = InlineMarker[name];
|
|
2954
|
-
const size = inlineMarkerText(markType).length;
|
|
2955
|
-
const openEnd = node.from + size;
|
|
2956
|
-
const closeStart = node.to - size;
|
|
2957
|
-
if (markType === type) {
|
|
2958
|
-
if (openEnd <= from && closeStart >= from) {
|
|
2959
|
-
startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
|
|
2960
|
-
from: node.from,
|
|
2961
|
-
to: openEnd
|
|
2962
|
-
} : true;
|
|
2963
|
-
}
|
|
2964
|
-
if (openEnd <= to && closeStart >= to) {
|
|
2965
|
-
endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
|
|
2966
|
-
from: closeStart,
|
|
2967
|
-
to: node.to
|
|
2968
|
-
} : true;
|
|
2969
|
-
}
|
|
2970
|
-
}
|
|
2971
|
-
if (markType === type || type === 3 && enable) {
|
|
2972
|
-
if (node.from >= from && openEnd <= to) {
|
|
2973
|
-
changes2.push({
|
|
2974
|
-
from: node.from,
|
|
2975
|
-
to: openEnd
|
|
2976
|
-
});
|
|
2977
|
-
if (markType !== type && closeStart >= to) {
|
|
2978
|
-
changesAtEnd.push({
|
|
2979
|
-
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2980
|
-
insert: inlineMarkerText(markType)
|
|
2981
|
-
});
|
|
2982
|
-
}
|
|
2983
|
-
}
|
|
2984
|
-
if (closeStart >= from && node.to <= to) {
|
|
2985
|
-
changes2.push({
|
|
2986
|
-
from: closeStart,
|
|
2987
|
-
to: node.to
|
|
2988
|
-
});
|
|
2989
|
-
if (markType !== type && openEnd <= from) {
|
|
2990
|
-
changes2.push({
|
|
2991
|
-
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2992
|
-
insert: inlineMarkerText(markType)
|
|
2993
|
-
});
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
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";
|
|
2997
2895
|
}
|
|
2998
2896
|
},
|
|
2999
2897
|
leave: (node) => {
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
insert: marker
|
|
3023
|
-
});
|
|
3024
|
-
}
|
|
3025
|
-
if (typeof endCovered === "object") {
|
|
3026
|
-
changes2.push(endCovered);
|
|
3027
|
-
} else if (endCovered) {
|
|
3028
|
-
changes2.push({
|
|
3029
|
-
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
3030
|
-
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)
|
|
3031
2920
|
});
|
|
3032
2921
|
}
|
|
3033
2922
|
}
|
|
2923
|
+
if (node.to >= to) {
|
|
2924
|
+
renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
|
|
2925
|
+
}
|
|
2926
|
+
return false;
|
|
3034
2927
|
}
|
|
3035
2928
|
}
|
|
3036
2929
|
});
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
};
|
|
3045
|
-
}
|
|
3046
|
-
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
3047
|
-
return {
|
|
3048
|
-
changes: changeSet,
|
|
3049
|
-
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
3050
|
-
};
|
|
3051
|
-
});
|
|
3052
|
-
dispatch(state.update(changes, {
|
|
3053
|
-
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",
|
|
3054
2937
|
scrollIntoView: true
|
|
3055
2938
|
}));
|
|
3056
2939
|
return true;
|
|
3057
2940
|
};
|
|
3058
|
-
var
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
3063
|
-
};
|
|
3064
|
-
var toggleStrong = toggleStyle(0);
|
|
3065
|
-
var toggleEmphasis = toggleStyle(1);
|
|
3066
|
-
var toggleStrikethrough = toggleStyle(2);
|
|
3067
|
-
var toggleInlineCode = toggleStyle(3);
|
|
3068
|
-
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
3069
|
-
var blockContentStart = (node) => {
|
|
3070
|
-
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
3071
|
-
if (atx) {
|
|
3072
|
-
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
3073
|
-
}
|
|
3074
|
-
return node.from;
|
|
3075
|
-
};
|
|
3076
|
-
var blockContentEnd = (node, doc) => {
|
|
3077
|
-
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
3078
|
-
const lastLine = doc.lineAt(node.to);
|
|
3079
|
-
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
3080
|
-
return lastLine.from - 1;
|
|
3081
|
-
}
|
|
3082
|
-
return node.to;
|
|
3083
|
-
};
|
|
3084
|
-
var skipSpaces = (pos, doc, dir, limit) => {
|
|
3085
|
-
const line = doc.lineAt(pos);
|
|
3086
|
-
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
3087
|
-
pos += dir;
|
|
3088
|
-
}
|
|
3089
|
-
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);
|
|
3090
2945
|
};
|
|
3091
|
-
var
|
|
3092
|
-
for (; ; ) {
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
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++;
|
|
3100
2961
|
}
|
|
3101
|
-
pos = moveTo;
|
|
3102
2962
|
}
|
|
3103
2963
|
};
|
|
3104
|
-
var
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
"| #{val3} | #{val4} |",
|
|
3117
|
-
""
|
|
3118
|
-
].join("\n"))
|
|
3119
|
-
};
|
|
3120
|
-
var insertTable = (view) => {
|
|
3121
|
-
const { selection: { main }, doc } = view.state;
|
|
3122
|
-
const { number } = doc.lineAt(main.anchor);
|
|
3123
|
-
const { from } = doc.line(number);
|
|
3124
|
-
snippets.table(view, null, from, from);
|
|
3125
|
-
};
|
|
3126
|
-
var removeLinkInner = (from, to, changes, state) => {
|
|
3127
|
-
syntaxTree2(state).iterate({
|
|
3128
|
-
from,
|
|
3129
|
-
to,
|
|
3130
|
-
enter: (node) => {
|
|
3131
|
-
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
3132
|
-
node.node.cursor().iterate((node2) => {
|
|
3133
|
-
const { name } = node2;
|
|
3134
|
-
if (name === "LinkMark" || name === "LinkLabel") {
|
|
3135
|
-
changes.push({
|
|
3136
|
-
from: node2.from,
|
|
3137
|
-
to: node2.to
|
|
3138
|
-
});
|
|
3139
|
-
} else if (name === "LinkTitle" || name === "URL") {
|
|
3140
|
-
changes.push({
|
|
3141
|
-
from: skipSpaces(node2.from, state.doc, -1),
|
|
3142
|
-
to: skipSpaces(node2.to, state.doc, 1)
|
|
3143
|
-
});
|
|
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;
|
|
3144
2976
|
}
|
|
3145
|
-
|
|
3146
|
-
|
|
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
|
+
}
|
|
3147
3002
|
}
|
|
3003
|
+
});
|
|
3004
|
+
let line;
|
|
3005
|
+
if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
|
|
3006
|
+
lines.push(line);
|
|
3148
3007
|
}
|
|
3149
|
-
}
|
|
3150
|
-
};
|
|
3151
|
-
var removeLink = ({ state, dispatch }) => {
|
|
3008
|
+
}
|
|
3152
3009
|
const changes = [];
|
|
3153
|
-
for (const
|
|
3154
|
-
|
|
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
|
+
}
|
|
3155
3025
|
}
|
|
3156
|
-
if (!changes) {
|
|
3026
|
+
if (!changes.length) {
|
|
3157
3027
|
return false;
|
|
3158
3028
|
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
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",
|
|
3162
3034
|
scrollIntoView: true
|
|
3163
3035
|
}));
|
|
3164
3036
|
return true;
|
|
3165
3037
|
};
|
|
3166
|
-
var
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
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({
|
|
3172
3059
|
from,
|
|
3173
3060
|
to,
|
|
3174
3061
|
enter: (node) => {
|
|
3175
3062
|
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
} else {
|
|
3183
|
-
cutStyles.push(sNode);
|
|
3184
|
-
}
|
|
3185
|
-
} else if (node.from >= from && node.to > to) {
|
|
3186
|
-
if (sNode.lastChild.from === to) {
|
|
3187
|
-
to = node.to;
|
|
3188
|
-
} else {
|
|
3189
|
-
cutStyles.push(sNode);
|
|
3190
|
-
}
|
|
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);
|
|
3191
3069
|
}
|
|
3192
3070
|
}
|
|
3193
3071
|
}
|
|
3194
3072
|
});
|
|
3195
|
-
if (
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
};
|
|
3203
|
-
}
|
|
3204
|
-
const changes2 = [];
|
|
3205
|
-
const changesAfter = [];
|
|
3206
|
-
removeLinkInner(from, to, changesAfter, state);
|
|
3207
|
-
let cursorOffset = 1;
|
|
3208
|
-
for (const style of cutStyles) {
|
|
3209
|
-
const type = InlineMarker[style.name];
|
|
3210
|
-
const mark2 = inlineMarkerText(type);
|
|
3211
|
-
if (style.from < from) {
|
|
3212
|
-
changes2.push({
|
|
3213
|
-
from: skipSpaces(from, state.doc, -1),
|
|
3214
|
-
insert: mark2
|
|
3215
|
-
});
|
|
3216
|
-
changesAfter.push({
|
|
3217
|
-
from: skipSpaces(from, state.doc, 1, to),
|
|
3218
|
-
insert: mark2
|
|
3219
|
-
});
|
|
3220
|
-
} else {
|
|
3221
|
-
changes2.push({
|
|
3222
|
-
from: skipSpaces(to, state.doc, -1, from),
|
|
3223
|
-
insert: mark2
|
|
3224
|
-
});
|
|
3225
|
-
const after = skipSpaces(to, state.doc, 1);
|
|
3226
|
-
if (after === to) {
|
|
3227
|
-
cursorOffset += mark2.length;
|
|
3228
|
-
}
|
|
3229
|
-
changesAfter.push({
|
|
3230
|
-
from: after,
|
|
3231
|
-
insert: mark2
|
|
3232
|
-
});
|
|
3233
|
-
}
|
|
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
|
+
});
|
|
3234
3080
|
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
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
|
+
];
|
|
3247
3097
|
});
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
dispatch(state.update(changes, {
|
|
3252
|
-
userEvent: "format.link.add",
|
|
3098
|
+
dispatch(state2.update({
|
|
3099
|
+
changes,
|
|
3100
|
+
userEvent: "format.codeblock.add",
|
|
3253
3101
|
scrollIntoView: true
|
|
3254
3102
|
}));
|
|
3255
3103
|
return true;
|
|
3256
3104
|
};
|
|
3257
|
-
var
|
|
3105
|
+
var removeCodeblock = ({ state: state2, dispatch }) => {
|
|
3106
|
+
const changes = [];
|
|
3258
3107
|
let lastBlock = -1;
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
let parentColumn = null;
|
|
3262
|
-
const blocks = [];
|
|
3263
|
-
for (const { from, to } of state.selection.ranges) {
|
|
3264
|
-
syntaxTree2(state).iterate({
|
|
3108
|
+
for (const { from, to } of state2.selection.ranges) {
|
|
3109
|
+
syntaxTree(state2).iterate({
|
|
3265
3110
|
from,
|
|
3266
3111
|
to,
|
|
3267
3112
|
enter: (node) => {
|
|
3268
|
-
if (
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
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
|
+
});
|
|
3273
3127
|
}
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
counter = +mark2[1] + 1;
|
|
3284
|
-
}
|
|
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;
|
|
3285
3137
|
}
|
|
3286
3138
|
}
|
|
3287
|
-
first = false;
|
|
3288
|
-
}
|
|
3289
|
-
if (node.from === lastBlock) {
|
|
3290
|
-
return;
|
|
3291
3139
|
}
|
|
3292
|
-
lastBlock = node.from;
|
|
3293
|
-
blocks.push({
|
|
3294
|
-
node: node.node,
|
|
3295
|
-
counter,
|
|
3296
|
-
parentColumn
|
|
3297
|
-
});
|
|
3298
|
-
counter++;
|
|
3299
|
-
return false;
|
|
3300
|
-
}
|
|
3301
|
-
},
|
|
3302
|
-
leave: (node) => {
|
|
3303
|
-
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
3304
|
-
counter = 1;
|
|
3305
|
-
parentColumn = null;
|
|
3306
3140
|
}
|
|
3307
3141
|
}
|
|
3308
3142
|
});
|
|
3309
3143
|
}
|
|
3310
|
-
if (!
|
|
3311
|
-
const { from, to } = state.doc.lineAt(state.selection.main.anchor);
|
|
3312
|
-
if (from === to) {
|
|
3313
|
-
const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
|
|
3314
|
-
dispatch(state.update({
|
|
3315
|
-
changes: [
|
|
3316
|
-
{
|
|
3317
|
-
from,
|
|
3318
|
-
insert
|
|
3319
|
-
}
|
|
3320
|
-
],
|
|
3321
|
-
selection: {
|
|
3322
|
-
anchor: from + insert.length
|
|
3323
|
-
},
|
|
3324
|
-
userEvent: "format.list.add",
|
|
3325
|
-
scrollIntoView: true
|
|
3326
|
-
}));
|
|
3327
|
-
return true;
|
|
3328
|
-
}
|
|
3144
|
+
if (!changes.length) {
|
|
3329
3145
|
return false;
|
|
3330
3146
|
}
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
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;
|
|
3338
3222
|
}
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
padding = Math.max(padding, parentColumn2 - column);
|
|
3223
|
+
upto = Math.min(upto, currentBlock.end);
|
|
3224
|
+
if (upto <= currentBlock.pos) {
|
|
3225
|
+
return;
|
|
3343
3226
|
}
|
|
3344
|
-
let
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
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;
|
|
3352
3234
|
}
|
|
3353
|
-
const num = String(counter2);
|
|
3354
|
-
padding = Math.max(String(max).length, padding);
|
|
3355
|
-
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
3356
|
-
} else {
|
|
3357
|
-
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
3358
|
-
}
|
|
3359
|
-
changes.push({
|
|
3360
|
-
from: nodeFrom,
|
|
3361
|
-
insert: mark2
|
|
3362
|
-
});
|
|
3363
|
-
while (line.to < node.to) {
|
|
3364
|
-
line = state.doc.lineAt(line.to + 1);
|
|
3365
|
-
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3366
|
-
changes.push({
|
|
3367
|
-
from: line.from + Math.min(open, column),
|
|
3368
|
-
insert: " ".repeat(mark2.length)
|
|
3369
|
-
});
|
|
3370
3235
|
}
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
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);
|
|
3377
3241
|
}
|
|
3378
|
-
|
|
3379
|
-
|
|
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
|
+
}
|
|
3380
3266
|
}
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
changes: changeSet,
|
|
3385
|
-
selection: state.selection.map(changeSet, 1),
|
|
3386
|
-
userEvent: "format.list.add",
|
|
3387
|
-
scrollIntoView: true
|
|
3388
|
-
}));
|
|
3389
|
-
return true;
|
|
3390
|
-
};
|
|
3391
|
-
var removeList = (type) => ({ state, dispatch }) => {
|
|
3392
|
-
let lastBlock = -1;
|
|
3393
|
-
const changes = [];
|
|
3394
|
-
const stack = [];
|
|
3395
|
-
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
3396
|
-
for (const { from, to } of state.selection.ranges) {
|
|
3397
|
-
syntaxTree2(state).iterate({
|
|
3398
|
-
from,
|
|
3399
|
-
to,
|
|
3267
|
+
syntaxTree(state2).iterate({
|
|
3268
|
+
from: range.from,
|
|
3269
|
+
to: range.to,
|
|
3400
3270
|
enter: (node) => {
|
|
3271
|
+
advanceInline(node.from);
|
|
3401
3272
|
const { name } = node;
|
|
3402
3273
|
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
3403
3274
|
stack.push(name);
|
|
3404
|
-
} else if (name === "
|
|
3405
|
-
|
|
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);
|
|
3406
3307
|
}
|
|
3407
3308
|
},
|
|
3408
3309
|
leave: (node) => {
|
|
3310
|
+
advanceInline(node.to);
|
|
3409
3311
|
const { name } = node;
|
|
3410
3312
|
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
3411
3313
|
stack.pop();
|
|
3412
|
-
} else if (
|
|
3413
|
-
|
|
3414
|
-
let
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
changes.push({
|
|
3421
|
-
from: node.from,
|
|
3422
|
-
to: node.from + mark2[0].length
|
|
3423
|
-
});
|
|
3424
|
-
while (line.to < node.to) {
|
|
3425
|
-
line = state.doc.lineAt(line.to + 1);
|
|
3426
|
-
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
3427
|
-
if (open > column) {
|
|
3428
|
-
changes.push({
|
|
3429
|
-
from: line.from + column,
|
|
3430
|
-
to: line.from + Math.min(column + mark2[0].length, open)
|
|
3431
|
-
});
|
|
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";
|
|
3432
3322
|
}
|
|
3433
3323
|
}
|
|
3434
|
-
if (
|
|
3435
|
-
|
|
3324
|
+
if (blockQuote === null) {
|
|
3325
|
+
blockQuote = hasQuote;
|
|
3326
|
+
} else if (!hasQuote && blockQuote) {
|
|
3327
|
+
blockQuote = false;
|
|
3436
3328
|
}
|
|
3437
|
-
|
|
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;
|
|
3438
3337
|
}
|
|
3439
3338
|
}
|
|
3440
3339
|
});
|
|
3441
3340
|
}
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
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
|
+
};
|
|
3456
3354
|
};
|
|
3457
|
-
var
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
from: item.from + Math.max(0, size - newNum.length),
|
|
3468
|
-
to: item.from + size,
|
|
3469
|
-
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;
|
|
3470
3365
|
});
|
|
3471
|
-
counter++;
|
|
3472
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;
|
|
3473
3417
|
}
|
|
3418
|
+
requestAnimationFrame(() => {
|
|
3419
|
+
if (!view.hasFocus) {
|
|
3420
|
+
view.focus();
|
|
3421
|
+
}
|
|
3422
|
+
});
|
|
3474
3423
|
};
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
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
|
-
|
|
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"
|
|
3518
3614
|
}
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
changes.push({
|
|
3524
|
-
from: line.from,
|
|
3525
|
-
insert: /\S/.test(line.text) ? "> " : ">"
|
|
3526
|
-
});
|
|
3527
|
-
} else {
|
|
3528
|
-
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
3529
|
-
if (quote) {
|
|
3530
|
-
changes.push({
|
|
3531
|
-
from: line.from + quote[1].length,
|
|
3532
|
-
to: line.from + quote[0].length
|
|
3533
|
-
});
|
|
3534
|
-
}
|
|
3615
|
+
], {
|
|
3616
|
+
scope: markdownLanguage2,
|
|
3617
|
+
all: {
|
|
3618
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
3535
3619
|
}
|
|
3536
|
-
}
|
|
3537
|
-
if (!changes.length) {
|
|
3538
|
-
return false;
|
|
3539
|
-
}
|
|
3540
|
-
const changeSet = state.changes(changes);
|
|
3541
|
-
dispatch(state.update({
|
|
3542
|
-
changes: changeSet,
|
|
3543
|
-
selection: state.selection.map(changeSet, 1),
|
|
3544
|
-
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
3545
|
-
scrollIntoView: true
|
|
3546
|
-
}));
|
|
3547
|
-
return true;
|
|
3620
|
+
});
|
|
3548
3621
|
};
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
var
|
|
3552
|
-
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
|
+
];
|
|
3553
3657
|
};
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
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;
|
|
3564
3669
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
to,
|
|
3572
|
-
enter: (node) => {
|
|
3573
|
-
if (Object.hasOwn(Textblocks, node.name)) {
|
|
3574
|
-
if (from >= node.from && to <= node.to) {
|
|
3575
|
-
blockFrom = node.from;
|
|
3576
|
-
blockTo = node.to;
|
|
3577
|
-
} else {
|
|
3578
|
-
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
3579
|
-
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
3580
|
-
}
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
});
|
|
3584
|
-
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
3585
|
-
ranges[ranges.length - 1].to = blockTo;
|
|
3586
|
-
} else {
|
|
3587
|
-
ranges.push({
|
|
3588
|
-
from: blockFrom,
|
|
3589
|
-
to: blockTo
|
|
3590
|
-
});
|
|
3591
|
-
}
|
|
3670
|
+
};
|
|
3671
|
+
var LinkButton = class extends WidgetType3 {
|
|
3672
|
+
constructor(url, render) {
|
|
3673
|
+
super();
|
|
3674
|
+
this.url = url;
|
|
3675
|
+
this.render = render;
|
|
3592
3676
|
}
|
|
3593
|
-
|
|
3594
|
-
return
|
|
3677
|
+
eq(other) {
|
|
3678
|
+
return this.url === other.url;
|
|
3595
3679
|
}
|
|
3596
|
-
|
|
3597
|
-
const
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
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
|
-
if (node.name === "FencedCode") {
|
|
3628
|
-
changes.push({
|
|
3629
|
-
from: node.from,
|
|
3630
|
-
to: firstLine.to + 1 + node.from - firstLine.from
|
|
3631
|
-
});
|
|
3632
|
-
const lastLine = state.doc.lineAt(node.to);
|
|
3633
|
-
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
3634
|
-
changes.push({
|
|
3635
|
-
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
3636
|
-
to: lastLine.to
|
|
3637
|
-
});
|
|
3638
|
-
}
|
|
3639
|
-
} else {
|
|
3640
|
-
const column = node.from - firstLine.from;
|
|
3641
|
-
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
3642
|
-
changes.push({
|
|
3643
|
-
from: line.from + column - 4,
|
|
3644
|
-
to: line.from + column
|
|
3645
|
-
});
|
|
3646
|
-
if (line.to >= node.to) {
|
|
3647
|
-
break;
|
|
3648
|
-
}
|
|
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"
|
|
3649
3711
|
}
|
|
3650
|
-
}
|
|
3712
|
+
});
|
|
3713
|
+
event.preventDefault();
|
|
3651
3714
|
}
|
|
3652
|
-
}
|
|
3653
|
-
}
|
|
3715
|
+
};
|
|
3716
|
+
}
|
|
3717
|
+
return input;
|
|
3654
3718
|
}
|
|
3655
|
-
|
|
3719
|
+
ignoreEvent() {
|
|
3656
3720
|
return false;
|
|
3657
3721
|
}
|
|
3658
|
-
dispatch(state.update({
|
|
3659
|
-
changes,
|
|
3660
|
-
userEvent: "format.codeblock.remove",
|
|
3661
|
-
scrollIntoView: true
|
|
3662
|
-
}));
|
|
3663
|
-
return true;
|
|
3664
|
-
};
|
|
3665
|
-
var toggleCodeblock = (target) => {
|
|
3666
|
-
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
3667
|
-
};
|
|
3668
|
-
var formattingKeymap = (options = {}) => {
|
|
3669
|
-
return [
|
|
3670
|
-
keymap6.of([
|
|
3671
|
-
{
|
|
3672
|
-
key: "meta-b",
|
|
3673
|
-
run: toggleStrong
|
|
3674
|
-
}
|
|
3675
|
-
])
|
|
3676
|
-
];
|
|
3677
3722
|
};
|
|
3678
|
-
var
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
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;
|
|
3683
3745
|
};
|
|
3684
|
-
var
|
|
3685
|
-
"Autolink",
|
|
3746
|
+
var MarksByParent = /* @__PURE__ */ new Set([
|
|
3686
3747
|
"CodeMark",
|
|
3687
|
-
"CodeText",
|
|
3688
|
-
"Comment",
|
|
3689
3748
|
"EmphasisMark",
|
|
3690
|
-
"Hardbreak",
|
|
3691
|
-
"HeaderMark",
|
|
3692
|
-
"HTMLTag",
|
|
3693
|
-
"LinkMark",
|
|
3694
|
-
"ListMark",
|
|
3695
|
-
"ProcessingInstruction",
|
|
3696
|
-
"QuoteMark",
|
|
3697
3749
|
"StrikethroughMark",
|
|
3698
3750
|
"SubscriptMark",
|
|
3699
|
-
"SuperscriptMark"
|
|
3700
|
-
"TaskMarker"
|
|
3751
|
+
"SuperscriptMark"
|
|
3701
3752
|
]);
|
|
3702
|
-
var
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
FencedCode: "codeblock",
|
|
3711
|
-
Paragraph: "paragraph",
|
|
3712
|
-
SetextHeading1: "heading1",
|
|
3713
|
-
SetextHeading2: "heading2",
|
|
3714
|
-
TableCell: "tablecell",
|
|
3715
|
-
Task: "paragraph"
|
|
3716
|
-
};
|
|
3717
|
-
var getFormatting = (state) => {
|
|
3718
|
-
let blockType = null;
|
|
3719
|
-
const inline = [
|
|
3720
|
-
null,
|
|
3721
|
-
null,
|
|
3722
|
-
null,
|
|
3723
|
-
null
|
|
3724
|
-
];
|
|
3725
|
-
let link = false;
|
|
3726
|
-
let blockQuote = null;
|
|
3727
|
-
let listStyle = null;
|
|
3728
|
-
const stack = [];
|
|
3729
|
-
let currentBlock = null;
|
|
3730
|
-
const advanceInline = (upto) => {
|
|
3731
|
-
if (!currentBlock) {
|
|
3732
|
-
return;
|
|
3733
|
-
}
|
|
3734
|
-
upto = Math.min(upto, currentBlock.end);
|
|
3735
|
-
if (upto <= currentBlock.pos) {
|
|
3736
|
-
return;
|
|
3737
|
-
}
|
|
3738
|
-
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
3739
|
-
if (inline[i] === false) {
|
|
3740
|
-
continue;
|
|
3741
|
-
} else if (currentBlock.active[i]) {
|
|
3742
|
-
inline[i] = true;
|
|
3743
|
-
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
3744
|
-
inline[i] = false;
|
|
3745
|
-
}
|
|
3746
|
-
}
|
|
3747
|
-
currentBlock.pos = upto;
|
|
3748
|
-
};
|
|
3749
|
-
const skipInline = (upto) => {
|
|
3750
|
-
if (currentBlock && upto > currentBlock.pos) {
|
|
3751
|
-
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
3752
|
-
}
|
|
3753
|
-
};
|
|
3754
|
-
const { selection } = state;
|
|
3755
|
-
for (const range of selection.ranges) {
|
|
3756
|
-
if (range.empty && inline.some((v) => v === null)) {
|
|
3757
|
-
const contextSize = Math.min(range.head, 6);
|
|
3758
|
-
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
3759
|
-
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
3760
|
-
for (let i = 0; i < contextSize; i++) {
|
|
3761
|
-
const ch = contextAfter[i];
|
|
3762
|
-
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
3763
|
-
contextAfter = contextAfter.slice(0, i);
|
|
3764
|
-
break;
|
|
3765
|
-
}
|
|
3766
|
-
}
|
|
3767
|
-
for (let i = 0; i < inline.length; i++) {
|
|
3768
|
-
const mark2 = inlineMarkerText(i);
|
|
3769
|
-
const found = contextAfter.indexOf(mark2);
|
|
3770
|
-
if (found > -1) {
|
|
3771
|
-
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
3772
|
-
if (inline[i] === null) {
|
|
3773
|
-
inline[i] = true;
|
|
3774
|
-
}
|
|
3775
|
-
}
|
|
3776
|
-
}
|
|
3777
|
-
}
|
|
3778
|
-
syntaxTree2(state).iterate({
|
|
3779
|
-
from: range.from,
|
|
3780
|
-
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,
|
|
3781
3761
|
enter: (node) => {
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
}
|
|
3798
|
-
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
3799
|
-
currentBlock = {
|
|
3800
|
-
pos: Math.max(range.from, node.from),
|
|
3801
|
-
end: Math.min(range.to, node.to),
|
|
3802
|
-
active: [
|
|
3803
|
-
false,
|
|
3804
|
-
false,
|
|
3805
|
-
false,
|
|
3806
|
-
false
|
|
3807
|
-
]
|
|
3808
|
-
};
|
|
3809
|
-
}
|
|
3810
|
-
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3811
|
-
const index = InlineMarker[name];
|
|
3812
|
-
if (range.empty && inline[index] === null) {
|
|
3813
|
-
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
|
+
}
|
|
3814
3777
|
}
|
|
3815
|
-
|
|
3816
|
-
} else if (
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
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);
|
|
3833
3801
|
}
|
|
3834
3802
|
}
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
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);
|
|
3839
3808
|
}
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
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);
|
|
3844
3824
|
}
|
|
3845
|
-
currentBlock = null;
|
|
3846
|
-
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
3847
|
-
currentBlock.active[InlineMarker[name]] = false;
|
|
3848
3825
|
}
|
|
3849
3826
|
}
|
|
3850
3827
|
});
|
|
3851
3828
|
}
|
|
3852
|
-
const { from, to } = state.doc.lineAt(selection.main.anchor);
|
|
3853
|
-
const blankLine = from === to;
|
|
3854
3829
|
return {
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
blockQuote: blockQuote ?? false,
|
|
3858
|
-
code: inline[3] ?? false,
|
|
3859
|
-
emphasis: inline[1] ?? false,
|
|
3860
|
-
strong: inline[0] ?? false,
|
|
3861
|
-
strikethrough: inline[2] ?? false,
|
|
3862
|
-
link,
|
|
3863
|
-
listStyle: listStyle || null
|
|
3830
|
+
deco: deco.finish(),
|
|
3831
|
+
atomicDeco: atomicDeco.finish()
|
|
3864
3832
|
};
|
|
3865
3833
|
};
|
|
3866
|
-
var
|
|
3867
|
-
|
|
3868
|
-
const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
|
|
3869
|
-
if (update2.docChanged || update2.selectionSet) {
|
|
3870
|
-
const newState = getFormatting(update2.state);
|
|
3871
|
-
if (!state || !compareFormatting(state, newState)) {
|
|
3872
|
-
setState(newState);
|
|
3873
|
-
}
|
|
3874
|
-
}
|
|
3875
|
-
}), []);
|
|
3834
|
+
var forceUpdate = StateEffect4.define();
|
|
3835
|
+
var decorateMarkdown = (options = {}) => {
|
|
3876
3836
|
return [
|
|
3877
|
-
|
|
3878
|
-
|
|
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
|
|
3879
3876
|
];
|
|
3880
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
|
+
});
|
|
3881
3926
|
|
|
3882
3927
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3883
3928
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
3884
3929
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
3885
|
-
import { Decoration as Decoration6, EditorView as
|
|
3930
|
+
import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3886
3931
|
var image = (options = {}) => {
|
|
3887
3932
|
return StateField5.define({
|
|
3888
|
-
create: (
|
|
3889
|
-
return Decoration6.set(buildDecorations2(0,
|
|
3933
|
+
create: (state2) => {
|
|
3934
|
+
return Decoration6.set(buildDecorations2(0, state2.doc.length, state2));
|
|
3890
3935
|
},
|
|
3891
3936
|
update: (value, tr) => {
|
|
3892
3937
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -3909,7 +3954,7 @@ var image = (options = {}) => {
|
|
|
3909
3954
|
add: buildDecorations2(from, to, tr.state)
|
|
3910
3955
|
});
|
|
3911
3956
|
},
|
|
3912
|
-
provide: (field) =>
|
|
3957
|
+
provide: (field) => EditorView13.decorations.from(field)
|
|
3913
3958
|
});
|
|
3914
3959
|
};
|
|
3915
3960
|
var preloaded = /* @__PURE__ */ new Set();
|
|
@@ -3920,16 +3965,16 @@ var preloadImage = (url) => {
|
|
|
3920
3965
|
preloaded.add(url);
|
|
3921
3966
|
}
|
|
3922
3967
|
};
|
|
3923
|
-
var buildDecorations2 = (from, to,
|
|
3968
|
+
var buildDecorations2 = (from, to, state2) => {
|
|
3924
3969
|
const decorations = [];
|
|
3925
|
-
const cursor =
|
|
3926
|
-
syntaxTree3(
|
|
3970
|
+
const cursor = state2.selection.main.head;
|
|
3971
|
+
syntaxTree3(state2).iterate({
|
|
3927
3972
|
enter: (node) => {
|
|
3928
3973
|
if (node.name === "Image") {
|
|
3929
3974
|
const urlNode = node.node.getChild("URL");
|
|
3930
3975
|
if (urlNode) {
|
|
3931
|
-
const hide2 =
|
|
3932
|
-
const url =
|
|
3976
|
+
const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
|
|
3977
|
+
const url = state2.sliceDoc(urlNode.from, urlNode.to);
|
|
3933
3978
|
preloadImage(url);
|
|
3934
3979
|
decorations.push(Decoration6.replace({
|
|
3935
3980
|
block: true,
|
|
@@ -3959,6 +4004,8 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
3959
4004
|
return img;
|
|
3960
4005
|
}
|
|
3961
4006
|
};
|
|
4007
|
+
var imageUpload = (options = {}) => {
|
|
4008
|
+
};
|
|
3962
4009
|
|
|
3963
4010
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
3964
4011
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
@@ -3997,24 +4044,24 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
|
3997
4044
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
3998
4045
|
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
3999
4046
|
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
|
|
4000
|
-
import { Decoration as Decoration7, EditorView as
|
|
4047
|
+
import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4001
4048
|
var table = (options = {}) => {
|
|
4002
4049
|
return StateField6.define({
|
|
4003
|
-
create: (
|
|
4050
|
+
create: (state2) => update(state2, options),
|
|
4004
4051
|
update: (_, tr) => update(tr.state, options),
|
|
4005
|
-
provide: (field) =>
|
|
4052
|
+
provide: (field) => EditorView14.decorations.from(field)
|
|
4006
4053
|
});
|
|
4007
4054
|
};
|
|
4008
|
-
var update = (
|
|
4055
|
+
var update = (state2, options) => {
|
|
4009
4056
|
const builder = new RangeSetBuilder3();
|
|
4010
|
-
const cursor =
|
|
4057
|
+
const cursor = state2.selection.main.head;
|
|
4011
4058
|
const tables = [];
|
|
4012
4059
|
const getTable = () => tables[tables.length - 1];
|
|
4013
4060
|
const getRow = () => {
|
|
4014
4061
|
const table2 = getTable();
|
|
4015
4062
|
return table2.rows?.[table2.rows.length - 1];
|
|
4016
4063
|
};
|
|
4017
|
-
syntaxTree5(
|
|
4064
|
+
syntaxTree5(state2).iterate({
|
|
4018
4065
|
enter: (node) => {
|
|
4019
4066
|
switch (node.name) {
|
|
4020
4067
|
case "Table": {
|
|
@@ -4035,9 +4082,9 @@ var update = (state, options) => {
|
|
|
4035
4082
|
case "TableCell": {
|
|
4036
4083
|
const row = getRow();
|
|
4037
4084
|
if (row) {
|
|
4038
|
-
row.push(
|
|
4085
|
+
row.push(state2.sliceDoc(node.from, node.to));
|
|
4039
4086
|
} else {
|
|
4040
|
-
getTable().header?.push(
|
|
4087
|
+
getTable().header?.push(state2.sliceDoc(node.from, node.to));
|
|
4041
4088
|
}
|
|
4042
4089
|
break;
|
|
4043
4090
|
}
|
|
@@ -4045,7 +4092,7 @@ var update = (state, options) => {
|
|
|
4045
4092
|
}
|
|
4046
4093
|
});
|
|
4047
4094
|
tables.forEach((table2) => {
|
|
4048
|
-
const hide2 =
|
|
4095
|
+
const hide2 = state2.readOnly || cursor < table2.from || cursor > table2.to;
|
|
4049
4096
|
if (hide2) {
|
|
4050
4097
|
builder.add(table2.from, table2.to, Decoration7.replace({
|
|
4051
4098
|
widget: new TableWidget(table2)
|
|
@@ -4096,8 +4143,8 @@ var TableWidget = class extends WidgetType5 {
|
|
|
4096
4143
|
|
|
4097
4144
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
4098
4145
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
4099
|
-
import { log as
|
|
4100
|
-
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";
|
|
4101
4148
|
var mention = ({ onSearch }) => {
|
|
4102
4149
|
return autocompletion2({
|
|
4103
4150
|
// TODO(burdon): Not working.
|
|
@@ -4109,10 +4156,10 @@ var mention = ({ onSearch }) => {
|
|
|
4109
4156
|
icons: false,
|
|
4110
4157
|
override: [
|
|
4111
4158
|
(context) => {
|
|
4112
|
-
|
|
4159
|
+
log6.info("completion context", {
|
|
4113
4160
|
context
|
|
4114
4161
|
}, {
|
|
4115
|
-
F:
|
|
4162
|
+
F: __dxlog_file8,
|
|
4116
4163
|
L: 26,
|
|
4117
4164
|
S: void 0,
|
|
4118
4165
|
C: (f, a) => f(...a)
|
|
@@ -4134,25 +4181,35 @@ var mention = ({ onSearch }) => {
|
|
|
4134
4181
|
|
|
4135
4182
|
// packages/ui/react-ui-editor/src/extensions/modes.ts
|
|
4136
4183
|
import { Facet as Facet6 } from "@codemirror/state";
|
|
4137
|
-
import { keymap as
|
|
4184
|
+
import { keymap as keymap8 } from "@codemirror/view";
|
|
4138
4185
|
import { vim } from "@replit/codemirror-vim";
|
|
4186
|
+
import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
|
|
4187
|
+
var focusEvent = "focus.container";
|
|
4139
4188
|
var editorMode = Facet6.define({
|
|
4140
4189
|
combine: (modes) => modes[0] ?? {}
|
|
4141
4190
|
});
|
|
4142
4191
|
var EditorModes = {
|
|
4143
4192
|
default: [],
|
|
4193
|
+
vscode: [
|
|
4194
|
+
// https://github.com/replit/codemirror-vscode-keymap
|
|
4195
|
+
editorMode.of({
|
|
4196
|
+
type: "vscode"
|
|
4197
|
+
}),
|
|
4198
|
+
keymap8.of(vscodeKeymap)
|
|
4199
|
+
],
|
|
4144
4200
|
vim: [
|
|
4201
|
+
// https://github.com/replit/codemirror-vim
|
|
4145
4202
|
vim(),
|
|
4146
4203
|
editorMode.of({
|
|
4147
4204
|
type: "vim",
|
|
4148
4205
|
noTabster: true
|
|
4149
4206
|
}),
|
|
4150
|
-
|
|
4207
|
+
keymap8.of([
|
|
4151
4208
|
{
|
|
4152
4209
|
key: "Alt-Escape",
|
|
4153
4210
|
run: (view) => {
|
|
4154
4211
|
view.dispatch({
|
|
4155
|
-
userEvent:
|
|
4212
|
+
userEvent: focusEvent
|
|
4156
4213
|
});
|
|
4157
4214
|
return true;
|
|
4158
4215
|
}
|
|
@@ -4161,8 +4218,95 @@ var EditorModes = {
|
|
|
4161
4218
|
]
|
|
4162
4219
|
};
|
|
4163
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
|
+
|
|
4164
4308
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
4165
|
-
import { keymap as
|
|
4309
|
+
import { keymap as keymap10 } from "@codemirror/view";
|
|
4166
4310
|
var defaultItems = [
|
|
4167
4311
|
"hello world!",
|
|
4168
4312
|
"this is a test.",
|
|
@@ -4172,7 +4316,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4172
4316
|
let t;
|
|
4173
4317
|
let idx = 0;
|
|
4174
4318
|
return [
|
|
4175
|
-
|
|
4319
|
+
keymap10.of([
|
|
4176
4320
|
{
|
|
4177
4321
|
// Reset.
|
|
4178
4322
|
key: "alt-meta-'",
|
|
@@ -4219,9 +4363,11 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
4219
4363
|
};
|
|
4220
4364
|
|
|
4221
4365
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
4222
|
-
var
|
|
4366
|
+
var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
4223
4367
|
var instanceCount = 0;
|
|
4224
|
-
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) => {
|
|
4225
4371
|
const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
|
|
4226
4372
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
4227
4373
|
tabBehavior: "limited"
|
|
@@ -4240,24 +4386,24 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4240
4386
|
autoFocus
|
|
4241
4387
|
]);
|
|
4242
4388
|
useEffect2(() => {
|
|
4243
|
-
|
|
4389
|
+
log7("create", {
|
|
4244
4390
|
id,
|
|
4245
4391
|
instanceId
|
|
4246
4392
|
}, {
|
|
4247
|
-
F:
|
|
4393
|
+
F: __dxlog_file10,
|
|
4248
4394
|
L: 88,
|
|
4249
4395
|
S: void 0,
|
|
4250
4396
|
C: (f, a) => f(...a)
|
|
4251
4397
|
});
|
|
4252
|
-
const
|
|
4398
|
+
const state2 = EditorState2.create({
|
|
4253
4399
|
doc,
|
|
4254
4400
|
selection,
|
|
4255
4401
|
extensions: [
|
|
4256
4402
|
id && documentId2.of(id),
|
|
4257
4403
|
// TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
|
|
4258
4404
|
EditorView16.exceptionSink.of((err) => {
|
|
4259
|
-
|
|
4260
|
-
F:
|
|
4405
|
+
log7.catch(err, void 0, {
|
|
4406
|
+
F: __dxlog_file10,
|
|
4261
4407
|
L: 101,
|
|
4262
4408
|
S: void 0,
|
|
4263
4409
|
C: (f, a) => f(...a)
|
|
@@ -4266,16 +4412,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4266
4412
|
// Focus.
|
|
4267
4413
|
EditorView16.updateListener.of((update2) => {
|
|
4268
4414
|
update2.transactions.forEach((transaction) => {
|
|
4269
|
-
if (transaction.isUserEvent(
|
|
4415
|
+
if (transaction.isUserEvent(focusEvent)) {
|
|
4270
4416
|
rootRef.current?.focus();
|
|
4271
4417
|
}
|
|
4272
4418
|
});
|
|
4273
4419
|
}),
|
|
4274
4420
|
extensions
|
|
4275
|
-
].filter(
|
|
4421
|
+
].filter(isNotFalsy4)
|
|
4276
4422
|
});
|
|
4277
4423
|
const view2 = new EditorView16({
|
|
4278
|
-
state,
|
|
4424
|
+
state: state2,
|
|
4279
4425
|
parent: rootRef.current,
|
|
4280
4426
|
scrollTo,
|
|
4281
4427
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
@@ -4287,21 +4433,29 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4287
4433
|
view3.update(trs);
|
|
4288
4434
|
}
|
|
4289
4435
|
});
|
|
4290
|
-
|
|
4291
|
-
if (moveToEndOfLine) {
|
|
4436
|
+
if (moveToEndOfLine && !(scrollTo || selection)) {
|
|
4292
4437
|
const { to } = view2.state.doc.lineAt(0);
|
|
4293
|
-
view2
|
|
4438
|
+
view2.dispatch({
|
|
4294
4439
|
selection: {
|
|
4295
4440
|
anchor: to
|
|
4296
4441
|
}
|
|
4297
4442
|
});
|
|
4298
4443
|
}
|
|
4299
|
-
if (
|
|
4444
|
+
if (state2.facet(editorMode).noTabster) {
|
|
4300
4445
|
rootRef.current?.removeAttribute("data-tabster");
|
|
4301
4446
|
}
|
|
4447
|
+
setView(view2);
|
|
4302
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
|
+
});
|
|
4303
4458
|
view2?.destroy();
|
|
4304
|
-
setView(null);
|
|
4305
4459
|
};
|
|
4306
4460
|
}, [
|
|
4307
4461
|
doc,
|
|
@@ -4331,9 +4485,10 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
|
|
|
4331
4485
|
});
|
|
4332
4486
|
|
|
4333
4487
|
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
4334
|
-
import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic
|
|
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";
|
|
4335
4489
|
import { createContext } from "@radix-ui/react-context";
|
|
4336
|
-
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";
|
|
4337
4492
|
import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
|
|
4338
4493
|
import { getSize } from "@dxos/react-ui-theme";
|
|
4339
4494
|
var tooltipProps = {
|
|
@@ -4350,10 +4505,10 @@ var HeadingIcons = {
|
|
|
4350
4505
|
"6": TextHSix
|
|
4351
4506
|
};
|
|
4352
4507
|
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
4353
|
-
var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
4508
|
+
var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
|
|
4354
4509
|
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
4355
4510
|
onAction,
|
|
4356
|
-
state
|
|
4511
|
+
state: state2
|
|
4357
4512
|
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
4358
4513
|
density: "fine"
|
|
4359
4514
|
}, /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
@@ -4367,7 +4522,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
|
|
|
4367
4522
|
};
|
|
4368
4523
|
var buttonStyles = "min-bs-0 p-2";
|
|
4369
4524
|
var iconStyles = getSize(5);
|
|
4370
|
-
var
|
|
4525
|
+
var ToolbarToggleButton = ({ Icon, children, ...props }) => {
|
|
4371
4526
|
return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
4372
4527
|
asChild: true
|
|
4373
4528
|
}, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
|
|
@@ -4380,14 +4535,27 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
|
|
|
4380
4535
|
className: "sr-only"
|
|
4381
4536
|
}, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4382
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
|
+
};
|
|
4383
4551
|
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4384
4552
|
role: "separator",
|
|
4385
4553
|
className: "grow"
|
|
4386
4554
|
});
|
|
4387
4555
|
var MarkdownHeading = () => {
|
|
4388
4556
|
const { t } = useTranslation(translationKey);
|
|
4389
|
-
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
4390
|
-
const blockType =
|
|
4557
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
|
|
4558
|
+
const blockType = state2 ? state2.blockType : "paragraph";
|
|
4391
4559
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
4392
4560
|
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
|
|
4393
4561
|
const HeadingIcon = HeadingIcons[value ?? "0"];
|
|
@@ -4461,43 +4629,43 @@ var markdownStyles = [
|
|
|
4461
4629
|
{
|
|
4462
4630
|
type: "strong",
|
|
4463
4631
|
Icon: TextB,
|
|
4464
|
-
getState: (
|
|
4632
|
+
getState: (state2) => state2.strong
|
|
4465
4633
|
},
|
|
4466
4634
|
{
|
|
4467
4635
|
type: "emphasis",
|
|
4468
4636
|
Icon: TextItalic,
|
|
4469
|
-
getState: (
|
|
4637
|
+
getState: (state2) => state2.emphasis
|
|
4470
4638
|
},
|
|
4471
4639
|
{
|
|
4472
4640
|
type: "strikethrough",
|
|
4473
4641
|
Icon: TextStrikethrough,
|
|
4474
|
-
getState: (
|
|
4642
|
+
getState: (state2) => state2.strikethrough
|
|
4475
4643
|
},
|
|
4476
4644
|
{
|
|
4477
4645
|
type: "code",
|
|
4478
4646
|
Icon: Code,
|
|
4479
|
-
getState: (
|
|
4647
|
+
getState: (state2) => state2.code
|
|
4480
4648
|
},
|
|
4481
4649
|
{
|
|
4482
4650
|
type: "link",
|
|
4483
4651
|
Icon: Link,
|
|
4484
|
-
getState: (
|
|
4652
|
+
getState: (state2) => state2.link
|
|
4485
4653
|
}
|
|
4486
4654
|
];
|
|
4487
4655
|
var MarkdownStyles = () => {
|
|
4488
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4656
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4489
4657
|
const { t } = useTranslation(translationKey);
|
|
4490
4658
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4491
4659
|
type: "multiple",
|
|
4492
|
-
value: markdownStyles.filter(({ getState }) =>
|
|
4493
|
-
}, 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, {
|
|
4494
4662
|
key: type,
|
|
4495
4663
|
value: type,
|
|
4496
4664
|
Icon,
|
|
4497
|
-
disabled:
|
|
4498
|
-
onClick:
|
|
4665
|
+
disabled: state2?.blockType === "codeblock",
|
|
4666
|
+
onClick: state2 ? () => onAction?.({
|
|
4499
4667
|
type,
|
|
4500
|
-
data: !getState(
|
|
4668
|
+
data: !getState(state2)
|
|
4501
4669
|
}) : void 0
|
|
4502
4670
|
}, t(`${type} label`))));
|
|
4503
4671
|
};
|
|
@@ -4505,32 +4673,32 @@ var markdownLists = [
|
|
|
4505
4673
|
{
|
|
4506
4674
|
type: "list-bullet",
|
|
4507
4675
|
Icon: ListBullets,
|
|
4508
|
-
getState: (
|
|
4676
|
+
getState: (state2) => state2.listStyle === "bullet"
|
|
4509
4677
|
},
|
|
4510
4678
|
{
|
|
4511
4679
|
type: "list-ordered",
|
|
4512
4680
|
Icon: ListNumbers,
|
|
4513
|
-
getState: (
|
|
4681
|
+
getState: (state2) => state2.listStyle === "ordered"
|
|
4514
4682
|
},
|
|
4515
4683
|
{
|
|
4516
4684
|
type: "list-task",
|
|
4517
4685
|
Icon: ListChecks,
|
|
4518
|
-
getState: (
|
|
4686
|
+
getState: (state2) => state2.listStyle === "task"
|
|
4519
4687
|
}
|
|
4520
4688
|
];
|
|
4521
4689
|
var MarkdownLists = () => {
|
|
4522
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4690
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4523
4691
|
const { t } = useTranslation(translationKey);
|
|
4524
4692
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4525
4693
|
type: "single",
|
|
4526
|
-
value:
|
|
4527
|
-
}, 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, {
|
|
4528
4696
|
key: type,
|
|
4529
4697
|
value: type,
|
|
4530
4698
|
Icon,
|
|
4531
|
-
onClick:
|
|
4699
|
+
onClick: state2 ? () => onAction?.({
|
|
4532
4700
|
type,
|
|
4533
|
-
data: !getState(
|
|
4701
|
+
data: !getState(state2)
|
|
4534
4702
|
}) : void 0
|
|
4535
4703
|
}, t(`${type} label`))));
|
|
4536
4704
|
};
|
|
@@ -4538,111 +4706,106 @@ var markdownBlocks = [
|
|
|
4538
4706
|
{
|
|
4539
4707
|
type: "blockquote",
|
|
4540
4708
|
Icon: Quotes,
|
|
4541
|
-
getState: (
|
|
4709
|
+
getState: (state2) => state2.blockQuote
|
|
4542
4710
|
},
|
|
4543
4711
|
{
|
|
4544
4712
|
type: "codeblock",
|
|
4545
4713
|
Icon: CodeBlock,
|
|
4546
|
-
getState: (
|
|
4714
|
+
getState: (state2) => state2.blockType === "codeblock"
|
|
4547
4715
|
},
|
|
4548
4716
|
{
|
|
4549
4717
|
type: "table",
|
|
4550
4718
|
Icon: Table2,
|
|
4551
|
-
getState: (
|
|
4552
|
-
disabled: (
|
|
4719
|
+
getState: (state2) => state2.blockType === "tablecell",
|
|
4720
|
+
disabled: (state2) => !state2.blankLine
|
|
4553
4721
|
}
|
|
4554
4722
|
];
|
|
4555
4723
|
var MarkdownBlocks = () => {
|
|
4556
|
-
const { onAction, state } = useToolbarContext("MarkdownStyles");
|
|
4724
|
+
const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
|
|
4557
4725
|
const { t } = useTranslation(translationKey);
|
|
4558
|
-
const value = markdownBlocks.find(({ getState }) =>
|
|
4726
|
+
const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
|
|
4559
4727
|
return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
|
|
4560
4728
|
type: "single",
|
|
4561
4729
|
value: value?.type ?? ""
|
|
4562
|
-
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(
|
|
4730
|
+
}, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
|
|
4563
4731
|
key: type,
|
|
4564
4732
|
value: type,
|
|
4565
4733
|
Icon,
|
|
4566
|
-
disabled: !
|
|
4567
|
-
onClick:
|
|
4734
|
+
disabled: !state2 || disabled?.(state2),
|
|
4735
|
+
onClick: state2 ? () => onAction?.({
|
|
4568
4736
|
type,
|
|
4569
|
-
data: !getState(
|
|
4737
|
+
data: !getState(state2)
|
|
4570
4738
|
}) : void 0
|
|
4571
4739
|
}, t(`${type} label`))));
|
|
4572
4740
|
};
|
|
4573
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));
|
|
4574
|
-
var
|
|
4742
|
+
var MarkdownCustom = ({ onUpload } = {}) => {
|
|
4575
4743
|
const { onAction } = useToolbarContext("MarkdownStyles");
|
|
4576
4744
|
const { t } = useTranslation(translationKey);
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
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,
|
|
4581
4791
|
"data-testid": "editor.toolbar.comment",
|
|
4582
4792
|
onClick: () => onAction?.({
|
|
4583
4793
|
type: "comment"
|
|
4584
|
-
})
|
|
4585
|
-
|
|
4586
|
-
}, /* @__PURE__ */ React2.createElement(ChatText, {
|
|
4587
|
-
className: iconStyles
|
|
4588
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
4589
|
-
className: "sr-only"
|
|
4590
|
-
}, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
|
|
4794
|
+
})
|
|
4795
|
+
}, t("comment label")));
|
|
4591
4796
|
};
|
|
4592
4797
|
var Toolbar = {
|
|
4593
4798
|
Root: ToolbarRoot,
|
|
4594
|
-
Button:
|
|
4799
|
+
Button: ToolbarToggleButton,
|
|
4595
4800
|
Separator: ToolbarSeparator,
|
|
4596
4801
|
Markdown: MarkdownStandard,
|
|
4597
|
-
|
|
4802
|
+
Custom: MarkdownCustom,
|
|
4803
|
+
Actions: MarkdownActions
|
|
4598
4804
|
};
|
|
4599
4805
|
|
|
4600
4806
|
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
4601
4807
|
var useActionHandler = (view) => {
|
|
4602
|
-
return (action) =>
|
|
4603
|
-
if (!view) {
|
|
4604
|
-
return;
|
|
4605
|
-
}
|
|
4606
|
-
let inlineType, listType;
|
|
4607
|
-
switch (action.type) {
|
|
4608
|
-
case "heading":
|
|
4609
|
-
setHeading(parseInt(action.data))(view);
|
|
4610
|
-
break;
|
|
4611
|
-
case "strong":
|
|
4612
|
-
case "emphasis":
|
|
4613
|
-
case "strikethrough":
|
|
4614
|
-
case "code":
|
|
4615
|
-
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4616
|
-
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
4617
|
-
break;
|
|
4618
|
-
case "list-ordered":
|
|
4619
|
-
case "list-bullet":
|
|
4620
|
-
case "list-task":
|
|
4621
|
-
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4622
|
-
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
4623
|
-
break;
|
|
4624
|
-
case "blockquote":
|
|
4625
|
-
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
4626
|
-
break;
|
|
4627
|
-
case "codeblock":
|
|
4628
|
-
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
4629
|
-
break;
|
|
4630
|
-
case "table":
|
|
4631
|
-
insertTable(view);
|
|
4632
|
-
break;
|
|
4633
|
-
case "link":
|
|
4634
|
-
(action.data === false ? removeLink : addLink)(view);
|
|
4635
|
-
break;
|
|
4636
|
-
case "comment":
|
|
4637
|
-
createComment(view);
|
|
4638
|
-
break;
|
|
4639
|
-
}
|
|
4640
|
-
setTimeout(() => {
|
|
4641
|
-
if (!view.hasFocus) {
|
|
4642
|
-
view.focus();
|
|
4643
|
-
}
|
|
4644
|
-
});
|
|
4645
|
-
};
|
|
4808
|
+
return (action) => view && processAction(view, action);
|
|
4646
4809
|
};
|
|
4647
4810
|
|
|
4648
4811
|
// packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
|
|
@@ -4661,28 +4824,36 @@ var useDocAccessor = (text) => {
|
|
|
4661
4824
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4662
4825
|
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4663
4826
|
import { EditorView as EditorView17 } from "@codemirror/view";
|
|
4664
|
-
import { useEffect as
|
|
4665
|
-
import { log as
|
|
4666
|
-
import { isNotFalsy as
|
|
4667
|
-
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";
|
|
4668
4831
|
var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
4669
4832
|
let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
|
|
4670
4833
|
const onUpdate = useRef3();
|
|
4671
4834
|
const [view, setView] = useState4();
|
|
4672
4835
|
const parentRef = useRef3(null);
|
|
4673
|
-
|
|
4836
|
+
useEffect4(() => {
|
|
4674
4837
|
let view2;
|
|
4675
4838
|
if (parentRef.current) {
|
|
4676
|
-
|
|
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({
|
|
4677
4848
|
doc,
|
|
4678
4849
|
selection,
|
|
4679
4850
|
extensions: [
|
|
4680
4851
|
id && documentId2.of(id),
|
|
4681
4852
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4682
4853
|
EditorView17.exceptionSink.of((err) => {
|
|
4683
|
-
|
|
4684
|
-
F:
|
|
4685
|
-
L:
|
|
4854
|
+
log8.catch(err, void 0, {
|
|
4855
|
+
F: __dxlog_file11,
|
|
4856
|
+
L: 46,
|
|
4686
4857
|
S: void 0,
|
|
4687
4858
|
C: (f, a) => f(...a)
|
|
4688
4859
|
});
|
|
@@ -4691,12 +4862,12 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4691
4862
|
EditorView17.updateListener.of(() => {
|
|
4692
4863
|
onUpdate.current?.();
|
|
4693
4864
|
})
|
|
4694
|
-
].filter(
|
|
4865
|
+
].filter(isNotFalsy5)
|
|
4695
4866
|
});
|
|
4696
4867
|
view2 = new EditorView17({
|
|
4697
4868
|
parent: parentRef.current,
|
|
4698
4869
|
scrollTo,
|
|
4699
|
-
state,
|
|
4870
|
+
state: state2,
|
|
4700
4871
|
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4701
4872
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4702
4873
|
dispatchTransactions: (trs, view3) => {
|
|
@@ -4709,10 +4880,18 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
|
|
|
4709
4880
|
setView(view2);
|
|
4710
4881
|
}
|
|
4711
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
|
+
});
|
|
4712
4891
|
view2?.destroy();
|
|
4713
4892
|
};
|
|
4714
4893
|
}, deps);
|
|
4715
|
-
|
|
4894
|
+
useEffect4(() => {
|
|
4716
4895
|
if (view) {
|
|
4717
4896
|
if (!selection && !view.state.selection.main.anchor) {
|
|
4718
4897
|
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
@@ -4771,36 +4950,39 @@ export {
|
|
|
4771
4950
|
callbackWrapper,
|
|
4772
4951
|
command,
|
|
4773
4952
|
comments,
|
|
4774
|
-
compareFormatting,
|
|
4775
4953
|
createBasicExtensions,
|
|
4776
4954
|
createComment,
|
|
4777
4955
|
createDataExtensions,
|
|
4778
4956
|
createMarkdownExtensions,
|
|
4779
4957
|
createThemeExtensions,
|
|
4780
|
-
cursorLineMargin,
|
|
4781
4958
|
decorateMarkdown,
|
|
4782
4959
|
defaultOptions,
|
|
4783
4960
|
defaultTheme,
|
|
4784
|
-
dnd,
|
|
4785
4961
|
documentId2 as documentId,
|
|
4962
|
+
dropFile,
|
|
4786
4963
|
editorFillLayoutEditor,
|
|
4787
4964
|
editorFillLayoutRoot,
|
|
4788
4965
|
editorMode,
|
|
4789
4966
|
editorWithToolbarLayout,
|
|
4790
4967
|
focusComment,
|
|
4968
|
+
focusEvent,
|
|
4969
|
+
formattingEquals,
|
|
4791
4970
|
formattingKeymap,
|
|
4792
4971
|
getFormatting,
|
|
4793
4972
|
getToken,
|
|
4794
4973
|
image,
|
|
4974
|
+
imageUpload,
|
|
4795
4975
|
insertTable,
|
|
4796
|
-
|
|
4976
|
+
keymap11 as keymap,
|
|
4797
4977
|
linkTooltip,
|
|
4798
4978
|
listener,
|
|
4979
|
+
localStorageStateStoreAdapter,
|
|
4799
4980
|
logChanges,
|
|
4800
4981
|
markdownHighlightStyle,
|
|
4801
4982
|
markdownTags,
|
|
4802
4983
|
markdownTagsExtensions,
|
|
4803
4984
|
mention,
|
|
4985
|
+
processAction,
|
|
4804
4986
|
removeBlockquote,
|
|
4805
4987
|
removeCodeblock,
|
|
4806
4988
|
removeLink,
|
|
@@ -4811,6 +4993,7 @@ export {
|
|
|
4811
4993
|
setHeading,
|
|
4812
4994
|
setSelection,
|
|
4813
4995
|
setStyle,
|
|
4996
|
+
state,
|
|
4814
4997
|
table,
|
|
4815
4998
|
tags2 as tags,
|
|
4816
4999
|
toggleBlockquote,
|