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