@dxos/react-ui-editor 0.3.11-main.b00882f → 0.3.11-main.b3f97d8
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 +2386 -968
- 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 +1 -2
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- 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/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 +5 -5
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +2 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -4
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +1 -1
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +11 -3
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +0 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -2
- 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.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 +1 -4
- package/dist/types/src/hooks/defs.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -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 +36 -14
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +12 -0
- 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/package.json +39 -29
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +15 -19
- package/src/components/TextEditor/TextEditor.tsx +27 -19
- 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/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +26 -11
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +9 -9
- package/src/extensions/automerge/semaphore.ts +17 -19
- package/src/extensions/automerge/update-automerge.ts +12 -6
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +21 -35
- package/src/extensions/basic.ts +15 -13
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +126 -68
- package/src/extensions/index.ts +0 -7
- package/src/extensions/markdown/bundle.ts +9 -8
- 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/{hr.ts → markdown/hr.ts} +3 -4
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +13 -4
- package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +2 -3
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +1 -6
- package/src/hooks/index.ts +2 -2
- package/src/hooks/useActionHandler.ts +93 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +143 -19
- package/src/hooks/useTextModel.ts +65 -12
- package/src/index.ts +1 -1
- package/src/styles/markdown.ts +9 -10
- package/src/themes/default.ts +11 -8
- 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.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 -4
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -28
- 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 -357
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -104
- 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 -53
- package/src/hooks/yjs.ts +0 -157
- 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/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.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 as
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
15
15
|
import { log as log2 } from "@dxos/log";
|
|
16
|
-
import { useThemeContext
|
|
17
|
-
import {
|
|
16
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
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";
|
|
@@ -53,14 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
56
58
|
import { StateField } from "@codemirror/state";
|
|
57
59
|
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
58
|
-
import { next as
|
|
59
|
-
import { invariant } from "@dxos/invariant";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
60
61
|
|
|
61
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
62
63
|
import get from "lodash.get";
|
|
63
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
64
65
|
var cursorConverter = (handle, path) => ({
|
|
65
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
66
67
|
toCursor: (pos) => {
|
|
@@ -72,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
72
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
73
74
|
return "end";
|
|
74
75
|
}
|
|
75
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
76
77
|
},
|
|
77
78
|
fromCursor: (cursor) => {
|
|
78
79
|
if (cursor === "") {
|
|
@@ -90,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
90
91
|
return 0;
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
94
95
|
}
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
98
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
99
|
-
var effectType = StateEffect.define({});
|
|
100
|
-
var reconcileAnnotationType = Annotation.define();
|
|
101
100
|
var getPath = (state, field) => state.field(field).path;
|
|
102
101
|
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
103
|
-
var
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
104
104
|
newHeads
|
|
105
105
|
});
|
|
106
|
-
var
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
107
110
|
|
|
108
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
110
113
|
|
|
111
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
113
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
117
|
const { lastHeads, path } = state.field(field);
|
|
115
118
|
let hasChanges = false;
|
|
@@ -122,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
122
125
|
return void 0;
|
|
123
126
|
}
|
|
124
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
125
129
|
for (const tr of transactions) {
|
|
126
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
127
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
128
136
|
});
|
|
129
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
130
141
|
});
|
|
131
142
|
return newHeads ?? void 0;
|
|
132
143
|
};
|
|
@@ -141,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
141
152
|
selection = selection.map(changeSet, 1);
|
|
142
153
|
view.dispatch({
|
|
143
154
|
changes: changeSet,
|
|
144
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
145
156
|
});
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
view.dispatch({
|
|
149
160
|
selection,
|
|
150
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
151
162
|
});
|
|
152
163
|
};
|
|
153
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -168,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
168
179
|
if (index == null) {
|
|
169
180
|
return [];
|
|
170
181
|
}
|
|
171
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
172
183
|
return [
|
|
173
184
|
{
|
|
174
185
|
from: index,
|
|
@@ -246,36 +257,37 @@ var PatchSemaphore = class {
|
|
|
246
257
|
this._state = _state;
|
|
247
258
|
this._inReconcile = false;
|
|
248
259
|
}
|
|
249
|
-
// NOTE: Cannot destruct view.state.
|
|
250
260
|
reconcile(view) {
|
|
251
|
-
if (this._inReconcile) {
|
|
252
|
-
|
|
261
|
+
if (!this._inReconcile) {
|
|
262
|
+
this._inReconcile = true;
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
253
265
|
}
|
|
254
|
-
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
255
268
|
const path = getPath(view.state, this._state);
|
|
256
269
|
const oldHeads = getLastHeads(view.state, this._state);
|
|
257
270
|
let selection = view.state.selection;
|
|
258
|
-
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
259
272
|
const toInvert = transactions.slice().reverse();
|
|
260
|
-
for (const
|
|
261
|
-
const inverted =
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
262
275
|
selection = selection.map(inverted);
|
|
263
276
|
view.dispatch({
|
|
264
277
|
changes: inverted,
|
|
265
|
-
annotations:
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
266
279
|
});
|
|
267
280
|
}
|
|
268
281
|
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
269
282
|
if (newHeads === null || newHeads === void 0) {
|
|
270
|
-
newHeads =
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
271
284
|
}
|
|
272
|
-
const diff =
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
273
286
|
updateCodeMirror(view, selection, path, diff);
|
|
274
287
|
view.dispatch({
|
|
275
288
|
effects: updateHeads(newHeads),
|
|
276
|
-
annotations:
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
277
290
|
});
|
|
278
|
-
this._inReconcile = false;
|
|
279
291
|
}
|
|
280
292
|
};
|
|
281
293
|
|
|
@@ -293,9 +305,9 @@ var Cursor = class _Cursor {
|
|
|
293
305
|
}
|
|
294
306
|
static {
|
|
295
307
|
this.getCursorFromRange = (state, range) => {
|
|
296
|
-
const
|
|
297
|
-
const from =
|
|
298
|
-
const to =
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
299
311
|
return [
|
|
300
312
|
from,
|
|
301
313
|
to
|
|
@@ -304,10 +316,10 @@ var Cursor = class _Cursor {
|
|
|
304
316
|
}
|
|
305
317
|
static {
|
|
306
318
|
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
-
const
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
320
|
const parts = cursor.split(":");
|
|
309
|
-
const from =
|
|
310
|
-
const to =
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
311
323
|
return from !== void 0 && to !== void 0 ? {
|
|
312
324
|
from,
|
|
313
325
|
to
|
|
@@ -317,12 +329,11 @@ var Cursor = class _Cursor {
|
|
|
317
329
|
};
|
|
318
330
|
|
|
319
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
320
|
-
var
|
|
321
|
-
|
|
322
|
-
const state = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
323
334
|
create: () => ({
|
|
324
335
|
path: path.slice(),
|
|
325
|
-
lastHeads:
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
326
337
|
unreconciledTransactions: []
|
|
327
338
|
}),
|
|
328
339
|
update: (value, tr) => {
|
|
@@ -333,7 +344,7 @@ var automerge3 = ({ handle, path }) => {
|
|
|
333
344
|
};
|
|
334
345
|
let clearUnreconciled = false;
|
|
335
346
|
for (const effect of tr.effects) {
|
|
336
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
337
348
|
result.lastHeads = effect.value.newHeads;
|
|
338
349
|
clearUnreconciled = true;
|
|
339
350
|
}
|
|
@@ -341,29 +352,21 @@ var automerge3 = ({ handle, path }) => {
|
|
|
341
352
|
if (clearUnreconciled) {
|
|
342
353
|
result.unreconciledTransactions = [];
|
|
343
354
|
} else {
|
|
344
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
345
356
|
result.unreconciledTransactions.push(tr);
|
|
346
357
|
}
|
|
347
358
|
}
|
|
348
359
|
return result;
|
|
349
360
|
}
|
|
350
361
|
});
|
|
351
|
-
const semaphore = new PatchSemaphore(handle,
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
352
363
|
return [
|
|
353
364
|
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
354
366
|
// Reconcile external updates.
|
|
355
367
|
ViewPlugin.fromClass(class {
|
|
356
368
|
constructor(_view) {
|
|
357
369
|
this._view = _view;
|
|
358
|
-
invariant(this._view, void 0, {
|
|
359
|
-
F: __dxlog_file,
|
|
360
|
-
L: 66,
|
|
361
|
-
S: this,
|
|
362
|
-
A: [
|
|
363
|
-
"this._view",
|
|
364
|
-
""
|
|
365
|
-
]
|
|
366
|
-
});
|
|
367
370
|
handle.addListener("change", this._handleChange.bind(this));
|
|
368
371
|
}
|
|
369
372
|
destroy() {
|
|
@@ -379,65 +382,48 @@ var automerge3 = ({ handle, path }) => {
|
|
|
379
382
|
semaphore.reconcile(view);
|
|
380
383
|
}
|
|
381
384
|
}),
|
|
382
|
-
|
|
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) => {
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
383
396
|
];
|
|
384
397
|
};
|
|
385
398
|
|
|
386
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
387
400
|
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
388
401
|
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
389
|
-
import { useEffect } from "react";
|
|
390
402
|
import { Event } from "@dxos/async";
|
|
391
403
|
import { Context } from "@dxos/context";
|
|
392
|
-
import { generateName } from "@dxos/display-name";
|
|
393
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
394
|
-
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
395
404
|
var dummyProvider = {
|
|
396
405
|
remoteStateChange: new Event(),
|
|
397
406
|
open: () => {
|
|
398
407
|
},
|
|
399
408
|
close: () => {
|
|
400
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
401
411
|
update: () => {
|
|
402
|
-
}
|
|
403
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
404
413
|
};
|
|
405
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
406
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
407
416
|
});
|
|
408
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
409
418
|
var awareness = (provider = dummyProvider) => {
|
|
410
419
|
return [
|
|
411
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
412
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
413
422
|
decorations: (value) => value.decorations
|
|
414
423
|
}),
|
|
415
424
|
styles
|
|
416
425
|
];
|
|
417
426
|
};
|
|
418
|
-
var useAwareness = ({ awareness: awareness2, peer }) => {
|
|
419
|
-
const { themeMode } = useThemeContext();
|
|
420
|
-
useEffect(() => {
|
|
421
|
-
if (awareness2 && peer) {
|
|
422
|
-
awareness2.setLocalStateField("user", {
|
|
423
|
-
name: peer.name ?? generateName(peer.id),
|
|
424
|
-
color: getColorForValue({
|
|
425
|
-
value: peer.id,
|
|
426
|
-
type: "color"
|
|
427
|
-
}),
|
|
428
|
-
colorLight: getColorForValue({
|
|
429
|
-
value: peer.id,
|
|
430
|
-
themeMode,
|
|
431
|
-
type: "highlight"
|
|
432
|
-
})
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
}, [
|
|
436
|
-
awareness2,
|
|
437
|
-
peer,
|
|
438
|
-
themeMode
|
|
439
|
-
]);
|
|
440
|
-
};
|
|
441
427
|
var RemoteSelectionsDecorator = class {
|
|
442
428
|
constructor(view) {
|
|
443
429
|
this.decorations = RangeSet.of([]);
|
|
@@ -445,7 +431,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
445
431
|
this._lastAnchor = void 0;
|
|
446
432
|
this._lastHead = void 0;
|
|
447
433
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
448
|
-
this._provider = view.state.facet(
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
449
435
|
this._provider.open();
|
|
450
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
451
437
|
view.dispatch({
|
|
@@ -599,39 +585,41 @@ var styles = EditorView2.baseTheme({
|
|
|
599
585
|
marginLeft: "-1px",
|
|
600
586
|
marginRight: "-1px",
|
|
601
587
|
boxSizing: "border-box",
|
|
602
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
603
590
|
},
|
|
604
591
|
".cm-collab-selectionCaretDot": {
|
|
605
592
|
borderRadius: "50%",
|
|
606
593
|
position: "absolute",
|
|
607
|
-
width: ".
|
|
608
|
-
height: ".
|
|
609
|
-
top: "-.
|
|
610
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
611
598
|
backgroundColor: "inherit",
|
|
612
599
|
transition: "transform .3s ease-in-out",
|
|
613
600
|
boxSizing: "border-box"
|
|
614
601
|
},
|
|
615
602
|
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
616
|
-
|
|
617
|
-
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
618
605
|
},
|
|
619
606
|
".cm-collab-selectionInfo": {
|
|
620
607
|
position: "absolute",
|
|
621
|
-
|
|
622
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
623
611
|
fontSize: ".75em",
|
|
624
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
625
613
|
fontStyle: "normal",
|
|
626
614
|
fontWeight: "normal",
|
|
627
615
|
lineHeight: "normal",
|
|
628
616
|
userSelect: "none",
|
|
629
617
|
color: "white",
|
|
630
|
-
|
|
631
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
632
619
|
zIndex: 101,
|
|
633
620
|
transition: "opacity .3s ease-in-out",
|
|
634
621
|
backgroundColor: "inherit",
|
|
622
|
+
borderRadius: "2px",
|
|
635
623
|
// These should be separate.
|
|
636
624
|
opacity: 0,
|
|
637
625
|
transitionDelay: "0s",
|
|
@@ -649,24 +637,25 @@ import { history } from "@codemirror/commands";
|
|
|
649
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
650
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
651
639
|
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
652
|
-
|
|
653
|
-
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
654
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
655
644
|
bracketMatching(),
|
|
656
645
|
closeBrackets(),
|
|
657
646
|
drawSelection(),
|
|
658
647
|
highlightActiveLine(),
|
|
659
648
|
history(),
|
|
660
|
-
_placeholder
|
|
649
|
+
_placeholder && placeholder(_placeholder),
|
|
661
650
|
// https://github.com/codemirror/theme-one-dark
|
|
662
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
663
|
-
];
|
|
652
|
+
].filter(isNotFalsy);
|
|
664
653
|
|
|
665
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
666
655
|
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
667
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
668
|
-
import { invariant
|
|
669
|
-
var
|
|
657
|
+
import { invariant } from "@dxos/invariant";
|
|
658
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
670
659
|
var defaultOptions = {
|
|
671
660
|
effect: 2,
|
|
672
661
|
maxParticles: 200,
|
|
@@ -699,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
699
688
|
const getPoint = (view, pos) => {
|
|
700
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
701
690
|
const element = document.elementFromPoint(x, y);
|
|
702
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
703
692
|
const point = {
|
|
704
693
|
x: x - left,
|
|
705
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
706
695
|
};
|
|
707
696
|
return {
|
|
708
697
|
element,
|
|
@@ -792,9 +781,9 @@ var Blaster = class {
|
|
|
792
781
|
return this._node;
|
|
793
782
|
}
|
|
794
783
|
initialize() {
|
|
795
|
-
|
|
796
|
-
F:
|
|
797
|
-
L:
|
|
784
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
785
|
+
F: __dxlog_file,
|
|
786
|
+
L: 141,
|
|
798
787
|
S: this,
|
|
799
788
|
A: [
|
|
800
789
|
"!this._canvas && !this._ctx",
|
|
@@ -829,9 +818,9 @@ var Blaster = class {
|
|
|
829
818
|
}
|
|
830
819
|
}
|
|
831
820
|
start() {
|
|
832
|
-
|
|
833
|
-
F:
|
|
834
|
-
L:
|
|
821
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
822
|
+
F: __dxlog_file,
|
|
823
|
+
L: 180,
|
|
835
824
|
S: this,
|
|
836
825
|
A: [
|
|
837
826
|
"this._canvas && this._ctx",
|
|
@@ -972,9 +961,14 @@ var random = (min, max) => {
|
|
|
972
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
973
962
|
};
|
|
974
963
|
|
|
975
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
976
|
-
import {
|
|
977
|
-
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";
|
|
978
972
|
|
|
979
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
980
974
|
import * as random2 from "lib0/random";
|
|
@@ -1017,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
1017
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
1018
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
1019
1013
|
var headings = {
|
|
1020
|
-
1:
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1030
|
-
"-ml-[7px]"
|
|
1031
|
-
],
|
|
1032
|
-
4: [
|
|
1033
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1034
|
-
"-ml-[6px]"
|
|
1035
|
-
],
|
|
1036
|
-
5: [
|
|
1037
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1038
|
-
"-ml-[5px]"
|
|
1039
|
-
],
|
|
1040
|
-
6: [
|
|
1041
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1042
|
-
"-ml-[4px]"
|
|
1043
|
-
]
|
|
1044
|
-
};
|
|
1045
|
-
var heading = (level, readonly) => {
|
|
1046
|
-
const [style, offset] = headings[level];
|
|
1047
|
-
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];
|
|
1048
1023
|
};
|
|
1049
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1050
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1062,98 +1037,15 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1062
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1063
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1064
1039
|
|
|
1065
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1066
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1067
|
-
var styles2 = EditorView5.baseTheme({
|
|
1068
|
-
"& .cm-codeblock": {
|
|
1069
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1070
|
-
},
|
|
1071
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1072
|
-
background: getToken("extend.colors.neutral.50")
|
|
1073
|
-
},
|
|
1074
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1075
|
-
background: getToken("extend.colors.neutral.850")
|
|
1076
|
-
},
|
|
1077
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1078
|
-
display: "block",
|
|
1079
|
-
paddingInline: "4px !important"
|
|
1080
|
-
},
|
|
1081
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1082
|
-
paddingTop: "4px !important",
|
|
1083
|
-
borderTopLeftRadius: "4px",
|
|
1084
|
-
borderTopRightRadius: "4px"
|
|
1085
|
-
},
|
|
1086
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1087
|
-
paddingBottom: "4px !important",
|
|
1088
|
-
borderBottomLeftRadius: "4px",
|
|
1089
|
-
borderBottomRightRadius: "4px"
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
var getLineRange = (lines, from, to) => {
|
|
1093
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1094
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1095
|
-
return [
|
|
1096
|
-
start,
|
|
1097
|
-
end
|
|
1098
|
-
];
|
|
1099
|
-
};
|
|
1100
|
-
var code2 = () => {
|
|
1101
|
-
const buildDecorations5 = (view) => {
|
|
1102
|
-
const decorations = [];
|
|
1103
|
-
const text = view.state.doc.sliceString(0);
|
|
1104
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1105
|
-
const blocks = view.viewportLineBlocks;
|
|
1106
|
-
for (const match of matches) {
|
|
1107
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1108
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1109
|
-
const block = blocks[i];
|
|
1110
|
-
decorations.push(Decoration2.line({
|
|
1111
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1112
|
-
}).range(block.from));
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
return Decoration2.set(decorations);
|
|
1116
|
-
};
|
|
1117
|
-
return [
|
|
1118
|
-
ViewPlugin3.fromClass(class {
|
|
1119
|
-
constructor(view) {
|
|
1120
|
-
this.hasFocus = false;
|
|
1121
|
-
this.decorations = buildDecorations5(view);
|
|
1122
|
-
}
|
|
1123
|
-
update(update2) {
|
|
1124
|
-
if (
|
|
1125
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1126
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1127
|
-
) {
|
|
1128
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1129
|
-
this.decorations = buildDecorations5(update2.view);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}, {
|
|
1133
|
-
decorations: (value) => value.decorations
|
|
1134
|
-
}),
|
|
1135
|
-
styles2
|
|
1136
|
-
];
|
|
1137
|
-
};
|
|
1138
|
-
|
|
1139
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1140
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1141
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1142
|
-
import sortBy from "lodash.sortby";
|
|
1143
|
-
import { useEffect as useEffect2 } from "react";
|
|
1144
|
-
import { debounce } from "@dxos/async";
|
|
1145
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1146
|
-
import { nonNullable } from "@dxos/util";
|
|
1147
|
-
|
|
1148
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1149
1041
|
import { log } from "@dxos/log";
|
|
1150
|
-
var
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1151
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1152
1044
|
try {
|
|
1153
1045
|
return fn(...args);
|
|
1154
1046
|
} catch (err) {
|
|
1155
1047
|
log.catch(err, void 0, {
|
|
1156
|
-
F:
|
|
1048
|
+
F: __dxlog_file2,
|
|
1157
1049
|
L: 18,
|
|
1158
1050
|
S: void 0,
|
|
1159
1051
|
C: (f, a) => f(...a)
|
|
@@ -1181,24 +1073,35 @@ var logChanges = (trs) => {
|
|
|
1181
1073
|
};
|
|
1182
1074
|
|
|
1183
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1184
|
-
var
|
|
1185
|
-
|
|
1186
|
-
|
|
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": {
|
|
1187
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1188
1085
|
},
|
|
1189
|
-
"& .cm-comment-current": {
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1190
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")
|
|
1191
1096
|
}
|
|
1192
1097
|
});
|
|
1193
|
-
var
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
};
|
|
1201
|
-
var setFocus = (view, id, center = true) => {
|
|
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) => {
|
|
1202
1105
|
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1203
1106
|
if (!comment?.comment.cursor) {
|
|
1204
1107
|
return;
|
|
@@ -1211,7 +1114,7 @@ var setFocus = (view, id, center = true) => {
|
|
|
1211
1114
|
},
|
|
1212
1115
|
effects: [
|
|
1213
1116
|
//
|
|
1214
|
-
|
|
1117
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1215
1118
|
y: "center"
|
|
1216
1119
|
} : void 0),
|
|
1217
1120
|
setSelection.of({
|
|
@@ -1260,7 +1163,7 @@ var commentsState = StateField2.define({
|
|
|
1260
1163
|
return value;
|
|
1261
1164
|
}
|
|
1262
1165
|
});
|
|
1263
|
-
var
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1264
1167
|
commentsState
|
|
1265
1168
|
], (state) => {
|
|
1266
1169
|
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
@@ -1271,12 +1174,12 @@ var highlightDecorations = EditorView6.decorations.compute([
|
|
|
1271
1174
|
return void 0;
|
|
1272
1175
|
}
|
|
1273
1176
|
if (comment.comment.id === current) {
|
|
1274
|
-
return
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1275
1178
|
} else {
|
|
1276
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1277
1180
|
}
|
|
1278
1181
|
}).filter(nonNullable);
|
|
1279
|
-
return
|
|
1182
|
+
return Decoration2.set(decorations);
|
|
1280
1183
|
});
|
|
1281
1184
|
var trackPastedComments = (onUpdate) => {
|
|
1282
1185
|
let tracked = null;
|
|
@@ -1298,96 +1201,140 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1298
1201
|
}
|
|
1299
1202
|
};
|
|
1300
1203
|
return [
|
|
1301
|
-
|
|
1204
|
+
EditorView5.domEventHandlers({
|
|
1302
1205
|
cut: handleTrack,
|
|
1303
1206
|
copy: handleTrack
|
|
1304
1207
|
}),
|
|
1305
|
-
//
|
|
1306
|
-
|
|
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;
|
|
1224
|
+
}),
|
|
1225
|
+
// Handle paste or the undo of comment deletion.
|
|
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
|
+
}
|
|
1307
1239
|
if (tracked) {
|
|
1308
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1240
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1309
1241
|
if (paste) {
|
|
1310
1242
|
let found = -1;
|
|
1311
1243
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1312
1244
|
if (text.eq(tracked.text)) {
|
|
1313
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1314
|
-
fromB = transactions[i].changes.mapPos(fromB);
|
|
1245
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1246
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1315
1247
|
}
|
|
1316
1248
|
found = fromB;
|
|
1317
1249
|
}
|
|
1318
1250
|
});
|
|
1319
1251
|
if (found > -1) {
|
|
1320
1252
|
for (const moved of tracked.comments) {
|
|
1321
|
-
|
|
1253
|
+
restore.push({
|
|
1254
|
+
id: moved.id,
|
|
1322
1255
|
from: found + moved.from,
|
|
1323
1256
|
to: found + moved.to
|
|
1324
|
-
};
|
|
1325
|
-
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1326
|
-
onUpdate(moved.id, cursor);
|
|
1257
|
+
});
|
|
1327
1258
|
}
|
|
1328
1259
|
}
|
|
1329
1260
|
tracked = null;
|
|
1330
1261
|
}
|
|
1331
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
|
+
}
|
|
1332
1271
|
})
|
|
1333
1272
|
];
|
|
1334
1273
|
};
|
|
1335
|
-
var
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
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
|
+
}
|
|
1347
1297
|
});
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1298
|
+
}
|
|
1299
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1300
|
+
from,
|
|
1301
|
+
to
|
|
1302
|
+
});
|
|
1303
|
+
if (cursor) {
|
|
1304
|
+
const id = options.onCreate?.({
|
|
1305
|
+
cursor,
|
|
1306
|
+
from,
|
|
1307
|
+
location: view.coordsAtPos(from)
|
|
1308
|
+
});
|
|
1309
|
+
if (id) {
|
|
1353
1310
|
view.dispatch({
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1357
1316
|
}
|
|
1358
1317
|
});
|
|
1318
|
+
return true;
|
|
1359
1319
|
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
if (id) {
|
|
1367
|
-
view.dispatch({
|
|
1368
|
-
effects: setSelection.of({
|
|
1369
|
-
current: id
|
|
1370
|
-
}),
|
|
1371
|
-
selection: {
|
|
1372
|
-
anchor: from
|
|
1373
|
-
}
|
|
1374
|
-
});
|
|
1375
|
-
return true;
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
return false;
|
|
1379
|
-
};
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1380
1326
|
return [
|
|
1327
|
+
optionsFacet.of(options),
|
|
1381
1328
|
commentsState,
|
|
1382
|
-
|
|
1383
|
-
|
|
1329
|
+
commentsDecorations,
|
|
1330
|
+
styles2,
|
|
1384
1331
|
//
|
|
1385
1332
|
// Keymap.
|
|
1386
1333
|
//
|
|
1387
1334
|
options.onCreate ? keymap3.of([
|
|
1388
1335
|
{
|
|
1389
1336
|
key: shortcut,
|
|
1390
|
-
run: callbackWrapper(
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1391
1338
|
}
|
|
1392
1339
|
]) : [],
|
|
1393
1340
|
//
|
|
@@ -1423,7 +1370,7 @@ var comments = (options = {}) => {
|
|
|
1423
1370
|
//
|
|
1424
1371
|
// Track deleted ranges and update ranges for decorations.
|
|
1425
1372
|
//
|
|
1426
|
-
|
|
1373
|
+
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1427
1374
|
let mod = false;
|
|
1428
1375
|
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1429
1376
|
changes.iterChanges((from, to, from2, to2) => {
|
|
@@ -1453,7 +1400,7 @@ var comments = (options = {}) => {
|
|
|
1453
1400
|
//
|
|
1454
1401
|
// Track selection/proximity.
|
|
1455
1402
|
//
|
|
1456
|
-
|
|
1403
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1457
1404
|
let min = Infinity;
|
|
1458
1405
|
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1459
1406
|
const { head } = state.selection.main;
|
|
@@ -1489,7 +1436,7 @@ var comments = (options = {}) => {
|
|
|
1489
1436
|
];
|
|
1490
1437
|
};
|
|
1491
1438
|
var useComments = (view, comments2 = []) => {
|
|
1492
|
-
|
|
1439
|
+
useEffect(() => {
|
|
1493
1440
|
if (view) {
|
|
1494
1441
|
view.dispatch({
|
|
1495
1442
|
effects: setComments.of(comments2)
|
|
@@ -1501,329 +1448,66 @@ var useComments = (view, comments2 = []) => {
|
|
|
1501
1448
|
]);
|
|
1502
1449
|
};
|
|
1503
1450
|
|
|
1504
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1505
|
-
import {
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
const el = document.createElement("div");
|
|
1517
|
-
el.className = "cm-hr";
|
|
1518
|
-
return el;
|
|
1519
|
-
}
|
|
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;
|
|
1520
1463
|
};
|
|
1521
|
-
|
|
1522
|
-
|
|
1464
|
+
|
|
1465
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1466
|
+
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1467
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1468
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1469
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1470
|
+
import { languages } from "@codemirror/language-data";
|
|
1471
|
+
import { searchKeymap } from "@codemirror/search";
|
|
1472
|
+
import { EditorState } from "@codemirror/state";
|
|
1473
|
+
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
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";
|
|
1476
|
+
|
|
1477
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1478
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1479
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
1480
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1481
|
+
import { Table } from "@lezer/markdown";
|
|
1482
|
+
var markdownTags = {
|
|
1483
|
+
Blockquote: Tag.define(),
|
|
1484
|
+
CodeMark: Tag.define(),
|
|
1485
|
+
CodeText: Tag.define(),
|
|
1486
|
+
EmphasisMark: Tag.define(),
|
|
1487
|
+
HeaderMark: Tag.define(),
|
|
1488
|
+
InlineCode: Tag.define(),
|
|
1489
|
+
LinkLabel: Tag.define(),
|
|
1490
|
+
LinkReference: Tag.define(),
|
|
1491
|
+
ListMark: Tag.define(),
|
|
1492
|
+
QuoteMark: Tag.define(),
|
|
1493
|
+
URL: Tag.define(),
|
|
1494
|
+
// Custom.
|
|
1495
|
+
TableCell: Tag.define()
|
|
1496
|
+
};
|
|
1497
|
+
Table.defineNodes?.forEach((node) => {
|
|
1498
|
+
switch (node?.name) {
|
|
1499
|
+
case "TableCell": {
|
|
1500
|
+
node.style = markdownTags.TableCell;
|
|
1501
|
+
break;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1523
1504
|
});
|
|
1524
|
-
var
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
enter: (node) => {
|
|
1531
|
-
if (node.name === "HorizontalRule") {
|
|
1532
|
-
if (cursor <= node.from || cursor >= node.to) {
|
|
1533
|
-
builder.add(node.from, node.to, decoration);
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
},
|
|
1537
|
-
from,
|
|
1538
|
-
to
|
|
1539
|
-
});
|
|
1540
|
-
}
|
|
1541
|
-
return builder.finish();
|
|
1542
|
-
};
|
|
1543
|
-
var hr = () => {
|
|
1544
|
-
return [
|
|
1545
|
-
styles4,
|
|
1546
|
-
ViewPlugin4.fromClass(class {
|
|
1547
|
-
constructor(view) {
|
|
1548
|
-
this.decorations = buildDecorations(view);
|
|
1549
|
-
}
|
|
1550
|
-
update(update2) {
|
|
1551
|
-
this.decorations = buildDecorations(update2.view);
|
|
1552
|
-
}
|
|
1553
|
-
}, {
|
|
1554
|
-
decorations: (v) => v.decorations
|
|
1555
|
-
})
|
|
1556
|
-
];
|
|
1557
|
-
};
|
|
1558
|
-
|
|
1559
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1560
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1561
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1562
|
-
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1563
|
-
var image = (options = {}) => {
|
|
1564
|
-
return StateField3.define({
|
|
1565
|
-
create: (state) => {
|
|
1566
|
-
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1567
|
-
},
|
|
1568
|
-
update: (value, tr) => {
|
|
1569
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1570
|
-
return value;
|
|
1571
|
-
}
|
|
1572
|
-
const cursor = tr.state.selection.main.head;
|
|
1573
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1574
|
-
let from = Math.min(cursor, oldCursor);
|
|
1575
|
-
let to = Math.max(cursor, oldCursor);
|
|
1576
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1577
|
-
from = Math.min(from, fromB);
|
|
1578
|
-
to = Math.max(to, toB);
|
|
1579
|
-
});
|
|
1580
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1581
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1582
|
-
return value.map(tr.changes).update({
|
|
1583
|
-
filterFrom: from,
|
|
1584
|
-
filterTo: to,
|
|
1585
|
-
filter: () => false,
|
|
1586
|
-
add: buildDecorations2(from, to, tr.state)
|
|
1587
|
-
});
|
|
1588
|
-
},
|
|
1589
|
-
provide: (field) => EditorView8.decorations.from(field)
|
|
1590
|
-
});
|
|
1591
|
-
};
|
|
1592
|
-
var buildDecorations2 = (from, to, state) => {
|
|
1593
|
-
const decorations = [];
|
|
1594
|
-
const cursor = state.selection.main.head;
|
|
1595
|
-
syntaxTree2(state).iterate({
|
|
1596
|
-
enter: (node) => {
|
|
1597
|
-
if (node.name === "Image") {
|
|
1598
|
-
const urlNode = node.node.getChild("URL");
|
|
1599
|
-
if (urlNode) {
|
|
1600
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1601
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1602
|
-
decorations.push(Decoration5.replace({
|
|
1603
|
-
block: true,
|
|
1604
|
-
widget: new ImageWidget(url)
|
|
1605
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
},
|
|
1609
|
-
from,
|
|
1610
|
-
to
|
|
1611
|
-
});
|
|
1612
|
-
return decorations;
|
|
1613
|
-
};
|
|
1614
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1615
|
-
constructor(_url) {
|
|
1616
|
-
super();
|
|
1617
|
-
this._url = _url;
|
|
1618
|
-
}
|
|
1619
|
-
eq(other) {
|
|
1620
|
-
return this._url === other._url;
|
|
1621
|
-
}
|
|
1622
|
-
toDOM(view) {
|
|
1623
|
-
const img = document.createElement("img");
|
|
1624
|
-
img.setAttribute("src", this._url);
|
|
1625
|
-
img.setAttribute("class", "cm-image");
|
|
1626
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1627
|
-
return img;
|
|
1628
|
-
}
|
|
1629
|
-
};
|
|
1630
|
-
|
|
1631
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1632
|
-
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1633
|
-
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1634
|
-
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1635
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1636
|
-
var link = (options = {}) => {
|
|
1637
|
-
const extensions = [
|
|
1638
|
-
ViewPlugin5.fromClass(class {
|
|
1639
|
-
constructor(view) {
|
|
1640
|
-
this.decorations = buildDecorations3(view, options);
|
|
1641
|
-
}
|
|
1642
|
-
update(update2) {
|
|
1643
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1644
|
-
this.decorations = buildDecorations3(update2.view, options);
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
}, {
|
|
1648
|
-
decorations: (v) => v.decorations
|
|
1649
|
-
})
|
|
1650
|
-
];
|
|
1651
|
-
if (options.onHover) {
|
|
1652
|
-
extensions.push(
|
|
1653
|
-
// https://codemirror.net/examples/tooltip
|
|
1654
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1655
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1656
|
-
hoverTooltip2((view, pos, side) => {
|
|
1657
|
-
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1658
|
-
let link2 = null;
|
|
1659
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1660
|
-
link2 = node.name === "Link" ? node : null;
|
|
1661
|
-
}
|
|
1662
|
-
const url = link2 && link2.getChild("URL");
|
|
1663
|
-
if (!url || !link2) {
|
|
1664
|
-
return null;
|
|
1665
|
-
}
|
|
1666
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1667
|
-
return {
|
|
1668
|
-
pos: link2.from,
|
|
1669
|
-
end: link2.to,
|
|
1670
|
-
above: true,
|
|
1671
|
-
create: () => {
|
|
1672
|
-
const el = document.createElement("div");
|
|
1673
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1674
|
-
options.onHover(el, urlText);
|
|
1675
|
-
return {
|
|
1676
|
-
dom: el,
|
|
1677
|
-
offset: {
|
|
1678
|
-
x: 0,
|
|
1679
|
-
y: 4
|
|
1680
|
-
}
|
|
1681
|
-
};
|
|
1682
|
-
}
|
|
1683
|
-
};
|
|
1684
|
-
})
|
|
1685
|
-
);
|
|
1686
|
-
}
|
|
1687
|
-
return extensions;
|
|
1688
|
-
};
|
|
1689
|
-
var LinkButton = class extends WidgetType4 {
|
|
1690
|
-
constructor(_url, _onAttach) {
|
|
1691
|
-
super();
|
|
1692
|
-
this._url = _url;
|
|
1693
|
-
this._onAttach = _onAttach;
|
|
1694
|
-
}
|
|
1695
|
-
eq(other) {
|
|
1696
|
-
return this._url === other._url;
|
|
1697
|
-
}
|
|
1698
|
-
toDOM(view) {
|
|
1699
|
-
const el = document.createElement("span");
|
|
1700
|
-
this._onAttach(el, this._url);
|
|
1701
|
-
return el;
|
|
1702
|
-
}
|
|
1703
|
-
};
|
|
1704
|
-
var LinkText = class extends WidgetType4 {
|
|
1705
|
-
constructor(_text, _url) {
|
|
1706
|
-
super();
|
|
1707
|
-
this._text = _text;
|
|
1708
|
-
this._url = _url;
|
|
1709
|
-
}
|
|
1710
|
-
eq(other) {
|
|
1711
|
-
return this._url === other._url;
|
|
1712
|
-
}
|
|
1713
|
-
toDOM(view) {
|
|
1714
|
-
const link2 = document.createElement("a");
|
|
1715
|
-
link2.setAttribute("class", "cm-link");
|
|
1716
|
-
link2.textContent = this._text;
|
|
1717
|
-
if (this._url) {
|
|
1718
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1719
|
-
link2.setAttribute("target", "_blank");
|
|
1720
|
-
link2.href = this._url;
|
|
1721
|
-
} else {
|
|
1722
|
-
link2.onclick = () => {
|
|
1723
|
-
view.dispatch({
|
|
1724
|
-
selection: {
|
|
1725
|
-
anchor: view.posAtDOM(link2)
|
|
1726
|
-
}
|
|
1727
|
-
});
|
|
1728
|
-
};
|
|
1729
|
-
}
|
|
1730
|
-
return link2;
|
|
1731
|
-
}
|
|
1732
|
-
};
|
|
1733
|
-
var buildDecorations3 = (view, options) => {
|
|
1734
|
-
const builder = new RangeSetBuilder2();
|
|
1735
|
-
const { state } = view;
|
|
1736
|
-
const cursor = state.selection.main.head;
|
|
1737
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1738
|
-
syntaxTree3(state).iterate({
|
|
1739
|
-
enter: (node) => {
|
|
1740
|
-
if (node.name === "Link") {
|
|
1741
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1742
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1743
|
-
const urlNode = node.node.getChild("URL");
|
|
1744
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1745
|
-
if (!url) {
|
|
1746
|
-
return false;
|
|
1747
|
-
}
|
|
1748
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1749
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1750
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1751
|
-
}));
|
|
1752
|
-
}
|
|
1753
|
-
if (options.onRender) {
|
|
1754
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1755
|
-
widget: new LinkButton(url, options.onRender)
|
|
1756
|
-
}));
|
|
1757
|
-
}
|
|
1758
|
-
return false;
|
|
1759
|
-
}
|
|
1760
|
-
},
|
|
1761
|
-
from,
|
|
1762
|
-
to
|
|
1763
|
-
});
|
|
1764
|
-
}
|
|
1765
|
-
return builder.finish();
|
|
1766
|
-
};
|
|
1767
|
-
|
|
1768
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1769
|
-
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1770
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1771
|
-
const extensions = [];
|
|
1772
|
-
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1773
|
-
onFocus(focused);
|
|
1774
|
-
return null;
|
|
1775
|
-
}));
|
|
1776
|
-
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1777
|
-
onChange(update2.state.doc.toString());
|
|
1778
|
-
}));
|
|
1779
|
-
return extensions;
|
|
1780
|
-
};
|
|
1781
|
-
|
|
1782
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1783
|
-
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1784
|
-
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1785
|
-
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1786
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1787
|
-
import { languages } from "@codemirror/language-data";
|
|
1788
|
-
import { searchKeymap } from "@codemirror/search";
|
|
1789
|
-
import { EditorState } from "@codemirror/state";
|
|
1790
|
-
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1791
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1792
|
-
|
|
1793
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1794
|
-
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1795
|
-
import { HighlightStyle } from "@codemirror/language";
|
|
1796
|
-
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1797
|
-
import { Table } from "@lezer/markdown";
|
|
1798
|
-
var markdownTags = {
|
|
1799
|
-
Blockquote: Tag.define(),
|
|
1800
|
-
CodeMark: Tag.define(),
|
|
1801
|
-
CodeText: Tag.define(),
|
|
1802
|
-
EmphasisMark: Tag.define(),
|
|
1803
|
-
HeaderMark: Tag.define(),
|
|
1804
|
-
InlineCode: Tag.define(),
|
|
1805
|
-
LinkLabel: Tag.define(),
|
|
1806
|
-
LinkReference: Tag.define(),
|
|
1807
|
-
ListMark: Tag.define(),
|
|
1808
|
-
QuoteMark: Tag.define(),
|
|
1809
|
-
URL: Tag.define(),
|
|
1810
|
-
// Custom.
|
|
1811
|
-
TableCell: Tag.define()
|
|
1812
|
-
};
|
|
1813
|
-
Table.defineNodes?.forEach((node) => {
|
|
1814
|
-
switch (node?.name) {
|
|
1815
|
-
case "TableCell": {
|
|
1816
|
-
node.style = markdownTags.TableCell;
|
|
1817
|
-
break;
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
});
|
|
1821
|
-
var markdownTagsExtensions = [
|
|
1822
|
-
Table,
|
|
1823
|
-
{
|
|
1824
|
-
props: [
|
|
1825
|
-
styleTags(markdownTags)
|
|
1826
|
-
]
|
|
1505
|
+
var markdownTagsExtensions = [
|
|
1506
|
+
Table,
|
|
1507
|
+
{
|
|
1508
|
+
props: [
|
|
1509
|
+
styleTags(markdownTags)
|
|
1510
|
+
]
|
|
1827
1511
|
}
|
|
1828
1512
|
];
|
|
1829
1513
|
var markdownHighlightStyle = (readonly) => {
|
|
@@ -1885,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1885
1569
|
markdownTags.QuoteMark,
|
|
1886
1570
|
markdownTags.EmphasisMark
|
|
1887
1571
|
],
|
|
1888
|
-
class:
|
|
1572
|
+
class: mark
|
|
1889
1573
|
},
|
|
1890
1574
|
// E.g., code block language (after ```).
|
|
1891
1575
|
{
|
|
@@ -1893,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1893
1577
|
tags.function(tags.variableName),
|
|
1894
1578
|
tags.labelName
|
|
1895
1579
|
],
|
|
1896
|
-
class:
|
|
1580
|
+
class: codeMark
|
|
1897
1581
|
},
|
|
1898
1582
|
{
|
|
1899
1583
|
tag: [
|
|
@@ -1904,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1904
1588
|
// Headings.
|
|
1905
1589
|
{
|
|
1906
1590
|
tag: tags.heading1,
|
|
1907
|
-
class: heading(1
|
|
1591
|
+
class: heading(1)
|
|
1908
1592
|
},
|
|
1909
1593
|
{
|
|
1910
1594
|
tag: tags.heading2,
|
|
1911
|
-
class: heading(2
|
|
1595
|
+
class: heading(2)
|
|
1912
1596
|
},
|
|
1913
1597
|
{
|
|
1914
1598
|
tag: tags.heading3,
|
|
1915
|
-
class: heading(3
|
|
1599
|
+
class: heading(3)
|
|
1916
1600
|
},
|
|
1917
1601
|
{
|
|
1918
1602
|
tag: tags.heading4,
|
|
1919
|
-
class: heading(4
|
|
1603
|
+
class: heading(4)
|
|
1920
1604
|
},
|
|
1921
1605
|
{
|
|
1922
1606
|
tag: tags.heading5,
|
|
1923
|
-
class: heading(5
|
|
1607
|
+
class: heading(5)
|
|
1924
1608
|
},
|
|
1925
1609
|
{
|
|
1926
1610
|
tag: tags.heading6,
|
|
1927
|
-
class: heading(6
|
|
1611
|
+
class: heading(6)
|
|
1928
1612
|
},
|
|
1929
1613
|
// Emphasis.
|
|
1930
1614
|
{
|
|
@@ -1950,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1950
1634
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1951
1635
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1952
1636
|
// the code, but all other CSS properties will be inherited.
|
|
1953
|
-
// 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.
|
|
1954
1638
|
{
|
|
1955
1639
|
tag: [
|
|
1956
1640
|
markdownTags.CodeText,
|
|
@@ -1979,11 +1663,11 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1979
1663
|
};
|
|
1980
1664
|
|
|
1981
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1982
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1983
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1984
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1985
1670
|
EditorState.tabSize.of(2),
|
|
1986
|
-
EditorView10.lineWrapping,
|
|
1987
1671
|
// https://github.com/codemirror/basic-setup
|
|
1988
1672
|
bracketMatching2(),
|
|
1989
1673
|
closeBrackets2(),
|
|
@@ -1993,7 +1677,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1993
1677
|
highlightActiveLine2(),
|
|
1994
1678
|
history2(),
|
|
1995
1679
|
indentOnInput(),
|
|
1996
|
-
_placeholder
|
|
1680
|
+
_placeholder && placeholder2(_placeholder),
|
|
1997
1681
|
// Main extension.
|
|
1998
1682
|
// https://github.com/codemirror/lang-markdown
|
|
1999
1683
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -2015,7 +1699,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
2015
1699
|
// https://github.com/codemirror/theme-one-dark
|
|
2016
1700
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
2017
1701
|
// Custom styles.
|
|
2018
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1702
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
2019
1703
|
keymap4.of([
|
|
2020
1704
|
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
2021
1705
|
indentWithTab,
|
|
@@ -2028,56 +1712,1519 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
2028
1712
|
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2029
1713
|
...standardKeymap
|
|
2030
1714
|
])
|
|
2031
|
-
];
|
|
1715
|
+
].filter(isNotFalsy2);
|
|
2032
1716
|
};
|
|
2033
1717
|
|
|
2034
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
2035
|
-
import {
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
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
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
from,
|
|
1812
|
+
to
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return builder.finish();
|
|
1816
|
+
};
|
|
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);
|
|
2058
2941
|
}
|
|
2059
|
-
|
|
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
|
|
2060
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
|
+
}
|
|
2061
3076
|
};
|
|
2062
3077
|
|
|
2063
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
2064
|
-
|
|
2065
|
-
|
|
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();
|
|
2066
3213
|
};
|
|
2067
3214
|
|
|
2068
|
-
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
2069
|
-
import { syntaxTree as
|
|
2070
|
-
import { RangeSetBuilder as
|
|
2071
|
-
import { Decoration as
|
|
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";
|
|
2072
3219
|
var table = (options = {}) => {
|
|
2073
3220
|
return StateField4.define({
|
|
2074
3221
|
create: (state) => update(state, options),
|
|
2075
3222
|
update: (_, tr) => update(tr.state, options),
|
|
2076
|
-
provide: (field) =>
|
|
3223
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
2077
3224
|
});
|
|
2078
3225
|
};
|
|
2079
3226
|
var update = (state, options) => {
|
|
2080
|
-
const builder = new
|
|
3227
|
+
const builder = new RangeSetBuilder6();
|
|
2081
3228
|
const cursor = state.selection.main.head;
|
|
2082
3229
|
const tables = [];
|
|
2083
3230
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2085,7 +3232,7 @@ var update = (state, options) => {
|
|
|
2085
3232
|
const table2 = getTable();
|
|
2086
3233
|
return table2.rows?.[table2.rows.length - 1];
|
|
2087
3234
|
};
|
|
2088
|
-
|
|
3235
|
+
syntaxTree7(state).iterate({
|
|
2089
3236
|
enter: (node) => {
|
|
2090
3237
|
switch (node.name) {
|
|
2091
3238
|
case "Table": {
|
|
@@ -2117,16 +3264,16 @@ var update = (state, options) => {
|
|
|
2117
3264
|
});
|
|
2118
3265
|
tables.forEach((table2) => {
|
|
2119
3266
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2120
|
-
hide && builder.add(table2.from, table2.to,
|
|
3267
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2121
3268
|
widget: new TableWidget(table2)
|
|
2122
3269
|
}));
|
|
2123
|
-
builder.add(table2.from, table2.to,
|
|
3270
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2124
3271
|
class: "cm-table"
|
|
2125
3272
|
}));
|
|
2126
3273
|
});
|
|
2127
3274
|
return builder.finish();
|
|
2128
3275
|
};
|
|
2129
|
-
var TableWidget = class extends
|
|
3276
|
+
var TableWidget = class extends WidgetType6 {
|
|
2130
3277
|
constructor(_table) {
|
|
2131
3278
|
super();
|
|
2132
3279
|
this._table = _table;
|
|
@@ -2163,11 +3310,11 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2163
3310
|
}
|
|
2164
3311
|
};
|
|
2165
3312
|
|
|
2166
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2167
|
-
import { syntaxTree as
|
|
2168
|
-
import { RangeSetBuilder as
|
|
2169
|
-
import { EditorView as
|
|
2170
|
-
var styles5 =
|
|
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({
|
|
2171
3318
|
"& .cm-task": {
|
|
2172
3319
|
color: getToken("extend.colors.blue.500")
|
|
2173
3320
|
},
|
|
@@ -2176,7 +3323,7 @@ var styles5 = EditorView12.baseTheme({
|
|
|
2176
3323
|
marginRight: "4px"
|
|
2177
3324
|
}
|
|
2178
3325
|
});
|
|
2179
|
-
var CheckboxWidget = class extends
|
|
3326
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2180
3327
|
constructor(_checked) {
|
|
2181
3328
|
super();
|
|
2182
3329
|
this._checked = _checked;
|
|
@@ -2213,23 +3360,23 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2213
3360
|
return false;
|
|
2214
3361
|
}
|
|
2215
3362
|
};
|
|
2216
|
-
var checkedDecoration =
|
|
3363
|
+
var checkedDecoration = Decoration10.replace({
|
|
2217
3364
|
widget: new CheckboxWidget(true)
|
|
2218
3365
|
});
|
|
2219
|
-
var uncheckedDecoration =
|
|
3366
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2220
3367
|
widget: new CheckboxWidget(false)
|
|
2221
3368
|
});
|
|
2222
|
-
var
|
|
2223
|
-
const builder = new
|
|
3369
|
+
var buildDecorations6 = (view) => {
|
|
3370
|
+
const builder = new RangeSetBuilder7();
|
|
2224
3371
|
const { state } = view;
|
|
2225
3372
|
const cursor = state.selection.main.head;
|
|
2226
3373
|
for (const { from, to } of view.visibleRanges) {
|
|
2227
|
-
|
|
3374
|
+
syntaxTree8(state).iterate({
|
|
2228
3375
|
enter: (node) => {
|
|
2229
3376
|
if (node.name === "TaskMarker") {
|
|
2230
3377
|
if (cursor < node.from || cursor > node.to) {
|
|
2231
3378
|
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2232
|
-
builder.add(node.from - 2, node.from - 1,
|
|
3379
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2233
3380
|
class: "cm-task"
|
|
2234
3381
|
}));
|
|
2235
3382
|
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
@@ -2244,24 +3391,58 @@ var buildDecorations4 = (view) => {
|
|
|
2244
3391
|
};
|
|
2245
3392
|
var tasklist = (options = {}) => {
|
|
2246
3393
|
return [
|
|
2247
|
-
|
|
3394
|
+
ViewPlugin8.fromClass(class {
|
|
2248
3395
|
constructor(view) {
|
|
2249
|
-
this.decorations =
|
|
3396
|
+
this.decorations = buildDecorations6(view);
|
|
2250
3397
|
}
|
|
2251
3398
|
update(update2) {
|
|
2252
3399
|
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2253
|
-
this.decorations =
|
|
3400
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2254
3401
|
}
|
|
2255
3402
|
}
|
|
2256
3403
|
}, {
|
|
2257
|
-
decorations: (
|
|
3404
|
+
decorations: (value) => value.decorations
|
|
2258
3405
|
}),
|
|
2259
3406
|
styles5
|
|
2260
3407
|
];
|
|
2261
3408
|
};
|
|
2262
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
|
+
};
|
|
3443
|
+
|
|
2263
3444
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2264
|
-
import { keymap as
|
|
3445
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2265
3446
|
var defaultItems = [
|
|
2266
3447
|
"hello world!",
|
|
2267
3448
|
"this is a test.",
|
|
@@ -2271,7 +3452,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2271
3452
|
let t;
|
|
2272
3453
|
let idx = 0;
|
|
2273
3454
|
return [
|
|
2274
|
-
|
|
3455
|
+
keymap6.of([
|
|
2275
3456
|
{
|
|
2276
3457
|
// Reset.
|
|
2277
3458
|
key: "alt-meta-'",
|
|
@@ -2317,27 +3498,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2317
3498
|
];
|
|
2318
3499
|
};
|
|
2319
3500
|
|
|
2320
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2321
|
-
import { yCollab } from "y-codemirror.next";
|
|
2322
|
-
|
|
2323
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2324
|
-
import * as Y from "yjs";
|
|
2325
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2326
|
-
var cursorConverter2 = (text) => ({
|
|
2327
|
-
toCursor: (index, assoc) => {
|
|
2328
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2329
|
-
},
|
|
2330
|
-
fromCursor: (cursor) => {
|
|
2331
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2332
|
-
}
|
|
2333
|
-
});
|
|
2334
|
-
|
|
2335
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2336
|
-
var yjs = (content, awareness2) => [
|
|
2337
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2338
|
-
yCollab(content, awareness2)
|
|
2339
|
-
];
|
|
2340
|
-
|
|
2341
3501
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2342
3502
|
import get3 from "lodash.get";
|
|
2343
3503
|
var defaultTheme = {
|
|
@@ -2369,8 +3529,9 @@ var defaultTheme = {
|
|
|
2369
3529
|
outline: "none"
|
|
2370
3530
|
},
|
|
2371
3531
|
".cm-scroller": {
|
|
2372
|
-
overflow:
|
|
2373
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3532
|
+
// overflow: 'visible',
|
|
3533
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3534
|
+
lineHeight: 1.4
|
|
2374
3535
|
},
|
|
2375
3536
|
".cm-content": {
|
|
2376
3537
|
padding: 0,
|
|
@@ -2378,11 +3539,11 @@ var defaultTheme = {
|
|
|
2378
3539
|
fontSize: "16px"
|
|
2379
3540
|
},
|
|
2380
3541
|
"&light .cm-content": {
|
|
2381
|
-
color: get3(tokens, "extend.
|
|
3542
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2382
3543
|
caretColor: "black"
|
|
2383
3544
|
},
|
|
2384
3545
|
"&dark .cm-content": {
|
|
2385
|
-
color: get3(tokens, "extend.
|
|
3546
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2386
3547
|
caretColor: "white"
|
|
2387
3548
|
},
|
|
2388
3549
|
//
|
|
@@ -2394,8 +3555,11 @@ var defaultTheme = {
|
|
|
2394
3555
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2395
3556
|
borderLeft: "2px solid white"
|
|
2396
3557
|
},
|
|
2397
|
-
".cm-placeholder": {
|
|
2398
|
-
|
|
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)")
|
|
2399
3563
|
},
|
|
2400
3564
|
//
|
|
2401
3565
|
// line
|
|
@@ -2404,7 +3568,7 @@ var defaultTheme = {
|
|
|
2404
3568
|
paddingInline: 0
|
|
2405
3569
|
},
|
|
2406
3570
|
".cm-activeLine": {
|
|
2407
|
-
background: "
|
|
3571
|
+
background: "transparent"
|
|
2408
3572
|
},
|
|
2409
3573
|
//
|
|
2410
3574
|
// Selection
|
|
@@ -2575,31 +3739,35 @@ var codeTheme = {
|
|
|
2575
3739
|
};
|
|
2576
3740
|
|
|
2577
3741
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2578
|
-
var
|
|
3742
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2579
3743
|
var EditorModes = [
|
|
2580
3744
|
"default",
|
|
2581
3745
|
"vim"
|
|
2582
3746
|
];
|
|
2583
3747
|
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2584
|
-
const
|
|
2585
|
-
tabBehavior: "limited"
|
|
2586
|
-
});
|
|
2587
|
-
const { themeMode } = useThemeContext2();
|
|
3748
|
+
const { themeMode } = useThemeContext();
|
|
2588
3749
|
const rootRef = useRef(null);
|
|
2589
|
-
const [view, setView] =
|
|
3750
|
+
const [view, setView] = useState2(null);
|
|
2590
3751
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2591
3752
|
view
|
|
2592
3753
|
]);
|
|
2593
|
-
|
|
2594
|
-
if (autoFocus) {
|
|
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
|
+
}
|
|
2595
3764
|
view?.focus();
|
|
2596
3765
|
}
|
|
2597
3766
|
}, [
|
|
2598
3767
|
view,
|
|
2599
3768
|
autoFocus
|
|
2600
3769
|
]);
|
|
2601
|
-
|
|
2602
|
-
useEffect3(() => {
|
|
3770
|
+
useEffect2(() => {
|
|
2603
3771
|
if (!model || !rootRef.current) {
|
|
2604
3772
|
return;
|
|
2605
3773
|
}
|
|
@@ -2608,37 +3776,38 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2608
3776
|
selection,
|
|
2609
3777
|
extensions: [
|
|
2610
3778
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2611
|
-
|
|
3779
|
+
EditorView14.exceptionSink.of((err) => {
|
|
2612
3780
|
log2.catch(err, void 0, {
|
|
2613
|
-
F:
|
|
2614
|
-
L:
|
|
3781
|
+
F: __dxlog_file3,
|
|
3782
|
+
L: 134,
|
|
2615
3783
|
S: void 0,
|
|
2616
3784
|
C: (f, a) => f(...a)
|
|
2617
3785
|
});
|
|
2618
3786
|
}),
|
|
2619
3787
|
// Theme.
|
|
2620
3788
|
// TODO(burdon): Make configurable.
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
3789
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3790
|
+
EditorView14.theme(theme ?? {}),
|
|
3791
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3792
|
+
EditorView14.editorAttributes.of({
|
|
2625
3793
|
class: slots.editor?.className ?? ""
|
|
2626
3794
|
}),
|
|
2627
|
-
|
|
3795
|
+
EditorView14.contentAttributes.of({
|
|
2628
3796
|
class: slots.content?.className ?? ""
|
|
2629
3797
|
}),
|
|
2630
3798
|
// State.
|
|
3799
|
+
EditorView14.editable.of(!readonly),
|
|
2631
3800
|
EditorState2.readOnly.of(!!readonly),
|
|
2632
3801
|
// Storage and replication.
|
|
2633
3802
|
// NOTE: This must come before user extensions.
|
|
2634
3803
|
model.extension,
|
|
2635
|
-
// TODO(burdon): Factor out (
|
|
3804
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2636
3805
|
editorMode === "vim" && vim(),
|
|
2637
3806
|
// Custom.
|
|
2638
3807
|
...extensions
|
|
2639
|
-
].filter(
|
|
3808
|
+
].filter(isNotFalsy3)
|
|
2640
3809
|
});
|
|
2641
|
-
const newView = new
|
|
3810
|
+
const newView = new EditorView14({
|
|
2642
3811
|
state,
|
|
2643
3812
|
parent: rootRef.current,
|
|
2644
3813
|
scrollTo,
|
|
@@ -2673,7 +3842,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2673
3842
|
}
|
|
2674
3843
|
case "Escape": {
|
|
2675
3844
|
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2676
|
-
|
|
3845
|
+
view?.focus();
|
|
2677
3846
|
}
|
|
2678
3847
|
break;
|
|
2679
3848
|
}
|
|
@@ -2686,20 +3855,20 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2686
3855
|
key: model.id,
|
|
2687
3856
|
role: "none",
|
|
2688
3857
|
tabIndex: 0,
|
|
2689
|
-
onKeyUp: handleKeyUp,
|
|
2690
3858
|
...slots.root,
|
|
2691
|
-
...editorMode !==
|
|
3859
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3860
|
+
onKeyUp: handleKeyUp,
|
|
2692
3861
|
ref: rootRef
|
|
2693
3862
|
});
|
|
2694
3863
|
});
|
|
2695
3864
|
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2696
|
-
const { themeMode } =
|
|
3865
|
+
const { themeMode } = useThemeContext();
|
|
2697
3866
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2698
3867
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2699
3868
|
ref: forwardedRef,
|
|
2700
3869
|
readonly,
|
|
2701
3870
|
extensions: [
|
|
2702
|
-
|
|
3871
|
+
createBasicBundle({
|
|
2703
3872
|
themeMode,
|
|
2704
3873
|
placeholder: placeholder3,
|
|
2705
3874
|
lineWrapping
|
|
@@ -2712,15 +3881,14 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2712
3881
|
});
|
|
2713
3882
|
});
|
|
2714
3883
|
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2715
|
-
const { themeMode } =
|
|
3884
|
+
const { themeMode } = useThemeContext();
|
|
2716
3885
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2717
3886
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2718
3887
|
ref: forwardedRef,
|
|
2719
3888
|
readonly,
|
|
2720
3889
|
extensions: [
|
|
2721
|
-
|
|
3890
|
+
createMarkdownExtensions({
|
|
2722
3891
|
themeMode,
|
|
2723
|
-
readonly,
|
|
2724
3892
|
placeholder: placeholder3
|
|
2725
3893
|
}),
|
|
2726
3894
|
...extensions
|
|
@@ -2732,11 +3900,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2732
3900
|
});
|
|
2733
3901
|
var defaultSlots = {
|
|
2734
3902
|
root: {
|
|
2735
|
-
|
|
2736
|
-
className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
|
|
3903
|
+
className: mx3("grow", focusRing)
|
|
2737
3904
|
},
|
|
2738
3905
|
editor: {
|
|
2739
|
-
className: "
|
|
3906
|
+
className: "bs-full"
|
|
2740
3907
|
}
|
|
2741
3908
|
};
|
|
2742
3909
|
var defaultTextSlots = {
|
|
@@ -2746,22 +3913,205 @@ var defaultMarkdownSlots = {
|
|
|
2746
3913
|
...defaultSlots
|
|
2747
3914
|
};
|
|
2748
3915
|
|
|
2749
|
-
// packages/ui/react-ui-editor/src/
|
|
2750
|
-
import
|
|
2751
|
-
import {
|
|
2752
|
-
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
|
+
};
|
|
2753
4103
|
|
|
2754
4104
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2755
4105
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2756
4106
|
import { Context as Context2 } from "@dxos/context";
|
|
2757
|
-
import { invariant as
|
|
4107
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2758
4108
|
import { log as log3 } from "@dxos/log";
|
|
2759
|
-
var
|
|
4109
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2760
4110
|
var DEBOUNCE_INTERVAL = 100;
|
|
2761
4111
|
var SpaceAwarenessProvider = class {
|
|
2762
4112
|
constructor(params) {
|
|
2763
|
-
this.remoteStateChange = new Event2();
|
|
2764
4113
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
4114
|
+
this.remoteStateChange = new Event2();
|
|
2765
4115
|
this._space = params.space;
|
|
2766
4116
|
this._channel = params.channel;
|
|
2767
4117
|
this._peerId = params.peerId;
|
|
@@ -2778,7 +4128,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2778
4128
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2779
4129
|
}
|
|
2780
4130
|
});
|
|
2781
|
-
|
|
4131
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2782
4132
|
switch (message.payload.kind) {
|
|
2783
4133
|
case "query": {
|
|
2784
4134
|
this._handleQueryMessage();
|
|
@@ -2789,16 +4139,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2789
4139
|
break;
|
|
2790
4140
|
}
|
|
2791
4141
|
}
|
|
2792
|
-
});
|
|
2793
|
-
this._ctx.onDispose(unsubscribe);
|
|
4142
|
+
}));
|
|
2794
4143
|
void this._space.postMessage(this._channel, {
|
|
2795
4144
|
kind: "query"
|
|
2796
4145
|
}).catch((err) => {
|
|
2797
4146
|
log3.debug("failed to query awareness", {
|
|
2798
4147
|
err
|
|
2799
4148
|
}, {
|
|
2800
|
-
F:
|
|
2801
|
-
L:
|
|
4149
|
+
F: __dxlog_file4,
|
|
4150
|
+
L: 89,
|
|
2802
4151
|
S: this,
|
|
2803
4152
|
C: (f, a) => f(...a)
|
|
2804
4153
|
});
|
|
@@ -2809,10 +4158,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2809
4158
|
this._ctx = void 0;
|
|
2810
4159
|
this._postTask = void 0;
|
|
2811
4160
|
}
|
|
4161
|
+
getRemoteStates() {
|
|
4162
|
+
return Array.from(this._remoteStates.values());
|
|
4163
|
+
}
|
|
2812
4164
|
update(position) {
|
|
2813
|
-
|
|
2814
|
-
F:
|
|
2815
|
-
L:
|
|
4165
|
+
invariant2(this._postTask, void 0, {
|
|
4166
|
+
F: __dxlog_file4,
|
|
4167
|
+
L: 104,
|
|
2816
4168
|
S: this,
|
|
2817
4169
|
A: [
|
|
2818
4170
|
"this._postTask",
|
|
@@ -2826,13 +4178,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2826
4178
|
};
|
|
2827
4179
|
this._postTask.schedule();
|
|
2828
4180
|
}
|
|
2829
|
-
getRemoteStates() {
|
|
2830
|
-
return Array.from(this._remoteStates.values());
|
|
2831
|
-
}
|
|
2832
4181
|
_handleQueryMessage() {
|
|
2833
|
-
|
|
2834
|
-
F:
|
|
2835
|
-
L:
|
|
4182
|
+
invariant2(this._postTask, void 0, {
|
|
4183
|
+
F: __dxlog_file4,
|
|
4184
|
+
L: 115,
|
|
2836
4185
|
S: this,
|
|
2837
4186
|
A: [
|
|
2838
4187
|
"this._postTask",
|
|
@@ -2842,9 +4191,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2842
4191
|
this._postTask.schedule();
|
|
2843
4192
|
}
|
|
2844
4193
|
_handlePostMessage(message) {
|
|
2845
|
-
|
|
2846
|
-
F:
|
|
2847
|
-
L:
|
|
4194
|
+
invariant2(message.kind === "post", void 0, {
|
|
4195
|
+
F: __dxlog_file4,
|
|
4196
|
+
L: 120,
|
|
2848
4197
|
S: this,
|
|
2849
4198
|
A: [
|
|
2850
4199
|
"message.kind === 'post'",
|
|
@@ -2863,180 +4212,58 @@ var modelState = StateField5.define({
|
|
|
2863
4212
|
update: (model) => model
|
|
2864
4213
|
});
|
|
2865
4214
|
|
|
2866
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2867
|
-
var
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
displayName: identity?.profile?.displayName ?? "",
|
|
2877
|
-
color: cursorColor.color,
|
|
2878
|
-
lightColor: cursorColor.light
|
|
2879
|
-
},
|
|
2880
|
-
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2881
|
-
});
|
|
2882
|
-
const model = {
|
|
2883
|
-
id: obj.id,
|
|
2884
|
-
content: doc,
|
|
2885
|
-
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2886
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2887
|
-
extension: [
|
|
2888
|
-
modelState.init(() => model),
|
|
2889
|
-
automerge3({
|
|
2890
|
-
handle: doc.handle,
|
|
2891
|
-
path: doc.path
|
|
2892
|
-
}),
|
|
2893
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2894
|
-
awareness()
|
|
2895
|
-
].filter(isNotNullOrUndefined),
|
|
2896
|
-
peer: identity ? {
|
|
2897
|
-
id: identity.identityKey.toHex(),
|
|
2898
|
-
name: identity.profile?.displayName
|
|
2899
|
-
} : void 0
|
|
2900
|
-
};
|
|
2901
|
-
return model;
|
|
2902
|
-
};
|
|
2903
|
-
|
|
2904
|
-
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2905
|
-
import * as decoding from "lib0/decoding";
|
|
2906
|
-
import * as encoding from "lib0/encoding";
|
|
2907
|
-
import { Observable } from "lib0/observable";
|
|
2908
|
-
import * as YP from "y-protocols/awareness";
|
|
2909
|
-
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2910
|
-
import { log as log4 } from "@dxos/log";
|
|
2911
|
-
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2912
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2913
|
-
invariant5(text?.doc && text?.content, void 0, {
|
|
2914
|
-
F: __dxlog_file7,
|
|
2915
|
-
L: 22,
|
|
2916
|
-
S: void 0,
|
|
2917
|
-
A: [
|
|
2918
|
-
"text?.doc && text?.content",
|
|
2919
|
-
""
|
|
2920
|
-
]
|
|
2921
|
-
});
|
|
2922
|
-
const provider = space ? new YAwarenessProvider({
|
|
2923
|
-
space,
|
|
2924
|
-
doc: text.doc,
|
|
2925
|
-
channel: `yjs.awareness.${text.id}`
|
|
2926
|
-
}) : void 0;
|
|
2927
|
-
const model = {
|
|
2928
|
-
id: text.doc.guid,
|
|
2929
|
-
content: text.content,
|
|
2930
|
-
text: () => text.content.toString(),
|
|
2931
|
-
extension: [
|
|
2932
|
-
modelState.init(() => model),
|
|
2933
|
-
yjs(text.content, provider?.awareness)
|
|
2934
|
-
],
|
|
2935
|
-
awareness: provider?.awareness,
|
|
2936
|
-
peer: identity ? {
|
|
2937
|
-
id: identity.identityKey.toHex(),
|
|
2938
|
-
name: identity.profile?.displayName
|
|
2939
|
-
} : void 0
|
|
2940
|
-
};
|
|
2941
|
-
return model;
|
|
2942
|
-
};
|
|
2943
|
-
var messageAwareness = 1;
|
|
2944
|
-
var messageQueryAwareness = 3;
|
|
2945
|
-
var YAwarenessProvider = class extends Observable {
|
|
2946
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2947
|
-
super();
|
|
2948
|
-
this._space = space;
|
|
2949
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2950
|
-
this._channel = channel;
|
|
2951
|
-
this._clientId = doc.clientID;
|
|
2952
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2953
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2954
|
-
if (typeof window !== "undefined") {
|
|
2955
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2956
|
-
} else if (typeof process !== "undefined") {
|
|
2957
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2958
|
-
}
|
|
2959
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2960
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2961
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2962
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2963
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2964
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2965
|
-
this._clientId
|
|
2966
|
-
]));
|
|
2967
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2968
|
-
}
|
|
2969
|
-
get awareness() {
|
|
2970
|
-
return this._awareness;
|
|
2971
|
-
}
|
|
2972
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2973
|
-
log4("awareness update", {
|
|
2974
|
-
added,
|
|
2975
|
-
updated,
|
|
2976
|
-
removed,
|
|
2977
|
-
origin
|
|
2978
|
-
}, {
|
|
2979
|
-
F: __dxlog_file7,
|
|
2980
|
-
L: 101,
|
|
2981
|
-
S: this,
|
|
2982
|
-
C: (f, a) => f(...a)
|
|
2983
|
-
});
|
|
2984
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2985
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2986
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2987
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2988
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2989
|
-
}
|
|
2990
|
-
_handleSpaceMessage({ payload }) {
|
|
2991
|
-
log4("space message", payload, {
|
|
2992
|
-
F: __dxlog_file7,
|
|
2993
|
-
L: 110,
|
|
2994
|
-
S: this,
|
|
2995
|
-
C: (f, a) => f(...a)
|
|
2996
|
-
});
|
|
2997
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2998
|
-
const encoder = this._readMessage(data);
|
|
2999
|
-
if (encoder) {
|
|
3000
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
_readMessage(message) {
|
|
3004
|
-
const decoder = decoding.createDecoder(message);
|
|
3005
|
-
const encoder = encoding.createEncoder();
|
|
3006
|
-
const messageType = decoding.readVarUint(decoder);
|
|
3007
|
-
let sendReply = false;
|
|
3008
|
-
switch (messageType) {
|
|
3009
|
-
case messageAwareness: {
|
|
3010
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
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);
|
|
3011
4225
|
break;
|
|
3012
|
-
|
|
3013
|
-
case
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
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);
|
|
3017
4253
|
break;
|
|
3018
|
-
}
|
|
3019
|
-
default: {
|
|
3020
|
-
console.error("Invalid message:", messageType);
|
|
3021
|
-
return encoder;
|
|
3022
|
-
}
|
|
3023
|
-
}
|
|
3024
|
-
if (!sendReply) {
|
|
3025
|
-
return null;
|
|
3026
4254
|
}
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
}
|
|
4255
|
+
setTimeout(() => {
|
|
4256
|
+
if (!view.hasFocus) {
|
|
4257
|
+
view.focus();
|
|
4258
|
+
}
|
|
4259
|
+
});
|
|
4260
|
+
};
|
|
3034
4261
|
};
|
|
3035
4262
|
|
|
3036
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
3037
|
-
import { useState as
|
|
3038
|
-
var
|
|
3039
|
-
const [view, setView] =
|
|
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);
|
|
3040
4267
|
return [
|
|
3041
4268
|
(ref) => {
|
|
3042
4269
|
setView(ref);
|
|
@@ -3045,12 +4272,124 @@ var useTextEditor = () => {
|
|
|
3045
4272
|
];
|
|
3046
4273
|
};
|
|
3047
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);
|
|
4332
|
+
}
|
|
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
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
if (autoFocus) {
|
|
4346
|
+
view.focus();
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
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);
|
|
4380
|
+
};
|
|
4381
|
+
|
|
3048
4382
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
3049
|
-
import
|
|
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";
|
|
3050
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";
|
|
3051
4390
|
var useTextModel = (props) => {
|
|
3052
4391
|
const { identity, space, text } = props;
|
|
3053
|
-
const [model, setModel] =
|
|
4392
|
+
const [model, setModel] = useState5();
|
|
3054
4393
|
useEffect4(() => setModel(createModel(props)), [
|
|
3055
4394
|
identity,
|
|
3056
4395
|
space,
|
|
@@ -3058,53 +4397,114 @@ var useTextModel = (props) => {
|
|
|
3058
4397
|
]);
|
|
3059
4398
|
return model;
|
|
3060
4399
|
};
|
|
3061
|
-
var
|
|
3062
|
-
const
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
4400
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4401
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4402
|
+
return {
|
|
4403
|
+
id,
|
|
4404
|
+
content,
|
|
4405
|
+
setContent,
|
|
4406
|
+
text: () => content
|
|
4407
|
+
};
|
|
4408
|
+
};
|
|
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
|
+
});
|
|
4419
|
+
const obj = text;
|
|
4420
|
+
const doc = getRawDoc(obj, [
|
|
4421
|
+
obj.field
|
|
4422
|
+
]);
|
|
4423
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
4424
|
+
space,
|
|
4425
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
4426
|
+
info: {
|
|
4427
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
4428
|
+
color: cursorColor.color,
|
|
4429
|
+
lightColor: cursorColor.light
|
|
4430
|
+
},
|
|
4431
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
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));
|
|
3069
4443
|
}
|
|
4444
|
+
const model = {
|
|
4445
|
+
id: obj.id,
|
|
4446
|
+
content: doc,
|
|
4447
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
4448
|
+
extension: extensions,
|
|
4449
|
+
peer: identity ? {
|
|
4450
|
+
id: identity.identityKey.toHex(),
|
|
4451
|
+
name: identity.profile?.displayName
|
|
4452
|
+
} : void 0
|
|
4453
|
+
};
|
|
4454
|
+
return model;
|
|
3070
4455
|
};
|
|
3071
4456
|
export {
|
|
3072
|
-
AwarenessProvider,
|
|
3073
4457
|
BaseTextEditor,
|
|
3074
4458
|
Cursor,
|
|
3075
4459
|
Doc,
|
|
3076
4460
|
EditorModes,
|
|
4461
|
+
Inline,
|
|
4462
|
+
List,
|
|
3077
4463
|
MarkdownEditor,
|
|
3078
4464
|
RemoteSelectionsDecorator,
|
|
3079
4465
|
SpaceAwarenessProvider,
|
|
3080
4466
|
TextEditor,
|
|
3081
4467
|
TextKind,
|
|
3082
|
-
|
|
4468
|
+
Toolbar,
|
|
3083
4469
|
YText,
|
|
3084
4470
|
YXmlFragment,
|
|
4471
|
+
addBlockquote,
|
|
4472
|
+
addCodeblock,
|
|
4473
|
+
addLink,
|
|
4474
|
+
addList,
|
|
4475
|
+
addStyle,
|
|
3085
4476
|
autocomplete,
|
|
3086
|
-
|
|
4477
|
+
automerge,
|
|
3087
4478
|
awareness,
|
|
3088
|
-
|
|
4479
|
+
awarenessProvider,
|
|
3089
4480
|
blast,
|
|
3090
4481
|
callbackWrapper,
|
|
3091
4482
|
code2 as code,
|
|
3092
4483
|
codeTheme,
|
|
3093
4484
|
comments,
|
|
3094
|
-
|
|
3095
|
-
|
|
4485
|
+
compareFormatting,
|
|
4486
|
+
createBasicBundle,
|
|
4487
|
+
createComment,
|
|
4488
|
+
createDataExtensions,
|
|
4489
|
+
createMarkdownExtensions,
|
|
4490
|
+
createThemeExtensions,
|
|
3096
4491
|
defaultMarkdownSlots,
|
|
3097
4492
|
defaultOptions,
|
|
3098
4493
|
defaultSlots,
|
|
3099
4494
|
defaultTextSlots,
|
|
3100
4495
|
defaultTheme,
|
|
4496
|
+
focusComment,
|
|
4497
|
+
formatting,
|
|
4498
|
+
getFormatting,
|
|
3101
4499
|
getToken,
|
|
4500
|
+
heading2 as heading,
|
|
3102
4501
|
hr,
|
|
3103
4502
|
image,
|
|
4503
|
+
insertTable,
|
|
4504
|
+
keymap7 as keymap,
|
|
3104
4505
|
link,
|
|
3105
4506
|
listener,
|
|
3106
4507
|
logChanges,
|
|
3107
|
-
markdownBundle,
|
|
3108
4508
|
markdownHighlightStyle,
|
|
3109
4509
|
markdownTags,
|
|
3110
4510
|
markdownTagsExtensions,
|
|
@@ -3112,18 +4512,36 @@ export {
|
|
|
3112
4512
|
mention,
|
|
3113
4513
|
modelState,
|
|
3114
4514
|
outliner,
|
|
4515
|
+
removeBlockquote,
|
|
4516
|
+
removeCodeblock,
|
|
4517
|
+
removeLink,
|
|
4518
|
+
removeList,
|
|
4519
|
+
removeStyle,
|
|
4520
|
+
setBlockquote,
|
|
3115
4521
|
setComments,
|
|
3116
|
-
|
|
4522
|
+
setHeading,
|
|
3117
4523
|
setSelection,
|
|
4524
|
+
setStyle,
|
|
3118
4525
|
table,
|
|
3119
4526
|
tags2 as tags,
|
|
3120
4527
|
tasklist,
|
|
3121
4528
|
textTheme,
|
|
4529
|
+
toggleBlockquote,
|
|
4530
|
+
toggleCodeblock,
|
|
4531
|
+
toggleEmphasis,
|
|
4532
|
+
toggleInlineCode,
|
|
4533
|
+
toggleList,
|
|
4534
|
+
toggleStrikethrough,
|
|
4535
|
+
toggleStrong,
|
|
4536
|
+
toggleStyle,
|
|
3122
4537
|
typewriter,
|
|
3123
|
-
|
|
4538
|
+
useActionHandler,
|
|
3124
4539
|
useComments,
|
|
4540
|
+
useEditorView,
|
|
4541
|
+
useFormattingState,
|
|
4542
|
+
useInMemoryTextModel,
|
|
3125
4543
|
useTextEditor,
|
|
3126
4544
|
useTextModel,
|
|
3127
|
-
|
|
4545
|
+
useToolbarContext
|
|
3128
4546
|
};
|
|
3129
4547
|
//# sourceMappingURL=index.mjs.map
|