@dxos/react-ui-editor 0.3.11-main.47875f3 → 0.3.11-main.47fbf79
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 +2614 -1077
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -15
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +14 -6
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/{yjs.stories.d.ts → hooks.stories.d.ts} +13 -2
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +29 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +8 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +37 -20
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor.d.ts +3 -3
- package/dist/types/src/extensions/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts +57 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +8 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts +3 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +14 -27
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +2 -0
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +46 -36
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +74 -83
- package/src/components/TextEditor/TextEditor.tsx +111 -75
- package/src/components/TextEditor/automerge.stories.tsx +1 -2
- package/src/components/TextEditor/hooks.stories.tsx +111 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +102 -0
- package/src/components/Toolbar/Toolbar.tsx +245 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +54 -45
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +13 -34
- package/src/extensions/automerge/semaphore.ts +33 -32
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +22 -18
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +285 -189
- package/src/extensions/cursor.ts +7 -3
- package/src/extensions/index.ts +1 -7
- package/src/extensions/markdown/bundle.ts +23 -28
- package/src/extensions/markdown/code.ts +150 -0
- package/src/extensions/markdown/formatting.test.ts +481 -0
- package/src/extensions/markdown/formatting.ts +1198 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -15
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +16 -7
- package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +48 -33
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +93 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +66 -56
- package/src/index.ts +1 -1
- package/src/styles/markdown.ts +9 -10
- package/src/themes/default.ts +11 -8
- package/src/util.ts +26 -3
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +0 -26
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts +0 -7
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/comments.stories.tsx +0 -329
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -106
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/yjs/cursor.ts +0 -22
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -156
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
- /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
3
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
4
5
|
|
|
5
6
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
7
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
8
|
|
|
8
9
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
10
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
11
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle,
|
|
15
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
18
19
|
|
|
19
20
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
21
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
@@ -29,9 +30,11 @@ var autocomplete = ({ onSearch }) => {
|
|
|
29
30
|
// https://codemirror.net/examples/autocompletion
|
|
30
31
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
31
32
|
autocompletion({
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
33
|
+
activateOnTyping: true,
|
|
34
|
+
// closeOnBlur: false,
|
|
35
|
+
// defaultKeymap: false,
|
|
36
|
+
// TODO(burdon): Styles/fragments.
|
|
37
|
+
tooltipClass: () => "shadow rounded"
|
|
35
38
|
}),
|
|
36
39
|
// TODO(burdon): Option to create new page?
|
|
37
40
|
// TODO(burdon): Optional decoration via addToOptions
|
|
@@ -51,13 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
57
61
|
|
|
58
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
59
63
|
import get from "lodash.get";
|
|
60
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
61
65
|
var cursorConverter = (handle, path) => ({
|
|
62
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
63
67
|
toCursor: (pos) => {
|
|
@@ -69,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
69
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
70
74
|
return "end";
|
|
71
75
|
}
|
|
72
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
73
77
|
},
|
|
74
78
|
fromCursor: (cursor) => {
|
|
75
79
|
if (cursor === "") {
|
|
@@ -87,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
87
91
|
return 0;
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
|
-
var
|
|
97
|
-
var
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
98
104
|
newHeads
|
|
99
105
|
});
|
|
100
|
-
var
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
104
110
|
|
|
105
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
106
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
107
113
|
|
|
108
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
109
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
110
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
111
117
|
const { lastHeads, path } = state.field(field);
|
|
112
118
|
let hasChanges = false;
|
|
@@ -119,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
119
125
|
return void 0;
|
|
120
126
|
}
|
|
121
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
122
129
|
for (const tr of transactions) {
|
|
123
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
124
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
125
136
|
});
|
|
126
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
127
141
|
});
|
|
128
142
|
return newHeads ?? void 0;
|
|
129
143
|
};
|
|
@@ -138,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
138
152
|
selection = selection.map(changeSet, 1);
|
|
139
153
|
view.dispatch({
|
|
140
154
|
changes: changeSet,
|
|
141
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
142
156
|
});
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
view.dispatch({
|
|
146
160
|
selection,
|
|
147
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
148
162
|
});
|
|
149
163
|
};
|
|
150
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -165,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
165
179
|
if (index == null) {
|
|
166
180
|
return [];
|
|
167
181
|
}
|
|
168
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
169
183
|
return [
|
|
170
184
|
{
|
|
171
185
|
from: index,
|
|
@@ -237,40 +251,43 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
251
|
|
|
238
252
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
239
253
|
var PatchSemaphore = class {
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
256
|
+
this._handle = _handle;
|
|
257
|
+
this._state = _state;
|
|
242
258
|
this._inReconcile = false;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
248
262
|
this._inReconcile = true;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
263
|
-
if (newHeads === null || newHeads === void 0) {
|
|
264
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
265
|
-
}
|
|
266
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
267
|
-
updateCodeMirror(view, selection, path, diff);
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
268
276
|
view.dispatch({
|
|
269
|
-
|
|
270
|
-
annotations:
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
271
279
|
});
|
|
272
|
-
|
|
273
|
-
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
274
291
|
}
|
|
275
292
|
};
|
|
276
293
|
|
|
@@ -280,16 +297,17 @@ var defaultCursorConverter = {
|
|
|
280
297
|
toCursor: (position) => position.toString(),
|
|
281
298
|
fromCursor: (cursor) => parseInt(cursor)
|
|
282
299
|
};
|
|
283
|
-
var Cursor = class {
|
|
300
|
+
var Cursor = class _Cursor {
|
|
284
301
|
static {
|
|
285
302
|
this.converter = Facet.define({
|
|
286
303
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
287
304
|
});
|
|
288
305
|
}
|
|
289
306
|
static {
|
|
290
|
-
this.getCursorFromRange = (
|
|
291
|
-
const
|
|
292
|
-
const
|
|
307
|
+
this.getCursorFromRange = (state, range) => {
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
293
311
|
return [
|
|
294
312
|
from,
|
|
295
313
|
to
|
|
@@ -297,10 +315,11 @@ var Cursor = class {
|
|
|
297
315
|
};
|
|
298
316
|
}
|
|
299
317
|
static {
|
|
300
|
-
this.getRangeFromCursor = (
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
301
320
|
const parts = cursor.split(":");
|
|
302
|
-
const from =
|
|
303
|
-
const to =
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
304
323
|
return from !== void 0 && to !== void 0 ? {
|
|
305
324
|
from,
|
|
306
325
|
to
|
|
@@ -310,25 +329,22 @@ var Cursor = class {
|
|
|
310
329
|
};
|
|
311
330
|
|
|
312
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
313
|
-
var
|
|
314
|
-
|
|
315
|
-
});
|
|
316
|
-
var automerge3 = ({ handle, path }) => {
|
|
317
|
-
const stateField = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
318
334
|
create: () => ({
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
322
338
|
}),
|
|
323
339
|
update: (value, tr) => {
|
|
324
340
|
const result = {
|
|
341
|
+
path: path.slice(),
|
|
325
342
|
lastHeads: value.lastHeads,
|
|
326
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
327
|
-
path: path.slice()
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
328
344
|
};
|
|
329
345
|
let clearUnreconciled = false;
|
|
330
346
|
for (const effect of tr.effects) {
|
|
331
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
332
348
|
result.lastHeads = effect.value.newHeads;
|
|
333
349
|
clearUnreconciled = true;
|
|
334
350
|
}
|
|
@@ -336,46 +352,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
336
352
|
if (clearUnreconciled) {
|
|
337
353
|
result.unreconciledTransactions = [];
|
|
338
354
|
} else {
|
|
339
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
340
356
|
result.unreconciledTransactions.push(tr);
|
|
341
357
|
}
|
|
342
358
|
}
|
|
343
359
|
return result;
|
|
344
360
|
}
|
|
345
361
|
});
|
|
346
|
-
const semaphore = new PatchSemaphore(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
363
|
+
return [
|
|
364
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
366
|
+
// Reconcile external updates.
|
|
367
|
+
ViewPlugin.fromClass(class {
|
|
368
|
+
constructor(_view) {
|
|
369
|
+
this._view = _view;
|
|
370
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
destroy() {
|
|
373
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
374
|
+
}
|
|
375
|
+
_handleChange() {
|
|
376
|
+
semaphore.reconcile(this._view);
|
|
377
|
+
}
|
|
378
|
+
}),
|
|
379
|
+
// Reconcile local updates.
|
|
380
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
381
|
+
if (!changes.empty) {
|
|
382
|
+
semaphore.reconcile(view);
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
385
|
+
// TODO(burdon): Record undo transactions.
|
|
386
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
387
|
+
// https://codemirror.net/examples/inverted-effect
|
|
388
|
+
invertedEffects.of((tr) => {
|
|
389
|
+
const effects = [];
|
|
390
|
+
if (!tr.changes.empty) {
|
|
391
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
359
392
|
});
|
|
360
393
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
return {
|
|
367
|
-
extension: [
|
|
368
|
-
Cursor.converter.of(cursorConverter(handle, path)),
|
|
369
|
-
semaphoreFacet.of(semaphore),
|
|
370
|
-
stateField,
|
|
371
|
-
viewPlugin
|
|
372
|
-
]
|
|
373
|
-
};
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
396
|
+
];
|
|
374
397
|
};
|
|
375
398
|
|
|
376
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
377
|
-
import { Annotation as Annotation2, Facet as
|
|
378
|
-
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
400
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
401
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
379
402
|
import { Event } from "@dxos/async";
|
|
380
403
|
import { Context } from "@dxos/context";
|
|
381
404
|
var dummyProvider = {
|
|
@@ -384,17 +407,17 @@ var dummyProvider = {
|
|
|
384
407
|
},
|
|
385
408
|
close: () => {
|
|
386
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
387
411
|
update: () => {
|
|
388
|
-
}
|
|
389
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
390
413
|
};
|
|
391
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
392
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
393
416
|
});
|
|
394
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
395
418
|
var awareness = (provider = dummyProvider) => {
|
|
396
419
|
return [
|
|
397
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
398
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
399
422
|
decorations: (value) => value.decorations
|
|
400
423
|
}),
|
|
@@ -408,7 +431,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
408
431
|
this._lastAnchor = void 0;
|
|
409
432
|
this._lastHead = void 0;
|
|
410
433
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
411
|
-
this._provider = view.state.facet(
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
412
435
|
this._provider.open();
|
|
413
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
414
437
|
view.dispatch({
|
|
@@ -549,7 +572,7 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
549
572
|
return true;
|
|
550
573
|
}
|
|
551
574
|
};
|
|
552
|
-
var styles =
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
553
576
|
".cm-collab-selection": {},
|
|
554
577
|
".cm-collab-selectionLine": {
|
|
555
578
|
padding: 0,
|
|
@@ -562,40 +585,42 @@ var styles = EditorView.baseTheme({
|
|
|
562
585
|
marginLeft: "-1px",
|
|
563
586
|
marginRight: "-1px",
|
|
564
587
|
boxSizing: "border-box",
|
|
565
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
566
590
|
},
|
|
567
591
|
".cm-collab-selectionCaretDot": {
|
|
568
592
|
borderRadius: "50%",
|
|
569
593
|
position: "absolute",
|
|
570
|
-
width: ".
|
|
571
|
-
height: ".
|
|
572
|
-
top: "-.
|
|
573
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
574
598
|
backgroundColor: "inherit",
|
|
575
599
|
transition: "transform .3s ease-in-out",
|
|
576
600
|
boxSizing: "border-box"
|
|
577
601
|
},
|
|
578
602
|
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
579
|
-
|
|
580
|
-
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
581
605
|
},
|
|
582
606
|
".cm-collab-selectionInfo": {
|
|
583
607
|
position: "absolute",
|
|
584
|
-
|
|
585
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
586
611
|
fontSize: ".75em",
|
|
587
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
588
613
|
fontStyle: "normal",
|
|
589
614
|
fontWeight: "normal",
|
|
590
615
|
lineHeight: "normal",
|
|
591
616
|
userSelect: "none",
|
|
592
617
|
color: "white",
|
|
593
|
-
|
|
594
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
595
619
|
zIndex: 101,
|
|
596
620
|
transition: "opacity .3s ease-in-out",
|
|
597
621
|
backgroundColor: "inherit",
|
|
598
|
-
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
599
624
|
opacity: 0,
|
|
600
625
|
transitionDelay: "0s",
|
|
601
626
|
whiteSpace: "nowrap"
|
|
@@ -608,23 +633,26 @@ var styles = EditorView.baseTheme({
|
|
|
608
633
|
|
|
609
634
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
610
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
611
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
612
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
613
|
-
import { drawSelection, EditorView as
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
639
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
617
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
618
644
|
bracketMatching(),
|
|
619
645
|
closeBrackets(),
|
|
620
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
621
649
|
_placeholder && placeholder(_placeholder),
|
|
622
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
623
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
624
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
625
653
|
|
|
626
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
627
|
-
import { EditorView as
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
628
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
629
657
|
import { invariant } from "@dxos/invariant";
|
|
630
658
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
@@ -660,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
660
688
|
const getPoint = (view, pos) => {
|
|
661
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
662
690
|
const element = document.elementFromPoint(x, y);
|
|
663
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
664
692
|
const point = {
|
|
665
693
|
x: x - left,
|
|
666
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
667
695
|
};
|
|
668
696
|
return {
|
|
669
697
|
element,
|
|
@@ -672,7 +700,7 @@ var blast = (options = defaultOptions) => {
|
|
|
672
700
|
};
|
|
673
701
|
return [
|
|
674
702
|
// Cursor moved.
|
|
675
|
-
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
676
704
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
677
705
|
if (blaster) {
|
|
678
706
|
blaster.destroy();
|
|
@@ -755,7 +783,7 @@ var Blaster = class {
|
|
|
755
783
|
initialize() {
|
|
756
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
757
785
|
F: __dxlog_file,
|
|
758
|
-
L:
|
|
786
|
+
L: 141,
|
|
759
787
|
S: this,
|
|
760
788
|
A: [
|
|
761
789
|
"!this._canvas && !this._ctx",
|
|
@@ -792,7 +820,7 @@ var Blaster = class {
|
|
|
792
820
|
start() {
|
|
793
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
794
822
|
F: __dxlog_file,
|
|
795
|
-
L:
|
|
823
|
+
L: 180,
|
|
796
824
|
S: this,
|
|
797
825
|
A: [
|
|
798
826
|
"this._canvas && this._ctx",
|
|
@@ -933,9 +961,14 @@ var random = (min, max) => {
|
|
|
933
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
934
962
|
};
|
|
935
963
|
|
|
936
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
937
|
-
import {
|
|
938
|
-
import {
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
939
972
|
|
|
940
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
941
974
|
import * as random2 from "lib0/random";
|
|
@@ -978,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
978
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
979
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
980
1013
|
var headings = {
|
|
981
|
-
1:
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
991
|
-
"-ml-[7px]"
|
|
992
|
-
],
|
|
993
|
-
4: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
995
|
-
"-ml-[6px]"
|
|
996
|
-
],
|
|
997
|
-
5: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
999
|
-
"-ml-[5px]"
|
|
1000
|
-
],
|
|
1001
|
-
6: [
|
|
1002
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1003
|
-
"-ml-[4px]"
|
|
1004
|
-
]
|
|
1005
|
-
};
|
|
1006
|
-
var heading = (level, readonly) => {
|
|
1007
|
-
const [style, offset] = headings[level];
|
|
1008
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1009
1023
|
};
|
|
1010
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1011
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1023,168 +1037,123 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1023
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1024
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1025
1039
|
|
|
1026
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1027
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1028
|
-
var styles2 = EditorView4.baseTheme({
|
|
1029
|
-
"& .cm-codeblock": {
|
|
1030
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1031
|
-
},
|
|
1032
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1033
|
-
background: getToken("extend.colors.neutral.50")
|
|
1034
|
-
},
|
|
1035
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1036
|
-
background: getToken("extend.colors.neutral.850")
|
|
1037
|
-
},
|
|
1038
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1039
|
-
display: "block",
|
|
1040
|
-
paddingInline: "4px !important"
|
|
1041
|
-
},
|
|
1042
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1043
|
-
paddingTop: "4px !important",
|
|
1044
|
-
borderTopLeftRadius: "4px",
|
|
1045
|
-
borderTopRightRadius: "4px"
|
|
1046
|
-
},
|
|
1047
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1048
|
-
paddingBottom: "4px !important",
|
|
1049
|
-
borderBottomLeftRadius: "4px",
|
|
1050
|
-
borderBottomRightRadius: "4px"
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
var getLineRange = (lines, from, to) => {
|
|
1054
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1055
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1056
|
-
return [
|
|
1057
|
-
start,
|
|
1058
|
-
end
|
|
1059
|
-
];
|
|
1060
|
-
};
|
|
1061
|
-
var code2 = () => {
|
|
1062
|
-
const getDecorations = (view) => {
|
|
1063
|
-
const decorations = [];
|
|
1064
|
-
if (!view.hasFocus || view.state.readOnly) {
|
|
1065
|
-
const text = view.state.doc.sliceString(0);
|
|
1066
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1067
|
-
const blocks = view.viewportLineBlocks;
|
|
1068
|
-
for (const match of matches) {
|
|
1069
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1070
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1071
|
-
const block = blocks[i];
|
|
1072
|
-
decorations.push(Decoration2.line({
|
|
1073
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1074
|
-
}).range(block.from));
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
return Decoration2.set(decorations);
|
|
1079
|
-
};
|
|
1080
|
-
return [
|
|
1081
|
-
ViewPlugin3.fromClass(class {
|
|
1082
|
-
constructor(view) {
|
|
1083
|
-
this.hasFocus = false;
|
|
1084
|
-
this.decorations = getDecorations(view);
|
|
1085
|
-
}
|
|
1086
|
-
update(update2) {
|
|
1087
|
-
if (
|
|
1088
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1089
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1090
|
-
) {
|
|
1091
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1092
|
-
this.decorations = getDecorations(update2.view);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
}, {
|
|
1096
|
-
decorations: (value) => value.decorations
|
|
1097
|
-
}),
|
|
1098
|
-
styles2
|
|
1099
|
-
];
|
|
1100
|
-
};
|
|
1101
|
-
|
|
1102
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1103
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1104
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
1105
|
-
import sortBy from "lodash.sortby";
|
|
1106
|
-
import { debounce } from "@dxos/async";
|
|
1107
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1108
|
-
import { log as log2 } from "@dxos/log";
|
|
1109
|
-
import { nonNullable } from "@dxos/util";
|
|
1110
|
-
|
|
1111
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1112
1041
|
import { log } from "@dxos/log";
|
|
1113
1042
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1114
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1115
1044
|
try {
|
|
1116
1045
|
return fn(...args);
|
|
1117
|
-
} catch (
|
|
1118
|
-
log.catch(
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1119
1048
|
F: __dxlog_file2,
|
|
1120
|
-
L:
|
|
1049
|
+
L: 18,
|
|
1121
1050
|
S: void 0,
|
|
1122
1051
|
C: (f, a) => f(...a)
|
|
1123
1052
|
});
|
|
1124
1053
|
}
|
|
1125
1054
|
};
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1059
|
+
}
|
|
1060
|
+
const changes2 = [];
|
|
1061
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1062
|
+
fromA,
|
|
1063
|
+
toA,
|
|
1064
|
+
fromB,
|
|
1065
|
+
toB,
|
|
1066
|
+
inserted: inserted.toString()
|
|
1067
|
+
})));
|
|
1068
|
+
return changes2;
|
|
1069
|
+
}).filter(Boolean);
|
|
1070
|
+
if (changes.length) {
|
|
1071
|
+
console.log("changes", changes);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1126
1074
|
|
|
1127
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1128
|
-
var
|
|
1129
|
-
|
|
1130
|
-
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1077
|
+
"&light .cm-comment, &light .cm-comment-current": {
|
|
1078
|
+
mixBlendMode: "darken"
|
|
1079
|
+
},
|
|
1080
|
+
"&dark .cm-comment, &dark .cm-comment-current": {
|
|
1081
|
+
mixBlendMode: "plus-lighter"
|
|
1082
|
+
},
|
|
1083
|
+
"&light .cm-comment": {
|
|
1131
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1132
1085
|
},
|
|
1133
|
-
"& .cm-comment-
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1134
1087
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1088
|
+
},
|
|
1089
|
+
"&dark .cm-comment": {
|
|
1090
|
+
color: getToken("extend.colors.yellow.50"),
|
|
1091
|
+
backgroundColor: getToken("extend.colors.yellow.900")
|
|
1092
|
+
},
|
|
1093
|
+
"&dark .cm-comment-current": {
|
|
1094
|
+
color: getToken("extend.colors.yellow.100"),
|
|
1095
|
+
backgroundColor: getToken("extend.colors.yellow.950")
|
|
1135
1096
|
}
|
|
1136
1097
|
});
|
|
1137
|
-
var
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1147
|
-
if (!range) {
|
|
1098
|
+
var commentMark = Decoration2.mark({
|
|
1099
|
+
class: "cm-comment"
|
|
1100
|
+
});
|
|
1101
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1102
|
+
class: "cm-comment-current"
|
|
1103
|
+
});
|
|
1104
|
+
var focusComment = (view, id, center = true) => {
|
|
1105
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1106
|
+
if (!comment?.comment.cursor) {
|
|
1148
1107
|
return;
|
|
1149
1108
|
}
|
|
1150
|
-
view.
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1109
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1110
|
+
if (range) {
|
|
1111
|
+
view.dispatch({
|
|
1112
|
+
selection: {
|
|
1113
|
+
anchor: range.from
|
|
1114
|
+
},
|
|
1115
|
+
effects: [
|
|
1116
|
+
//
|
|
1117
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1118
|
+
y: "center"
|
|
1119
|
+
} : void 0),
|
|
1120
|
+
setSelection.of({
|
|
1121
|
+
current: id
|
|
1122
|
+
})
|
|
1123
|
+
]
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1159
1126
|
};
|
|
1160
|
-
var
|
|
1127
|
+
var setComments = StateEffect2.define();
|
|
1161
1128
|
var setSelection = StateEffect2.define();
|
|
1162
1129
|
var setCommentState = StateEffect2.define();
|
|
1163
|
-
var
|
|
1130
|
+
var commentsState = StateField2.define({
|
|
1164
1131
|
create: () => ({
|
|
1165
|
-
|
|
1132
|
+
comments: [],
|
|
1133
|
+
selection: {}
|
|
1166
1134
|
}),
|
|
1167
1135
|
update: (value, tr) => {
|
|
1168
|
-
const cursorConverter3 = tr.state.facet(Cursor.converter);
|
|
1169
1136
|
for (const effect of tr.effects) {
|
|
1170
1137
|
if (effect.is(setSelection)) {
|
|
1171
1138
|
return {
|
|
1172
1139
|
...value,
|
|
1173
|
-
|
|
1140
|
+
selection: effect.value
|
|
1174
1141
|
};
|
|
1175
1142
|
}
|
|
1176
|
-
if (effect.is(
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1143
|
+
if (effect.is(setComments)) {
|
|
1144
|
+
const comments2 = effect.value.map((comment) => {
|
|
1145
|
+
if (!comment.cursor) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1180
1149
|
return range && {
|
|
1181
|
-
|
|
1182
|
-
|
|
1150
|
+
comment,
|
|
1151
|
+
range
|
|
1183
1152
|
};
|
|
1184
1153
|
}).filter(nonNullable);
|
|
1185
1154
|
return {
|
|
1186
1155
|
...value,
|
|
1187
|
-
|
|
1156
|
+
comments: comments2
|
|
1188
1157
|
};
|
|
1189
1158
|
}
|
|
1190
1159
|
if (effect.is(setCommentState)) {
|
|
@@ -1194,51 +1163,79 @@ var commentsStateField = StateField2.define({
|
|
|
1194
1163
|
return value;
|
|
1195
1164
|
}
|
|
1196
1165
|
});
|
|
1197
|
-
var
|
|
1198
|
-
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1167
|
+
commentsState
|
|
1199
1168
|
], (state) => {
|
|
1200
|
-
const {
|
|
1201
|
-
const decorations = sortBy(
|
|
1202
|
-
|
|
1169
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1170
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1171
|
+
const range = comment.range;
|
|
1172
|
+
if (!range || range.from === range.to) {
|
|
1173
|
+
console.warn("Invalid range:", range);
|
|
1203
1174
|
return void 0;
|
|
1204
1175
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
to: selection.to
|
|
1208
|
-
};
|
|
1209
|
-
if (selection.id === active) {
|
|
1210
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1176
|
+
if (comment.comment.id === current) {
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1211
1178
|
} else {
|
|
1212
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1213
1180
|
}
|
|
1214
|
-
}).filter(nonNullable)
|
|
1215
|
-
return
|
|
1181
|
+
}).filter(nonNullable);
|
|
1182
|
+
return Decoration2.set(decorations);
|
|
1216
1183
|
});
|
|
1217
|
-
var trackPastedComments = (
|
|
1184
|
+
var trackPastedComments = (onUpdate) => {
|
|
1218
1185
|
let tracked = null;
|
|
1219
|
-
const
|
|
1220
|
-
const comments2 = view.state.field(
|
|
1186
|
+
const handleTrack = (event, view) => {
|
|
1187
|
+
const comments2 = view.state.field(commentsState);
|
|
1221
1188
|
const { main } = view.state.selection;
|
|
1222
|
-
const
|
|
1223
|
-
if (!
|
|
1189
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1190
|
+
if (!selectedRanges.length) {
|
|
1224
1191
|
tracked = null;
|
|
1225
1192
|
} else {
|
|
1226
1193
|
tracked = {
|
|
1227
1194
|
text: view.state.doc.slice(main.from, main.to),
|
|
1228
|
-
comments:
|
|
1195
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1196
|
+
id: comment.id,
|
|
1229
1197
|
from: range.from - main.from,
|
|
1230
|
-
to: range.to - main.from
|
|
1231
|
-
id: range.id
|
|
1198
|
+
to: range.to - main.from
|
|
1232
1199
|
}))
|
|
1233
1200
|
};
|
|
1234
1201
|
}
|
|
1235
1202
|
};
|
|
1236
1203
|
return [
|
|
1237
1204
|
EditorView5.domEventHandlers({
|
|
1238
|
-
cut:
|
|
1239
|
-
copy:
|
|
1205
|
+
cut: handleTrack,
|
|
1206
|
+
copy: handleTrack
|
|
1207
|
+
}),
|
|
1208
|
+
// Track deleted comments.
|
|
1209
|
+
invertedEffects2.of((tr) => {
|
|
1210
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1211
|
+
const effects = [];
|
|
1212
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1213
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1214
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1215
|
+
effects.push(restoreCommentEffect.of({
|
|
1216
|
+
id,
|
|
1217
|
+
from,
|
|
1218
|
+
to
|
|
1219
|
+
}));
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
return effects;
|
|
1240
1224
|
}),
|
|
1225
|
+
// Handle paste or the undo of comment deletion.
|
|
1241
1226
|
EditorView5.updateListener.of((update2) => {
|
|
1227
|
+
const restore = [];
|
|
1228
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1229
|
+
const tr = update2.transactions[i];
|
|
1230
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1231
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1232
|
+
}
|
|
1233
|
+
for (const effect of tr.effects) {
|
|
1234
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1235
|
+
restore.push(effect.value);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1242
1239
|
if (tracked) {
|
|
1243
1240
|
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1244
1241
|
if (paste) {
|
|
@@ -1252,83 +1249,92 @@ var trackPastedComments = (onMove) => {
|
|
|
1252
1249
|
}
|
|
1253
1250
|
});
|
|
1254
1251
|
if (found > -1) {
|
|
1255
|
-
const active = update2.view.state.field(commentsStateField).ranges;
|
|
1256
1252
|
for (const moved of tracked.comments) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1253
|
+
restore.push({
|
|
1254
|
+
id: moved.id,
|
|
1255
|
+
from: found + moved.from,
|
|
1256
|
+
to: found + moved.to
|
|
1257
|
+
});
|
|
1263
1258
|
}
|
|
1264
1259
|
}
|
|
1265
1260
|
tracked = null;
|
|
1266
1261
|
}
|
|
1267
1262
|
}
|
|
1263
|
+
for (const comment of restore) {
|
|
1264
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1265
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1266
|
+
if (!exists) {
|
|
1267
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1268
|
+
onUpdate(comment.id, cursor);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1268
1271
|
})
|
|
1269
1272
|
];
|
|
1270
1273
|
};
|
|
1271
|
-
var
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1274
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1275
|
+
id: comment.id,
|
|
1276
|
+
from: changes.mapPos(comment.from, 1),
|
|
1277
|
+
to: changes.mapPos(comment.to, 1)
|
|
1278
|
+
});
|
|
1279
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1280
|
+
map: mapTrackedComment
|
|
1281
|
+
});
|
|
1282
|
+
var optionsFacet = Facet3.define({
|
|
1283
|
+
combine: (providers) => providers[0]
|
|
1284
|
+
});
|
|
1285
|
+
var createComment = (view) => {
|
|
1286
|
+
const options = view.state.facet(optionsFacet);
|
|
1287
|
+
const { from, to } = view.state.selection.main;
|
|
1288
|
+
if (from === to) {
|
|
1289
|
+
return false;
|
|
1290
|
+
}
|
|
1291
|
+
if (to === view.state.doc.length) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
changes: {
|
|
1294
|
+
from: to,
|
|
1295
|
+
insert: "\n"
|
|
1296
|
+
}
|
|
1284
1297
|
});
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1298
|
+
}
|
|
1299
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1300
|
+
from,
|
|
1301
|
+
to
|
|
1302
|
+
});
|
|
1303
|
+
if (cursor) {
|
|
1304
|
+
const id = options.onCreate?.({
|
|
1305
|
+
cursor,
|
|
1290
1306
|
from,
|
|
1291
|
-
|
|
1307
|
+
location: view.coordsAtPos(from)
|
|
1292
1308
|
});
|
|
1293
|
-
if (
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
selection: {
|
|
1301
|
-
anchor: from
|
|
1302
|
-
}
|
|
1303
|
-
});
|
|
1304
|
-
if (options.footnote) {
|
|
1305
|
-
const tag = `[^${id}]`;
|
|
1306
|
-
view.dispatch({
|
|
1307
|
-
changes: {
|
|
1308
|
-
from: head,
|
|
1309
|
-
insert: tag
|
|
1310
|
-
},
|
|
1311
|
-
selection: {
|
|
1312
|
-
anchor: head + tag.length
|
|
1313
|
-
}
|
|
1314
|
-
});
|
|
1309
|
+
if (id) {
|
|
1310
|
+
view.dispatch({
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1315
1316
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1317
|
+
});
|
|
1318
|
+
return true;
|
|
1318
1319
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1321
1326
|
return [
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1327
|
+
optionsFacet.of(options),
|
|
1328
|
+
commentsState,
|
|
1329
|
+
commentsDecorations,
|
|
1330
|
+
styles2,
|
|
1325
1331
|
//
|
|
1326
1332
|
// Keymap.
|
|
1327
1333
|
//
|
|
1328
1334
|
options.onCreate ? keymap3.of([
|
|
1329
1335
|
{
|
|
1330
1336
|
key: shortcut,
|
|
1331
|
-
run: callbackWrapper(
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1332
1338
|
}
|
|
1333
1339
|
]) : [],
|
|
1334
1340
|
//
|
|
@@ -1344,7 +1350,7 @@ var comments = (options = {}) => {
|
|
|
1344
1350
|
above: true,
|
|
1345
1351
|
create: () => {
|
|
1346
1352
|
const el = document.createElement("div");
|
|
1347
|
-
options.onHover
|
|
1353
|
+
options.onHover(el, shortcut);
|
|
1348
1354
|
return {
|
|
1349
1355
|
dom: el,
|
|
1350
1356
|
offset: {
|
|
@@ -1357,365 +1363,116 @@ var comments = (options = {}) => {
|
|
|
1357
1363
|
}
|
|
1358
1364
|
return null;
|
|
1359
1365
|
}, {
|
|
1360
|
-
|
|
1366
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1367
|
+
// hideOnChange: true,
|
|
1361
1368
|
hoverTime: 1e3
|
|
1362
1369
|
}) : [],
|
|
1363
1370
|
//
|
|
1364
|
-
//
|
|
1365
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1371
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1366
1372
|
//
|
|
1367
1373
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1368
|
-
|
|
1369
|
-
{
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
if (
|
|
1375
|
-
|
|
1376
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1377
|
-
log2.info("deleted comment", {
|
|
1378
|
-
thread: range.id
|
|
1379
|
-
}, {
|
|
1380
|
-
F: __dxlog_file3,
|
|
1381
|
-
L: 337,
|
|
1382
|
-
S: void 0,
|
|
1383
|
-
C: (f, a) => f(...a)
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
if (from <= range.to) {
|
|
1388
|
-
const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1389
|
-
Object.assign(range, newRange);
|
|
1390
|
-
mod = true;
|
|
1374
|
+
let mod = false;
|
|
1375
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1376
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1377
|
+
comments2.forEach(({ comment, range }) => {
|
|
1378
|
+
if (from2 === to2) {
|
|
1379
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1380
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1381
|
+
options.onDelete?.(comment.id);
|
|
1391
1382
|
}
|
|
1392
|
-
}
|
|
1383
|
+
}
|
|
1384
|
+
if (from <= range.to) {
|
|
1385
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1386
|
+
Object.assign(range, newRange);
|
|
1387
|
+
mod = true;
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
if (mod) {
|
|
1392
|
+
view.dispatch({
|
|
1393
|
+
effects: setCommentState.of({
|
|
1394
|
+
comments: comments2,
|
|
1395
|
+
...value
|
|
1396
|
+
})
|
|
1393
1397
|
});
|
|
1394
|
-
if (mod) {
|
|
1395
|
-
view.dispatch({
|
|
1396
|
-
effects: setCommentState.of({
|
|
1397
|
-
active,
|
|
1398
|
-
ranges
|
|
1399
|
-
})
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
1398
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1399
|
+
}),
|
|
1400
|
+
//
|
|
1401
|
+
// Track selection/proximity.
|
|
1402
|
+
//
|
|
1403
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1404
|
+
let min = Infinity;
|
|
1405
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1406
|
+
const { head } = state.selection.main;
|
|
1407
|
+
const selection = {};
|
|
1408
|
+
comments2.forEach(({ comment, range }) => {
|
|
1409
|
+
if (head >= range.from && head <= range.to) {
|
|
1410
|
+
selection.current = comment.id;
|
|
1411
|
+
selection.closest = void 0;
|
|
1412
|
+
}
|
|
1413
|
+
if (!selection.current) {
|
|
1414
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1416
1415
|
if (d < min) {
|
|
1417
|
-
|
|
1416
|
+
selection.closest = comment.id;
|
|
1418
1417
|
min = d;
|
|
1419
1418
|
}
|
|
1420
|
-
});
|
|
1421
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1422
|
-
view.dispatch({
|
|
1423
|
-
effects: setSelection.of(selected)
|
|
1424
|
-
});
|
|
1425
|
-
handleSelect({
|
|
1426
|
-
...selected,
|
|
1427
|
-
ranges: ranges.map((range) => ({
|
|
1428
|
-
...range,
|
|
1429
|
-
location: view.coordsAtPos(range.from)
|
|
1430
|
-
}))
|
|
1431
|
-
});
|
|
1432
1419
|
}
|
|
1420
|
+
});
|
|
1421
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1422
|
+
view.dispatch({
|
|
1423
|
+
effects: setSelection.of(selection)
|
|
1424
|
+
});
|
|
1425
|
+
handleSelect({
|
|
1426
|
+
selection,
|
|
1427
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1428
|
+
comment,
|
|
1429
|
+
range,
|
|
1430
|
+
location: view.coordsAtPos(range.from)
|
|
1431
|
+
}))
|
|
1432
|
+
});
|
|
1433
1433
|
}
|
|
1434
1434
|
}),
|
|
1435
|
-
options.
|
|
1435
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1436
1436
|
];
|
|
1437
1437
|
};
|
|
1438
|
+
var useComments = (view, comments2 = []) => {
|
|
1439
|
+
useEffect(() => {
|
|
1440
|
+
if (view) {
|
|
1441
|
+
view.dispatch({
|
|
1442
|
+
effects: setComments.of(comments2)
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
}, [
|
|
1446
|
+
view,
|
|
1447
|
+
comments2
|
|
1448
|
+
]);
|
|
1449
|
+
};
|
|
1438
1450
|
|
|
1439
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1440
|
-
import {
|
|
1441
|
-
var
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
this._pos = _pos;
|
|
1452
|
-
}
|
|
1453
|
-
eq(other) {
|
|
1454
|
-
return this._pos === other._pos;
|
|
1455
|
-
}
|
|
1456
|
-
toDOM(view) {
|
|
1457
|
-
const el = document.createElement("div");
|
|
1458
|
-
el.className = "cm-hr";
|
|
1459
|
-
return el;
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
var placeholderMatcher = new MatchDecorator({
|
|
1463
|
-
regexp: /^---$/g,
|
|
1464
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1465
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1466
|
-
})
|
|
1467
|
-
});
|
|
1468
|
-
var hr = () => [
|
|
1469
|
-
styles4,
|
|
1470
|
-
ViewPlugin4.fromClass(class {
|
|
1471
|
-
constructor(view) {
|
|
1472
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1473
|
-
}
|
|
1474
|
-
update(update2) {
|
|
1475
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1476
|
-
}
|
|
1477
|
-
}, {
|
|
1478
|
-
decorations: (instance) => instance.rules,
|
|
1479
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1480
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1482
|
-
})
|
|
1483
|
-
})
|
|
1484
|
-
];
|
|
1485
|
-
|
|
1486
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1487
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1488
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1490
|
-
var image = (options = {}) => {
|
|
1491
|
-
return StateField3.define({
|
|
1492
|
-
create: (state) => {
|
|
1493
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1494
|
-
},
|
|
1495
|
-
update: (value, tr) => {
|
|
1496
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1497
|
-
return value;
|
|
1498
|
-
}
|
|
1499
|
-
const cursor = tr.state.selection.main.head;
|
|
1500
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1501
|
-
let from = Math.min(cursor, oldCursor);
|
|
1502
|
-
let to = Math.max(cursor, oldCursor);
|
|
1503
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1504
|
-
from = Math.min(from, fromB);
|
|
1505
|
-
to = Math.max(to, toB);
|
|
1506
|
-
});
|
|
1507
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1508
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1509
|
-
return value.map(tr.changes).update({
|
|
1510
|
-
filterFrom: from,
|
|
1511
|
-
filterTo: to,
|
|
1512
|
-
filter: () => false,
|
|
1513
|
-
add: buildDecorations(from, to, tr.state)
|
|
1514
|
-
});
|
|
1515
|
-
},
|
|
1516
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1517
|
-
});
|
|
1518
|
-
};
|
|
1519
|
-
var buildDecorations = (from, to, state) => {
|
|
1520
|
-
const decorations = [];
|
|
1521
|
-
const cursor = state.selection.main.head;
|
|
1522
|
-
syntaxTree(state).iterate({
|
|
1523
|
-
enter: (node) => {
|
|
1524
|
-
if (node.name === "Image") {
|
|
1525
|
-
const urlNode = node.node.getChild("URL");
|
|
1526
|
-
if (urlNode) {
|
|
1527
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1528
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1529
|
-
decorations.push(Decoration5.replace({
|
|
1530
|
-
block: true,
|
|
1531
|
-
widget: new ImageWidget(url)
|
|
1532
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
},
|
|
1536
|
-
from,
|
|
1537
|
-
to
|
|
1538
|
-
});
|
|
1539
|
-
return decorations;
|
|
1540
|
-
};
|
|
1541
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1542
|
-
constructor(_url) {
|
|
1543
|
-
super();
|
|
1544
|
-
this._url = _url;
|
|
1545
|
-
}
|
|
1546
|
-
eq(other) {
|
|
1547
|
-
return this._url === other._url;
|
|
1548
|
-
}
|
|
1549
|
-
toDOM(view) {
|
|
1550
|
-
const img = document.createElement("img");
|
|
1551
|
-
img.setAttribute("src", this._url);
|
|
1552
|
-
img.setAttribute("class", "cm-image");
|
|
1553
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1554
|
-
return img;
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
|
|
1558
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1559
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1560
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1561
|
-
import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1562
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1563
|
-
var link = (options = {}) => {
|
|
1564
|
-
const extensions = [
|
|
1565
|
-
ViewPlugin5.fromClass(class {
|
|
1566
|
-
constructor(view) {
|
|
1567
|
-
this.decorations = buildDecorations2(view, options);
|
|
1568
|
-
}
|
|
1569
|
-
update(update2) {
|
|
1570
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1571
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
}, {
|
|
1575
|
-
decorations: (v) => v.decorations
|
|
1576
|
-
})
|
|
1577
|
-
];
|
|
1578
|
-
if (options.onHover) {
|
|
1579
|
-
extensions.push(
|
|
1580
|
-
// https://codemirror.net/examples/tooltip
|
|
1581
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1582
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1583
|
-
hoverTooltip2((view, pos, side) => {
|
|
1584
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1585
|
-
let link2 = null;
|
|
1586
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1587
|
-
link2 = node.name === "Link" ? node : null;
|
|
1588
|
-
}
|
|
1589
|
-
const url = link2 && link2.getChild("URL");
|
|
1590
|
-
if (!url || !link2) {
|
|
1591
|
-
return null;
|
|
1592
|
-
}
|
|
1593
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1594
|
-
return {
|
|
1595
|
-
pos: link2.from,
|
|
1596
|
-
end: link2.to,
|
|
1597
|
-
above: true,
|
|
1598
|
-
create: () => {
|
|
1599
|
-
const el = document.createElement("div");
|
|
1600
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1601
|
-
options.onHover(el, urlText);
|
|
1602
|
-
return {
|
|
1603
|
-
dom: el,
|
|
1604
|
-
offset: {
|
|
1605
|
-
x: 0,
|
|
1606
|
-
y: 4
|
|
1607
|
-
}
|
|
1608
|
-
};
|
|
1609
|
-
}
|
|
1610
|
-
};
|
|
1611
|
-
})
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
return extensions;
|
|
1615
|
-
};
|
|
1616
|
-
var LinkButton = class extends WidgetType4 {
|
|
1617
|
-
constructor(_url, _onAttach) {
|
|
1618
|
-
super();
|
|
1619
|
-
this._url = _url;
|
|
1620
|
-
this._onAttach = _onAttach;
|
|
1621
|
-
}
|
|
1622
|
-
eq(other) {
|
|
1623
|
-
return this._url === other._url;
|
|
1624
|
-
}
|
|
1625
|
-
toDOM(view) {
|
|
1626
|
-
const el = document.createElement("span");
|
|
1627
|
-
this._onAttach(el, this._url);
|
|
1628
|
-
return el;
|
|
1629
|
-
}
|
|
1630
|
-
};
|
|
1631
|
-
var LinkText = class extends WidgetType4 {
|
|
1632
|
-
constructor(_text, _url) {
|
|
1633
|
-
super();
|
|
1634
|
-
this._text = _text;
|
|
1635
|
-
this._url = _url;
|
|
1636
|
-
}
|
|
1637
|
-
eq(other) {
|
|
1638
|
-
return this._url === other._url;
|
|
1639
|
-
}
|
|
1640
|
-
toDOM(view) {
|
|
1641
|
-
const link2 = document.createElement("a");
|
|
1642
|
-
link2.setAttribute("class", "cm-link");
|
|
1643
|
-
link2.textContent = this._text;
|
|
1644
|
-
if (this._url) {
|
|
1645
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1646
|
-
link2.setAttribute("target", "_blank");
|
|
1647
|
-
link2.href = this._url;
|
|
1648
|
-
} else {
|
|
1649
|
-
link2.onclick = () => {
|
|
1650
|
-
view.dispatch({
|
|
1651
|
-
selection: {
|
|
1652
|
-
anchor: view.posAtDOM(link2)
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
};
|
|
1656
|
-
}
|
|
1657
|
-
return link2;
|
|
1658
|
-
}
|
|
1659
|
-
};
|
|
1660
|
-
var buildDecorations2 = (view, options) => {
|
|
1661
|
-
const builder = new RangeSetBuilder();
|
|
1662
|
-
const { state } = view;
|
|
1663
|
-
const cursor = state.selection.main.head;
|
|
1664
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1665
|
-
syntaxTree2(state).iterate({
|
|
1666
|
-
enter: (node) => {
|
|
1667
|
-
if (node.name === "Link") {
|
|
1668
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1669
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1670
|
-
const urlNode = node.node.getChild("URL");
|
|
1671
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1672
|
-
if (!url) {
|
|
1673
|
-
return false;
|
|
1674
|
-
}
|
|
1675
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1676
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1677
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1678
|
-
}));
|
|
1679
|
-
}
|
|
1680
|
-
if (options.onRender) {
|
|
1681
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1682
|
-
widget: new LinkButton(url, options.onRender)
|
|
1683
|
-
}));
|
|
1684
|
-
}
|
|
1685
|
-
return false;
|
|
1686
|
-
}
|
|
1687
|
-
},
|
|
1688
|
-
from,
|
|
1689
|
-
to
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
return builder.finish();
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1696
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1697
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1698
|
-
const extensions = [];
|
|
1699
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1700
|
-
onFocus(focused);
|
|
1701
|
-
return null;
|
|
1702
|
-
}));
|
|
1703
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1704
|
-
onChange(update2.state.doc.toString());
|
|
1705
|
-
}));
|
|
1706
|
-
return extensions;
|
|
1451
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1452
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1453
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1454
|
+
const extensions = [];
|
|
1455
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1456
|
+
onFocus(focused);
|
|
1457
|
+
return null;
|
|
1458
|
+
}));
|
|
1459
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1460
|
+
onChange(update2.state.doc.toString());
|
|
1461
|
+
}));
|
|
1462
|
+
return extensions;
|
|
1707
1463
|
};
|
|
1708
1464
|
|
|
1709
1465
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1710
1466
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1711
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1467
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1712
1468
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1713
1469
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1714
1470
|
import { languages } from "@codemirror/language-data";
|
|
1715
1471
|
import { searchKeymap } from "@codemirror/search";
|
|
1716
1472
|
import { EditorState } from "@codemirror/state";
|
|
1717
1473
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1718
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1474
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1475
|
+
import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1719
1476
|
|
|
1720
1477
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1721
1478
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1812,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1812
1569
|
markdownTags.QuoteMark,
|
|
1813
1570
|
markdownTags.EmphasisMark
|
|
1814
1571
|
],
|
|
1815
|
-
class:
|
|
1572
|
+
class: mark
|
|
1816
1573
|
},
|
|
1817
1574
|
// E.g., code block language (after ```).
|
|
1818
1575
|
{
|
|
@@ -1820,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1820
1577
|
tags.function(tags.variableName),
|
|
1821
1578
|
tags.labelName
|
|
1822
1579
|
],
|
|
1823
|
-
class:
|
|
1580
|
+
class: codeMark
|
|
1824
1581
|
},
|
|
1825
1582
|
{
|
|
1826
1583
|
tag: [
|
|
@@ -1831,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1831
1588
|
// Headings.
|
|
1832
1589
|
{
|
|
1833
1590
|
tag: tags.heading1,
|
|
1834
|
-
class: heading(1
|
|
1591
|
+
class: heading(1)
|
|
1835
1592
|
},
|
|
1836
1593
|
{
|
|
1837
1594
|
tag: tags.heading2,
|
|
1838
|
-
class: heading(2
|
|
1595
|
+
class: heading(2)
|
|
1839
1596
|
},
|
|
1840
1597
|
{
|
|
1841
1598
|
tag: tags.heading3,
|
|
1842
|
-
class: heading(3
|
|
1599
|
+
class: heading(3)
|
|
1843
1600
|
},
|
|
1844
1601
|
{
|
|
1845
1602
|
tag: tags.heading4,
|
|
1846
|
-
class: heading(4
|
|
1603
|
+
class: heading(4)
|
|
1847
1604
|
},
|
|
1848
1605
|
{
|
|
1849
1606
|
tag: tags.heading5,
|
|
1850
|
-
class: heading(5
|
|
1607
|
+
class: heading(5)
|
|
1851
1608
|
},
|
|
1852
1609
|
{
|
|
1853
1610
|
tag: tags.heading6,
|
|
1854
|
-
class: heading(6
|
|
1611
|
+
class: heading(6)
|
|
1855
1612
|
},
|
|
1856
1613
|
// Emphasis.
|
|
1857
1614
|
{
|
|
@@ -1877,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1877
1634
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1878
1635
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1879
1636
|
// the code, but all other CSS properties will be inherited.
|
|
1880
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1637
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1881
1638
|
{
|
|
1882
1639
|
tag: [
|
|
1883
1640
|
markdownTags.CodeText,
|
|
@@ -1906,19 +1663,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1906
1663
|
};
|
|
1907
1664
|
|
|
1908
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1909
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1910
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1911
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1912
1670
|
EditorState.tabSize.of(2),
|
|
1913
|
-
|
|
1914
|
-
customKeymap(),
|
|
1671
|
+
// https://github.com/codemirror/basic-setup
|
|
1915
1672
|
bracketMatching2(),
|
|
1916
1673
|
closeBrackets2(),
|
|
1917
1674
|
crosshairCursor(),
|
|
1918
1675
|
dropCursor(),
|
|
1919
1676
|
drawSelection2(),
|
|
1920
|
-
|
|
1921
|
-
|
|
1677
|
+
highlightActiveLine2(),
|
|
1678
|
+
history2(),
|
|
1922
1679
|
indentOnInput(),
|
|
1923
1680
|
_placeholder && placeholder2(_placeholder),
|
|
1924
1681
|
// Main extension.
|
|
@@ -1942,58 +1699,1532 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1942
1699
|
// https://github.com/codemirror/theme-one-dark
|
|
1943
1700
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1944
1701
|
// Custom styles.
|
|
1945
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1702
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1703
|
+
keymap4.of([
|
|
1704
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1705
|
+
indentWithTab,
|
|
1706
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1707
|
+
...closeBracketsKeymap,
|
|
1708
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1709
|
+
...historyKeymap,
|
|
1710
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1711
|
+
...searchKeymap,
|
|
1712
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1713
|
+
...standardKeymap
|
|
1714
|
+
])
|
|
1715
|
+
].filter(isNotFalsy2);
|
|
1716
|
+
};
|
|
1960
1717
|
|
|
1961
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1962
|
-
import {
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1718
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1719
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1720
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1721
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1722
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1723
|
+
var styles3 = EditorView8.baseTheme({
|
|
1724
|
+
"& .cm-code": {
|
|
1725
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1726
|
+
},
|
|
1727
|
+
"& .cm-codeblock": {
|
|
1728
|
+
width: "100%",
|
|
1729
|
+
paddingInline: "1rem !important",
|
|
1730
|
+
position: "relative",
|
|
1731
|
+
"&::after": {
|
|
1732
|
+
content: '""',
|
|
1733
|
+
position: "absolute",
|
|
1734
|
+
inset: 0
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
"&light .cm-codeblock": {
|
|
1738
|
+
"&::after": {
|
|
1739
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1740
|
+
mixBlendMode: "darken"
|
|
1741
|
+
}
|
|
1742
|
+
},
|
|
1743
|
+
"&dark .cm-codeblock": {
|
|
1744
|
+
"&::after": {
|
|
1745
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1746
|
+
mixBlendMode: "lighten"
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
"& .cm-codeblock-first": {
|
|
1750
|
+
display: "inline-block",
|
|
1751
|
+
"&::after": {
|
|
1752
|
+
borderTopLeftRadius: ".5rem",
|
|
1753
|
+
borderTopRightRadius: ".5rem"
|
|
1754
|
+
}
|
|
1755
|
+
},
|
|
1756
|
+
"& .cm-codeblock-last": {
|
|
1757
|
+
display: "inline-block",
|
|
1758
|
+
"&::after": {
|
|
1759
|
+
borderBottomLeftRadius: ".5rem",
|
|
1760
|
+
borderBottomRightRadius: ".5rem"
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
var getLineRange = (lines, from, to) => {
|
|
1765
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1766
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1767
|
+
return [
|
|
1768
|
+
start,
|
|
1769
|
+
end
|
|
1770
|
+
];
|
|
1771
|
+
};
|
|
1772
|
+
var LineWidget = class extends WidgetType2 {
|
|
1773
|
+
constructor(_className) {
|
|
1774
|
+
super();
|
|
1775
|
+
this._className = _className;
|
|
1776
|
+
}
|
|
1777
|
+
toDOM() {
|
|
1778
|
+
const el = document.createElement("span");
|
|
1779
|
+
el.innerHTML = " ";
|
|
1780
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1781
|
+
return el;
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1785
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1786
|
+
var buildDecorations = (view) => {
|
|
1787
|
+
const builder = new RangeSetBuilder();
|
|
1788
|
+
const { state } = view;
|
|
1789
|
+
const blocks = view.viewportLineBlocks;
|
|
1790
|
+
const cursor = state.selection.main.head;
|
|
1791
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1792
|
+
syntaxTree(state).iterate({
|
|
1793
|
+
enter: (node) => {
|
|
1794
|
+
if (node.name === "FencedCode") {
|
|
1795
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1796
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1797
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1798
|
+
const block = blocks[i];
|
|
1799
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1800
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1801
|
+
widget: i === range[0] ? top : bottom
|
|
1802
|
+
}));
|
|
1803
|
+
} else {
|
|
1804
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1805
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1806
|
+
}));
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1971
1809
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
};
|
|
1979
|
-
}
|
|
1980
|
-
]
|
|
1981
|
-
});
|
|
1810
|
+
},
|
|
1811
|
+
from,
|
|
1812
|
+
to
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return builder.finish();
|
|
1982
1816
|
};
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1817
|
+
var code2 = () => {
|
|
1818
|
+
return [
|
|
1819
|
+
ViewPlugin3.fromClass(class {
|
|
1820
|
+
constructor(view) {
|
|
1821
|
+
this.decorations = buildDecorations(view);
|
|
1822
|
+
}
|
|
1823
|
+
update(update2) {
|
|
1824
|
+
this.decorations = buildDecorations(update2.view);
|
|
1825
|
+
}
|
|
1826
|
+
}, {
|
|
1827
|
+
decorations: (value) => value.decorations
|
|
1828
|
+
}),
|
|
1829
|
+
styles3
|
|
1830
|
+
];
|
|
1831
|
+
};
|
|
1832
|
+
|
|
1833
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1834
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1835
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1836
|
+
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1837
|
+
import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
+
import { useState, useMemo } from "react";
|
|
1839
|
+
var compareFormatting = (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;
|
|
1840
|
+
var Inline;
|
|
1841
|
+
(function(Inline2) {
|
|
1842
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
1843
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
1844
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
1845
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
1846
|
+
})(Inline || (Inline = {}));
|
|
1847
|
+
var List;
|
|
1848
|
+
(function(List2) {
|
|
1849
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
1850
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
1851
|
+
List2[List2["Task"] = 2] = "Task";
|
|
1852
|
+
})(List || (List = {}));
|
|
1853
|
+
var setHeading = (level) => ({ state, dispatch }) => {
|
|
1854
|
+
const { selection: { ranges }, doc } = state;
|
|
1855
|
+
const changes = [];
|
|
1856
|
+
let prevBlock = -1;
|
|
1857
|
+
for (const range of ranges) {
|
|
1858
|
+
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1861
|
+
enter: (node) => {
|
|
1862
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
prevBlock = node.from;
|
|
1866
|
+
const blockType = Textblocks[node.name];
|
|
1867
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
1868
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
1869
|
+
if (curLevel < 0 || curLevel === level) {
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (curLevel === 0) {
|
|
1873
|
+
changes.push({
|
|
1874
|
+
from: node.from,
|
|
1875
|
+
insert: "#".repeat(level) + " "
|
|
1876
|
+
});
|
|
1877
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
1878
|
+
const nextLine = doc.lineAt(node.to);
|
|
1879
|
+
if (level) {
|
|
1880
|
+
changes.push({
|
|
1881
|
+
from: node.from,
|
|
1882
|
+
insert: "#".repeat(level) + " "
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
changes.push({
|
|
1886
|
+
from: nextLine.from - 1,
|
|
1887
|
+
to: nextLine.to
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
if (level === 0) {
|
|
1891
|
+
changes.push({
|
|
1892
|
+
from: node.from,
|
|
1893
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
1894
|
+
});
|
|
1895
|
+
} else if (level < curLevel) {
|
|
1896
|
+
changes.push({
|
|
1897
|
+
from: node.from,
|
|
1898
|
+
to: node.from + (curLevel - level)
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
changes.push({
|
|
1902
|
+
from: node.from,
|
|
1903
|
+
insert: "#".repeat(level - curLevel)
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
if (!changes.length) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
dispatch(state.update({
|
|
1914
|
+
changes,
|
|
1915
|
+
userEvent: "format.setHeading",
|
|
1916
|
+
scrollIntoView: true
|
|
1917
|
+
}));
|
|
1918
|
+
return true;
|
|
1919
|
+
};
|
|
1920
|
+
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
1921
|
+
const marker = inlineMarkerText(type);
|
|
1922
|
+
const changes = state.changeByRange((range) => {
|
|
1923
|
+
if (!enable && range.empty) {
|
|
1924
|
+
const after = state.doc.sliceString(range.head, range.head + 6);
|
|
1925
|
+
const found = after.indexOf(marker);
|
|
1926
|
+
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
1927
|
+
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
1928
|
+
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
1929
|
+
...before.slice(before.length - found)
|
|
1930
|
+
].reverse().join("") === after.slice(0, found)) {
|
|
1931
|
+
return {
|
|
1932
|
+
changes: [
|
|
1933
|
+
{
|
|
1934
|
+
from: range.head - marker.length - found,
|
|
1935
|
+
to: range.head - found
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
from: range.head + found,
|
|
1939
|
+
to: range.head + found + marker.length
|
|
1940
|
+
}
|
|
1941
|
+
],
|
|
1942
|
+
range: EditorSelection.cursor(range.from - marker.length)
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
const changes2 = [];
|
|
1948
|
+
const changesAtEnd = [];
|
|
1949
|
+
let blockStart = -1;
|
|
1950
|
+
let blockEnd = -1;
|
|
1951
|
+
let startCovered = false;
|
|
1952
|
+
let endCovered = false;
|
|
1953
|
+
let { from, to } = range;
|
|
1954
|
+
syntaxTree2(state).iterate({
|
|
1955
|
+
from,
|
|
1956
|
+
to,
|
|
1957
|
+
enter: (node) => {
|
|
1958
|
+
const { name } = node;
|
|
1959
|
+
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
1960
|
+
blockStart = blockContentStart(node);
|
|
1961
|
+
blockEnd = blockContentEnd(node, state.doc);
|
|
1962
|
+
startCovered = endCovered = false;
|
|
1963
|
+
} else if (name === "Link" || name === "Image" && enable) {
|
|
1964
|
+
if (from < node.from && to > node.from && to <= node.to) {
|
|
1965
|
+
to = node.to;
|
|
1966
|
+
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
1967
|
+
from = node.from;
|
|
1968
|
+
}
|
|
1969
|
+
} else if (IgnoreInline.has(name) && enable) {
|
|
1970
|
+
if (node.from < from && node.to > from) {
|
|
1971
|
+
if (to === from) {
|
|
1972
|
+
to = node.to;
|
|
1973
|
+
}
|
|
1974
|
+
from = node.to;
|
|
1975
|
+
}
|
|
1976
|
+
if (node.from < to && node.to > to) {
|
|
1977
|
+
to = node.from;
|
|
1978
|
+
}
|
|
1979
|
+
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
1980
|
+
const markType = InlineMarker[name];
|
|
1981
|
+
const size = inlineMarkerText(markType).length;
|
|
1982
|
+
const openEnd = node.from + size;
|
|
1983
|
+
const closeStart = node.to - size;
|
|
1984
|
+
if (markType === type) {
|
|
1985
|
+
if (openEnd <= from && closeStart >= from) {
|
|
1986
|
+
startCovered = openEnd === from ? "adjacent" : true;
|
|
1987
|
+
}
|
|
1988
|
+
if (openEnd <= to && closeStart >= to) {
|
|
1989
|
+
endCovered = closeStart === to ? "adjacent" : true;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (markType === type || type === 3 && enable) {
|
|
1993
|
+
if (node.from >= from && openEnd <= to) {
|
|
1994
|
+
changes2.push({
|
|
1995
|
+
from: node.from,
|
|
1996
|
+
to: openEnd
|
|
1997
|
+
});
|
|
1998
|
+
if (markType !== type && closeStart >= to) {
|
|
1999
|
+
changesAtEnd.push({
|
|
2000
|
+
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2001
|
+
insert: inlineMarkerText(markType)
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
if (closeStart >= from && node.to <= to) {
|
|
2006
|
+
changes2.push({
|
|
2007
|
+
from: closeStart,
|
|
2008
|
+
to: node.to
|
|
2009
|
+
});
|
|
2010
|
+
if (markType !== type && openEnd <= from) {
|
|
2011
|
+
changes2.push({
|
|
2012
|
+
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2013
|
+
insert: inlineMarkerText(markType)
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
leave: (node) => {
|
|
2021
|
+
if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
|
|
2022
|
+
const rangeStart = Math.max(from, blockStart);
|
|
2023
|
+
const rangeEnd = Math.min(to, blockEnd);
|
|
2024
|
+
if (enable) {
|
|
2025
|
+
if (!startCovered) {
|
|
2026
|
+
changes2.push({
|
|
2027
|
+
from: rangeStart,
|
|
2028
|
+
insert: marker
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (!endCovered) {
|
|
2032
|
+
changes2.push({
|
|
2033
|
+
from: rangeEnd,
|
|
2034
|
+
insert: marker
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
} else {
|
|
2038
|
+
if (startCovered === "adjacent") {
|
|
2039
|
+
changes2.push({
|
|
2040
|
+
from: from - marker.length,
|
|
2041
|
+
to: from
|
|
2042
|
+
});
|
|
2043
|
+
} else if (startCovered) {
|
|
2044
|
+
changes2.push({
|
|
2045
|
+
from: skipSpaces(rangeStart, state.doc, -1, blockStart),
|
|
2046
|
+
insert: marker
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (endCovered === "adjacent") {
|
|
2050
|
+
changes2.push({
|
|
2051
|
+
from: to,
|
|
2052
|
+
to: to + marker.length
|
|
2053
|
+
});
|
|
2054
|
+
} else if (endCovered) {
|
|
2055
|
+
changes2.push({
|
|
2056
|
+
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
2057
|
+
insert: marker
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
});
|
|
2064
|
+
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
2065
|
+
return {
|
|
2066
|
+
changes: changeSet,
|
|
2067
|
+
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
2068
|
+
};
|
|
2069
|
+
});
|
|
2070
|
+
dispatch(state.update(changes, {
|
|
2071
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2072
|
+
scrollIntoView: true
|
|
2073
|
+
}));
|
|
2074
|
+
return true;
|
|
2075
|
+
};
|
|
2076
|
+
var addStyle = (style) => setStyle(style, true);
|
|
2077
|
+
var removeStyle = (style) => setStyle(style, false);
|
|
2078
|
+
var toggleStyle = (style) => (arg) => {
|
|
2079
|
+
const form = getFormatting(arg.state);
|
|
2080
|
+
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
2081
|
+
};
|
|
2082
|
+
var toggleStrong = toggleStyle(0);
|
|
2083
|
+
var toggleEmphasis = toggleStyle(1);
|
|
2084
|
+
var toggleStrikethrough = toggleStyle(2);
|
|
2085
|
+
var toggleInlineCode = toggleStyle(3);
|
|
2086
|
+
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
2087
|
+
var blockContentStart = (node) => {
|
|
2088
|
+
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
2089
|
+
if (atx) {
|
|
2090
|
+
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
2091
|
+
}
|
|
2092
|
+
return node.from;
|
|
2093
|
+
};
|
|
2094
|
+
var blockContentEnd = (node, doc) => {
|
|
2095
|
+
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
2096
|
+
const lastLine = doc.lineAt(node.to);
|
|
2097
|
+
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
2098
|
+
return lastLine.from - 1;
|
|
2099
|
+
}
|
|
2100
|
+
return node.to;
|
|
2101
|
+
};
|
|
2102
|
+
var skipSpaces = (pos, doc, dir, limit) => {
|
|
2103
|
+
const line = doc.lineAt(pos);
|
|
2104
|
+
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
2105
|
+
pos += dir;
|
|
2106
|
+
}
|
|
2107
|
+
return pos;
|
|
2108
|
+
};
|
|
2109
|
+
var snippets = {
|
|
2110
|
+
codeblock: snippet([
|
|
2111
|
+
"```#{lang}",
|
|
2112
|
+
"#{}",
|
|
2113
|
+
"```"
|
|
2114
|
+
].join("\n")),
|
|
2115
|
+
table: snippet([
|
|
2116
|
+
"| #{col1} | #{col2} |",
|
|
2117
|
+
"| ---- | ---- |",
|
|
2118
|
+
"| #{val1} | #{val2} |",
|
|
2119
|
+
"| #{val3} | #{val4} |"
|
|
2120
|
+
].join("\n"))
|
|
2121
|
+
};
|
|
2122
|
+
var insertTable = (view) => {
|
|
2123
|
+
const { selection: { main }, doc } = view.state;
|
|
2124
|
+
const { number } = doc.lineAt(main.anchor);
|
|
2125
|
+
const { from } = doc.line(number);
|
|
2126
|
+
snippets.table(view, null, from, from);
|
|
2127
|
+
};
|
|
2128
|
+
var removeLinkInner = (from, to, changes, state) => {
|
|
2129
|
+
syntaxTree2(state).iterate({
|
|
2130
|
+
from,
|
|
2131
|
+
to,
|
|
2132
|
+
enter: (node) => {
|
|
2133
|
+
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
2134
|
+
node.node.cursor().iterate((node2) => {
|
|
2135
|
+
const { name } = node2;
|
|
2136
|
+
if (name === "LinkMark" || name === "LinkLabel") {
|
|
2137
|
+
changes.push({
|
|
2138
|
+
from: node2.from,
|
|
2139
|
+
to: node2.to
|
|
2140
|
+
});
|
|
2141
|
+
} else if (name === "LinkTitle" || name === "URL") {
|
|
2142
|
+
changes.push({
|
|
2143
|
+
from: skipSpaces(node2.from, state.doc, -1),
|
|
2144
|
+
to: skipSpaces(node2.to, state.doc, 1)
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
});
|
|
2152
|
+
};
|
|
2153
|
+
var removeLink = ({ state, dispatch }) => {
|
|
2154
|
+
const changes = [];
|
|
2155
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2156
|
+
removeLinkInner(from, to, changes, state);
|
|
2157
|
+
}
|
|
2158
|
+
if (!changes) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
dispatch(state.update({
|
|
2162
|
+
changes,
|
|
2163
|
+
userEvent: "format.link.remove",
|
|
2164
|
+
scrollIntoView: true
|
|
2165
|
+
}));
|
|
2166
|
+
return true;
|
|
2167
|
+
};
|
|
2168
|
+
var addLink = ({ state, dispatch }) => {
|
|
2169
|
+
const changes = state.changeByRange((range) => {
|
|
2170
|
+
let { from, to } = range;
|
|
2171
|
+
const cutStyles = [];
|
|
2172
|
+
let okay = null;
|
|
2173
|
+
syntaxTree2(state).iterate({
|
|
2174
|
+
from,
|
|
2175
|
+
to,
|
|
2176
|
+
enter: (node) => {
|
|
2177
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2178
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
|
|
2179
|
+
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
2180
|
+
const sNode = node.node;
|
|
2181
|
+
if (node.from < from && node.to <= to) {
|
|
2182
|
+
if (sNode.firstChild.to === from) {
|
|
2183
|
+
from = node.from;
|
|
2184
|
+
} else {
|
|
2185
|
+
cutStyles.push(sNode);
|
|
2186
|
+
}
|
|
2187
|
+
} else if (node.from >= from && node.to > to) {
|
|
2188
|
+
if (sNode.lastChild.from === to) {
|
|
2189
|
+
to = node.to;
|
|
2190
|
+
} else {
|
|
2191
|
+
cutStyles.push(sNode);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
if (okay === null) {
|
|
2198
|
+
const line = state.doc.lineAt(from);
|
|
2199
|
+
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
2200
|
+
}
|
|
2201
|
+
if (!okay) {
|
|
2202
|
+
return {
|
|
2203
|
+
range
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
const changes2 = [];
|
|
2207
|
+
const changesAfter = [];
|
|
2208
|
+
removeLinkInner(from, to, changesAfter, state);
|
|
2209
|
+
let cursorOffset = 1;
|
|
2210
|
+
for (const style of cutStyles) {
|
|
2211
|
+
const type = InlineMarker[style.name];
|
|
2212
|
+
const mark2 = inlineMarkerText(type);
|
|
2213
|
+
if (style.from < from) {
|
|
2214
|
+
changes2.push({
|
|
2215
|
+
from: skipSpaces(from, state.doc, -1),
|
|
2216
|
+
insert: mark2
|
|
2217
|
+
});
|
|
2218
|
+
changesAfter.push({
|
|
2219
|
+
from: skipSpaces(from, state.doc, 1, to),
|
|
2220
|
+
insert: mark2
|
|
2221
|
+
});
|
|
2222
|
+
} else {
|
|
2223
|
+
changes2.push({
|
|
2224
|
+
from: skipSpaces(to, state.doc, -1, from),
|
|
2225
|
+
insert: mark2
|
|
2226
|
+
});
|
|
2227
|
+
const after = skipSpaces(to, state.doc, 1);
|
|
2228
|
+
if (after === to) {
|
|
2229
|
+
cursorOffset += mark2.length;
|
|
2230
|
+
}
|
|
2231
|
+
changesAfter.push({
|
|
2232
|
+
from: after,
|
|
2233
|
+
insert: mark2
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
changes2.push({
|
|
2238
|
+
from,
|
|
2239
|
+
insert: "["
|
|
2240
|
+
}, {
|
|
2241
|
+
from: to,
|
|
2242
|
+
insert: "]()"
|
|
2243
|
+
});
|
|
2244
|
+
const changeSet = state.changes(changes2.concat(changesAfter));
|
|
2245
|
+
return {
|
|
2246
|
+
changes: changeSet,
|
|
2247
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
2248
|
+
};
|
|
2249
|
+
});
|
|
2250
|
+
if (changes.changes.empty) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
dispatch(state.update(changes, {
|
|
2254
|
+
userEvent: "format.link.add",
|
|
2255
|
+
scrollIntoView: true
|
|
2256
|
+
}));
|
|
2257
|
+
return true;
|
|
2258
|
+
};
|
|
2259
|
+
var addList = (type) => ({ state, dispatch }) => {
|
|
2260
|
+
let lastBlock = -1;
|
|
2261
|
+
let counter = 1;
|
|
2262
|
+
let first = true;
|
|
2263
|
+
let parentColumn = null;
|
|
2264
|
+
const blocks = [];
|
|
2265
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2266
|
+
syntaxTree2(state).iterate({
|
|
2267
|
+
from,
|
|
2268
|
+
to,
|
|
2269
|
+
enter: (node) => {
|
|
2270
|
+
if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
|
|
2271
|
+
if (first) {
|
|
2272
|
+
let before = node.node.prevSibling;
|
|
2273
|
+
while (before && /Mark$/.test(before.name)) {
|
|
2274
|
+
before = before.prevSibling;
|
|
2275
|
+
}
|
|
2276
|
+
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
2277
|
+
const item = before.lastChild;
|
|
2278
|
+
const itemLine = state.doc.lineAt(item.from);
|
|
2279
|
+
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
2280
|
+
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
2281
|
+
if (type === 0) {
|
|
2282
|
+
const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
|
|
2283
|
+
if (mark2) {
|
|
2284
|
+
parentColumn += mark2[1].length;
|
|
2285
|
+
counter = +mark2[1] + 1;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
first = false;
|
|
2290
|
+
}
|
|
2291
|
+
if (node.from === lastBlock) {
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
lastBlock = node.from;
|
|
2295
|
+
blocks.push({
|
|
2296
|
+
node: node.node,
|
|
2297
|
+
counter,
|
|
2298
|
+
parentColumn
|
|
2299
|
+
});
|
|
2300
|
+
counter++;
|
|
2301
|
+
return false;
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
leave: (node) => {
|
|
2305
|
+
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
2306
|
+
counter = 1;
|
|
2307
|
+
parentColumn = null;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
if (!blocks.length) {
|
|
2313
|
+
return false;
|
|
2314
|
+
}
|
|
2315
|
+
const changes = [];
|
|
2316
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
2317
|
+
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
2318
|
+
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
2319
|
+
let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
2320
|
+
if (type === 0) {
|
|
2321
|
+
padding += String(counter2).length;
|
|
2322
|
+
}
|
|
2323
|
+
let line = state.doc.lineAt(nodeFrom);
|
|
2324
|
+
const column = nodeFrom - line.from;
|
|
2325
|
+
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
2326
|
+
padding = Math.max(padding, parentColumn2 - column);
|
|
2327
|
+
}
|
|
2328
|
+
let mark2;
|
|
2329
|
+
if (type === 0) {
|
|
2330
|
+
let max = counter2;
|
|
2331
|
+
for (let j = i + 1; j < blocks.length; j++) {
|
|
2332
|
+
if (blocks[j].counter !== max + 1) {
|
|
2333
|
+
break;
|
|
2334
|
+
}
|
|
2335
|
+
max++;
|
|
2336
|
+
}
|
|
2337
|
+
const num = String(counter2);
|
|
2338
|
+
padding = Math.max(String(max).length, padding);
|
|
2339
|
+
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
2340
|
+
} else {
|
|
2341
|
+
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
2342
|
+
}
|
|
2343
|
+
changes.push({
|
|
2344
|
+
from: nodeFrom,
|
|
2345
|
+
insert: mark2
|
|
2346
|
+
});
|
|
2347
|
+
while (line.to < node.to) {
|
|
2348
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2349
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2350
|
+
changes.push({
|
|
2351
|
+
from: line.from + Math.min(open, column),
|
|
2352
|
+
insert: " ".repeat(mark2.length)
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
if (type === 0) {
|
|
2357
|
+
const last = blocks[blocks.length - 1];
|
|
2358
|
+
let next = last.node.nextSibling;
|
|
2359
|
+
while (next && /Mark$/.test(next.name)) {
|
|
2360
|
+
next = next.nextSibling;
|
|
2361
|
+
}
|
|
2362
|
+
if (next?.name === "OrderedList") {
|
|
2363
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
dispatch(state.update({
|
|
2367
|
+
changes,
|
|
2368
|
+
userEvent: "format.list.add",
|
|
2369
|
+
scrollIntoView: true
|
|
2370
|
+
}));
|
|
2371
|
+
return true;
|
|
2372
|
+
};
|
|
2373
|
+
var removeList = (type) => ({ state, dispatch }) => {
|
|
2374
|
+
let lastBlock = -1;
|
|
2375
|
+
const changes = [];
|
|
2376
|
+
const stack = [];
|
|
2377
|
+
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
2378
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2379
|
+
syntaxTree2(state).iterate({
|
|
2380
|
+
from,
|
|
2381
|
+
to,
|
|
2382
|
+
enter: (node) => {
|
|
2383
|
+
const { name } = node;
|
|
2384
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2385
|
+
stack.push(name);
|
|
2386
|
+
} else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2387
|
+
stack[stack.length - 1] = "TaskList";
|
|
2388
|
+
}
|
|
2389
|
+
},
|
|
2390
|
+
leave: (node) => {
|
|
2391
|
+
const { name } = node;
|
|
2392
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2393
|
+
stack.pop();
|
|
2394
|
+
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
2395
|
+
lastBlock = node.from;
|
|
2396
|
+
let line = state.doc.lineAt(node.from);
|
|
2397
|
+
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
2398
|
+
if (!mark2) {
|
|
2399
|
+
return false;
|
|
2400
|
+
}
|
|
2401
|
+
const column = node.from - line.from;
|
|
2402
|
+
changes.push({
|
|
2403
|
+
from: node.from,
|
|
2404
|
+
to: node.from + mark2[0].length
|
|
2405
|
+
});
|
|
2406
|
+
while (line.to < node.to) {
|
|
2407
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2408
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2409
|
+
if (open > column) {
|
|
2410
|
+
changes.push({
|
|
2411
|
+
from: line.from + column,
|
|
2412
|
+
to: line.from + Math.min(column + mark2[0].length, open)
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
if (node.to >= to) {
|
|
2417
|
+
renumberListItems(node.node.nextSibling, 1, changes, state.doc);
|
|
2418
|
+
}
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
if (!changes.length) {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
dispatch(state.update({
|
|
2428
|
+
changes,
|
|
2429
|
+
userEvent: "format.list.remove",
|
|
2430
|
+
scrollIntoView: true
|
|
2431
|
+
}));
|
|
2432
|
+
return true;
|
|
2433
|
+
};
|
|
2434
|
+
var toggleList = (type) => (target) => {
|
|
2435
|
+
const formatting2 = getFormatting(target.state);
|
|
2436
|
+
const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
|
|
2437
|
+
return (active ? removeList(type) : addList(type))(target);
|
|
2438
|
+
};
|
|
2439
|
+
var renumberListItems = (item, counter, changes, doc) => {
|
|
2440
|
+
for (; item; item = item.nextSibling) {
|
|
2441
|
+
if (item.name === "ListItem") {
|
|
2442
|
+
const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
|
|
2443
|
+
if (!number || +number[2] === counter) {
|
|
2444
|
+
break;
|
|
2445
|
+
}
|
|
2446
|
+
const size = number[1].length + number[2].length;
|
|
2447
|
+
const newNum = String(counter);
|
|
2448
|
+
changes.push({
|
|
2449
|
+
from: item.from + Math.max(0, size - newNum.length),
|
|
2450
|
+
to: item.from + size,
|
|
2451
|
+
insert: newNum
|
|
2452
|
+
});
|
|
2453
|
+
counter++;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
2458
|
+
const lines = [];
|
|
2459
|
+
let lastBlock = -1;
|
|
2460
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2461
|
+
syntaxTree2(state).iterate({
|
|
2462
|
+
from,
|
|
2463
|
+
to,
|
|
2464
|
+
enter: (node) => {
|
|
2465
|
+
if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
|
|
2466
|
+
if (node.from === lastBlock) {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
lastBlock = node.from;
|
|
2470
|
+
let line = state.doc.lineAt(node.from);
|
|
2471
|
+
if (line.number > 1) {
|
|
2472
|
+
const prevLine = state.doc.line(line.number - 1);
|
|
2473
|
+
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2474
|
+
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2475
|
+
lines.push(prevLine);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
for (; ; ) {
|
|
2480
|
+
lines.push(line);
|
|
2481
|
+
if (line.to >= node.to) {
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
line = state.doc.line(line.number + 1);
|
|
2485
|
+
}
|
|
2486
|
+
if (!enable && line.number < state.doc.lines) {
|
|
2487
|
+
const nextLine = state.doc.line(line.number + 1);
|
|
2488
|
+
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2489
|
+
lines.push(nextLine);
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return false;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
const changes = [];
|
|
2498
|
+
for (const line of lines) {
|
|
2499
|
+
if (enable) {
|
|
2500
|
+
changes.push({
|
|
2501
|
+
from: line.from,
|
|
2502
|
+
insert: /\S/.test(line.text) ? "> " : ">"
|
|
2503
|
+
});
|
|
2504
|
+
} else {
|
|
2505
|
+
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
2506
|
+
if (quote) {
|
|
2507
|
+
changes.push({
|
|
2508
|
+
from: line.from + quote[1].length,
|
|
2509
|
+
to: line.from + quote[0].length
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (!changes.length) {
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
dispatch(state.update({
|
|
2518
|
+
changes,
|
|
2519
|
+
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
2520
|
+
scrollIntoView: true
|
|
2521
|
+
}));
|
|
2522
|
+
return true;
|
|
2523
|
+
};
|
|
2524
|
+
var addBlockquote = setBlockquote(true);
|
|
2525
|
+
var removeBlockquote = setBlockquote(false);
|
|
2526
|
+
var toggleBlockquote = (target) => {
|
|
2527
|
+
return (getFormatting(target.state).blockquote ? removeBlockquote : addBlockquote)(target);
|
|
2528
|
+
};
|
|
2529
|
+
var addCodeblock = (target) => {
|
|
2530
|
+
const { state, dispatch } = target;
|
|
2531
|
+
const { selection } = state;
|
|
2532
|
+
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
2533
|
+
const { head } = selection.main;
|
|
2534
|
+
const line = state.doc.lineAt(head);
|
|
2535
|
+
if (!/\S/.test(line.text) && head === line.from) {
|
|
2536
|
+
snippets.codeblock(target, null, line.from, line.to);
|
|
2537
|
+
return true;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const ranges = [];
|
|
2541
|
+
for (const { from, to } of selection.ranges) {
|
|
2542
|
+
let blockFrom = from;
|
|
2543
|
+
let blockTo = to;
|
|
2544
|
+
syntaxTree2(state).iterate({
|
|
2545
|
+
from,
|
|
2546
|
+
to,
|
|
2547
|
+
enter: (node) => {
|
|
2548
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2549
|
+
if (from >= node.from && to <= node.to) {
|
|
2550
|
+
blockFrom = node.from;
|
|
2551
|
+
blockTo = node.to;
|
|
2552
|
+
} else {
|
|
2553
|
+
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
2554
|
+
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
});
|
|
2559
|
+
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
2560
|
+
ranges[ranges.length - 1].to = blockTo;
|
|
2561
|
+
} else {
|
|
2562
|
+
ranges.push({
|
|
2563
|
+
from: blockFrom,
|
|
2564
|
+
to: blockTo
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if (!ranges.length) {
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
const changes = ranges.map(({ from, to }) => {
|
|
2572
|
+
const column = from - state.doc.lineAt(from).from;
|
|
2573
|
+
return [
|
|
2574
|
+
{
|
|
2575
|
+
from,
|
|
2576
|
+
insert: "```\n" + " ".repeat(column)
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
from: to,
|
|
2580
|
+
insert: "\n" + " ".repeat(column) + "```"
|
|
2581
|
+
}
|
|
2582
|
+
];
|
|
2583
|
+
});
|
|
2584
|
+
dispatch(state.update({
|
|
2585
|
+
changes,
|
|
2586
|
+
userEvent: "format.codeblock.add",
|
|
2587
|
+
scrollIntoView: true
|
|
2588
|
+
}));
|
|
2589
|
+
return true;
|
|
2590
|
+
};
|
|
2591
|
+
var removeCodeblock = ({ state, dispatch }) => {
|
|
2592
|
+
const changes = [];
|
|
2593
|
+
let lastBlock = -1;
|
|
2594
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2595
|
+
syntaxTree2(state).iterate({
|
|
2596
|
+
from,
|
|
2597
|
+
to,
|
|
2598
|
+
enter: (node) => {
|
|
2599
|
+
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
2600
|
+
lastBlock = node.from;
|
|
2601
|
+
const firstLine = state.doc.lineAt(node.from);
|
|
2602
|
+
if (node.name === "FencedCode") {
|
|
2603
|
+
changes.push({
|
|
2604
|
+
from: node.from,
|
|
2605
|
+
to: firstLine.to + 1 + node.from - firstLine.from
|
|
2606
|
+
});
|
|
2607
|
+
const lastLine = state.doc.lineAt(node.to);
|
|
2608
|
+
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
2609
|
+
changes.push({
|
|
2610
|
+
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
2611
|
+
to: lastLine.to
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2614
|
+
} else {
|
|
2615
|
+
const column = node.from - firstLine.from;
|
|
2616
|
+
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
2617
|
+
changes.push({
|
|
2618
|
+
from: line.from + column - 4,
|
|
2619
|
+
to: line.from + column
|
|
2620
|
+
});
|
|
2621
|
+
if (line.to >= node.to) {
|
|
2622
|
+
break;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
if (!changes.length) {
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
dispatch(state.update({
|
|
2634
|
+
changes,
|
|
2635
|
+
userEvent: "format.codeblock.remove",
|
|
2636
|
+
scrollIntoView: true
|
|
2637
|
+
}));
|
|
2638
|
+
return true;
|
|
2639
|
+
};
|
|
2640
|
+
var toggleCodeblock = (target) => {
|
|
2641
|
+
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
2642
|
+
};
|
|
2643
|
+
var formatting = (options = {}) => {
|
|
2644
|
+
return [
|
|
2645
|
+
keymap5.of([
|
|
2646
|
+
{
|
|
2647
|
+
key: "meta-b",
|
|
2648
|
+
run: toggleStrong
|
|
2649
|
+
}
|
|
2650
|
+
]),
|
|
2651
|
+
styling()
|
|
2652
|
+
];
|
|
2653
|
+
};
|
|
2654
|
+
var styling = () => {
|
|
2655
|
+
const buildDecorations7 = (view) => {
|
|
2656
|
+
const builder = new RangeSetBuilder2();
|
|
2657
|
+
const { state } = view;
|
|
2658
|
+
const cursor = state.selection.main.head;
|
|
2659
|
+
const replace = (node, marks) => {
|
|
2660
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2661
|
+
for (const mark2 of marks) {
|
|
2662
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2667
|
+
syntaxTree2(state).iterate({
|
|
2668
|
+
enter: (node) => {
|
|
2669
|
+
switch (node.name) {
|
|
2670
|
+
case "Emphasis":
|
|
2671
|
+
case "StrongEmphasis": {
|
|
2672
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
2673
|
+
replace(node, marks);
|
|
2674
|
+
break;
|
|
2675
|
+
}
|
|
2676
|
+
case "Strikethrough": {
|
|
2677
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
2678
|
+
replace(node, marks);
|
|
2679
|
+
break;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
},
|
|
2683
|
+
from,
|
|
2684
|
+
to
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
return builder.finish();
|
|
2688
|
+
};
|
|
2689
|
+
return [
|
|
2690
|
+
ViewPlugin4.fromClass(class {
|
|
2691
|
+
constructor(view) {
|
|
2692
|
+
this.decorations = buildDecorations7(view);
|
|
2693
|
+
}
|
|
2694
|
+
update(update2) {
|
|
2695
|
+
this.decorations = buildDecorations7(update2.view);
|
|
2696
|
+
}
|
|
2697
|
+
}, {
|
|
2698
|
+
decorations: (value) => value.decorations
|
|
2699
|
+
})
|
|
2700
|
+
];
|
|
2701
|
+
};
|
|
2702
|
+
var InlineMarker = {
|
|
2703
|
+
Emphasis: 1,
|
|
2704
|
+
StrongEmphasis: 0,
|
|
2705
|
+
InlineCode: 3,
|
|
2706
|
+
Strikethrough: 2
|
|
2707
|
+
};
|
|
2708
|
+
var IgnoreInline = /* @__PURE__ */ new Set([
|
|
2709
|
+
"Hardbreak",
|
|
2710
|
+
"HTMLTag",
|
|
2711
|
+
"Comment",
|
|
2712
|
+
"ProcessingInstruction",
|
|
2713
|
+
"Autolink",
|
|
2714
|
+
"HeaderMark",
|
|
2715
|
+
"QuoteMark",
|
|
2716
|
+
"ListMark",
|
|
2717
|
+
"LinkMark",
|
|
2718
|
+
"EmphasisMark",
|
|
2719
|
+
"CodeMark",
|
|
2720
|
+
"CodeText",
|
|
2721
|
+
"StrikethroughMark",
|
|
2722
|
+
"TaskMarker",
|
|
2723
|
+
"SuperscriptMark",
|
|
2724
|
+
"SubscriptMark"
|
|
2725
|
+
]);
|
|
2726
|
+
var Textblocks = {
|
|
2727
|
+
Paragraph: "paragraph",
|
|
2728
|
+
Task: "paragraph",
|
|
2729
|
+
CodeBlock: "codeblock",
|
|
2730
|
+
FencedCode: "codeblock",
|
|
2731
|
+
ATXHeading1: "heading1",
|
|
2732
|
+
ATXHeading2: "heading2",
|
|
2733
|
+
ATXHeading3: "heading3",
|
|
2734
|
+
ATXHeading4: "heading4",
|
|
2735
|
+
ATXHeading5: "heading5",
|
|
2736
|
+
ATXHeading6: "heading6",
|
|
2737
|
+
SetextHeading1: "heading1",
|
|
2738
|
+
SetextHeading2: "heading2",
|
|
2739
|
+
TableCell: "tablecell"
|
|
2740
|
+
};
|
|
2741
|
+
var getFormatting = (state) => {
|
|
2742
|
+
let blockType = null;
|
|
2743
|
+
const inline = [
|
|
2744
|
+
null,
|
|
2745
|
+
null,
|
|
2746
|
+
null,
|
|
2747
|
+
null
|
|
2748
|
+
];
|
|
2749
|
+
let link2 = false;
|
|
2750
|
+
let blockquote2 = null;
|
|
2751
|
+
let listStyle = null;
|
|
2752
|
+
const stack = [];
|
|
2753
|
+
let currentBlock = null;
|
|
2754
|
+
const advanceInline = (upto) => {
|
|
2755
|
+
if (!currentBlock) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
upto = Math.min(upto, currentBlock.end);
|
|
2759
|
+
if (upto <= currentBlock.pos) {
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
2763
|
+
if (inline[i] === false) {
|
|
2764
|
+
continue;
|
|
2765
|
+
} else if (currentBlock.active[i]) {
|
|
2766
|
+
inline[i] = true;
|
|
2767
|
+
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
2768
|
+
inline[i] = false;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
currentBlock.pos = upto;
|
|
2772
|
+
};
|
|
2773
|
+
const skipInline = (upto) => {
|
|
2774
|
+
if (currentBlock && upto > currentBlock.pos) {
|
|
2775
|
+
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
2776
|
+
}
|
|
2777
|
+
};
|
|
2778
|
+
const { selection } = state;
|
|
2779
|
+
for (const range of selection.ranges) {
|
|
2780
|
+
if (range.empty && inline.some((v) => v === null)) {
|
|
2781
|
+
const contextSize = Math.min(range.head, 6);
|
|
2782
|
+
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
2783
|
+
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
2784
|
+
for (let i = 0; i < contextSize; i++) {
|
|
2785
|
+
const ch = contextAfter[i];
|
|
2786
|
+
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
2787
|
+
contextAfter = contextAfter.slice(0, i);
|
|
2788
|
+
break;
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
for (let i = 0; i < inline.length; i++) {
|
|
2792
|
+
const mark2 = inlineMarkerText(i);
|
|
2793
|
+
const found = contextAfter.indexOf(mark2);
|
|
2794
|
+
if (found > -1) {
|
|
2795
|
+
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
2796
|
+
if (inline[i] === null) {
|
|
2797
|
+
inline[i] = true;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
syntaxTree2(state).iterate({
|
|
2803
|
+
from: range.from,
|
|
2804
|
+
to: range.to,
|
|
2805
|
+
enter: (node) => {
|
|
2806
|
+
advanceInline(node.from);
|
|
2807
|
+
const { name } = node;
|
|
2808
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2809
|
+
stack.push(name);
|
|
2810
|
+
} else if (name === "Link") {
|
|
2811
|
+
link2 = true;
|
|
2812
|
+
} else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
|
|
2813
|
+
if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2814
|
+
stack[stack.length - 1] = "TaskList";
|
|
2815
|
+
}
|
|
2816
|
+
const blockCode = Textblocks[name];
|
|
2817
|
+
if (blockType === null) {
|
|
2818
|
+
blockType = blockCode;
|
|
2819
|
+
} else if (blockType !== blockCode) {
|
|
2820
|
+
blockType = false;
|
|
2821
|
+
}
|
|
2822
|
+
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
2823
|
+
currentBlock = {
|
|
2824
|
+
pos: Math.max(range.from, node.from),
|
|
2825
|
+
end: Math.min(range.to, node.to),
|
|
2826
|
+
active: [
|
|
2827
|
+
false,
|
|
2828
|
+
false,
|
|
2829
|
+
false,
|
|
2830
|
+
false
|
|
2831
|
+
]
|
|
2832
|
+
};
|
|
2833
|
+
}
|
|
2834
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2835
|
+
const index = InlineMarker[name];
|
|
2836
|
+
if (range.empty && inline[index] === null) {
|
|
2837
|
+
inline[index] = true;
|
|
2838
|
+
}
|
|
2839
|
+
currentBlock.active[index] = true;
|
|
2840
|
+
} else if (IgnoreInline.has(name)) {
|
|
2841
|
+
skipInline(node.to);
|
|
2842
|
+
}
|
|
2843
|
+
},
|
|
2844
|
+
leave: (node) => {
|
|
2845
|
+
advanceInline(node.to);
|
|
2846
|
+
const { name } = node;
|
|
2847
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2848
|
+
stack.pop();
|
|
2849
|
+
} else if (Object.hasOwn(Textblocks, name)) {
|
|
2850
|
+
let hasList = false;
|
|
2851
|
+
let hasQuote = false;
|
|
2852
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2853
|
+
if (stack[i] === "Blockquote") {
|
|
2854
|
+
hasQuote = true;
|
|
2855
|
+
} else if (!hasList) {
|
|
2856
|
+
hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
if (blockquote2 === null) {
|
|
2860
|
+
blockquote2 = hasQuote;
|
|
2861
|
+
} else if (!hasQuote && blockquote2) {
|
|
2862
|
+
blockquote2 = false;
|
|
2863
|
+
}
|
|
2864
|
+
if (listStyle === null) {
|
|
2865
|
+
listStyle = hasList;
|
|
2866
|
+
} else if (listStyle !== hasList) {
|
|
2867
|
+
listStyle = false;
|
|
2868
|
+
}
|
|
2869
|
+
currentBlock = null;
|
|
2870
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2871
|
+
currentBlock.active[InlineMarker[name]] = false;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
return {
|
|
2877
|
+
blockType: blockType || null,
|
|
2878
|
+
strong: inline[0] ?? false,
|
|
2879
|
+
emphasis: inline[1] ?? false,
|
|
2880
|
+
code: inline[3] ?? false,
|
|
2881
|
+
strikethrough: inline[2] ?? false,
|
|
2882
|
+
link: link2,
|
|
2883
|
+
blockquote: blockquote2 ?? false,
|
|
2884
|
+
listStyle: listStyle || null
|
|
2885
|
+
};
|
|
2886
|
+
};
|
|
2887
|
+
var useFormattingState = () => {
|
|
2888
|
+
const [state, setState] = useState(null);
|
|
2889
|
+
const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
|
|
2890
|
+
if (update2.docChanged || update2.selectionSet) {
|
|
2891
|
+
const newState = getFormatting(update2.state);
|
|
2892
|
+
if (!state || !compareFormatting(state, newState)) {
|
|
2893
|
+
setState(newState);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}), []);
|
|
2897
|
+
return [
|
|
2898
|
+
state,
|
|
2899
|
+
observer
|
|
2900
|
+
];
|
|
2901
|
+
};
|
|
2902
|
+
|
|
2903
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
2904
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
2905
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
2906
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
2907
|
+
var buildDecorations2 = (view) => {
|
|
2908
|
+
const builder = new RangeSetBuilder3();
|
|
2909
|
+
const { state } = view;
|
|
2910
|
+
const cursor = state.selection.main.head;
|
|
2911
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2912
|
+
syntaxTree3(state).iterate({
|
|
2913
|
+
enter: (node) => {
|
|
2914
|
+
switch (node.name) {
|
|
2915
|
+
case "ATXHeading1":
|
|
2916
|
+
case "ATXHeading2":
|
|
2917
|
+
case "ATXHeading3":
|
|
2918
|
+
case "ATXHeading4":
|
|
2919
|
+
case "ATXHeading5":
|
|
2920
|
+
case "ATXHeading6": {
|
|
2921
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
2922
|
+
if (mark2) {
|
|
2923
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2924
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
from,
|
|
2931
|
+
to
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
return builder.finish();
|
|
2935
|
+
};
|
|
2936
|
+
var heading2 = () => {
|
|
2937
|
+
return [
|
|
2938
|
+
ViewPlugin5.fromClass(class {
|
|
2939
|
+
constructor(view) {
|
|
2940
|
+
this.decorations = buildDecorations2(view);
|
|
2941
|
+
}
|
|
2942
|
+
update(update2) {
|
|
2943
|
+
this.decorations = buildDecorations2(update2.view);
|
|
2944
|
+
}
|
|
2945
|
+
}, {
|
|
2946
|
+
decorations: (value) => value.decorations
|
|
2947
|
+
})
|
|
2948
|
+
];
|
|
2949
|
+
};
|
|
2950
|
+
|
|
2951
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2952
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2953
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2954
|
+
import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2955
|
+
var styles4 = EditorView10.baseTheme({
|
|
2956
|
+
"& .cm-hr": {
|
|
2957
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2958
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2962
|
+
toDOM() {
|
|
2963
|
+
const el = document.createElement("div");
|
|
2964
|
+
el.className = "cm-hr";
|
|
2965
|
+
return el;
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
var decoration = Decoration6.replace({
|
|
2969
|
+
widget: new HorizontalRuleWidget()
|
|
2970
|
+
});
|
|
2971
|
+
var buildDecorations3 = (view) => {
|
|
2972
|
+
const builder = new RangeSetBuilder4();
|
|
2973
|
+
const { state } = view;
|
|
2974
|
+
const cursor = state.selection.main.head;
|
|
2975
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2976
|
+
syntaxTree4(state).iterate({
|
|
2977
|
+
enter: (node) => {
|
|
2978
|
+
if (node.name === "HorizontalRule") {
|
|
2979
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2980
|
+
builder.add(node.from, node.to, decoration);
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
},
|
|
2984
|
+
from,
|
|
2985
|
+
to
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
return builder.finish();
|
|
2989
|
+
};
|
|
2990
|
+
var hr = () => {
|
|
2991
|
+
return [
|
|
2992
|
+
ViewPlugin6.fromClass(class {
|
|
2993
|
+
constructor(view) {
|
|
2994
|
+
this.decorations = buildDecorations3(view);
|
|
2995
|
+
}
|
|
2996
|
+
update(update2) {
|
|
2997
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2998
|
+
}
|
|
2999
|
+
}, {
|
|
3000
|
+
decorations: (value) => value.decorations
|
|
3001
|
+
}),
|
|
3002
|
+
styles4
|
|
3003
|
+
];
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3007
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
3008
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
3009
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3010
|
+
var image = (options = {}) => {
|
|
3011
|
+
return StateField3.define({
|
|
3012
|
+
create: (state) => {
|
|
3013
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
3014
|
+
},
|
|
3015
|
+
update: (value, tr) => {
|
|
3016
|
+
if (!tr.docChanged && !tr.selection) {
|
|
3017
|
+
return value;
|
|
3018
|
+
}
|
|
3019
|
+
const cursor = tr.state.selection.main.head;
|
|
3020
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
3021
|
+
let from = Math.min(cursor, oldCursor);
|
|
3022
|
+
let to = Math.max(cursor, oldCursor);
|
|
3023
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
3024
|
+
from = Math.min(from, fromB);
|
|
3025
|
+
to = Math.max(to, toB);
|
|
3026
|
+
});
|
|
3027
|
+
from = tr.state.doc.lineAt(from).from;
|
|
3028
|
+
to = tr.state.doc.lineAt(to).to;
|
|
3029
|
+
return value.map(tr.changes).update({
|
|
3030
|
+
filterFrom: from,
|
|
3031
|
+
filterTo: to,
|
|
3032
|
+
filter: () => false,
|
|
3033
|
+
add: buildDecorations4(from, to, tr.state)
|
|
3034
|
+
});
|
|
3035
|
+
},
|
|
3036
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
3037
|
+
});
|
|
3038
|
+
};
|
|
3039
|
+
var buildDecorations4 = (from, to, state) => {
|
|
3040
|
+
const decorations = [];
|
|
3041
|
+
const cursor = state.selection.main.head;
|
|
3042
|
+
syntaxTree5(state).iterate({
|
|
3043
|
+
enter: (node) => {
|
|
3044
|
+
if (node.name === "Image") {
|
|
3045
|
+
const urlNode = node.node.getChild("URL");
|
|
3046
|
+
if (urlNode) {
|
|
3047
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
3048
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
3049
|
+
decorations.push(Decoration7.replace({
|
|
3050
|
+
block: true,
|
|
3051
|
+
widget: new ImageWidget(url)
|
|
3052
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
},
|
|
3056
|
+
from,
|
|
3057
|
+
to
|
|
3058
|
+
});
|
|
3059
|
+
return decorations;
|
|
3060
|
+
};
|
|
3061
|
+
var ImageWidget = class extends WidgetType4 {
|
|
3062
|
+
constructor(_url) {
|
|
3063
|
+
super();
|
|
3064
|
+
this._url = _url;
|
|
3065
|
+
}
|
|
3066
|
+
eq(other) {
|
|
3067
|
+
return this._url === other._url;
|
|
3068
|
+
}
|
|
3069
|
+
toDOM(view) {
|
|
3070
|
+
const img = document.createElement("img");
|
|
3071
|
+
img.setAttribute("src", this._url);
|
|
3072
|
+
img.setAttribute("class", "cm-image");
|
|
3073
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
3074
|
+
return img;
|
|
3075
|
+
}
|
|
3076
|
+
};
|
|
3077
|
+
|
|
3078
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
3079
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
3080
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
3081
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
3082
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
3083
|
+
var link = (options = {}) => {
|
|
3084
|
+
const extensions = [
|
|
3085
|
+
ViewPlugin7.fromClass(class {
|
|
3086
|
+
constructor(view) {
|
|
3087
|
+
this.decorations = buildDecorations5(view, options);
|
|
3088
|
+
}
|
|
3089
|
+
update(update2) {
|
|
3090
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
3091
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
}, {
|
|
3095
|
+
decorations: (value) => value.decorations
|
|
3096
|
+
})
|
|
3097
|
+
];
|
|
3098
|
+
if (options.onHover) {
|
|
3099
|
+
extensions.push(
|
|
3100
|
+
// https://codemirror.net/examples/tooltip
|
|
3101
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
3102
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
3103
|
+
hoverTooltip2((view, pos, side) => {
|
|
3104
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
3105
|
+
let link2 = null;
|
|
3106
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
3107
|
+
link2 = node.name === "Link" ? node : null;
|
|
3108
|
+
}
|
|
3109
|
+
const url = link2 && link2.getChild("URL");
|
|
3110
|
+
if (!url || !link2) {
|
|
3111
|
+
return null;
|
|
3112
|
+
}
|
|
3113
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
3114
|
+
return {
|
|
3115
|
+
pos: link2.from,
|
|
3116
|
+
end: link2.to,
|
|
3117
|
+
above: true,
|
|
3118
|
+
create: () => {
|
|
3119
|
+
const el = document.createElement("div");
|
|
3120
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
3121
|
+
options.onHover(el, urlText);
|
|
3122
|
+
return {
|
|
3123
|
+
dom: el,
|
|
3124
|
+
offset: {
|
|
3125
|
+
x: 0,
|
|
3126
|
+
y: 4
|
|
3127
|
+
}
|
|
3128
|
+
};
|
|
3129
|
+
}
|
|
3130
|
+
};
|
|
3131
|
+
})
|
|
3132
|
+
);
|
|
3133
|
+
}
|
|
3134
|
+
return extensions;
|
|
3135
|
+
};
|
|
3136
|
+
var LinkButton = class extends WidgetType5 {
|
|
3137
|
+
constructor(_url, _onAttach) {
|
|
3138
|
+
super();
|
|
3139
|
+
this._url = _url;
|
|
3140
|
+
this._onAttach = _onAttach;
|
|
3141
|
+
}
|
|
3142
|
+
eq(other) {
|
|
3143
|
+
return this._url === other._url;
|
|
3144
|
+
}
|
|
3145
|
+
toDOM(view) {
|
|
3146
|
+
const el = document.createElement("span");
|
|
3147
|
+
this._onAttach(el, this._url);
|
|
3148
|
+
return el;
|
|
3149
|
+
}
|
|
3150
|
+
};
|
|
3151
|
+
var LinkText = class extends WidgetType5 {
|
|
3152
|
+
constructor(_text, _url) {
|
|
3153
|
+
super();
|
|
3154
|
+
this._text = _text;
|
|
3155
|
+
this._url = _url;
|
|
3156
|
+
}
|
|
3157
|
+
eq(other) {
|
|
3158
|
+
return this._url === other._url;
|
|
3159
|
+
}
|
|
3160
|
+
toDOM(view) {
|
|
3161
|
+
const link2 = document.createElement("a");
|
|
3162
|
+
link2.setAttribute("class", "cm-link");
|
|
3163
|
+
link2.textContent = this._text;
|
|
3164
|
+
if (this._url) {
|
|
3165
|
+
link2.setAttribute("rel", "noreferrer");
|
|
3166
|
+
link2.setAttribute("target", "_blank");
|
|
3167
|
+
link2.href = this._url;
|
|
3168
|
+
} else {
|
|
3169
|
+
link2.onclick = () => {
|
|
3170
|
+
view.dispatch({
|
|
3171
|
+
selection: {
|
|
3172
|
+
anchor: view.posAtDOM(link2)
|
|
3173
|
+
}
|
|
3174
|
+
});
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
return link2;
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
var buildDecorations5 = (view, options) => {
|
|
3181
|
+
const builder = new RangeSetBuilder5();
|
|
3182
|
+
const { state } = view;
|
|
3183
|
+
const cursor = state.selection.main.head;
|
|
3184
|
+
for (const { from, to } of view.visibleRanges) {
|
|
3185
|
+
syntaxTree6(state).iterate({
|
|
3186
|
+
enter: (node) => {
|
|
3187
|
+
if (node.name === "Link") {
|
|
3188
|
+
const marks = node.node.getChildren("LinkMark");
|
|
3189
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
3190
|
+
const urlNode = node.node.getChild("URL");
|
|
3191
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
3192
|
+
if (!url) {
|
|
3193
|
+
return false;
|
|
3194
|
+
}
|
|
3195
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
3196
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
3197
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
3198
|
+
}));
|
|
3199
|
+
}
|
|
3200
|
+
if (options.onRender) {
|
|
3201
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
3202
|
+
widget: new LinkButton(url, options.onRender)
|
|
3203
|
+
}));
|
|
3204
|
+
}
|
|
3205
|
+
return false;
|
|
3206
|
+
}
|
|
3207
|
+
},
|
|
3208
|
+
from,
|
|
3209
|
+
to
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
return builder.finish();
|
|
3213
|
+
};
|
|
3214
|
+
|
|
3215
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
3216
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
3217
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
3218
|
+
import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1988
3219
|
var table = (options = {}) => {
|
|
1989
3220
|
return StateField4.define({
|
|
1990
3221
|
create: (state) => update(state, options),
|
|
1991
3222
|
update: (_, tr) => update(tr.state, options),
|
|
1992
|
-
provide: (field) =>
|
|
3223
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
1993
3224
|
});
|
|
1994
3225
|
};
|
|
1995
3226
|
var update = (state, options) => {
|
|
1996
|
-
const builder = new
|
|
3227
|
+
const builder = new RangeSetBuilder6();
|
|
1997
3228
|
const cursor = state.selection.main.head;
|
|
1998
3229
|
const tables = [];
|
|
1999
3230
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2001,7 +3232,7 @@ var update = (state, options) => {
|
|
|
2001
3232
|
const table2 = getTable();
|
|
2002
3233
|
return table2.rows?.[table2.rows.length - 1];
|
|
2003
3234
|
};
|
|
2004
|
-
|
|
3235
|
+
syntaxTree7(state).iterate({
|
|
2005
3236
|
enter: (node) => {
|
|
2006
3237
|
switch (node.name) {
|
|
2007
3238
|
case "Table": {
|
|
@@ -2033,16 +3264,16 @@ var update = (state, options) => {
|
|
|
2033
3264
|
});
|
|
2034
3265
|
tables.forEach((table2) => {
|
|
2035
3266
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2036
|
-
hide && builder.add(table2.from, table2.to,
|
|
3267
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2037
3268
|
widget: new TableWidget(table2)
|
|
2038
3269
|
}));
|
|
2039
|
-
builder.add(table2.from, table2.to,
|
|
3270
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2040
3271
|
class: "cm-table"
|
|
2041
3272
|
}));
|
|
2042
3273
|
});
|
|
2043
3274
|
return builder.finish();
|
|
2044
3275
|
};
|
|
2045
|
-
var TableWidget = class extends
|
|
3276
|
+
var TableWidget = class extends WidgetType6 {
|
|
2046
3277
|
constructor(_table) {
|
|
2047
3278
|
super();
|
|
2048
3279
|
this._table = _table;
|
|
@@ -2079,11 +3310,20 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2079
3310
|
}
|
|
2080
3311
|
};
|
|
2081
3312
|
|
|
2082
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2083
|
-
import { syntaxTree as
|
|
2084
|
-
import { RangeSetBuilder as
|
|
2085
|
-
import { EditorView as
|
|
2086
|
-
var
|
|
3313
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
3314
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
3315
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
3316
|
+
import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
3317
|
+
var styles5 = EditorView13.baseTheme({
|
|
3318
|
+
"& .cm-task": {
|
|
3319
|
+
color: getToken("extend.colors.blue.500")
|
|
3320
|
+
},
|
|
3321
|
+
"& .cm-task-checkbox": {
|
|
3322
|
+
marginLeft: "4px",
|
|
3323
|
+
marginRight: "4px"
|
|
3324
|
+
}
|
|
3325
|
+
});
|
|
3326
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2087
3327
|
constructor(_checked) {
|
|
2088
3328
|
super();
|
|
2089
3329
|
this._checked = _checked;
|
|
@@ -2093,6 +3333,7 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2093
3333
|
}
|
|
2094
3334
|
toDOM(view) {
|
|
2095
3335
|
const input = document.createElement("input");
|
|
3336
|
+
input.className = "cm-task-checkbox";
|
|
2096
3337
|
input.type = "checkbox";
|
|
2097
3338
|
input.checked = this._checked;
|
|
2098
3339
|
if (view.state.readOnly) {
|
|
@@ -2119,39 +3360,27 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2119
3360
|
return false;
|
|
2120
3361
|
}
|
|
2121
3362
|
};
|
|
2122
|
-
var
|
|
3363
|
+
var checkedDecoration = Decoration10.replace({
|
|
2123
3364
|
widget: new CheckboxWidget(true)
|
|
2124
3365
|
});
|
|
2125
|
-
var
|
|
3366
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2126
3367
|
widget: new CheckboxWidget(false)
|
|
2127
3368
|
});
|
|
2128
|
-
var
|
|
2129
|
-
|
|
2130
|
-
constructor(view) {
|
|
2131
|
-
this.decorations = buildDecorations3(view);
|
|
2132
|
-
}
|
|
2133
|
-
update(update2) {
|
|
2134
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2135
|
-
this.decorations = buildDecorations3(update2.view);
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
}, {
|
|
2139
|
-
decorations: (v) => v.decorations,
|
|
2140
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2141
|
-
return view.plugin(plugin)?.decorations || Decoration8.none;
|
|
2142
|
-
})
|
|
2143
|
-
});
|
|
2144
|
-
};
|
|
2145
|
-
var buildDecorations3 = (view) => {
|
|
2146
|
-
const builder = new RangeSetBuilder3();
|
|
3369
|
+
var buildDecorations6 = (view) => {
|
|
3370
|
+
const builder = new RangeSetBuilder7();
|
|
2147
3371
|
const { state } = view;
|
|
2148
3372
|
const cursor = state.selection.main.head;
|
|
2149
3373
|
for (const { from, to } of view.visibleRanges) {
|
|
2150
|
-
|
|
3374
|
+
syntaxTree8(state).iterate({
|
|
2151
3375
|
enter: (node) => {
|
|
2152
|
-
if (node.name === "TaskMarker"
|
|
2153
|
-
|
|
2154
|
-
|
|
3376
|
+
if (node.name === "TaskMarker") {
|
|
3377
|
+
if (cursor < node.from || cursor > node.to) {
|
|
3378
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
3379
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
3380
|
+
class: "cm-task"
|
|
3381
|
+
}));
|
|
3382
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
3383
|
+
}
|
|
2155
3384
|
}
|
|
2156
3385
|
},
|
|
2157
3386
|
from,
|
|
@@ -2160,9 +3389,60 @@ var buildDecorations3 = (view) => {
|
|
|
2160
3389
|
}
|
|
2161
3390
|
return builder.finish();
|
|
2162
3391
|
};
|
|
3392
|
+
var tasklist = (options = {}) => {
|
|
3393
|
+
return [
|
|
3394
|
+
ViewPlugin8.fromClass(class {
|
|
3395
|
+
constructor(view) {
|
|
3396
|
+
this.decorations = buildDecorations6(view);
|
|
3397
|
+
}
|
|
3398
|
+
update(update2) {
|
|
3399
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
3400
|
+
this.decorations = buildDecorations6(update2.view);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
}, {
|
|
3404
|
+
decorations: (value) => value.decorations
|
|
3405
|
+
}),
|
|
3406
|
+
styles5
|
|
3407
|
+
];
|
|
3408
|
+
};
|
|
3409
|
+
|
|
3410
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
3411
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
3412
|
+
var mention = ({ onSearch }) => {
|
|
3413
|
+
return autocompletion2({
|
|
3414
|
+
// TODO(burdon): Not working.
|
|
3415
|
+
activateOnTyping: true,
|
|
3416
|
+
// activateOnTypingDelay: 100,
|
|
3417
|
+
// selectOnOpen: true,
|
|
3418
|
+
closeOnBlur: false,
|
|
3419
|
+
// defaultKeymap: false,
|
|
3420
|
+
icons: false,
|
|
3421
|
+
override: [
|
|
3422
|
+
(context) => {
|
|
3423
|
+
console.log(context);
|
|
3424
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
3425
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
3426
|
+
return null;
|
|
3427
|
+
}
|
|
3428
|
+
return {
|
|
3429
|
+
from: match.from,
|
|
3430
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
3431
|
+
label: `@${value}`
|
|
3432
|
+
}))
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
]
|
|
3436
|
+
});
|
|
3437
|
+
};
|
|
3438
|
+
|
|
3439
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
3440
|
+
var outliner = (options = {}) => {
|
|
3441
|
+
return [];
|
|
3442
|
+
};
|
|
2163
3443
|
|
|
2164
3444
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2165
|
-
import { keymap as
|
|
3445
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2166
3446
|
var defaultItems = [
|
|
2167
3447
|
"hello world!",
|
|
2168
3448
|
"this is a test.",
|
|
@@ -2172,7 +3452,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2172
3452
|
let t;
|
|
2173
3453
|
let idx = 0;
|
|
2174
3454
|
return [
|
|
2175
|
-
|
|
3455
|
+
keymap6.of([
|
|
2176
3456
|
{
|
|
2177
3457
|
// Reset.
|
|
2178
3458
|
key: "alt-meta-'",
|
|
@@ -2218,27 +3498,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2218
3498
|
];
|
|
2219
3499
|
};
|
|
2220
3500
|
|
|
2221
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2222
|
-
import { yCollab } from "y-codemirror.next";
|
|
2223
|
-
|
|
2224
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2225
|
-
import * as Y from "yjs";
|
|
2226
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2227
|
-
var cursorConverter2 = (text) => ({
|
|
2228
|
-
toCursor: (index, assoc) => {
|
|
2229
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2230
|
-
},
|
|
2231
|
-
fromCursor: (cursor) => {
|
|
2232
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2233
|
-
}
|
|
2234
|
-
});
|
|
2235
|
-
|
|
2236
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2237
|
-
var yjs = (content, awareness2) => [
|
|
2238
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2239
|
-
yCollab(content, awareness2)
|
|
2240
|
-
];
|
|
2241
|
-
|
|
2242
3501
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2243
3502
|
import get3 from "lodash.get";
|
|
2244
3503
|
var defaultTheme = {
|
|
@@ -2270,8 +3529,9 @@ var defaultTheme = {
|
|
|
2270
3529
|
outline: "none"
|
|
2271
3530
|
},
|
|
2272
3531
|
".cm-scroller": {
|
|
2273
|
-
overflow:
|
|
2274
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3532
|
+
// overflow: 'visible',
|
|
3533
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3534
|
+
lineHeight: 1.4
|
|
2275
3535
|
},
|
|
2276
3536
|
".cm-content": {
|
|
2277
3537
|
padding: 0,
|
|
@@ -2279,11 +3539,11 @@ var defaultTheme = {
|
|
|
2279
3539
|
fontSize: "16px"
|
|
2280
3540
|
},
|
|
2281
3541
|
"&light .cm-content": {
|
|
2282
|
-
color: get3(tokens, "extend.
|
|
3542
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2283
3543
|
caretColor: "black"
|
|
2284
3544
|
},
|
|
2285
3545
|
"&dark .cm-content": {
|
|
2286
|
-
color: get3(tokens, "extend.
|
|
3546
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2287
3547
|
caretColor: "white"
|
|
2288
3548
|
},
|
|
2289
3549
|
//
|
|
@@ -2295,8 +3555,11 @@ var defaultTheme = {
|
|
|
2295
3555
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2296
3556
|
borderLeft: "2px solid white"
|
|
2297
3557
|
},
|
|
2298
|
-
".cm-placeholder": {
|
|
2299
|
-
|
|
3558
|
+
"&light .cm-placeholder": {
|
|
3559
|
+
color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
|
|
3560
|
+
},
|
|
3561
|
+
"&dark .cm-placeholder": {
|
|
3562
|
+
color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
|
|
2300
3563
|
},
|
|
2301
3564
|
//
|
|
2302
3565
|
// line
|
|
@@ -2305,7 +3568,7 @@ var defaultTheme = {
|
|
|
2305
3568
|
paddingInline: 0
|
|
2306
3569
|
},
|
|
2307
3570
|
".cm-activeLine": {
|
|
2308
|
-
background: "
|
|
3571
|
+
background: "transparent"
|
|
2309
3572
|
},
|
|
2310
3573
|
//
|
|
2311
3574
|
// Selection
|
|
@@ -2476,90 +3739,88 @@ var codeTheme = {
|
|
|
2476
3739
|
};
|
|
2477
3740
|
|
|
2478
3741
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
3742
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2479
3743
|
var EditorModes = [
|
|
2480
3744
|
"default",
|
|
2481
3745
|
"vim"
|
|
2482
3746
|
];
|
|
2483
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2484
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2485
|
-
tabBehavior: "limited"
|
|
2486
|
-
});
|
|
3747
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2487
3748
|
const { themeMode } = useThemeContext();
|
|
2488
3749
|
const rootRef = useRef(null);
|
|
2489
|
-
const [view, setView] =
|
|
3750
|
+
const [view, setView] = useState2(null);
|
|
2490
3751
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2491
3752
|
view
|
|
2492
3753
|
]);
|
|
2493
|
-
|
|
2494
|
-
if (
|
|
2495
|
-
view.
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
awareness2.setLocalStateField("user", {
|
|
2505
|
-
name: peer.name ?? generateName(peer.id),
|
|
2506
|
-
color: getColorForValue({
|
|
2507
|
-
value: peer.id,
|
|
2508
|
-
type: "color"
|
|
2509
|
-
}),
|
|
2510
|
-
colorLight: getColorForValue({
|
|
2511
|
-
value: peer.id,
|
|
2512
|
-
themeMode,
|
|
2513
|
-
type: "highlight"
|
|
2514
|
-
})
|
|
2515
|
-
});
|
|
2516
|
-
}
|
|
2517
|
-
}, [
|
|
2518
|
-
awareness2,
|
|
2519
|
-
peer,
|
|
2520
|
-
themeMode
|
|
2521
|
-
]);
|
|
2522
|
-
useEffect(() => {
|
|
2523
|
-
if (view && comments2 !== void 0) {
|
|
2524
|
-
view.dispatch({
|
|
2525
|
-
effects: setCommentRange.of({
|
|
2526
|
-
model,
|
|
2527
|
-
comments: comments2
|
|
2528
|
-
})
|
|
2529
|
-
});
|
|
3754
|
+
useEffect2(() => {
|
|
3755
|
+
if (autoFocus && !view?.hasFocus) {
|
|
3756
|
+
if (view?.state.selection.main?.from === 0) {
|
|
3757
|
+
const { to } = view.state.doc.lineAt(0);
|
|
3758
|
+
view?.dispatch({
|
|
3759
|
+
selection: {
|
|
3760
|
+
anchor: to
|
|
3761
|
+
}
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3764
|
+
view?.focus();
|
|
2530
3765
|
}
|
|
2531
3766
|
}, [
|
|
2532
3767
|
view,
|
|
2533
|
-
|
|
3768
|
+
autoFocus
|
|
2534
3769
|
]);
|
|
2535
|
-
|
|
3770
|
+
useEffect2(() => {
|
|
2536
3771
|
if (!model || !rootRef.current) {
|
|
2537
3772
|
return;
|
|
2538
3773
|
}
|
|
2539
3774
|
const state = EditorState2.create({
|
|
2540
3775
|
doc: model.text(),
|
|
2541
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2542
3776
|
selection,
|
|
2543
3777
|
extensions: [
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
3778
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3779
|
+
EditorView14.exceptionSink.of((err) => {
|
|
3780
|
+
log2.catch(err, void 0, {
|
|
3781
|
+
F: __dxlog_file3,
|
|
3782
|
+
L: 134,
|
|
3783
|
+
S: void 0,
|
|
3784
|
+
C: (f, a) => f(...a)
|
|
3785
|
+
});
|
|
3786
|
+
}),
|
|
2547
3787
|
// Theme.
|
|
2548
|
-
// TODO(burdon): Make
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
3788
|
+
// TODO(burdon): Make configurable.
|
|
3789
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3790
|
+
EditorView14.theme(theme ?? {}),
|
|
3791
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3792
|
+
EditorView14.editorAttributes.of({
|
|
3793
|
+
class: slots.editor?.className ?? ""
|
|
3794
|
+
}),
|
|
3795
|
+
EditorView14.contentAttributes.of({
|
|
3796
|
+
class: slots.content?.className ?? ""
|
|
3797
|
+
}),
|
|
3798
|
+
// State.
|
|
3799
|
+
EditorView14.editable.of(!readonly),
|
|
3800
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2552
3801
|
// Storage and replication.
|
|
3802
|
+
// NOTE: This must come before user extensions.
|
|
2553
3803
|
model.extension,
|
|
3804
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
3805
|
+
editorMode === "vim" && vim(),
|
|
2554
3806
|
// Custom.
|
|
2555
3807
|
...extensions
|
|
2556
|
-
].filter(
|
|
3808
|
+
].filter(isNotFalsy3)
|
|
2557
3809
|
});
|
|
2558
|
-
|
|
2559
|
-
|
|
3810
|
+
const newView = new EditorView14({
|
|
3811
|
+
state,
|
|
2560
3812
|
parent: rootRef.current,
|
|
2561
|
-
|
|
3813
|
+
scrollTo,
|
|
3814
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
3815
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
3816
|
+
dispatchTransactions: (trs, view2) => {
|
|
3817
|
+
if (debug) {
|
|
3818
|
+
logChanges(trs);
|
|
3819
|
+
}
|
|
3820
|
+
view2.update(trs);
|
|
3821
|
+
}
|
|
2562
3822
|
});
|
|
3823
|
+
view?.destroy();
|
|
2563
3824
|
setView(newView);
|
|
2564
3825
|
return () => {
|
|
2565
3826
|
newView?.destroy();
|
|
@@ -2575,8 +3836,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2575
3836
|
const handleKeyUp = useCallback((event) => {
|
|
2576
3837
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2577
3838
|
switch (key) {
|
|
3839
|
+
case "Enter": {
|
|
3840
|
+
view?.focus();
|
|
3841
|
+
break;
|
|
3842
|
+
}
|
|
2578
3843
|
case "Escape": {
|
|
2579
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
3844
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
3845
|
+
view?.focus();
|
|
3846
|
+
}
|
|
2580
3847
|
break;
|
|
2581
3848
|
}
|
|
2582
3849
|
}
|
|
@@ -2587,24 +3854,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2587
3854
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2588
3855
|
key: model.id,
|
|
2589
3856
|
role: "none",
|
|
2590
|
-
ref: rootRef,
|
|
2591
3857
|
tabIndex: 0,
|
|
2592
|
-
onKeyUp: handleKeyUp,
|
|
2593
3858
|
...slots.root,
|
|
2594
|
-
...editorMode !==
|
|
3859
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3860
|
+
onKeyUp: handleKeyUp,
|
|
3861
|
+
ref: rootRef
|
|
2595
3862
|
});
|
|
2596
3863
|
});
|
|
2597
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
3864
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2598
3865
|
const { themeMode } = useThemeContext();
|
|
2599
3866
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2600
3867
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2601
3868
|
ref: forwardedRef,
|
|
2602
3869
|
readonly,
|
|
2603
3870
|
extensions: [
|
|
2604
|
-
|
|
2605
|
-
readonly,
|
|
3871
|
+
createBasicBundle({
|
|
2606
3872
|
themeMode,
|
|
2607
|
-
placeholder: placeholder3
|
|
3873
|
+
placeholder: placeholder3,
|
|
3874
|
+
lineWrapping
|
|
2608
3875
|
}),
|
|
2609
3876
|
...extensions
|
|
2610
3877
|
],
|
|
@@ -2613,15 +3880,14 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2613
3880
|
...props
|
|
2614
3881
|
});
|
|
2615
3882
|
});
|
|
2616
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
3883
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2617
3884
|
const { themeMode } = useThemeContext();
|
|
2618
3885
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2619
3886
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2620
3887
|
ref: forwardedRef,
|
|
2621
3888
|
readonly,
|
|
2622
3889
|
extensions: [
|
|
2623
|
-
|
|
2624
|
-
readonly,
|
|
3890
|
+
createMarkdownExtensions({
|
|
2625
3891
|
themeMode,
|
|
2626
3892
|
placeholder: placeholder3
|
|
2627
3893
|
}),
|
|
@@ -2634,7 +3900,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2634
3900
|
});
|
|
2635
3901
|
var defaultSlots = {
|
|
2636
3902
|
root: {
|
|
2637
|
-
className: mx3("
|
|
3903
|
+
className: mx3("grow", focusRing)
|
|
3904
|
+
},
|
|
3905
|
+
editor: {
|
|
3906
|
+
className: "bs-full"
|
|
2638
3907
|
}
|
|
2639
3908
|
};
|
|
2640
3909
|
var defaultTextSlots = {
|
|
@@ -2644,22 +3913,205 @@ var defaultMarkdownSlots = {
|
|
|
2644
3913
|
...defaultSlots
|
|
2645
3914
|
};
|
|
2646
3915
|
|
|
2647
|
-
// packages/ui/react-ui-editor/src/
|
|
2648
|
-
import
|
|
2649
|
-
import {
|
|
2650
|
-
import
|
|
3916
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
3917
|
+
import { CaretRight, ChatText, Code, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
|
|
3918
|
+
import { createContext } from "@radix-ui/react-context";
|
|
3919
|
+
import React2 from "react";
|
|
3920
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
3921
|
+
import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
|
|
3922
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
3923
|
+
var ToolbarRoot = ({ children, onAction, state }) => {
|
|
3924
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
3925
|
+
onAction,
|
|
3926
|
+
state
|
|
3927
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
3928
|
+
density: "fine"
|
|
3929
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
3930
|
+
role: "toolbar",
|
|
3931
|
+
className: "flex w-full shrink-0 p-1 gap-2 items-center whitespace-nowrap overflow-hidden"
|
|
3932
|
+
}, children)));
|
|
3933
|
+
};
|
|
3934
|
+
var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
|
|
3935
|
+
const { onAction, state } = useToolbarContext("ToolbarButton");
|
|
3936
|
+
const active = getState && state ? getState(state) : false;
|
|
3937
|
+
const disabled = disable && state ? disable(state) : false;
|
|
3938
|
+
const handleClick = (event) => {
|
|
3939
|
+
const action = onClick(state);
|
|
3940
|
+
if (action) {
|
|
3941
|
+
onAction?.(action);
|
|
3942
|
+
event.preventDefault();
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
3946
|
+
variant: "ghost",
|
|
3947
|
+
classNames: mx4("p-2", active && "ring-[1px]"),
|
|
3948
|
+
onMouseDown: handleClick,
|
|
3949
|
+
title,
|
|
3950
|
+
disabled
|
|
3951
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
3952
|
+
className: getSize(5)
|
|
3953
|
+
}));
|
|
3954
|
+
};
|
|
3955
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3956
|
+
className: "grow"
|
|
3957
|
+
});
|
|
3958
|
+
var MarkdownHeading = () => {
|
|
3959
|
+
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
3960
|
+
const blockType = state ? state.blockType : "paragraph";
|
|
3961
|
+
const header = blockType && /heading(\d)/.exec(blockType);
|
|
3962
|
+
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : null;
|
|
3963
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3964
|
+
disabled: value === null,
|
|
3965
|
+
value: value ?? "0",
|
|
3966
|
+
onValueChange: (value2) => onAction?.({
|
|
3967
|
+
type: "heading",
|
|
3968
|
+
data: parseInt(value2)
|
|
3969
|
+
})
|
|
3970
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, null, /* @__PURE__ */ React2.createElement(Paragraph, {
|
|
3971
|
+
className: getSize(5)
|
|
3972
|
+
})), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3973
|
+
value: "0"
|
|
3974
|
+
}, "Paragraph"), [
|
|
3975
|
+
1,
|
|
3976
|
+
2,
|
|
3977
|
+
3,
|
|
3978
|
+
4,
|
|
3979
|
+
5,
|
|
3980
|
+
6
|
|
3981
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3982
|
+
key: level,
|
|
3983
|
+
value: String(level)
|
|
3984
|
+
}, "Heading ", level))))));
|
|
3985
|
+
};
|
|
3986
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3987
|
+
role: "none"
|
|
3988
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3989
|
+
Icon: TextB,
|
|
3990
|
+
title: "String",
|
|
3991
|
+
disable: (s) => s.blockType === "codeblock",
|
|
3992
|
+
getState: (s) => s.strong,
|
|
3993
|
+
onClick: (s) => ({
|
|
3994
|
+
type: "strong",
|
|
3995
|
+
data: s ? !s.strong : null
|
|
3996
|
+
})
|
|
3997
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3998
|
+
Icon: TextItalic,
|
|
3999
|
+
title: "Emphasis",
|
|
4000
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4001
|
+
getState: (s) => s.emphasis,
|
|
4002
|
+
onClick: (s) => ({
|
|
4003
|
+
type: "emphasis",
|
|
4004
|
+
data: s ? !s.emphasis : null
|
|
4005
|
+
})
|
|
4006
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4007
|
+
Icon: TextStrikethrough,
|
|
4008
|
+
title: "Strike-through",
|
|
4009
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4010
|
+
getState: (s) => s.strikethrough,
|
|
4011
|
+
onClick: (s) => ({
|
|
4012
|
+
type: "strikethrough",
|
|
4013
|
+
data: s ? !s.strikethrough : null
|
|
4014
|
+
})
|
|
4015
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4016
|
+
Icon: Code,
|
|
4017
|
+
title: "Inline code",
|
|
4018
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4019
|
+
getState: (s) => s.code,
|
|
4020
|
+
onClick: (s) => ({
|
|
4021
|
+
type: "code",
|
|
4022
|
+
data: s ? !s.code : null
|
|
4023
|
+
})
|
|
4024
|
+
}));
|
|
4025
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4026
|
+
role: "none"
|
|
4027
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4028
|
+
Icon: ListBullets,
|
|
4029
|
+
title: "Bullet list",
|
|
4030
|
+
getState: (s) => s.listStyle === "bullet",
|
|
4031
|
+
onClick: (s) => ({
|
|
4032
|
+
type: "list-bullet",
|
|
4033
|
+
data: s ? s.listStyle !== "bullet" : null
|
|
4034
|
+
})
|
|
4035
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4036
|
+
Icon: ListNumbers,
|
|
4037
|
+
title: "Numbered list",
|
|
4038
|
+
getState: (s) => s.listStyle === "ordered",
|
|
4039
|
+
onClick: (s) => ({
|
|
4040
|
+
type: "list-ordered",
|
|
4041
|
+
data: s ? s.listStyle !== "ordered" : null
|
|
4042
|
+
})
|
|
4043
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4044
|
+
Icon: ListChecks,
|
|
4045
|
+
title: "Task list",
|
|
4046
|
+
getState: (s) => s.listStyle === "task",
|
|
4047
|
+
onClick: (s) => ({
|
|
4048
|
+
type: "list-tasks",
|
|
4049
|
+
data: s ? s.listStyle !== "task" : null
|
|
4050
|
+
})
|
|
4051
|
+
}));
|
|
4052
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4053
|
+
role: "none"
|
|
4054
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4055
|
+
Icon: CaretRight,
|
|
4056
|
+
title: "Block quote",
|
|
4057
|
+
getState: (s) => s.blockquote,
|
|
4058
|
+
onClick: (s) => ({
|
|
4059
|
+
type: "blockquote",
|
|
4060
|
+
data: s ? !s.blockquote : null
|
|
4061
|
+
})
|
|
4062
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4063
|
+
Icon: Code,
|
|
4064
|
+
title: "Code block",
|
|
4065
|
+
getState: (s) => s.blockType === "codeblock",
|
|
4066
|
+
onClick: (s) => ({
|
|
4067
|
+
type: "codeblock",
|
|
4068
|
+
data: s ? s.blockType !== "codeblock" : null
|
|
4069
|
+
})
|
|
4070
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4071
|
+
Icon: Table2,
|
|
4072
|
+
title: "Table",
|
|
4073
|
+
onClick: () => ({
|
|
4074
|
+
type: "table"
|
|
4075
|
+
})
|
|
4076
|
+
}));
|
|
4077
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4078
|
+
role: "none"
|
|
4079
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4080
|
+
Icon: Link,
|
|
4081
|
+
title: "Link",
|
|
4082
|
+
getState: (s) => s.link,
|
|
4083
|
+
onClick: (s) => ({
|
|
4084
|
+
type: "link",
|
|
4085
|
+
data: s ? !s.link : null
|
|
4086
|
+
})
|
|
4087
|
+
}));
|
|
4088
|
+
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), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
|
|
4089
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
4090
|
+
Icon: ChatText,
|
|
4091
|
+
title: "Create comment",
|
|
4092
|
+
onClick: () => ({
|
|
4093
|
+
type: "comment"
|
|
4094
|
+
})
|
|
4095
|
+
});
|
|
4096
|
+
var Toolbar = {
|
|
4097
|
+
Root: ToolbarRoot,
|
|
4098
|
+
Button: ToolbarButton,
|
|
4099
|
+
Separator: ToolbarSeparator,
|
|
4100
|
+
Markdown: MarkdownStandard,
|
|
4101
|
+
Extended: MarkdownExtended
|
|
4102
|
+
};
|
|
2651
4103
|
|
|
2652
4104
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2653
4105
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2654
4106
|
import { Context as Context2 } from "@dxos/context";
|
|
2655
|
-
import { invariant as
|
|
4107
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2656
4108
|
import { log as log3 } from "@dxos/log";
|
|
2657
4109
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2658
4110
|
var DEBOUNCE_INTERVAL = 100;
|
|
2659
4111
|
var SpaceAwarenessProvider = class {
|
|
2660
4112
|
constructor(params) {
|
|
2661
|
-
this.remoteStateChange = new Event2();
|
|
2662
4113
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
4114
|
+
this.remoteStateChange = new Event2();
|
|
2663
4115
|
this._space = params.space;
|
|
2664
4116
|
this._channel = params.channel;
|
|
2665
4117
|
this._peerId = params.peerId;
|
|
@@ -2676,7 +4128,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2676
4128
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2677
4129
|
}
|
|
2678
4130
|
});
|
|
2679
|
-
|
|
4131
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2680
4132
|
switch (message.payload.kind) {
|
|
2681
4133
|
case "query": {
|
|
2682
4134
|
this._handleQueryMessage();
|
|
@@ -2687,8 +4139,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2687
4139
|
break;
|
|
2688
4140
|
}
|
|
2689
4141
|
}
|
|
2690
|
-
});
|
|
2691
|
-
this._ctx.onDispose(unsubscribe);
|
|
4142
|
+
}));
|
|
2692
4143
|
void this._space.postMessage(this._channel, {
|
|
2693
4144
|
kind: "query"
|
|
2694
4145
|
}).catch((err) => {
|
|
@@ -2696,7 +4147,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2696
4147
|
err
|
|
2697
4148
|
}, {
|
|
2698
4149
|
F: __dxlog_file4,
|
|
2699
|
-
L:
|
|
4150
|
+
L: 89,
|
|
2700
4151
|
S: this,
|
|
2701
4152
|
C: (f, a) => f(...a)
|
|
2702
4153
|
});
|
|
@@ -2707,10 +4158,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2707
4158
|
this._ctx = void 0;
|
|
2708
4159
|
this._postTask = void 0;
|
|
2709
4160
|
}
|
|
4161
|
+
getRemoteStates() {
|
|
4162
|
+
return Array.from(this._remoteStates.values());
|
|
4163
|
+
}
|
|
2710
4164
|
update(position) {
|
|
2711
|
-
|
|
4165
|
+
invariant2(this._postTask, void 0, {
|
|
2712
4166
|
F: __dxlog_file4,
|
|
2713
|
-
L:
|
|
4167
|
+
L: 104,
|
|
2714
4168
|
S: this,
|
|
2715
4169
|
A: [
|
|
2716
4170
|
"this._postTask",
|
|
@@ -2724,13 +4178,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2724
4178
|
};
|
|
2725
4179
|
this._postTask.schedule();
|
|
2726
4180
|
}
|
|
2727
|
-
getRemoteStates() {
|
|
2728
|
-
return Array.from(this._remoteStates.values());
|
|
2729
|
-
}
|
|
2730
4181
|
_handleQueryMessage() {
|
|
2731
|
-
|
|
4182
|
+
invariant2(this._postTask, void 0, {
|
|
2732
4183
|
F: __dxlog_file4,
|
|
2733
|
-
L:
|
|
4184
|
+
L: 115,
|
|
2734
4185
|
S: this,
|
|
2735
4186
|
A: [
|
|
2736
4187
|
"this._postTask",
|
|
@@ -2740,9 +4191,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2740
4191
|
this._postTask.schedule();
|
|
2741
4192
|
}
|
|
2742
4193
|
_handlePostMessage(message) {
|
|
2743
|
-
|
|
4194
|
+
invariant2(message.kind === "post", void 0, {
|
|
2744
4195
|
F: __dxlog_file4,
|
|
2745
|
-
L:
|
|
4196
|
+
L: 120,
|
|
2746
4197
|
S: this,
|
|
2747
4198
|
A: [
|
|
2748
4199
|
"message.kind === 'post'",
|
|
@@ -2754,199 +4205,247 @@ var SpaceAwarenessProvider = class {
|
|
|
2754
4205
|
}
|
|
2755
4206
|
};
|
|
2756
4207
|
|
|
2757
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
4208
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2758
4209
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2759
|
-
|
|
2760
|
-
|
|
4210
|
+
var modelState = StateField5.define({
|
|
4211
|
+
create: () => void 0,
|
|
4212
|
+
update: (model) => model
|
|
4213
|
+
});
|
|
2761
4214
|
|
|
2762
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
4215
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
4216
|
+
var useActionHandler = (view) => {
|
|
4217
|
+
return (action) => {
|
|
4218
|
+
if (!view) {
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
let inlineType, listType;
|
|
4222
|
+
switch (action.type) {
|
|
4223
|
+
case "heading":
|
|
4224
|
+
setHeading(parseInt(action.data))(view);
|
|
4225
|
+
break;
|
|
4226
|
+
case "strong":
|
|
4227
|
+
case "emphasis":
|
|
4228
|
+
case "strikethrough":
|
|
4229
|
+
case "code":
|
|
4230
|
+
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4231
|
+
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
4232
|
+
break;
|
|
4233
|
+
case "list-ordered":
|
|
4234
|
+
case "list-bullet":
|
|
4235
|
+
case "list-tasks":
|
|
4236
|
+
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4237
|
+
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
4238
|
+
break;
|
|
4239
|
+
case "blockquote":
|
|
4240
|
+
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
4241
|
+
break;
|
|
4242
|
+
case "codeblock":
|
|
4243
|
+
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
4244
|
+
break;
|
|
4245
|
+
case "table":
|
|
4246
|
+
insertTable(view);
|
|
4247
|
+
break;
|
|
4248
|
+
case "link":
|
|
4249
|
+
(action.data === false ? removeLink : addLink)(view);
|
|
4250
|
+
break;
|
|
4251
|
+
case "comment":
|
|
4252
|
+
createComment(view);
|
|
4253
|
+
break;
|
|
4254
|
+
}
|
|
4255
|
+
setTimeout(() => {
|
|
4256
|
+
if (!view.hasFocus) {
|
|
4257
|
+
view.focus();
|
|
4258
|
+
}
|
|
4259
|
+
});
|
|
2798
4260
|
};
|
|
2799
|
-
return model;
|
|
2800
4261
|
};
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
4262
|
+
|
|
4263
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
4264
|
+
import { useState as useState3 } from "react";
|
|
4265
|
+
var useEditorView = () => {
|
|
4266
|
+
const [view, setView] = useState3(null);
|
|
4267
|
+
return [
|
|
4268
|
+
(ref) => {
|
|
4269
|
+
setView(ref);
|
|
4270
|
+
},
|
|
4271
|
+
view
|
|
4272
|
+
];
|
|
4273
|
+
};
|
|
4274
|
+
|
|
4275
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4276
|
+
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4277
|
+
import { EditorView as EditorView15 } from "@codemirror/view";
|
|
4278
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
4279
|
+
import { log as log4 } from "@dxos/log";
|
|
4280
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
4281
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4282
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
4283
|
+
const onUpdate = useRef2();
|
|
4284
|
+
const [view, setView] = useState4();
|
|
4285
|
+
const parentRef = useRef2(null);
|
|
4286
|
+
useEffect3(() => {
|
|
4287
|
+
if (parentRef.current) {
|
|
4288
|
+
const state = EditorState3.create({
|
|
4289
|
+
doc,
|
|
4290
|
+
selection,
|
|
4291
|
+
extensions: [
|
|
4292
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4293
|
+
EditorView15.exceptionSink.of((err) => {
|
|
4294
|
+
log4.catch(err, void 0, {
|
|
4295
|
+
F: __dxlog_file5,
|
|
4296
|
+
L: 57,
|
|
4297
|
+
S: void 0,
|
|
4298
|
+
C: (f, a) => f(...a)
|
|
4299
|
+
});
|
|
4300
|
+
}),
|
|
4301
|
+
extensions,
|
|
4302
|
+
EditorView15.updateListener.of(() => {
|
|
4303
|
+
onUpdate.current?.();
|
|
4304
|
+
})
|
|
4305
|
+
].filter(isNotFalsy4)
|
|
4306
|
+
});
|
|
4307
|
+
const view2 = new EditorView15({
|
|
4308
|
+
parent: parentRef.current,
|
|
4309
|
+
scrollTo,
|
|
4310
|
+
state,
|
|
4311
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4312
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4313
|
+
dispatchTransactions: (trs, view3) => {
|
|
4314
|
+
if (debug) {
|
|
4315
|
+
logChanges(trs);
|
|
4316
|
+
}
|
|
4317
|
+
view3.update(trs);
|
|
4318
|
+
}
|
|
4319
|
+
});
|
|
4320
|
+
setView(view2);
|
|
4321
|
+
}
|
|
4322
|
+
return () => {
|
|
4323
|
+
view?.destroy();
|
|
4324
|
+
};
|
|
4325
|
+
}, [
|
|
4326
|
+
parentRef
|
|
4327
|
+
]);
|
|
4328
|
+
useEffect3(() => {
|
|
4329
|
+
if (view) {
|
|
4330
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
4331
|
+
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
2870
4332
|
}
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
4333
|
+
if (selection || scrollTo) {
|
|
4334
|
+
onUpdate.current = () => {
|
|
4335
|
+
onUpdate.current = void 0;
|
|
4336
|
+
view.dispatch({
|
|
4337
|
+
selection,
|
|
4338
|
+
effects: scrollTo && [
|
|
4339
|
+
scrollTo
|
|
4340
|
+
],
|
|
4341
|
+
scrollIntoView: !scrollTo
|
|
4342
|
+
});
|
|
4343
|
+
};
|
|
2876
4344
|
}
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
return encoder;
|
|
4345
|
+
if (autoFocus) {
|
|
4346
|
+
view.focus();
|
|
2880
4347
|
}
|
|
2881
4348
|
}
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
}
|
|
4349
|
+
}, [
|
|
4350
|
+
view,
|
|
4351
|
+
autoFocus,
|
|
4352
|
+
selection,
|
|
4353
|
+
scrollTo
|
|
4354
|
+
]);
|
|
4355
|
+
return {
|
|
4356
|
+
parentRef,
|
|
4357
|
+
view
|
|
4358
|
+
};
|
|
4359
|
+
};
|
|
4360
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
4361
|
+
return [
|
|
4362
|
+
//
|
|
4363
|
+
EditorState3.readOnly.of(readonly),
|
|
4364
|
+
EditorView15.editable.of(!readonly)
|
|
4365
|
+
];
|
|
4366
|
+
};
|
|
4367
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
4368
|
+
return [
|
|
4369
|
+
//
|
|
4370
|
+
EditorView15.baseTheme(defaultTheme),
|
|
4371
|
+
theme && EditorView15.theme(theme),
|
|
4372
|
+
EditorView15.darkTheme.of(themeMode === "dark"),
|
|
4373
|
+
EditorView15.editorAttributes.of({
|
|
4374
|
+
class: slots?.editor?.className ?? ""
|
|
4375
|
+
}),
|
|
4376
|
+
EditorView15.contentAttributes.of({
|
|
4377
|
+
class: slots?.content?.className ?? ""
|
|
4378
|
+
})
|
|
4379
|
+
].filter(isNotFalsy4);
|
|
2892
4380
|
};
|
|
2893
4381
|
|
|
2894
4382
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
}
|
|
4383
|
+
import get4 from "lodash.get";
|
|
4384
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
4385
|
+
import { generateName } from "@dxos/display-name";
|
|
4386
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
4387
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
4388
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
4389
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2899
4390
|
var useTextModel = (props) => {
|
|
2900
4391
|
const { identity, space, text } = props;
|
|
2901
|
-
const [model, setModel] =
|
|
2902
|
-
|
|
4392
|
+
const [model, setModel] = useState5();
|
|
4393
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2903
4394
|
identity,
|
|
2904
4395
|
space,
|
|
2905
4396
|
text
|
|
2906
4397
|
]);
|
|
2907
4398
|
return model;
|
|
2908
4399
|
};
|
|
2909
|
-
var
|
|
2910
|
-
const
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
}
|
|
4400
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4401
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4402
|
+
return {
|
|
4403
|
+
id,
|
|
4404
|
+
content,
|
|
4405
|
+
setContent,
|
|
4406
|
+
text: () => content
|
|
4407
|
+
};
|
|
2918
4408
|
};
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
4409
|
+
var createModel = ({ space, identity, text }) => {
|
|
4410
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
4411
|
+
F: __dxlog_file6,
|
|
4412
|
+
L: 50,
|
|
4413
|
+
S: void 0,
|
|
4414
|
+
A: [
|
|
4415
|
+
"isAutomergeObject(text)",
|
|
4416
|
+
""
|
|
4417
|
+
]
|
|
4418
|
+
});
|
|
2922
4419
|
const obj = text;
|
|
2923
4420
|
const doc = getRawDoc(obj, [
|
|
2924
4421
|
obj.field
|
|
2925
4422
|
]);
|
|
2926
|
-
const
|
|
4423
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2927
4424
|
space,
|
|
2928
4425
|
channel: `automerge.awareness.${obj.id}`,
|
|
2929
4426
|
info: {
|
|
2930
|
-
displayName: identity
|
|
4427
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2931
4428
|
color: cursorColor.color,
|
|
2932
4429
|
lightColor: cursorColor.light
|
|
2933
4430
|
},
|
|
2934
4431
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2935
4432
|
});
|
|
4433
|
+
const extensions = [
|
|
4434
|
+
//
|
|
4435
|
+
modelState.init(() => model),
|
|
4436
|
+
automerge({
|
|
4437
|
+
handle: doc.handle,
|
|
4438
|
+
path: doc.path
|
|
4439
|
+
})
|
|
4440
|
+
];
|
|
4441
|
+
if (awarenessProvider2) {
|
|
4442
|
+
extensions.push(awareness(awarenessProvider2));
|
|
4443
|
+
}
|
|
2936
4444
|
const model = {
|
|
2937
4445
|
id: obj.id,
|
|
2938
4446
|
content: doc,
|
|
2939
4447
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2940
|
-
|
|
2941
|
-
extension: [
|
|
2942
|
-
modelState.init(() => model),
|
|
2943
|
-
automerge3({
|
|
2944
|
-
handle: doc.handle,
|
|
2945
|
-
path: doc.path
|
|
2946
|
-
}),
|
|
2947
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2948
|
-
awareness()
|
|
2949
|
-
].filter(isNotNullOrUndefined),
|
|
4448
|
+
extension: extensions,
|
|
2950
4449
|
peer: identity ? {
|
|
2951
4450
|
id: identity.identityKey.toHex(),
|
|
2952
4451
|
name: identity.profile?.displayName
|
|
@@ -2955,56 +4454,94 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2955
4454
|
return model;
|
|
2956
4455
|
};
|
|
2957
4456
|
export {
|
|
2958
|
-
AwarenessProvider,
|
|
2959
4457
|
BaseTextEditor,
|
|
2960
4458
|
Cursor,
|
|
2961
4459
|
Doc,
|
|
2962
4460
|
EditorModes,
|
|
4461
|
+
Inline,
|
|
4462
|
+
List,
|
|
2963
4463
|
MarkdownEditor,
|
|
2964
4464
|
RemoteSelectionsDecorator,
|
|
2965
4465
|
SpaceAwarenessProvider,
|
|
2966
4466
|
TextEditor,
|
|
2967
4467
|
TextKind,
|
|
2968
|
-
|
|
4468
|
+
Toolbar,
|
|
2969
4469
|
YText,
|
|
2970
4470
|
YXmlFragment,
|
|
4471
|
+
addBlockquote,
|
|
4472
|
+
addCodeblock,
|
|
4473
|
+
addLink,
|
|
4474
|
+
addList,
|
|
4475
|
+
addStyle,
|
|
2971
4476
|
autocomplete,
|
|
2972
|
-
|
|
4477
|
+
automerge,
|
|
2973
4478
|
awareness,
|
|
2974
|
-
|
|
4479
|
+
awarenessProvider,
|
|
2975
4480
|
blast,
|
|
2976
4481
|
callbackWrapper,
|
|
2977
4482
|
code2 as code,
|
|
2978
4483
|
codeTheme,
|
|
2979
4484
|
comments,
|
|
2980
|
-
|
|
2981
|
-
|
|
4485
|
+
compareFormatting,
|
|
4486
|
+
createBasicBundle,
|
|
4487
|
+
createComment,
|
|
4488
|
+
createDataExtensions,
|
|
4489
|
+
createMarkdownExtensions,
|
|
4490
|
+
createThemeExtensions,
|
|
2982
4491
|
defaultMarkdownSlots,
|
|
2983
4492
|
defaultOptions,
|
|
2984
4493
|
defaultSlots,
|
|
2985
4494
|
defaultTextSlots,
|
|
2986
4495
|
defaultTheme,
|
|
4496
|
+
focusComment,
|
|
4497
|
+
formatting,
|
|
4498
|
+
getFormatting,
|
|
2987
4499
|
getToken,
|
|
4500
|
+
heading2 as heading,
|
|
2988
4501
|
hr,
|
|
2989
4502
|
image,
|
|
4503
|
+
insertTable,
|
|
4504
|
+
keymap7 as keymap,
|
|
2990
4505
|
link,
|
|
2991
4506
|
listener,
|
|
2992
|
-
|
|
4507
|
+
logChanges,
|
|
2993
4508
|
markdownHighlightStyle,
|
|
2994
4509
|
markdownTags,
|
|
2995
4510
|
markdownTagsExtensions,
|
|
2996
4511
|
markdownTheme,
|
|
2997
4512
|
mention,
|
|
2998
4513
|
modelState,
|
|
2999
|
-
|
|
3000
|
-
|
|
4514
|
+
outliner,
|
|
4515
|
+
removeBlockquote,
|
|
4516
|
+
removeCodeblock,
|
|
4517
|
+
removeLink,
|
|
4518
|
+
removeList,
|
|
4519
|
+
removeStyle,
|
|
4520
|
+
setBlockquote,
|
|
4521
|
+
setComments,
|
|
4522
|
+
setHeading,
|
|
3001
4523
|
setSelection,
|
|
4524
|
+
setStyle,
|
|
3002
4525
|
table,
|
|
3003
4526
|
tags2 as tags,
|
|
3004
4527
|
tasklist,
|
|
3005
4528
|
textTheme,
|
|
4529
|
+
toggleBlockquote,
|
|
4530
|
+
toggleCodeblock,
|
|
4531
|
+
toggleEmphasis,
|
|
4532
|
+
toggleInlineCode,
|
|
4533
|
+
toggleList,
|
|
4534
|
+
toggleStrikethrough,
|
|
4535
|
+
toggleStrong,
|
|
4536
|
+
toggleStyle,
|
|
3006
4537
|
typewriter,
|
|
4538
|
+
useActionHandler,
|
|
4539
|
+
useComments,
|
|
4540
|
+
useEditorView,
|
|
4541
|
+
useFormattingState,
|
|
4542
|
+
useInMemoryTextModel,
|
|
4543
|
+
useTextEditor,
|
|
3007
4544
|
useTextModel,
|
|
3008
|
-
|
|
4545
|
+
useToolbarContext
|
|
3009
4546
|
};
|
|
3010
4547
|
//# sourceMappingURL=index.mjs.map
|