@dxos/react-ui-editor 0.3.11-main.74d6c88 → 0.3.11-main.764a9c1
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 +2720 -1106
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -15
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +14 -6
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/{yjs.stories.d.ts → hooks.stories.d.ts} +13 -2
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +29 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/index.d.ts +0 -1
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +8 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +40 -19
- 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.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 +48 -38
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +75 -84
- package/src/components/TextEditor/TextEditor.tsx +111 -75
- package/src/components/TextEditor/automerge.stories.tsx +1 -2
- package/src/components/TextEditor/hooks.stories.tsx +111 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +102 -0
- package/src/components/Toolbar/Toolbar.tsx +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 +54 -45
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +13 -34
- package/src/extensions/automerge/index.ts +0 -1
- package/src/extensions/automerge/semaphore.ts +33 -32
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +22 -18
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +328 -167
- 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/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +93 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +66 -56
- package/src/index.ts +1 -1
- package/src/styles/markdown.ts +9 -10
- package/src/themes/default.ts +11 -16
- 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.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 -315
- 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/tasklist.ts +0 -119
- 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/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
- /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
- /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
3
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
4
5
|
|
|
5
6
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
7
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
8
|
|
|
8
9
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
10
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
11
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle,
|
|
15
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
18
19
|
|
|
19
20
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
21
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
@@ -29,9 +30,11 @@ var autocomplete = ({ onSearch }) => {
|
|
|
29
30
|
// https://codemirror.net/examples/autocompletion
|
|
30
31
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
31
32
|
autocompletion({
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
33
|
+
activateOnTyping: true,
|
|
34
|
+
// closeOnBlur: false,
|
|
35
|
+
// defaultKeymap: false,
|
|
36
|
+
// TODO(burdon): Styles/fragments.
|
|
37
|
+
tooltipClass: () => "shadow rounded"
|
|
35
38
|
}),
|
|
36
39
|
// TODO(burdon): Option to create new page?
|
|
37
40
|
// TODO(burdon): Optional decoration via addToOptions
|
|
@@ -51,13 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
57
61
|
|
|
58
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
59
63
|
import get from "lodash.get";
|
|
60
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
61
65
|
var cursorConverter = (handle, path) => ({
|
|
62
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
63
67
|
toCursor: (pos) => {
|
|
@@ -69,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
69
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
70
74
|
return "end";
|
|
71
75
|
}
|
|
72
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
73
77
|
},
|
|
74
78
|
fromCursor: (cursor) => {
|
|
75
79
|
if (cursor === "") {
|
|
@@ -87,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
87
91
|
return 0;
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
|
-
var
|
|
97
|
-
var
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
98
104
|
newHeads
|
|
99
105
|
});
|
|
100
|
-
var
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
104
110
|
|
|
105
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
106
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
107
113
|
|
|
108
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
109
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
110
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
111
117
|
const { lastHeads, path } = state.field(field);
|
|
112
118
|
let hasChanges = false;
|
|
@@ -119,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
119
125
|
return void 0;
|
|
120
126
|
}
|
|
121
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
122
129
|
for (const tr of transactions) {
|
|
123
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
124
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
125
136
|
});
|
|
126
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
127
141
|
});
|
|
128
142
|
return newHeads ?? void 0;
|
|
129
143
|
};
|
|
@@ -138,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
138
152
|
selection = selection.map(changeSet, 1);
|
|
139
153
|
view.dispatch({
|
|
140
154
|
changes: changeSet,
|
|
141
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
142
156
|
});
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
view.dispatch({
|
|
146
160
|
selection,
|
|
147
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
148
162
|
});
|
|
149
163
|
};
|
|
150
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -165,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
165
179
|
if (index == null) {
|
|
166
180
|
return [];
|
|
167
181
|
}
|
|
168
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
169
183
|
return [
|
|
170
184
|
{
|
|
171
185
|
from: index,
|
|
@@ -237,40 +251,43 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
251
|
|
|
238
252
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
239
253
|
var PatchSemaphore = class {
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
256
|
+
this._handle = _handle;
|
|
257
|
+
this._state = _state;
|
|
242
258
|
this._inReconcile = false;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
248
262
|
this._inReconcile = true;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
263
|
-
if (newHeads === null || newHeads === void 0) {
|
|
264
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
265
|
-
}
|
|
266
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
267
|
-
updateCodeMirror(view, selection, path, diff);
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
268
276
|
view.dispatch({
|
|
269
|
-
|
|
270
|
-
annotations:
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
271
279
|
});
|
|
272
|
-
|
|
273
|
-
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
274
291
|
}
|
|
275
292
|
};
|
|
276
293
|
|
|
@@ -280,16 +297,17 @@ var defaultCursorConverter = {
|
|
|
280
297
|
toCursor: (position) => position.toString(),
|
|
281
298
|
fromCursor: (cursor) => parseInt(cursor)
|
|
282
299
|
};
|
|
283
|
-
var Cursor = class {
|
|
300
|
+
var Cursor = class _Cursor {
|
|
284
301
|
static {
|
|
285
302
|
this.converter = Facet.define({
|
|
286
303
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
287
304
|
});
|
|
288
305
|
}
|
|
289
306
|
static {
|
|
290
|
-
this.getCursorFromRange = (
|
|
291
|
-
const
|
|
292
|
-
const
|
|
307
|
+
this.getCursorFromRange = (state, range) => {
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
293
311
|
return [
|
|
294
312
|
from,
|
|
295
313
|
to
|
|
@@ -297,10 +315,11 @@ var Cursor = class {
|
|
|
297
315
|
};
|
|
298
316
|
}
|
|
299
317
|
static {
|
|
300
|
-
this.getRangeFromCursor = (
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
301
320
|
const parts = cursor.split(":");
|
|
302
|
-
const from =
|
|
303
|
-
const to =
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
304
323
|
return from !== void 0 && to !== void 0 ? {
|
|
305
324
|
from,
|
|
306
325
|
to
|
|
@@ -310,25 +329,22 @@ var Cursor = class {
|
|
|
310
329
|
};
|
|
311
330
|
|
|
312
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
313
|
-
var
|
|
314
|
-
|
|
315
|
-
});
|
|
316
|
-
var automerge3 = ({ handle, path }) => {
|
|
317
|
-
const stateField = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
318
334
|
create: () => ({
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
322
338
|
}),
|
|
323
339
|
update: (value, tr) => {
|
|
324
340
|
const result = {
|
|
341
|
+
path: path.slice(),
|
|
325
342
|
lastHeads: value.lastHeads,
|
|
326
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
327
|
-
path: path.slice()
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
328
344
|
};
|
|
329
345
|
let clearUnreconciled = false;
|
|
330
346
|
for (const effect of tr.effects) {
|
|
331
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
332
348
|
result.lastHeads = effect.value.newHeads;
|
|
333
349
|
clearUnreconciled = true;
|
|
334
350
|
}
|
|
@@ -336,46 +352,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
336
352
|
if (clearUnreconciled) {
|
|
337
353
|
result.unreconciledTransactions = [];
|
|
338
354
|
} else {
|
|
339
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
340
356
|
result.unreconciledTransactions.push(tr);
|
|
341
357
|
}
|
|
342
358
|
}
|
|
343
359
|
return result;
|
|
344
360
|
}
|
|
345
361
|
});
|
|
346
|
-
const semaphore = new PatchSemaphore(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
363
|
+
return [
|
|
364
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
366
|
+
// Reconcile external updates.
|
|
367
|
+
ViewPlugin.fromClass(class {
|
|
368
|
+
constructor(_view) {
|
|
369
|
+
this._view = _view;
|
|
370
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
destroy() {
|
|
373
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
374
|
+
}
|
|
375
|
+
_handleChange() {
|
|
376
|
+
semaphore.reconcile(this._view);
|
|
377
|
+
}
|
|
378
|
+
}),
|
|
379
|
+
// Reconcile local updates.
|
|
380
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
381
|
+
if (!changes.empty) {
|
|
382
|
+
semaphore.reconcile(view);
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
385
|
+
// TODO(burdon): Record undo transactions.
|
|
386
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
387
|
+
// https://codemirror.net/examples/inverted-effect
|
|
388
|
+
invertedEffects.of((tr) => {
|
|
389
|
+
const effects = [];
|
|
390
|
+
if (!tr.changes.empty) {
|
|
391
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
359
392
|
});
|
|
360
393
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
return {
|
|
367
|
-
extension: [
|
|
368
|
-
Cursor.converter.of(cursorConverter(handle, path)),
|
|
369
|
-
semaphoreFacet.of(semaphore),
|
|
370
|
-
stateField,
|
|
371
|
-
viewPlugin
|
|
372
|
-
]
|
|
373
|
-
};
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
396
|
+
];
|
|
374
397
|
};
|
|
375
398
|
|
|
376
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
377
|
-
import { Annotation as Annotation2, Facet as
|
|
378
|
-
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
400
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
401
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
379
402
|
import { Event } from "@dxos/async";
|
|
380
403
|
import { Context } from "@dxos/context";
|
|
381
404
|
var dummyProvider = {
|
|
@@ -384,17 +407,17 @@ var dummyProvider = {
|
|
|
384
407
|
},
|
|
385
408
|
close: () => {
|
|
386
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
387
411
|
update: () => {
|
|
388
|
-
}
|
|
389
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
390
413
|
};
|
|
391
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
392
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
393
416
|
});
|
|
394
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
395
418
|
var awareness = (provider = dummyProvider) => {
|
|
396
419
|
return [
|
|
397
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
398
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
399
422
|
decorations: (value) => value.decorations
|
|
400
423
|
}),
|
|
@@ -408,7 +431,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
408
431
|
this._lastAnchor = void 0;
|
|
409
432
|
this._lastHead = void 0;
|
|
410
433
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
411
|
-
this._provider = view.state.facet(
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
412
435
|
this._provider.open();
|
|
413
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
414
437
|
view.dispatch({
|
|
@@ -549,7 +572,7 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
549
572
|
return true;
|
|
550
573
|
}
|
|
551
574
|
};
|
|
552
|
-
var styles =
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
553
576
|
".cm-collab-selection": {},
|
|
554
577
|
".cm-collab-selectionLine": {
|
|
555
578
|
padding: 0,
|
|
@@ -562,40 +585,42 @@ var styles = EditorView.baseTheme({
|
|
|
562
585
|
marginLeft: "-1px",
|
|
563
586
|
marginRight: "-1px",
|
|
564
587
|
boxSizing: "border-box",
|
|
565
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
566
590
|
},
|
|
567
591
|
".cm-collab-selectionCaretDot": {
|
|
568
592
|
borderRadius: "50%",
|
|
569
593
|
position: "absolute",
|
|
570
|
-
width: ".
|
|
571
|
-
height: ".
|
|
572
|
-
top: "-.
|
|
573
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
574
598
|
backgroundColor: "inherit",
|
|
575
599
|
transition: "transform .3s ease-in-out",
|
|
576
600
|
boxSizing: "border-box"
|
|
577
601
|
},
|
|
578
602
|
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
579
|
-
|
|
580
|
-
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
581
605
|
},
|
|
582
606
|
".cm-collab-selectionInfo": {
|
|
583
607
|
position: "absolute",
|
|
584
|
-
|
|
585
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
586
611
|
fontSize: ".75em",
|
|
587
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
588
613
|
fontStyle: "normal",
|
|
589
614
|
fontWeight: "normal",
|
|
590
615
|
lineHeight: "normal",
|
|
591
616
|
userSelect: "none",
|
|
592
617
|
color: "white",
|
|
593
|
-
|
|
594
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
595
619
|
zIndex: 101,
|
|
596
620
|
transition: "opacity .3s ease-in-out",
|
|
597
621
|
backgroundColor: "inherit",
|
|
598
|
-
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
599
624
|
opacity: 0,
|
|
600
625
|
transitionDelay: "0s",
|
|
601
626
|
whiteSpace: "nowrap"
|
|
@@ -608,23 +633,26 @@ var styles = EditorView.baseTheme({
|
|
|
608
633
|
|
|
609
634
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
610
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
611
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
612
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
613
|
-
import { drawSelection, EditorView as
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
639
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
617
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
618
644
|
bracketMatching(),
|
|
619
645
|
closeBrackets(),
|
|
620
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
621
649
|
_placeholder && placeholder(_placeholder),
|
|
622
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
623
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
624
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
625
653
|
|
|
626
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
627
|
-
import { EditorView as
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
628
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
629
657
|
import { invariant } from "@dxos/invariant";
|
|
630
658
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
@@ -660,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
660
688
|
const getPoint = (view, pos) => {
|
|
661
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
662
690
|
const element = document.elementFromPoint(x, y);
|
|
663
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
664
692
|
const point = {
|
|
665
693
|
x: x - left,
|
|
666
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
667
695
|
};
|
|
668
696
|
return {
|
|
669
697
|
element,
|
|
@@ -672,7 +700,7 @@ var blast = (options = defaultOptions) => {
|
|
|
672
700
|
};
|
|
673
701
|
return [
|
|
674
702
|
// Cursor moved.
|
|
675
|
-
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
676
704
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
677
705
|
if (blaster) {
|
|
678
706
|
blaster.destroy();
|
|
@@ -755,7 +783,7 @@ var Blaster = class {
|
|
|
755
783
|
initialize() {
|
|
756
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
757
785
|
F: __dxlog_file,
|
|
758
|
-
L:
|
|
786
|
+
L: 141,
|
|
759
787
|
S: this,
|
|
760
788
|
A: [
|
|
761
789
|
"!this._canvas && !this._ctx",
|
|
@@ -792,7 +820,7 @@ var Blaster = class {
|
|
|
792
820
|
start() {
|
|
793
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
794
822
|
F: __dxlog_file,
|
|
795
|
-
L:
|
|
823
|
+
L: 180,
|
|
796
824
|
S: this,
|
|
797
825
|
A: [
|
|
798
826
|
"this._canvas && this._ctx",
|
|
@@ -933,9 +961,14 @@ var random = (min, max) => {
|
|
|
933
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
934
962
|
};
|
|
935
963
|
|
|
936
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
937
|
-
import {
|
|
938
|
-
import {
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
939
972
|
|
|
940
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
941
974
|
import * as random2 from "lib0/random";
|
|
@@ -978,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
978
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
979
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
980
1013
|
var headings = {
|
|
981
|
-
1:
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
991
|
-
"-ml-[7px]"
|
|
992
|
-
],
|
|
993
|
-
4: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
995
|
-
"-ml-[6px]"
|
|
996
|
-
],
|
|
997
|
-
5: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
999
|
-
"-ml-[5px]"
|
|
1000
|
-
],
|
|
1001
|
-
6: [
|
|
1002
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1003
|
-
"-ml-[4px]"
|
|
1004
|
-
]
|
|
1005
|
-
};
|
|
1006
|
-
var heading = (level, readonly) => {
|
|
1007
|
-
const [style, offset] = headings[level];
|
|
1008
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1009
1023
|
};
|
|
1010
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1011
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1023,168 +1037,123 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1023
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1024
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1025
1039
|
|
|
1026
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1027
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1028
|
-
var styles2 = EditorView4.baseTheme({
|
|
1029
|
-
"& .cm-codeblock": {
|
|
1030
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1031
|
-
},
|
|
1032
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1033
|
-
background: getToken("extend.colors.neutral.50")
|
|
1034
|
-
},
|
|
1035
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1036
|
-
background: getToken("extend.colors.neutral.850")
|
|
1037
|
-
},
|
|
1038
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1039
|
-
display: "block",
|
|
1040
|
-
paddingInline: "4px !important"
|
|
1041
|
-
},
|
|
1042
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1043
|
-
paddingTop: "4px !important",
|
|
1044
|
-
borderTopLeftRadius: "4px",
|
|
1045
|
-
borderTopRightRadius: "4px"
|
|
1046
|
-
},
|
|
1047
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1048
|
-
paddingBottom: "4px !important",
|
|
1049
|
-
borderBottomLeftRadius: "4px",
|
|
1050
|
-
borderBottomRightRadius: "4px"
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
var getLineRange = (lines, from, to) => {
|
|
1054
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1055
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1056
|
-
return [
|
|
1057
|
-
start,
|
|
1058
|
-
end
|
|
1059
|
-
];
|
|
1060
|
-
};
|
|
1061
|
-
var code2 = () => {
|
|
1062
|
-
const getDecorations = (view) => {
|
|
1063
|
-
const decorations = [];
|
|
1064
|
-
if (!view.hasFocus || view.state.readOnly) {
|
|
1065
|
-
const text = view.state.doc.sliceString(0);
|
|
1066
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1067
|
-
const blocks = view.viewportLineBlocks;
|
|
1068
|
-
for (const match of matches) {
|
|
1069
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1070
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1071
|
-
const block = blocks[i];
|
|
1072
|
-
decorations.push(Decoration2.line({
|
|
1073
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1074
|
-
}).range(block.from));
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
return Decoration2.set(decorations);
|
|
1079
|
-
};
|
|
1080
|
-
return [
|
|
1081
|
-
ViewPlugin3.fromClass(class {
|
|
1082
|
-
constructor(view) {
|
|
1083
|
-
this.hasFocus = false;
|
|
1084
|
-
this.decorations = getDecorations(view);
|
|
1085
|
-
}
|
|
1086
|
-
update(update2) {
|
|
1087
|
-
if (
|
|
1088
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1089
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1090
|
-
) {
|
|
1091
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1092
|
-
this.decorations = getDecorations(update2.view);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
}, {
|
|
1096
|
-
decorations: (value) => value.decorations
|
|
1097
|
-
}),
|
|
1098
|
-
styles2
|
|
1099
|
-
];
|
|
1100
|
-
};
|
|
1101
|
-
|
|
1102
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1103
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1104
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
1105
|
-
import sortBy from "lodash.sortby";
|
|
1106
|
-
import { debounce } from "@dxos/async";
|
|
1107
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1108
|
-
import { log as log2 } from "@dxos/log";
|
|
1109
|
-
import { nonNullable } from "@dxos/util";
|
|
1110
|
-
|
|
1111
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1112
1041
|
import { log } from "@dxos/log";
|
|
1113
1042
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1114
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1115
1044
|
try {
|
|
1116
1045
|
return fn(...args);
|
|
1117
|
-
} catch (
|
|
1118
|
-
log.catch(
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1119
1048
|
F: __dxlog_file2,
|
|
1120
|
-
L:
|
|
1049
|
+
L: 18,
|
|
1121
1050
|
S: void 0,
|
|
1122
1051
|
C: (f, a) => f(...a)
|
|
1123
1052
|
});
|
|
1124
1053
|
}
|
|
1125
1054
|
};
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1059
|
+
}
|
|
1060
|
+
const changes2 = [];
|
|
1061
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1062
|
+
fromA,
|
|
1063
|
+
toA,
|
|
1064
|
+
fromB,
|
|
1065
|
+
toB,
|
|
1066
|
+
inserted: inserted.toString()
|
|
1067
|
+
})));
|
|
1068
|
+
return changes2;
|
|
1069
|
+
}).filter(Boolean);
|
|
1070
|
+
if (changes.length) {
|
|
1071
|
+
console.log("changes", changes);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1126
1074
|
|
|
1127
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1128
|
-
var
|
|
1129
|
-
|
|
1130
|
-
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1077
|
+
"&light .cm-comment, &light .cm-comment-current": {
|
|
1078
|
+
mixBlendMode: "darken"
|
|
1079
|
+
},
|
|
1080
|
+
"&dark .cm-comment, &dark .cm-comment-current": {
|
|
1081
|
+
mixBlendMode: "plus-lighter"
|
|
1082
|
+
},
|
|
1083
|
+
"&light .cm-comment": {
|
|
1131
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1132
1085
|
},
|
|
1133
|
-
"& .cm-comment-
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1134
1087
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1088
|
+
},
|
|
1089
|
+
"&dark .cm-comment": {
|
|
1090
|
+
color: getToken("extend.colors.yellow.50"),
|
|
1091
|
+
backgroundColor: getToken("extend.colors.yellow.900")
|
|
1092
|
+
},
|
|
1093
|
+
"&dark .cm-comment-current": {
|
|
1094
|
+
color: getToken("extend.colors.yellow.100"),
|
|
1095
|
+
backgroundColor: getToken("extend.colors.yellow.950")
|
|
1135
1096
|
}
|
|
1136
1097
|
});
|
|
1137
|
-
var
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1147
|
-
if (!range) {
|
|
1098
|
+
var commentMark = Decoration2.mark({
|
|
1099
|
+
class: "cm-comment"
|
|
1100
|
+
});
|
|
1101
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1102
|
+
class: "cm-comment-current"
|
|
1103
|
+
});
|
|
1104
|
+
var focusComment = (view, id, center = true) => {
|
|
1105
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1106
|
+
if (!comment?.comment.cursor) {
|
|
1148
1107
|
return;
|
|
1149
1108
|
}
|
|
1150
|
-
view.
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1109
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1110
|
+
if (range) {
|
|
1111
|
+
view.dispatch({
|
|
1112
|
+
selection: {
|
|
1113
|
+
anchor: range.from
|
|
1114
|
+
},
|
|
1115
|
+
effects: [
|
|
1116
|
+
//
|
|
1117
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1118
|
+
y: "center"
|
|
1119
|
+
} : void 0),
|
|
1120
|
+
setSelection.of({
|
|
1121
|
+
current: id
|
|
1122
|
+
})
|
|
1123
|
+
]
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1159
1126
|
};
|
|
1160
|
-
var
|
|
1127
|
+
var setComments = StateEffect2.define();
|
|
1161
1128
|
var setSelection = StateEffect2.define();
|
|
1162
1129
|
var setCommentState = StateEffect2.define();
|
|
1163
|
-
var
|
|
1130
|
+
var commentsState = StateField2.define({
|
|
1164
1131
|
create: () => ({
|
|
1165
|
-
|
|
1132
|
+
comments: [],
|
|
1133
|
+
selection: {}
|
|
1166
1134
|
}),
|
|
1167
1135
|
update: (value, tr) => {
|
|
1168
|
-
const cursorConverter3 = tr.state.facet(Cursor.converter);
|
|
1169
1136
|
for (const effect of tr.effects) {
|
|
1170
1137
|
if (effect.is(setSelection)) {
|
|
1171
1138
|
return {
|
|
1172
1139
|
...value,
|
|
1173
|
-
|
|
1140
|
+
selection: effect.value
|
|
1174
1141
|
};
|
|
1175
1142
|
}
|
|
1176
|
-
if (effect.is(
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1143
|
+
if (effect.is(setComments)) {
|
|
1144
|
+
const comments2 = effect.value.map((comment) => {
|
|
1145
|
+
if (!comment.cursor) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1180
1149
|
return range && {
|
|
1181
|
-
|
|
1182
|
-
|
|
1150
|
+
comment,
|
|
1151
|
+
range
|
|
1183
1152
|
};
|
|
1184
1153
|
}).filter(nonNullable);
|
|
1185
1154
|
return {
|
|
1186
1155
|
...value,
|
|
1187
|
-
|
|
1156
|
+
comments: comments2
|
|
1188
1157
|
};
|
|
1189
1158
|
}
|
|
1190
1159
|
if (effect.is(setCommentState)) {
|
|
@@ -1194,87 +1163,178 @@ var commentsStateField = StateField2.define({
|
|
|
1194
1163
|
return value;
|
|
1195
1164
|
}
|
|
1196
1165
|
});
|
|
1197
|
-
var
|
|
1198
|
-
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1167
|
+
commentsState
|
|
1199
1168
|
], (state) => {
|
|
1200
|
-
const {
|
|
1201
|
-
const decorations = sortBy(
|
|
1202
|
-
|
|
1169
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1170
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1171
|
+
const range = comment.range;
|
|
1172
|
+
if (!range || range.from === range.to) {
|
|
1173
|
+
console.warn("Invalid range:", range);
|
|
1203
1174
|
return void 0;
|
|
1204
1175
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
to: selection.to
|
|
1208
|
-
};
|
|
1209
|
-
if (selection.id === active) {
|
|
1210
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1176
|
+
if (comment.comment.id === current) {
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1211
1178
|
} else {
|
|
1212
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1213
1180
|
}
|
|
1214
|
-
}).filter(nonNullable)
|
|
1215
|
-
return
|
|
1181
|
+
}).filter(nonNullable);
|
|
1182
|
+
return Decoration2.set(decorations);
|
|
1216
1183
|
});
|
|
1217
|
-
var
|
|
1218
|
-
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1184
|
+
var trackPastedComments = (onUpdate) => {
|
|
1185
|
+
let tracked = null;
|
|
1186
|
+
const handleTrack = (event, view) => {
|
|
1187
|
+
const comments2 = view.state.field(commentsState);
|
|
1188
|
+
const { main } = view.state.selection;
|
|
1189
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1190
|
+
if (!selectedRanges.length) {
|
|
1191
|
+
tracked = null;
|
|
1192
|
+
} else {
|
|
1193
|
+
tracked = {
|
|
1194
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1195
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1196
|
+
id: comment.id,
|
|
1197
|
+
from: range.from - main.from,
|
|
1198
|
+
to: range.to - main.from
|
|
1199
|
+
}))
|
|
1200
|
+
};
|
|
1234
1201
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1202
|
+
};
|
|
1203
|
+
return [
|
|
1204
|
+
EditorView5.domEventHandlers({
|
|
1205
|
+
cut: handleTrack,
|
|
1206
|
+
copy: handleTrack
|
|
1207
|
+
}),
|
|
1208
|
+
// Track deleted comments.
|
|
1209
|
+
invertedEffects2.of((tr) => {
|
|
1210
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1211
|
+
const effects = [];
|
|
1212
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1213
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1214
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1215
|
+
effects.push(restoreCommentEffect.of({
|
|
1216
|
+
id,
|
|
1217
|
+
from,
|
|
1218
|
+
to
|
|
1219
|
+
}));
|
|
1248
1220
|
}
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
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
|
+
}
|
|
1239
|
+
if (tracked) {
|
|
1240
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1241
|
+
if (paste) {
|
|
1242
|
+
let found = -1;
|
|
1243
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1244
|
+
if (text.eq(tracked.text)) {
|
|
1245
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1246
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1247
|
+
}
|
|
1248
|
+
found = fromB;
|
|
1259
1249
|
}
|
|
1260
1250
|
});
|
|
1251
|
+
if (found > -1) {
|
|
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
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
tracked = null;
|
|
1261
1261
|
}
|
|
1262
|
-
return true;
|
|
1263
1262
|
}
|
|
1264
|
-
|
|
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
|
+
}
|
|
1271
|
+
})
|
|
1272
|
+
];
|
|
1273
|
+
};
|
|
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) {
|
|
1265
1289
|
return false;
|
|
1266
|
-
}
|
|
1290
|
+
}
|
|
1291
|
+
if (to === view.state.doc.length) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
changes: {
|
|
1294
|
+
from: to,
|
|
1295
|
+
insert: "\n"
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1300
|
+
from,
|
|
1301
|
+
to
|
|
1302
|
+
});
|
|
1303
|
+
if (cursor) {
|
|
1304
|
+
const id = options.onCreate?.({
|
|
1305
|
+
cursor,
|
|
1306
|
+
from,
|
|
1307
|
+
location: view.coordsAtPos(from)
|
|
1308
|
+
});
|
|
1309
|
+
if (id) {
|
|
1310
|
+
view.dispatch({
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
return true;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1267
1326
|
return [
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1327
|
+
optionsFacet.of(options),
|
|
1328
|
+
commentsState,
|
|
1329
|
+
commentsDecorations,
|
|
1330
|
+
styles2,
|
|
1271
1331
|
//
|
|
1272
1332
|
// Keymap.
|
|
1273
1333
|
//
|
|
1274
1334
|
options.onCreate ? keymap3.of([
|
|
1275
1335
|
{
|
|
1276
1336
|
key: shortcut,
|
|
1277
|
-
run: callbackWrapper(
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1278
1338
|
}
|
|
1279
1339
|
]) : [],
|
|
1280
1340
|
//
|
|
@@ -1290,7 +1350,7 @@ var comments = (options = {}) => {
|
|
|
1290
1350
|
above: true,
|
|
1291
1351
|
create: () => {
|
|
1292
1352
|
const el = document.createElement("div");
|
|
1293
|
-
options.onHover
|
|
1353
|
+
options.onHover(el, shortcut);
|
|
1294
1354
|
return {
|
|
1295
1355
|
dom: el,
|
|
1296
1356
|
offset: {
|
|
@@ -1303,364 +1363,116 @@ var comments = (options = {}) => {
|
|
|
1303
1363
|
}
|
|
1304
1364
|
return null;
|
|
1305
1365
|
}, {
|
|
1306
|
-
|
|
1366
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1367
|
+
// hideOnChange: true,
|
|
1307
1368
|
hoverTime: 1e3
|
|
1308
1369
|
}) : [],
|
|
1309
1370
|
//
|
|
1310
|
-
//
|
|
1311
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1371
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1312
1372
|
//
|
|
1313
1373
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1314
|
-
|
|
1315
|
-
{
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
if (
|
|
1321
|
-
|
|
1322
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1323
|
-
log2.info("deleted comment", {
|
|
1324
|
-
thread: range.id
|
|
1325
|
-
}, {
|
|
1326
|
-
F: __dxlog_file3,
|
|
1327
|
-
L: 274,
|
|
1328
|
-
S: void 0,
|
|
1329
|
-
C: (f, a) => f(...a)
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
if (from <= range.to) {
|
|
1334
|
-
const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1335
|
-
Object.assign(range, newRange);
|
|
1336
|
-
mod = true;
|
|
1374
|
+
let mod = false;
|
|
1375
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1376
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1377
|
+
comments2.forEach(({ comment, range }) => {
|
|
1378
|
+
if (from2 === to2) {
|
|
1379
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1380
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1381
|
+
options.onDelete?.(comment.id);
|
|
1337
1382
|
}
|
|
1338
|
-
}
|
|
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
|
+
})
|
|
1339
1397
|
});
|
|
1340
|
-
if (mod) {
|
|
1341
|
-
view.dispatch({
|
|
1342
|
-
effects: setCommentState.of({
|
|
1343
|
-
active,
|
|
1344
|
-
ranges
|
|
1345
|
-
})
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
1398
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
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));
|
|
1362
1415
|
if (d < min) {
|
|
1363
|
-
|
|
1416
|
+
selection.closest = comment.id;
|
|
1364
1417
|
min = d;
|
|
1365
1418
|
}
|
|
1366
|
-
});
|
|
1367
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1368
|
-
view.dispatch({
|
|
1369
|
-
effects: setSelection.of(selected)
|
|
1370
|
-
});
|
|
1371
|
-
handleSelect({
|
|
1372
|
-
...selected,
|
|
1373
|
-
ranges: ranges.map((range) => ({
|
|
1374
|
-
...range,
|
|
1375
|
-
location: view.coordsAtPos(range.from)
|
|
1376
|
-
}))
|
|
1377
|
-
});
|
|
1378
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
|
+
});
|
|
1379
1433
|
}
|
|
1380
|
-
})
|
|
1434
|
+
}),
|
|
1435
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1381
1436
|
];
|
|
1382
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
|
+
};
|
|
1383
1450
|
|
|
1384
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1385
|
-
import {
|
|
1386
|
-
var
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
this._pos = _pos;
|
|
1397
|
-
}
|
|
1398
|
-
eq(other) {
|
|
1399
|
-
return this._pos === other._pos;
|
|
1400
|
-
}
|
|
1401
|
-
toDOM(view) {
|
|
1402
|
-
const el = document.createElement("div");
|
|
1403
|
-
el.className = "cm-hr";
|
|
1404
|
-
return el;
|
|
1405
|
-
}
|
|
1406
|
-
};
|
|
1407
|
-
var placeholderMatcher = new MatchDecorator({
|
|
1408
|
-
regexp: /^---$/g,
|
|
1409
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1410
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1411
|
-
})
|
|
1412
|
-
});
|
|
1413
|
-
var hr = () => [
|
|
1414
|
-
styles4,
|
|
1415
|
-
ViewPlugin4.fromClass(class {
|
|
1416
|
-
constructor(view) {
|
|
1417
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1418
|
-
}
|
|
1419
|
-
update(update2) {
|
|
1420
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1421
|
-
}
|
|
1422
|
-
}, {
|
|
1423
|
-
decorations: (instance) => instance.rules,
|
|
1424
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1425
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1426
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1427
|
-
})
|
|
1428
|
-
})
|
|
1429
|
-
];
|
|
1430
|
-
|
|
1431
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1432
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1433
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1434
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1435
|
-
var image = (options = {}) => {
|
|
1436
|
-
return StateField3.define({
|
|
1437
|
-
create: (state) => {
|
|
1438
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1439
|
-
},
|
|
1440
|
-
update: (value, tr) => {
|
|
1441
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1442
|
-
return value;
|
|
1443
|
-
}
|
|
1444
|
-
const cursor = tr.state.selection.main.head;
|
|
1445
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1446
|
-
let from = Math.min(cursor, oldCursor);
|
|
1447
|
-
let to = Math.max(cursor, oldCursor);
|
|
1448
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1449
|
-
from = Math.min(from, fromB);
|
|
1450
|
-
to = Math.max(to, toB);
|
|
1451
|
-
});
|
|
1452
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1453
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1454
|
-
return value.map(tr.changes).update({
|
|
1455
|
-
filterFrom: from,
|
|
1456
|
-
filterTo: to,
|
|
1457
|
-
filter: () => false,
|
|
1458
|
-
add: buildDecorations(from, to, tr.state)
|
|
1459
|
-
});
|
|
1460
|
-
},
|
|
1461
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1462
|
-
});
|
|
1463
|
-
};
|
|
1464
|
-
var buildDecorations = (from, to, state) => {
|
|
1465
|
-
const decorations = [];
|
|
1466
|
-
const cursor = state.selection.main.head;
|
|
1467
|
-
syntaxTree(state).iterate({
|
|
1468
|
-
enter: (node) => {
|
|
1469
|
-
if (node.name === "Image") {
|
|
1470
|
-
const urlNode = node.node.getChild("URL");
|
|
1471
|
-
if (urlNode) {
|
|
1472
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1473
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1474
|
-
decorations.push(Decoration5.replace({
|
|
1475
|
-
block: true,
|
|
1476
|
-
widget: new ImageWidget(url)
|
|
1477
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
},
|
|
1481
|
-
from,
|
|
1482
|
-
to
|
|
1483
|
-
});
|
|
1484
|
-
return decorations;
|
|
1485
|
-
};
|
|
1486
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1487
|
-
constructor(_url) {
|
|
1488
|
-
super();
|
|
1489
|
-
this._url = _url;
|
|
1490
|
-
}
|
|
1491
|
-
eq(other) {
|
|
1492
|
-
return this._url === other._url;
|
|
1493
|
-
}
|
|
1494
|
-
toDOM(view) {
|
|
1495
|
-
const img = document.createElement("img");
|
|
1496
|
-
img.setAttribute("src", this._url);
|
|
1497
|
-
img.setAttribute("class", "cm-image");
|
|
1498
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1499
|
-
return img;
|
|
1500
|
-
}
|
|
1501
|
-
};
|
|
1502
|
-
|
|
1503
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1504
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1505
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1506
|
-
import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1507
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1508
|
-
var link = (options = {}) => {
|
|
1509
|
-
const extensions = [
|
|
1510
|
-
ViewPlugin5.fromClass(class {
|
|
1511
|
-
constructor(view) {
|
|
1512
|
-
this.decorations = buildDecorations2(view, options);
|
|
1513
|
-
}
|
|
1514
|
-
update(update2) {
|
|
1515
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1516
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
}, {
|
|
1520
|
-
decorations: (v) => v.decorations
|
|
1521
|
-
})
|
|
1522
|
-
];
|
|
1523
|
-
if (options.onHover) {
|
|
1524
|
-
extensions.push(
|
|
1525
|
-
// https://codemirror.net/examples/tooltip
|
|
1526
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1527
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1528
|
-
hoverTooltip2((view, pos, side) => {
|
|
1529
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1530
|
-
let link2 = null;
|
|
1531
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1532
|
-
link2 = node.name === "Link" ? node : null;
|
|
1533
|
-
}
|
|
1534
|
-
const url = link2 && link2.getChild("URL");
|
|
1535
|
-
if (!url || !link2) {
|
|
1536
|
-
return null;
|
|
1537
|
-
}
|
|
1538
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1539
|
-
return {
|
|
1540
|
-
pos: link2.from,
|
|
1541
|
-
end: link2.to,
|
|
1542
|
-
above: true,
|
|
1543
|
-
create: () => {
|
|
1544
|
-
const el = document.createElement("div");
|
|
1545
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1546
|
-
options.onHover(el, urlText);
|
|
1547
|
-
return {
|
|
1548
|
-
dom: el,
|
|
1549
|
-
offset: {
|
|
1550
|
-
x: 0,
|
|
1551
|
-
y: 4
|
|
1552
|
-
}
|
|
1553
|
-
};
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
})
|
|
1557
|
-
);
|
|
1558
|
-
}
|
|
1559
|
-
return extensions;
|
|
1560
|
-
};
|
|
1561
|
-
var LinkButton = class extends WidgetType4 {
|
|
1562
|
-
constructor(_url, _onAttach) {
|
|
1563
|
-
super();
|
|
1564
|
-
this._url = _url;
|
|
1565
|
-
this._onAttach = _onAttach;
|
|
1566
|
-
}
|
|
1567
|
-
eq(other) {
|
|
1568
|
-
return this._url === other._url;
|
|
1569
|
-
}
|
|
1570
|
-
toDOM(view) {
|
|
1571
|
-
const el = document.createElement("span");
|
|
1572
|
-
this._onAttach(el, this._url);
|
|
1573
|
-
return el;
|
|
1574
|
-
}
|
|
1575
|
-
};
|
|
1576
|
-
var LinkText = class extends WidgetType4 {
|
|
1577
|
-
constructor(_text, _url) {
|
|
1578
|
-
super();
|
|
1579
|
-
this._text = _text;
|
|
1580
|
-
this._url = _url;
|
|
1581
|
-
}
|
|
1582
|
-
eq(other) {
|
|
1583
|
-
return this._url === other._url;
|
|
1584
|
-
}
|
|
1585
|
-
toDOM(view) {
|
|
1586
|
-
const link2 = document.createElement("a");
|
|
1587
|
-
link2.setAttribute("class", "cm-link");
|
|
1588
|
-
link2.textContent = this._text;
|
|
1589
|
-
if (this._url) {
|
|
1590
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1591
|
-
link2.setAttribute("target", "_blank");
|
|
1592
|
-
link2.href = this._url;
|
|
1593
|
-
} else {
|
|
1594
|
-
link2.onclick = () => {
|
|
1595
|
-
view.dispatch({
|
|
1596
|
-
selection: {
|
|
1597
|
-
anchor: view.posAtDOM(link2)
|
|
1598
|
-
}
|
|
1599
|
-
});
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
return link2;
|
|
1603
|
-
}
|
|
1604
|
-
};
|
|
1605
|
-
var buildDecorations2 = (view, options) => {
|
|
1606
|
-
const builder = new RangeSetBuilder();
|
|
1607
|
-
const { state } = view;
|
|
1608
|
-
const cursor = state.selection.main.head;
|
|
1609
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1610
|
-
syntaxTree2(state).iterate({
|
|
1611
|
-
enter: (node) => {
|
|
1612
|
-
if (node.name === "Link") {
|
|
1613
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1614
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1615
|
-
const urlNode = node.node.getChild("URL");
|
|
1616
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1617
|
-
if (!url) {
|
|
1618
|
-
return false;
|
|
1619
|
-
}
|
|
1620
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1621
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1622
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1623
|
-
}));
|
|
1624
|
-
}
|
|
1625
|
-
if (options.onRender) {
|
|
1626
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1627
|
-
widget: new LinkButton(url, options.onRender)
|
|
1628
|
-
}));
|
|
1629
|
-
}
|
|
1630
|
-
return false;
|
|
1631
|
-
}
|
|
1632
|
-
},
|
|
1633
|
-
from,
|
|
1634
|
-
to
|
|
1635
|
-
});
|
|
1636
|
-
}
|
|
1637
|
-
return builder.finish();
|
|
1638
|
-
};
|
|
1639
|
-
|
|
1640
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1641
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1642
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1643
|
-
const extensions = [];
|
|
1644
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1645
|
-
onFocus(focused);
|
|
1646
|
-
return null;
|
|
1647
|
-
}));
|
|
1648
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1649
|
-
onChange(update2.state.doc.toString());
|
|
1650
|
-
}));
|
|
1651
|
-
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;
|
|
1652
1463
|
};
|
|
1653
1464
|
|
|
1654
1465
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1655
1466
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1656
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1467
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1657
1468
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1658
1469
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1659
1470
|
import { languages } from "@codemirror/language-data";
|
|
1660
1471
|
import { searchKeymap } from "@codemirror/search";
|
|
1661
1472
|
import { EditorState } from "@codemirror/state";
|
|
1662
1473
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1663
|
-
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";
|
|
1664
1476
|
|
|
1665
1477
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1666
1478
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1757,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1757
1569
|
markdownTags.QuoteMark,
|
|
1758
1570
|
markdownTags.EmphasisMark
|
|
1759
1571
|
],
|
|
1760
|
-
class:
|
|
1572
|
+
class: mark
|
|
1761
1573
|
},
|
|
1762
1574
|
// E.g., code block language (after ```).
|
|
1763
1575
|
{
|
|
@@ -1765,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1765
1577
|
tags.function(tags.variableName),
|
|
1766
1578
|
tags.labelName
|
|
1767
1579
|
],
|
|
1768
|
-
class:
|
|
1580
|
+
class: codeMark
|
|
1769
1581
|
},
|
|
1770
1582
|
{
|
|
1771
1583
|
tag: [
|
|
@@ -1776,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1776
1588
|
// Headings.
|
|
1777
1589
|
{
|
|
1778
1590
|
tag: tags.heading1,
|
|
1779
|
-
class: heading(1
|
|
1591
|
+
class: heading(1)
|
|
1780
1592
|
},
|
|
1781
1593
|
{
|
|
1782
1594
|
tag: tags.heading2,
|
|
1783
|
-
class: heading(2
|
|
1595
|
+
class: heading(2)
|
|
1784
1596
|
},
|
|
1785
1597
|
{
|
|
1786
1598
|
tag: tags.heading3,
|
|
1787
|
-
class: heading(3
|
|
1599
|
+
class: heading(3)
|
|
1788
1600
|
},
|
|
1789
1601
|
{
|
|
1790
1602
|
tag: tags.heading4,
|
|
1791
|
-
class: heading(4
|
|
1603
|
+
class: heading(4)
|
|
1792
1604
|
},
|
|
1793
1605
|
{
|
|
1794
1606
|
tag: tags.heading5,
|
|
1795
|
-
class: heading(5
|
|
1607
|
+
class: heading(5)
|
|
1796
1608
|
},
|
|
1797
1609
|
{
|
|
1798
1610
|
tag: tags.heading6,
|
|
1799
|
-
class: heading(6
|
|
1611
|
+
class: heading(6)
|
|
1800
1612
|
},
|
|
1801
1613
|
// Emphasis.
|
|
1802
1614
|
{
|
|
@@ -1822,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1822
1634
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1823
1635
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1824
1636
|
// the code, but all other CSS properties will be inherited.
|
|
1825
|
-
// 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.
|
|
1826
1638
|
{
|
|
1827
1639
|
tag: [
|
|
1828
1640
|
markdownTags.CodeText,
|
|
@@ -1851,19 +1663,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1851
1663
|
};
|
|
1852
1664
|
|
|
1853
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1854
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1855
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1856
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1857
1670
|
EditorState.tabSize.of(2),
|
|
1858
|
-
|
|
1859
|
-
customKeymap(),
|
|
1671
|
+
// https://github.com/codemirror/basic-setup
|
|
1860
1672
|
bracketMatching2(),
|
|
1861
1673
|
closeBrackets2(),
|
|
1862
1674
|
crosshairCursor(),
|
|
1863
1675
|
dropCursor(),
|
|
1864
1676
|
drawSelection2(),
|
|
1865
|
-
|
|
1866
|
-
|
|
1677
|
+
highlightActiveLine2(),
|
|
1678
|
+
history2(),
|
|
1867
1679
|
indentOnInput(),
|
|
1868
1680
|
_placeholder && placeholder2(_placeholder),
|
|
1869
1681
|
// Main extension.
|
|
@@ -1887,66 +1699,1560 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1887
1699
|
// https://github.com/codemirror/theme-one-dark
|
|
1888
1700
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1889
1701
|
// Custom styles.
|
|
1890
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
]);
|
|
1905
|
-
|
|
1906
|
-
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1907
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1908
|
-
var mention = ({ onSearch }) => {
|
|
1909
|
-
return autocompletion2({
|
|
1910
|
-
closeOnBlur: false,
|
|
1911
|
-
override: [
|
|
1912
|
-
(context) => {
|
|
1913
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1914
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
1915
|
-
return null;
|
|
1916
|
-
}
|
|
1917
|
-
console.log(match);
|
|
1918
|
-
return {
|
|
1919
|
-
from: match.from,
|
|
1920
|
-
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1921
|
-
label: `@${value}`
|
|
1922
|
-
}))
|
|
1923
|
-
};
|
|
1924
|
-
}
|
|
1925
|
-
]
|
|
1926
|
-
});
|
|
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);
|
|
1927
1716
|
};
|
|
1928
1717
|
|
|
1929
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1930
|
-
import { syntaxTree
|
|
1931
|
-
import { RangeSetBuilder
|
|
1932
|
-
import {
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
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
|
+
];
|
|
1939
1771
|
};
|
|
1940
|
-
var
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1772
|
+
var LineWidget = class extends WidgetType2 {
|
|
1773
|
+
constructor(_className) {
|
|
1774
|
+
super();
|
|
1775
|
+
this._className = _className;
|
|
1776
|
+
}
|
|
1777
|
+
toDOM() {
|
|
1778
|
+
const el = document.createElement("span");
|
|
1779
|
+
el.innerHTML = " ";
|
|
1780
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1781
|
+
return el;
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1785
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1786
|
+
var buildDecorations = (view) => {
|
|
1787
|
+
const builder = new RangeSetBuilder();
|
|
1788
|
+
const { state } = view;
|
|
1789
|
+
const blocks = view.viewportLineBlocks;
|
|
1790
|
+
const cursor = state.selection.main.head;
|
|
1791
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1792
|
+
syntaxTree(state).iterate({
|
|
1793
|
+
enter: (node) => {
|
|
1794
|
+
if (node.name === "FencedCode") {
|
|
1795
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1796
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1797
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1798
|
+
const block = blocks[i];
|
|
1799
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1800
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1801
|
+
widget: i === range[0] ? top : bottom
|
|
1802
|
+
}));
|
|
1803
|
+
} else {
|
|
1804
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1805
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1806
|
+
}));
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
from,
|
|
1812
|
+
to
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return builder.finish();
|
|
1816
|
+
};
|
|
1817
|
+
var code2 = () => {
|
|
1818
|
+
return [
|
|
1819
|
+
ViewPlugin3.fromClass(class {
|
|
1820
|
+
constructor(view) {
|
|
1821
|
+
this.decorations = buildDecorations(view);
|
|
1822
|
+
}
|
|
1823
|
+
update(update2) {
|
|
1824
|
+
this.decorations = buildDecorations(update2.view);
|
|
1825
|
+
}
|
|
1826
|
+
}, {
|
|
1827
|
+
decorations: (value) => value.decorations
|
|
1828
|
+
}),
|
|
1829
|
+
styles3
|
|
1830
|
+
];
|
|
1831
|
+
};
|
|
1832
|
+
|
|
1833
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1834
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1835
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1836
|
+
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1837
|
+
import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
+
import { useState, useMemo } from "react";
|
|
1839
|
+
var compareFormatting = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
|
|
1840
|
+
var Inline;
|
|
1841
|
+
(function(Inline2) {
|
|
1842
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
1843
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
1844
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
1845
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
1846
|
+
})(Inline || (Inline = {}));
|
|
1847
|
+
var List;
|
|
1848
|
+
(function(List2) {
|
|
1849
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
1850
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
1851
|
+
List2[List2["Task"] = 2] = "Task";
|
|
1852
|
+
})(List || (List = {}));
|
|
1853
|
+
var setHeading = (level) => ({ state, dispatch }) => {
|
|
1854
|
+
const { selection: { ranges }, doc } = state;
|
|
1855
|
+
const changes = [];
|
|
1856
|
+
let prevBlock = -1;
|
|
1857
|
+
for (const range of ranges) {
|
|
1858
|
+
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1861
|
+
enter: (node) => {
|
|
1862
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
prevBlock = node.from;
|
|
1866
|
+
const blockType = Textblocks[node.name];
|
|
1867
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
1868
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
1869
|
+
if (curLevel < 0 || curLevel === level) {
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (curLevel === 0) {
|
|
1873
|
+
changes.push({
|
|
1874
|
+
from: node.from,
|
|
1875
|
+
insert: "#".repeat(level) + " "
|
|
1876
|
+
});
|
|
1877
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
1878
|
+
const nextLine = doc.lineAt(node.to);
|
|
1879
|
+
if (level) {
|
|
1880
|
+
changes.push({
|
|
1881
|
+
from: node.from,
|
|
1882
|
+
insert: "#".repeat(level) + " "
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
changes.push({
|
|
1886
|
+
from: nextLine.from - 1,
|
|
1887
|
+
to: nextLine.to
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
if (level === 0) {
|
|
1891
|
+
changes.push({
|
|
1892
|
+
from: node.from,
|
|
1893
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
1894
|
+
});
|
|
1895
|
+
} else if (level < curLevel) {
|
|
1896
|
+
changes.push({
|
|
1897
|
+
from: node.from,
|
|
1898
|
+
to: node.from + (curLevel - level)
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
changes.push({
|
|
1902
|
+
from: node.from,
|
|
1903
|
+
insert: "#".repeat(level - curLevel)
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
if (!changes.length) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
dispatch(state.update({
|
|
1914
|
+
changes,
|
|
1915
|
+
userEvent: "format.setHeading",
|
|
1916
|
+
scrollIntoView: true
|
|
1917
|
+
}));
|
|
1918
|
+
return true;
|
|
1919
|
+
};
|
|
1920
|
+
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
1921
|
+
const marker = inlineMarkerText(type);
|
|
1922
|
+
const changes = state.changeByRange((range) => {
|
|
1923
|
+
if (!enable && range.empty) {
|
|
1924
|
+
const after = state.doc.sliceString(range.head, range.head + 6);
|
|
1925
|
+
const found = after.indexOf(marker);
|
|
1926
|
+
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
1927
|
+
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
1928
|
+
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
1929
|
+
...before.slice(before.length - found)
|
|
1930
|
+
].reverse().join("") === after.slice(0, found)) {
|
|
1931
|
+
return {
|
|
1932
|
+
changes: [
|
|
1933
|
+
{
|
|
1934
|
+
from: range.head - marker.length - found,
|
|
1935
|
+
to: range.head - found
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
from: range.head + found,
|
|
1939
|
+
to: range.head + found + marker.length
|
|
1940
|
+
}
|
|
1941
|
+
],
|
|
1942
|
+
range: EditorSelection.cursor(range.from - marker.length)
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
const changes2 = [];
|
|
1948
|
+
const changesAtEnd = [];
|
|
1949
|
+
let blockStart = -1;
|
|
1950
|
+
let blockEnd = -1;
|
|
1951
|
+
let startCovered = false;
|
|
1952
|
+
let endCovered = false;
|
|
1953
|
+
let { from, to } = range;
|
|
1954
|
+
syntaxTree2(state).iterate({
|
|
1955
|
+
from,
|
|
1956
|
+
to,
|
|
1957
|
+
enter: (node) => {
|
|
1958
|
+
const { name } = node;
|
|
1959
|
+
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
1960
|
+
blockStart = blockContentStart(node);
|
|
1961
|
+
blockEnd = blockContentEnd(node, state.doc);
|
|
1962
|
+
startCovered = endCovered = false;
|
|
1963
|
+
} else if (name === "Link" || name === "Image" && enable) {
|
|
1964
|
+
if (from < node.from && to > node.from && to <= node.to) {
|
|
1965
|
+
to = node.to;
|
|
1966
|
+
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
1967
|
+
from = node.from;
|
|
1968
|
+
}
|
|
1969
|
+
} else if (IgnoreInline.has(name) && enable) {
|
|
1970
|
+
if (node.from < from && node.to > from) {
|
|
1971
|
+
if (to === from) {
|
|
1972
|
+
to = node.to;
|
|
1973
|
+
}
|
|
1974
|
+
from = node.to;
|
|
1975
|
+
}
|
|
1976
|
+
if (node.from < to && node.to > to) {
|
|
1977
|
+
to = node.from;
|
|
1978
|
+
}
|
|
1979
|
+
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
1980
|
+
const markType = InlineMarker[name];
|
|
1981
|
+
const size = inlineMarkerText(markType).length;
|
|
1982
|
+
const openEnd = node.from + size;
|
|
1983
|
+
const closeStart = node.to - size;
|
|
1984
|
+
if (markType === type) {
|
|
1985
|
+
if (openEnd <= from && closeStart >= from) {
|
|
1986
|
+
startCovered = openEnd === from ? "adjacent" : true;
|
|
1987
|
+
}
|
|
1988
|
+
if (openEnd <= to && closeStart >= to) {
|
|
1989
|
+
endCovered = closeStart === to ? "adjacent" : true;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (markType === type || type === 3 && enable) {
|
|
1993
|
+
if (node.from >= from && openEnd <= to) {
|
|
1994
|
+
changes2.push({
|
|
1995
|
+
from: node.from,
|
|
1996
|
+
to: openEnd
|
|
1997
|
+
});
|
|
1998
|
+
if (markType !== type && closeStart >= to) {
|
|
1999
|
+
changesAtEnd.push({
|
|
2000
|
+
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2001
|
+
insert: inlineMarkerText(markType)
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
if (closeStart >= from && node.to <= to) {
|
|
2006
|
+
changes2.push({
|
|
2007
|
+
from: closeStart,
|
|
2008
|
+
to: node.to
|
|
2009
|
+
});
|
|
2010
|
+
if (markType !== type && openEnd <= from) {
|
|
2011
|
+
changes2.push({
|
|
2012
|
+
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2013
|
+
insert: inlineMarkerText(markType)
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
leave: (node) => {
|
|
2021
|
+
if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
|
|
2022
|
+
const rangeStart = Math.max(from, blockStart);
|
|
2023
|
+
const rangeEnd = Math.min(to, blockEnd);
|
|
2024
|
+
if (enable) {
|
|
2025
|
+
if (!startCovered) {
|
|
2026
|
+
changes2.push({
|
|
2027
|
+
from: rangeStart,
|
|
2028
|
+
insert: marker
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (!endCovered) {
|
|
2032
|
+
changes2.push({
|
|
2033
|
+
from: rangeEnd,
|
|
2034
|
+
insert: marker
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
} else {
|
|
2038
|
+
if (startCovered === "adjacent") {
|
|
2039
|
+
changes2.push({
|
|
2040
|
+
from: from - marker.length,
|
|
2041
|
+
to: from
|
|
2042
|
+
});
|
|
2043
|
+
} else if (startCovered) {
|
|
2044
|
+
changes2.push({
|
|
2045
|
+
from: skipSpaces(rangeStart, state.doc, -1, blockStart),
|
|
2046
|
+
insert: marker
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (endCovered === "adjacent") {
|
|
2050
|
+
changes2.push({
|
|
2051
|
+
from: to,
|
|
2052
|
+
to: to + marker.length
|
|
2053
|
+
});
|
|
2054
|
+
} else if (endCovered) {
|
|
2055
|
+
changes2.push({
|
|
2056
|
+
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
2057
|
+
insert: marker
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
});
|
|
2064
|
+
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
2065
|
+
return {
|
|
2066
|
+
changes: changeSet,
|
|
2067
|
+
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
2068
|
+
};
|
|
2069
|
+
});
|
|
2070
|
+
dispatch(state.update(changes, {
|
|
2071
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2072
|
+
scrollIntoView: true
|
|
2073
|
+
}));
|
|
2074
|
+
return true;
|
|
2075
|
+
};
|
|
2076
|
+
var addStyle = (style) => setStyle(style, true);
|
|
2077
|
+
var removeStyle = (style) => setStyle(style, false);
|
|
2078
|
+
var toggleStyle = (style) => (arg) => {
|
|
2079
|
+
const form = getFormatting(arg.state);
|
|
2080
|
+
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
2081
|
+
};
|
|
2082
|
+
var toggleStrong = toggleStyle(0);
|
|
2083
|
+
var toggleEmphasis = toggleStyle(1);
|
|
2084
|
+
var toggleStrikethrough = toggleStyle(2);
|
|
2085
|
+
var toggleInlineCode = toggleStyle(3);
|
|
2086
|
+
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
2087
|
+
var blockContentStart = (node) => {
|
|
2088
|
+
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
2089
|
+
if (atx) {
|
|
2090
|
+
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
2091
|
+
}
|
|
2092
|
+
return node.from;
|
|
2093
|
+
};
|
|
2094
|
+
var blockContentEnd = (node, doc) => {
|
|
2095
|
+
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
2096
|
+
const lastLine = doc.lineAt(node.to);
|
|
2097
|
+
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
2098
|
+
return lastLine.from - 1;
|
|
2099
|
+
}
|
|
2100
|
+
return node.to;
|
|
2101
|
+
};
|
|
2102
|
+
var skipSpaces = (pos, doc, dir, limit) => {
|
|
2103
|
+
const line = doc.lineAt(pos);
|
|
2104
|
+
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
2105
|
+
pos += dir;
|
|
2106
|
+
}
|
|
2107
|
+
return pos;
|
|
2108
|
+
};
|
|
2109
|
+
var snippets = {
|
|
2110
|
+
codeblock: snippet([
|
|
2111
|
+
//
|
|
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];
|
|
1945
3251
|
const getRow = () => {
|
|
1946
3252
|
const table2 = getTable();
|
|
1947
3253
|
return table2.rows?.[table2.rows.length - 1];
|
|
1948
3254
|
};
|
|
1949
|
-
|
|
3255
|
+
syntaxTree7(state).iterate({
|
|
1950
3256
|
enter: (node) => {
|
|
1951
3257
|
switch (node.name) {
|
|
1952
3258
|
case "Table": {
|
|
@@ -1978,16 +3284,16 @@ var update = (state, options) => {
|
|
|
1978
3284
|
});
|
|
1979
3285
|
tables.forEach((table2) => {
|
|
1980
3286
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1981
|
-
hide && builder.add(table2.from, table2.to,
|
|
3287
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
1982
3288
|
widget: new TableWidget(table2)
|
|
1983
3289
|
}));
|
|
1984
|
-
builder.add(table2.from, table2.to,
|
|
3290
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
1985
3291
|
class: "cm-table"
|
|
1986
3292
|
}));
|
|
1987
3293
|
});
|
|
1988
3294
|
return builder.finish();
|
|
1989
3295
|
};
|
|
1990
|
-
var TableWidget = class extends
|
|
3296
|
+
var TableWidget = class extends WidgetType6 {
|
|
1991
3297
|
constructor(_table) {
|
|
1992
3298
|
super();
|
|
1993
3299
|
this._table = _table;
|
|
@@ -2024,92 +3330,139 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2024
3330
|
}
|
|
2025
3331
|
};
|
|
2026
3332
|
|
|
2027
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2028
|
-
import {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
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"
|
|
2033
3344
|
}
|
|
2034
3345
|
});
|
|
2035
|
-
var CheckboxWidget = class extends
|
|
2036
|
-
constructor(_checked
|
|
3346
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
3347
|
+
constructor(_checked) {
|
|
2037
3348
|
super();
|
|
2038
3349
|
this._checked = _checked;
|
|
2039
|
-
this._indent = _indent;
|
|
2040
|
-
this._onCheck = _onCheck;
|
|
2041
3350
|
}
|
|
2042
3351
|
eq(other) {
|
|
2043
|
-
return this._checked === other._checked
|
|
3352
|
+
return this._checked === other._checked;
|
|
2044
3353
|
}
|
|
2045
3354
|
toDOM(view) {
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2049
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2050
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
3355
|
+
const input = document.createElement("input");
|
|
3356
|
+
input.className = "cm-task-checkbox";
|
|
2051
3357
|
input.type = "checkbox";
|
|
2052
3358
|
input.checked = this._checked;
|
|
2053
|
-
if (
|
|
3359
|
+
if (view.state.readOnly) {
|
|
2054
3360
|
input.setAttribute("disabled", "true");
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
3361
|
+
} else {
|
|
3362
|
+
input.onmousedown = (event) => {
|
|
3363
|
+
const pos = view.posAtDOM(input);
|
|
3364
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
3365
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
3366
|
+
view.dispatch({
|
|
3367
|
+
changes: {
|
|
3368
|
+
from: pos + 1,
|
|
3369
|
+
to: pos + 2,
|
|
3370
|
+
insert: this._checked ? " " : "x"
|
|
3371
|
+
}
|
|
3372
|
+
});
|
|
3373
|
+
event.preventDefault();
|
|
3374
|
+
}
|
|
2060
3375
|
};
|
|
2061
3376
|
}
|
|
2062
|
-
return
|
|
3377
|
+
return input;
|
|
2063
3378
|
}
|
|
2064
3379
|
ignoreEvent() {
|
|
2065
3380
|
return false;
|
|
2066
3381
|
}
|
|
2067
3382
|
};
|
|
3383
|
+
var checkedDecoration = Decoration10.replace({
|
|
3384
|
+
widget: new CheckboxWidget(true)
|
|
3385
|
+
});
|
|
3386
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
3387
|
+
widget: new CheckboxWidget(false)
|
|
3388
|
+
});
|
|
3389
|
+
var buildDecorations6 = (view) => {
|
|
3390
|
+
const builder = new RangeSetBuilder7();
|
|
3391
|
+
const { state } = view;
|
|
3392
|
+
const cursor = state.selection.main.head;
|
|
3393
|
+
for (const { from, to } of view.visibleRanges) {
|
|
3394
|
+
syntaxTree8(state).iterate({
|
|
3395
|
+
enter: (node) => {
|
|
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
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
},
|
|
3406
|
+
from,
|
|
3407
|
+
to
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
return builder.finish();
|
|
3411
|
+
};
|
|
2068
3412
|
var tasklist = (options = {}) => {
|
|
2069
|
-
const taskMatcher = new MatchDecorator2({
|
|
2070
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2071
|
-
decoration: (match, view, pos) => {
|
|
2072
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2073
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2074
|
-
return Decoration8.replace({
|
|
2075
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2076
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2077
|
-
view.dispatch({
|
|
2078
|
-
changes: {
|
|
2079
|
-
from: idx,
|
|
2080
|
-
to: idx + 1,
|
|
2081
|
-
insert: checked2 ? "x" : " "
|
|
2082
|
-
},
|
|
2083
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2084
|
-
selection: {
|
|
2085
|
-
anchor: idx + 3
|
|
2086
|
-
}
|
|
2087
|
-
});
|
|
2088
|
-
})
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
|
-
});
|
|
2092
|
-
const tasks = ViewPlugin6.fromClass(class {
|
|
2093
|
-
constructor(view) {
|
|
2094
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2095
|
-
}
|
|
2096
|
-
update(update2) {
|
|
2097
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2098
|
-
}
|
|
2099
|
-
}, {
|
|
2100
|
-
decorations: (value) => value.tasks,
|
|
2101
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2102
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2103
|
-
})
|
|
2104
|
-
});
|
|
2105
3413
|
return [
|
|
2106
|
-
|
|
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
|
+
}),
|
|
2107
3426
|
styles5
|
|
2108
3427
|
];
|
|
2109
3428
|
};
|
|
2110
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
|
+
};
|
|
3463
|
+
|
|
2111
3464
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2112
|
-
import { keymap as
|
|
3465
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2113
3466
|
var defaultItems = [
|
|
2114
3467
|
"hello world!",
|
|
2115
3468
|
"this is a test.",
|
|
@@ -2119,7 +3472,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2119
3472
|
let t;
|
|
2120
3473
|
let idx = 0;
|
|
2121
3474
|
return [
|
|
2122
|
-
|
|
3475
|
+
keymap6.of([
|
|
2123
3476
|
{
|
|
2124
3477
|
// Reset.
|
|
2125
3478
|
key: "alt-meta-'",
|
|
@@ -2165,27 +3518,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2165
3518
|
];
|
|
2166
3519
|
};
|
|
2167
3520
|
|
|
2168
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2169
|
-
import { yCollab } from "y-codemirror.next";
|
|
2170
|
-
|
|
2171
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2172
|
-
import * as Y from "yjs";
|
|
2173
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2174
|
-
var cursorConverter2 = (text) => ({
|
|
2175
|
-
toCursor: (index, assoc) => {
|
|
2176
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2177
|
-
},
|
|
2178
|
-
fromCursor: (cursor) => {
|
|
2179
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2180
|
-
}
|
|
2181
|
-
});
|
|
2182
|
-
|
|
2183
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2184
|
-
var yjs = (content, awareness2) => [
|
|
2185
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2186
|
-
yCollab(content, awareness2)
|
|
2187
|
-
];
|
|
2188
|
-
|
|
2189
3521
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2190
3522
|
import get3 from "lodash.get";
|
|
2191
3523
|
var defaultTheme = {
|
|
@@ -2217,8 +3549,9 @@ var defaultTheme = {
|
|
|
2217
3549
|
outline: "none"
|
|
2218
3550
|
},
|
|
2219
3551
|
".cm-scroller": {
|
|
2220
|
-
overflow:
|
|
2221
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3552
|
+
// overflow: 'visible',
|
|
3553
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3554
|
+
lineHeight: 1.4
|
|
2222
3555
|
},
|
|
2223
3556
|
".cm-content": {
|
|
2224
3557
|
padding: 0,
|
|
@@ -2226,11 +3559,11 @@ var defaultTheme = {
|
|
|
2226
3559
|
fontSize: "16px"
|
|
2227
3560
|
},
|
|
2228
3561
|
"&light .cm-content": {
|
|
2229
|
-
color: get3(tokens, "extend.
|
|
3562
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2230
3563
|
caretColor: "black"
|
|
2231
3564
|
},
|
|
2232
3565
|
"&dark .cm-content": {
|
|
2233
|
-
color: get3(tokens, "extend.
|
|
3566
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2234
3567
|
caretColor: "white"
|
|
2235
3568
|
},
|
|
2236
3569
|
//
|
|
@@ -2242,8 +3575,11 @@ var defaultTheme = {
|
|
|
2242
3575
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2243
3576
|
borderLeft: "2px solid white"
|
|
2244
3577
|
},
|
|
2245
|
-
".cm-placeholder": {
|
|
2246
|
-
|
|
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)")
|
|
2247
3583
|
},
|
|
2248
3584
|
//
|
|
2249
3585
|
// line
|
|
@@ -2252,7 +3588,7 @@ var defaultTheme = {
|
|
|
2252
3588
|
paddingInline: 0
|
|
2253
3589
|
},
|
|
2254
3590
|
".cm-activeLine": {
|
|
2255
|
-
background: "
|
|
3591
|
+
background: "transparent"
|
|
2256
3592
|
},
|
|
2257
3593
|
//
|
|
2258
3594
|
// Selection
|
|
@@ -2315,13 +3651,6 @@ var defaultTheme = {
|
|
|
2315
3651
|
textDecoration: "none"
|
|
2316
3652
|
},
|
|
2317
3653
|
//
|
|
2318
|
-
// widgets
|
|
2319
|
-
//
|
|
2320
|
-
".cm-widgetBuffer": {
|
|
2321
|
-
display: "none",
|
|
2322
|
-
height: 0
|
|
2323
|
-
},
|
|
2324
|
-
//
|
|
2325
3654
|
// table
|
|
2326
3655
|
//
|
|
2327
3656
|
".cm-table *": {
|
|
@@ -2430,90 +3759,88 @@ var codeTheme = {
|
|
|
2430
3759
|
};
|
|
2431
3760
|
|
|
2432
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";
|
|
2433
3763
|
var EditorModes = [
|
|
2434
3764
|
"default",
|
|
2435
3765
|
"vim"
|
|
2436
3766
|
];
|
|
2437
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2438
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2439
|
-
tabBehavior: "limited"
|
|
2440
|
-
});
|
|
3767
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2441
3768
|
const { themeMode } = useThemeContext();
|
|
2442
3769
|
const rootRef = useRef(null);
|
|
2443
|
-
const [view, setView] =
|
|
3770
|
+
const [view, setView] = useState2(null);
|
|
2444
3771
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2445
3772
|
view
|
|
2446
3773
|
]);
|
|
2447
|
-
|
|
2448
|
-
if (
|
|
2449
|
-
view.
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
awareness2.setLocalStateField("user", {
|
|
2459
|
-
name: peer.name ?? generateName(peer.id),
|
|
2460
|
-
color: getColorForValue({
|
|
2461
|
-
value: peer.id,
|
|
2462
|
-
type: "color"
|
|
2463
|
-
}),
|
|
2464
|
-
colorLight: getColorForValue({
|
|
2465
|
-
value: peer.id,
|
|
2466
|
-
themeMode,
|
|
2467
|
-
type: "highlight"
|
|
2468
|
-
})
|
|
2469
|
-
});
|
|
2470
|
-
}
|
|
2471
|
-
}, [
|
|
2472
|
-
awareness2,
|
|
2473
|
-
peer,
|
|
2474
|
-
themeMode
|
|
2475
|
-
]);
|
|
2476
|
-
useEffect(() => {
|
|
2477
|
-
if (view && comments2 !== void 0) {
|
|
2478
|
-
view.dispatch({
|
|
2479
|
-
effects: setCommentRange.of({
|
|
2480
|
-
model,
|
|
2481
|
-
comments: comments2
|
|
2482
|
-
})
|
|
2483
|
-
});
|
|
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
|
+
}
|
|
3784
|
+
view?.focus();
|
|
2484
3785
|
}
|
|
2485
3786
|
}, [
|
|
2486
3787
|
view,
|
|
2487
|
-
|
|
3788
|
+
autoFocus
|
|
2488
3789
|
]);
|
|
2489
|
-
|
|
3790
|
+
useEffect2(() => {
|
|
2490
3791
|
if (!model || !rootRef.current) {
|
|
2491
3792
|
return;
|
|
2492
3793
|
}
|
|
2493
3794
|
const state = EditorState2.create({
|
|
2494
3795
|
doc: model.text(),
|
|
2495
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2496
3796
|
selection,
|
|
2497
3797
|
extensions: [
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
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
|
+
}),
|
|
2501
3807
|
// Theme.
|
|
2502
|
-
// TODO(burdon): Make
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
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),
|
|
2506
3821
|
// Storage and replication.
|
|
3822
|
+
// NOTE: This must come before user extensions.
|
|
2507
3823
|
model.extension,
|
|
3824
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
3825
|
+
editorMode === "vim" && vim(),
|
|
2508
3826
|
// Custom.
|
|
2509
3827
|
...extensions
|
|
2510
|
-
].filter(
|
|
3828
|
+
].filter(isNotFalsy3)
|
|
2511
3829
|
});
|
|
2512
|
-
|
|
2513
|
-
|
|
3830
|
+
const newView = new EditorView14({
|
|
3831
|
+
state,
|
|
2514
3832
|
parent: rootRef.current,
|
|
2515
|
-
|
|
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
|
+
}
|
|
2516
3842
|
});
|
|
3843
|
+
view?.destroy();
|
|
2517
3844
|
setView(newView);
|
|
2518
3845
|
return () => {
|
|
2519
3846
|
newView?.destroy();
|
|
@@ -2529,8 +3856,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2529
3856
|
const handleKeyUp = useCallback((event) => {
|
|
2530
3857
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2531
3858
|
switch (key) {
|
|
3859
|
+
case "Enter": {
|
|
3860
|
+
view?.focus();
|
|
3861
|
+
break;
|
|
3862
|
+
}
|
|
2532
3863
|
case "Escape": {
|
|
2533
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
3864
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
3865
|
+
view?.focus();
|
|
3866
|
+
}
|
|
2534
3867
|
break;
|
|
2535
3868
|
}
|
|
2536
3869
|
}
|
|
@@ -2541,24 +3874,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
|
|
|
2541
3874
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2542
3875
|
key: model.id,
|
|
2543
3876
|
role: "none",
|
|
2544
|
-
ref: rootRef,
|
|
2545
3877
|
tabIndex: 0,
|
|
2546
|
-
onKeyUp: handleKeyUp,
|
|
2547
3878
|
...slots.root,
|
|
2548
|
-
...editorMode !==
|
|
3879
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3880
|
+
onKeyUp: handleKeyUp,
|
|
3881
|
+
ref: rootRef
|
|
2549
3882
|
});
|
|
2550
3883
|
});
|
|
2551
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
3884
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2552
3885
|
const { themeMode } = useThemeContext();
|
|
2553
3886
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2554
3887
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2555
3888
|
ref: forwardedRef,
|
|
2556
3889
|
readonly,
|
|
2557
3890
|
extensions: [
|
|
2558
|
-
|
|
2559
|
-
readonly,
|
|
3891
|
+
createBasicBundle({
|
|
2560
3892
|
themeMode,
|
|
2561
|
-
placeholder: placeholder3
|
|
3893
|
+
placeholder: placeholder3,
|
|
3894
|
+
lineWrapping
|
|
2562
3895
|
}),
|
|
2563
3896
|
...extensions
|
|
2564
3897
|
],
|
|
@@ -2567,15 +3900,14 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2567
3900
|
...props
|
|
2568
3901
|
});
|
|
2569
3902
|
});
|
|
2570
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
3903
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2571
3904
|
const { themeMode } = useThemeContext();
|
|
2572
3905
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2573
3906
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2574
3907
|
ref: forwardedRef,
|
|
2575
3908
|
readonly,
|
|
2576
3909
|
extensions: [
|
|
2577
|
-
|
|
2578
|
-
readonly,
|
|
3910
|
+
createMarkdownExtensions({
|
|
2579
3911
|
themeMode,
|
|
2580
3912
|
placeholder: placeholder3
|
|
2581
3913
|
}),
|
|
@@ -2588,7 +3920,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2588
3920
|
});
|
|
2589
3921
|
var defaultSlots = {
|
|
2590
3922
|
root: {
|
|
2591
|
-
className: mx3("
|
|
3923
|
+
className: mx3("grow", focusRing)
|
|
3924
|
+
},
|
|
3925
|
+
editor: {
|
|
3926
|
+
className: "bs-full"
|
|
2592
3927
|
}
|
|
2593
3928
|
};
|
|
2594
3929
|
var defaultTextSlots = {
|
|
@@ -2598,22 +3933,217 @@ var defaultMarkdownSlots = {
|
|
|
2598
3933
|
...defaultSlots
|
|
2599
3934
|
};
|
|
2600
3935
|
|
|
2601
|
-
// packages/ui/react-ui-editor/src/
|
|
2602
|
-
import
|
|
2603
|
-
import {
|
|
2604
|
-
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
|
+
};
|
|
2605
4135
|
|
|
2606
4136
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2607
4137
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2608
4138
|
import { Context as Context2 } from "@dxos/context";
|
|
2609
|
-
import { invariant as
|
|
4139
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2610
4140
|
import { log as log3 } from "@dxos/log";
|
|
2611
4141
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2612
4142
|
var DEBOUNCE_INTERVAL = 100;
|
|
2613
4143
|
var SpaceAwarenessProvider = class {
|
|
2614
4144
|
constructor(params) {
|
|
2615
|
-
this.remoteStateChange = new Event2();
|
|
2616
4145
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
4146
|
+
this.remoteStateChange = new Event2();
|
|
2617
4147
|
this._space = params.space;
|
|
2618
4148
|
this._channel = params.channel;
|
|
2619
4149
|
this._peerId = params.peerId;
|
|
@@ -2630,7 +4160,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2630
4160
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2631
4161
|
}
|
|
2632
4162
|
});
|
|
2633
|
-
|
|
4163
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2634
4164
|
switch (message.payload.kind) {
|
|
2635
4165
|
case "query": {
|
|
2636
4166
|
this._handleQueryMessage();
|
|
@@ -2641,8 +4171,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2641
4171
|
break;
|
|
2642
4172
|
}
|
|
2643
4173
|
}
|
|
2644
|
-
});
|
|
2645
|
-
this._ctx.onDispose(unsubscribe);
|
|
4174
|
+
}));
|
|
2646
4175
|
void this._space.postMessage(this._channel, {
|
|
2647
4176
|
kind: "query"
|
|
2648
4177
|
}).catch((err) => {
|
|
@@ -2650,7 +4179,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2650
4179
|
err
|
|
2651
4180
|
}, {
|
|
2652
4181
|
F: __dxlog_file4,
|
|
2653
|
-
L:
|
|
4182
|
+
L: 89,
|
|
2654
4183
|
S: this,
|
|
2655
4184
|
C: (f, a) => f(...a)
|
|
2656
4185
|
});
|
|
@@ -2661,10 +4190,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2661
4190
|
this._ctx = void 0;
|
|
2662
4191
|
this._postTask = void 0;
|
|
2663
4192
|
}
|
|
4193
|
+
getRemoteStates() {
|
|
4194
|
+
return Array.from(this._remoteStates.values());
|
|
4195
|
+
}
|
|
2664
4196
|
update(position) {
|
|
2665
|
-
|
|
4197
|
+
invariant2(this._postTask, void 0, {
|
|
2666
4198
|
F: __dxlog_file4,
|
|
2667
|
-
L:
|
|
4199
|
+
L: 104,
|
|
2668
4200
|
S: this,
|
|
2669
4201
|
A: [
|
|
2670
4202
|
"this._postTask",
|
|
@@ -2678,13 +4210,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2678
4210
|
};
|
|
2679
4211
|
this._postTask.schedule();
|
|
2680
4212
|
}
|
|
2681
|
-
getRemoteStates() {
|
|
2682
|
-
return Array.from(this._remoteStates.values());
|
|
2683
|
-
}
|
|
2684
4213
|
_handleQueryMessage() {
|
|
2685
|
-
|
|
4214
|
+
invariant2(this._postTask, void 0, {
|
|
2686
4215
|
F: __dxlog_file4,
|
|
2687
|
-
L:
|
|
4216
|
+
L: 115,
|
|
2688
4217
|
S: this,
|
|
2689
4218
|
A: [
|
|
2690
4219
|
"this._postTask",
|
|
@@ -2694,9 +4223,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2694
4223
|
this._postTask.schedule();
|
|
2695
4224
|
}
|
|
2696
4225
|
_handlePostMessage(message) {
|
|
2697
|
-
|
|
4226
|
+
invariant2(message.kind === "post", void 0, {
|
|
2698
4227
|
F: __dxlog_file4,
|
|
2699
|
-
L:
|
|
4228
|
+
L: 120,
|
|
2700
4229
|
S: this,
|
|
2701
4230
|
A: [
|
|
2702
4231
|
"message.kind === 'post'",
|
|
@@ -2708,199 +4237,247 @@ var SpaceAwarenessProvider = class {
|
|
|
2708
4237
|
}
|
|
2709
4238
|
};
|
|
2710
4239
|
|
|
2711
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
4240
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2712
4241
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2713
|
-
|
|
2714
|
-
|
|
4242
|
+
var modelState = StateField5.define({
|
|
4243
|
+
create: () => void 0,
|
|
4244
|
+
update: (model) => model
|
|
4245
|
+
});
|
|
2715
4246
|
|
|
2716
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
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
|
+
});
|
|
2752
4292
|
};
|
|
2753
|
-
return model;
|
|
2754
4293
|
};
|
|
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
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
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
|
-
|
|
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);
|
|
2824
4364
|
}
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
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
|
+
};
|
|
2830
4376
|
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
return encoder;
|
|
4377
|
+
if (autoFocus) {
|
|
4378
|
+
view.focus();
|
|
2834
4379
|
}
|
|
2835
4380
|
}
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
}
|
|
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);
|
|
2846
4412
|
};
|
|
2847
4413
|
|
|
2848
4414
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
}
|
|
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";
|
|
2853
4422
|
var useTextModel = (props) => {
|
|
2854
4423
|
const { identity, space, text } = props;
|
|
2855
|
-
const [model, setModel] =
|
|
2856
|
-
|
|
4424
|
+
const [model, setModel] = useState5();
|
|
4425
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2857
4426
|
identity,
|
|
2858
4427
|
space,
|
|
2859
4428
|
text
|
|
2860
4429
|
]);
|
|
2861
4430
|
return model;
|
|
2862
4431
|
};
|
|
2863
|
-
var
|
|
2864
|
-
const
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
}
|
|
4432
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4433
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4434
|
+
return {
|
|
4435
|
+
id,
|
|
4436
|
+
content,
|
|
4437
|
+
setContent,
|
|
4438
|
+
text: () => content
|
|
4439
|
+
};
|
|
2872
4440
|
};
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
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
|
+
});
|
|
2876
4451
|
const obj = text;
|
|
2877
4452
|
const doc = getRawDoc(obj, [
|
|
2878
4453
|
obj.field
|
|
2879
4454
|
]);
|
|
2880
|
-
const
|
|
4455
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2881
4456
|
space,
|
|
2882
4457
|
channel: `automerge.awareness.${obj.id}`,
|
|
2883
4458
|
info: {
|
|
2884
|
-
displayName: identity
|
|
4459
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2885
4460
|
color: cursorColor.color,
|
|
2886
4461
|
lightColor: cursorColor.light
|
|
2887
4462
|
},
|
|
2888
4463
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2889
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
|
+
}
|
|
2890
4476
|
const model = {
|
|
2891
4477
|
id: obj.id,
|
|
2892
4478
|
content: doc,
|
|
2893
4479
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2894
|
-
|
|
2895
|
-
extension: [
|
|
2896
|
-
modelState.init(() => model),
|
|
2897
|
-
automerge3({
|
|
2898
|
-
handle: doc.handle,
|
|
2899
|
-
path: doc.path
|
|
2900
|
-
}),
|
|
2901
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2902
|
-
awareness()
|
|
2903
|
-
].filter(isNotNullOrUndefined),
|
|
4480
|
+
extension: extensions,
|
|
2904
4481
|
peer: identity ? {
|
|
2905
4482
|
id: identity.identityKey.toHex(),
|
|
2906
4483
|
name: identity.profile?.displayName
|
|
@@ -2909,57 +4486,94 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2909
4486
|
return model;
|
|
2910
4487
|
};
|
|
2911
4488
|
export {
|
|
2912
|
-
AwarenessProvider,
|
|
2913
4489
|
BaseTextEditor,
|
|
2914
4490
|
Cursor,
|
|
2915
4491
|
Doc,
|
|
2916
4492
|
EditorModes,
|
|
4493
|
+
Inline,
|
|
4494
|
+
List,
|
|
2917
4495
|
MarkdownEditor,
|
|
2918
4496
|
RemoteSelectionsDecorator,
|
|
2919
4497
|
SpaceAwarenessProvider,
|
|
2920
4498
|
TextEditor,
|
|
2921
4499
|
TextKind,
|
|
2922
|
-
|
|
4500
|
+
Toolbar,
|
|
2923
4501
|
YText,
|
|
2924
4502
|
YXmlFragment,
|
|
4503
|
+
addBlockquote,
|
|
4504
|
+
addCodeblock,
|
|
4505
|
+
addLink,
|
|
4506
|
+
addList,
|
|
4507
|
+
addStyle,
|
|
2925
4508
|
autocomplete,
|
|
2926
|
-
|
|
4509
|
+
automerge,
|
|
2927
4510
|
awareness,
|
|
2928
|
-
|
|
4511
|
+
awarenessProvider,
|
|
2929
4512
|
blast,
|
|
2930
4513
|
callbackWrapper,
|
|
2931
4514
|
code2 as code,
|
|
2932
4515
|
codeTheme,
|
|
2933
4516
|
comments,
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
4517
|
+
compareFormatting,
|
|
4518
|
+
createBasicBundle,
|
|
4519
|
+
createComment,
|
|
4520
|
+
createDataExtensions,
|
|
4521
|
+
createMarkdownExtensions,
|
|
4522
|
+
createThemeExtensions,
|
|
2937
4523
|
defaultMarkdownSlots,
|
|
2938
4524
|
defaultOptions,
|
|
2939
4525
|
defaultSlots,
|
|
2940
4526
|
defaultTextSlots,
|
|
2941
4527
|
defaultTheme,
|
|
4528
|
+
focusComment,
|
|
4529
|
+
formatting,
|
|
4530
|
+
getFormatting,
|
|
2942
4531
|
getToken,
|
|
4532
|
+
heading2 as heading,
|
|
2943
4533
|
hr,
|
|
2944
4534
|
image,
|
|
4535
|
+
insertTable,
|
|
4536
|
+
keymap7 as keymap,
|
|
2945
4537
|
link,
|
|
2946
4538
|
listener,
|
|
2947
|
-
|
|
4539
|
+
logChanges,
|
|
2948
4540
|
markdownHighlightStyle,
|
|
2949
4541
|
markdownTags,
|
|
2950
4542
|
markdownTagsExtensions,
|
|
2951
4543
|
markdownTheme,
|
|
2952
4544
|
mention,
|
|
2953
4545
|
modelState,
|
|
2954
|
-
|
|
2955
|
-
|
|
4546
|
+
outliner,
|
|
4547
|
+
removeBlockquote,
|
|
4548
|
+
removeCodeblock,
|
|
4549
|
+
removeLink,
|
|
4550
|
+
removeList,
|
|
4551
|
+
removeStyle,
|
|
4552
|
+
setBlockquote,
|
|
4553
|
+
setComments,
|
|
4554
|
+
setHeading,
|
|
2956
4555
|
setSelection,
|
|
4556
|
+
setStyle,
|
|
2957
4557
|
table,
|
|
2958
4558
|
tags2 as tags,
|
|
2959
4559
|
tasklist,
|
|
2960
4560
|
textTheme,
|
|
4561
|
+
toggleBlockquote,
|
|
4562
|
+
toggleCodeblock,
|
|
4563
|
+
toggleEmphasis,
|
|
4564
|
+
toggleInlineCode,
|
|
4565
|
+
toggleList,
|
|
4566
|
+
toggleStrikethrough,
|
|
4567
|
+
toggleStrong,
|
|
4568
|
+
toggleStyle,
|
|
2961
4569
|
typewriter,
|
|
4570
|
+
useActionHandler,
|
|
4571
|
+
useComments,
|
|
4572
|
+
useEditorView,
|
|
4573
|
+
useFormattingState,
|
|
4574
|
+
useInMemoryTextModel,
|
|
4575
|
+
useTextEditor,
|
|
2962
4576
|
useTextModel,
|
|
2963
|
-
|
|
4577
|
+
useToolbarContext
|
|
2964
4578
|
};
|
|
2965
4579
|
//# sourceMappingURL=index.mjs.map
|