@dxos/react-ui-editor 0.3.11-main.42059c4 → 0.3.11-main.463e5cd
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 +1610 -1059
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +13 -15
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +13 -5
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/{yjs.stories.d.ts → hooks.stories.d.ts} +13 -2
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +23 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +8 -10
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +7 -6
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +23 -15
- 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 +13 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +8 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts +3 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +14 -27
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +2 -0
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +46 -36
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +73 -82
- package/src/components/TextEditor/TextEditor.tsx +107 -71
- package/src/components/TextEditor/automerge.stories.tsx +1 -2
- package/src/components/TextEditor/hooks.stories.tsx +106 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +90 -0
- package/src/components/Toolbar/Toolbar.tsx +166 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +50 -41
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +11 -36
- package/src/extensions/automerge/semaphore.ts +31 -28
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +22 -18
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +253 -179
- 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.ts +188 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -15
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +16 -7
- package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +48 -33
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +4 -2
- package/src/hooks/useActionHandler.ts +62 -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 +9 -6
- package/src/util.ts +26 -3
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +0 -26
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts +0 -7
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/comments.stories.tsx +0 -355
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -106
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/yjs/cursor.ts +0 -22
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -156
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
- /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
3
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
4
5
|
|
|
5
6
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
7
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
8
|
|
|
8
9
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
10
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
11
|
+
import { EditorView as EditorView13 } 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 } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
18
19
|
|
|
19
20
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
21
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
@@ -29,9 +30,11 @@ var autocomplete = ({ onSearch }) => {
|
|
|
29
30
|
// https://codemirror.net/examples/autocompletion
|
|
30
31
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
31
32
|
autocompletion({
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
33
|
+
activateOnTyping: true,
|
|
34
|
+
// closeOnBlur: false,
|
|
35
|
+
// defaultKeymap: false,
|
|
36
|
+
// TODO(burdon): Styles/fragments.
|
|
37
|
+
tooltipClass: () => "shadow rounded"
|
|
35
38
|
}),
|
|
36
39
|
// TODO(burdon): Option to create new page?
|
|
37
40
|
// TODO(burdon): Optional decoration via addToOptions
|
|
@@ -51,13 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
54
58
|
import { StateField } from "@codemirror/state";
|
|
55
|
-
import { ViewPlugin } from "@codemirror/view";
|
|
56
|
-
import { next as
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
57
61
|
|
|
58
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
59
63
|
import get from "lodash.get";
|
|
60
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
61
65
|
var cursorConverter = (handle, path) => ({
|
|
62
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
63
67
|
toCursor: (pos) => {
|
|
@@ -69,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
69
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
70
74
|
return "end";
|
|
71
75
|
}
|
|
72
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
73
77
|
},
|
|
74
78
|
fromCursor: (cursor) => {
|
|
75
79
|
if (cursor === "") {
|
|
@@ -87,29 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
87
91
|
return 0;
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
|
-
import { Annotation, StateEffect
|
|
96
|
-
var effectType = StateEffect.define({});
|
|
97
|
-
var updateHeads = (newHeads) => effectType.of({
|
|
98
|
-
newHeads
|
|
99
|
-
});
|
|
100
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
99
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
101
100
|
var getPath = (state, field) => state.field(field).path;
|
|
102
|
-
var
|
|
103
|
-
var
|
|
104
|
-
var
|
|
105
|
-
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
104
|
+
newHeads
|
|
106
105
|
});
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
107
110
|
|
|
108
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
110
113
|
|
|
111
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
113
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
117
|
const { lastHeads, path } = state.field(field);
|
|
115
118
|
let hasChanges = false;
|
|
@@ -122,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
122
125
|
return void 0;
|
|
123
126
|
}
|
|
124
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
125
129
|
for (const tr of transactions) {
|
|
126
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
127
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
128
136
|
});
|
|
129
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
130
141
|
});
|
|
131
142
|
return newHeads ?? void 0;
|
|
132
143
|
};
|
|
@@ -141,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
141
152
|
selection = selection.map(changeSet, 1);
|
|
142
153
|
view.dispatch({
|
|
143
154
|
changes: changeSet,
|
|
144
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
145
156
|
});
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
view.dispatch({
|
|
149
160
|
selection,
|
|
150
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
151
162
|
});
|
|
152
163
|
};
|
|
153
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -168,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
168
179
|
if (index == null) {
|
|
169
180
|
return [];
|
|
170
181
|
}
|
|
171
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
172
183
|
return [
|
|
173
184
|
{
|
|
174
185
|
from: index,
|
|
@@ -240,59 +251,63 @@ var charPath = (textPath, candidatePath) => {
|
|
|
240
251
|
|
|
241
252
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
253
|
var PatchSemaphore = class {
|
|
243
|
-
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
244
256
|
this._handle = _handle;
|
|
245
|
-
this.
|
|
257
|
+
this._state = _state;
|
|
246
258
|
this._inReconcile = false;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
251
262
|
this._inReconcile = true;
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
let newHeads = updateAutomerge(this._field, this._handle, transactions, view.state);
|
|
266
|
-
if (newHeads === null || newHeads === void 0) {
|
|
267
|
-
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
268
|
-
}
|
|
269
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
270
|
-
updateCodeMirror(view, selection, path, diff);
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
271
276
|
view.dispatch({
|
|
272
|
-
|
|
273
|
-
annotations:
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
274
279
|
});
|
|
275
|
-
|
|
276
|
-
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
277
291
|
}
|
|
278
292
|
};
|
|
279
293
|
|
|
280
294
|
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
281
|
-
import { Facet
|
|
295
|
+
import { Facet } from "@codemirror/state";
|
|
282
296
|
var defaultCursorConverter = {
|
|
283
297
|
toCursor: (position) => position.toString(),
|
|
284
298
|
fromCursor: (cursor) => parseInt(cursor)
|
|
285
299
|
};
|
|
286
|
-
var Cursor = class {
|
|
300
|
+
var Cursor = class _Cursor {
|
|
287
301
|
static {
|
|
288
|
-
this.converter =
|
|
302
|
+
this.converter = Facet.define({
|
|
289
303
|
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
290
304
|
});
|
|
291
305
|
}
|
|
292
306
|
static {
|
|
293
|
-
this.getCursorFromRange = (
|
|
294
|
-
const
|
|
295
|
-
const
|
|
307
|
+
this.getCursorFromRange = (state, range) => {
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
296
311
|
return [
|
|
297
312
|
from,
|
|
298
313
|
to
|
|
@@ -300,10 +315,11 @@ var Cursor = class {
|
|
|
300
315
|
};
|
|
301
316
|
}
|
|
302
317
|
static {
|
|
303
|
-
this.getRangeFromCursor = (
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
304
320
|
const parts = cursor.split(":");
|
|
305
|
-
const from =
|
|
306
|
-
const to =
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
307
323
|
return from !== void 0 && to !== void 0 ? {
|
|
308
324
|
from,
|
|
309
325
|
to
|
|
@@ -313,22 +329,22 @@ var Cursor = class {
|
|
|
313
329
|
};
|
|
314
330
|
|
|
315
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
316
|
-
var
|
|
317
|
-
const
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
318
334
|
create: () => ({
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
322
338
|
}),
|
|
323
339
|
update: (value, tr) => {
|
|
324
340
|
const result = {
|
|
341
|
+
path: path.slice(),
|
|
325
342
|
lastHeads: value.lastHeads,
|
|
326
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
327
|
-
path: path.slice()
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
328
344
|
};
|
|
329
345
|
let clearUnreconciled = false;
|
|
330
346
|
for (const effect of tr.effects) {
|
|
331
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
332
348
|
result.lastHeads = effect.value.newHeads;
|
|
333
349
|
clearUnreconciled = true;
|
|
334
350
|
}
|
|
@@ -336,46 +352,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
336
352
|
if (clearUnreconciled) {
|
|
337
353
|
result.unreconciledTransactions = [];
|
|
338
354
|
} else {
|
|
339
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
340
356
|
result.unreconciledTransactions.push(tr);
|
|
341
357
|
}
|
|
342
358
|
}
|
|
343
359
|
return result;
|
|
344
360
|
}
|
|
345
361
|
});
|
|
346
|
-
const semaphore = new PatchSemaphore(handle,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
363
|
+
return [
|
|
364
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
366
|
+
// Reconcile external updates.
|
|
367
|
+
ViewPlugin.fromClass(class {
|
|
368
|
+
constructor(_view) {
|
|
369
|
+
this._view = _view;
|
|
370
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
destroy() {
|
|
373
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
374
|
+
}
|
|
375
|
+
_handleChange() {
|
|
376
|
+
semaphore.reconcile(this._view);
|
|
377
|
+
}
|
|
378
|
+
}),
|
|
379
|
+
// Reconcile local updates.
|
|
380
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
381
|
+
if (!changes.empty) {
|
|
382
|
+
semaphore.reconcile(view);
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
385
|
+
// TODO(burdon): Record undo transactions.
|
|
386
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
387
|
+
// https://codemirror.net/examples/inverted-effect
|
|
388
|
+
invertedEffects.of((tr) => {
|
|
389
|
+
const effects = [];
|
|
390
|
+
if (!tr.changes.empty) {
|
|
391
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
359
392
|
});
|
|
360
393
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
return {
|
|
367
|
-
extension: [
|
|
368
|
-
Cursor.converter.of(cursorConverter(handle, path)),
|
|
369
|
-
semaphoreFacet.of(semaphore),
|
|
370
|
-
stateField,
|
|
371
|
-
viewPlugin
|
|
372
|
-
]
|
|
373
|
-
};
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
396
|
+
];
|
|
374
397
|
};
|
|
375
398
|
|
|
376
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
377
|
-
import { Annotation as Annotation2, Facet as
|
|
378
|
-
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
400
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
401
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
379
402
|
import { Event } from "@dxos/async";
|
|
380
403
|
import { Context } from "@dxos/context";
|
|
381
404
|
var dummyProvider = {
|
|
@@ -384,17 +407,17 @@ var dummyProvider = {
|
|
|
384
407
|
},
|
|
385
408
|
close: () => {
|
|
386
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
387
411
|
update: () => {
|
|
388
|
-
}
|
|
389
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
390
413
|
};
|
|
391
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
392
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
393
416
|
});
|
|
394
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
395
418
|
var awareness = (provider = dummyProvider) => {
|
|
396
419
|
return [
|
|
397
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
398
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
399
422
|
decorations: (value) => value.decorations
|
|
400
423
|
}),
|
|
@@ -408,7 +431,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
408
431
|
this._lastAnchor = void 0;
|
|
409
432
|
this._lastHead = void 0;
|
|
410
433
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
411
|
-
this._provider = view.state.facet(
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
412
435
|
this._provider.open();
|
|
413
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
414
437
|
view.dispatch({
|
|
@@ -549,7 +572,7 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
549
572
|
return true;
|
|
550
573
|
}
|
|
551
574
|
};
|
|
552
|
-
var styles =
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
553
576
|
".cm-collab-selection": {},
|
|
554
577
|
".cm-collab-selectionLine": {
|
|
555
578
|
padding: 0,
|
|
@@ -562,40 +585,42 @@ var styles = EditorView.baseTheme({
|
|
|
562
585
|
marginLeft: "-1px",
|
|
563
586
|
marginRight: "-1px",
|
|
564
587
|
boxSizing: "border-box",
|
|
565
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
566
590
|
},
|
|
567
591
|
".cm-collab-selectionCaretDot": {
|
|
568
592
|
borderRadius: "50%",
|
|
569
593
|
position: "absolute",
|
|
570
|
-
width: ".
|
|
571
|
-
height: ".
|
|
572
|
-
top: "-.
|
|
573
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
574
598
|
backgroundColor: "inherit",
|
|
575
599
|
transition: "transform .3s ease-in-out",
|
|
576
600
|
boxSizing: "border-box"
|
|
577
601
|
},
|
|
578
602
|
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
579
|
-
|
|
580
|
-
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
581
605
|
},
|
|
582
606
|
".cm-collab-selectionInfo": {
|
|
583
607
|
position: "absolute",
|
|
584
|
-
|
|
585
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
586
611
|
fontSize: ".75em",
|
|
587
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
588
613
|
fontStyle: "normal",
|
|
589
614
|
fontWeight: "normal",
|
|
590
615
|
lineHeight: "normal",
|
|
591
616
|
userSelect: "none",
|
|
592
617
|
color: "white",
|
|
593
|
-
|
|
594
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
595
619
|
zIndex: 101,
|
|
596
620
|
transition: "opacity .3s ease-in-out",
|
|
597
621
|
backgroundColor: "inherit",
|
|
598
|
-
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
599
624
|
opacity: 0,
|
|
600
625
|
transitionDelay: "0s",
|
|
601
626
|
whiteSpace: "nowrap"
|
|
@@ -608,23 +633,26 @@ var styles = EditorView.baseTheme({
|
|
|
608
633
|
|
|
609
634
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
610
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
611
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
612
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
613
|
-
import { drawSelection, EditorView as
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
639
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
617
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
618
644
|
bracketMatching(),
|
|
619
645
|
closeBrackets(),
|
|
620
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
621
649
|
_placeholder && placeholder(_placeholder),
|
|
622
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
623
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
624
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
625
653
|
|
|
626
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
627
|
-
import { EditorView as
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
628
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
629
657
|
import { invariant } from "@dxos/invariant";
|
|
630
658
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
@@ -660,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
660
688
|
const getPoint = (view, pos) => {
|
|
661
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
662
690
|
const element = document.elementFromPoint(x, y);
|
|
663
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
664
692
|
const point = {
|
|
665
693
|
x: x - left,
|
|
666
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
667
695
|
};
|
|
668
696
|
return {
|
|
669
697
|
element,
|
|
@@ -672,7 +700,7 @@ var blast = (options = defaultOptions) => {
|
|
|
672
700
|
};
|
|
673
701
|
return [
|
|
674
702
|
// Cursor moved.
|
|
675
|
-
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
676
704
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
677
705
|
if (blaster) {
|
|
678
706
|
blaster.destroy();
|
|
@@ -755,7 +783,7 @@ var Blaster = class {
|
|
|
755
783
|
initialize() {
|
|
756
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
757
785
|
F: __dxlog_file,
|
|
758
|
-
L:
|
|
786
|
+
L: 141,
|
|
759
787
|
S: this,
|
|
760
788
|
A: [
|
|
761
789
|
"!this._canvas && !this._ctx",
|
|
@@ -792,7 +820,7 @@ var Blaster = class {
|
|
|
792
820
|
start() {
|
|
793
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
794
822
|
F: __dxlog_file,
|
|
795
|
-
L:
|
|
823
|
+
L: 180,
|
|
796
824
|
S: this,
|
|
797
825
|
A: [
|
|
798
826
|
"this._canvas && this._ctx",
|
|
@@ -933,9 +961,14 @@ var random = (min, max) => {
|
|
|
933
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
934
962
|
};
|
|
935
963
|
|
|
936
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
937
|
-
import {
|
|
938
|
-
import {
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
939
972
|
|
|
940
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
941
974
|
import * as random2 from "lib0/random";
|
|
@@ -978,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
978
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
979
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
980
1013
|
var headings = {
|
|
981
|
-
1:
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
991
|
-
"-ml-[7px]"
|
|
992
|
-
],
|
|
993
|
-
4: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
995
|
-
"-ml-[6px]"
|
|
996
|
-
],
|
|
997
|
-
5: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
999
|
-
"-ml-[5px]"
|
|
1000
|
-
],
|
|
1001
|
-
6: [
|
|
1002
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1003
|
-
"-ml-[4px]"
|
|
1004
|
-
]
|
|
1005
|
-
};
|
|
1006
|
-
var heading = (level, readonly) => {
|
|
1007
|
-
const [style, offset] = headings[level];
|
|
1008
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1009
1023
|
};
|
|
1010
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1011
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1023,167 +1037,109 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1023
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1024
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1025
1039
|
|
|
1026
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1027
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1028
|
-
var styles2 = EditorView4.baseTheme({
|
|
1029
|
-
"& .cm-codeblock": {
|
|
1030
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1031
|
-
},
|
|
1032
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1033
|
-
background: getToken("extend.colors.neutral.50")
|
|
1034
|
-
},
|
|
1035
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1036
|
-
background: getToken("extend.colors.neutral.850")
|
|
1037
|
-
},
|
|
1038
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1039
|
-
display: "block",
|
|
1040
|
-
paddingInline: "4px !important"
|
|
1041
|
-
},
|
|
1042
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1043
|
-
paddingTop: "4px !important",
|
|
1044
|
-
borderTopLeftRadius: "4px",
|
|
1045
|
-
borderTopRightRadius: "4px"
|
|
1046
|
-
},
|
|
1047
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1048
|
-
paddingBottom: "4px !important",
|
|
1049
|
-
borderBottomLeftRadius: "4px",
|
|
1050
|
-
borderBottomRightRadius: "4px"
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
var getLineRange = (lines, from, to) => {
|
|
1054
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1055
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1056
|
-
return [
|
|
1057
|
-
start,
|
|
1058
|
-
end
|
|
1059
|
-
];
|
|
1060
|
-
};
|
|
1061
|
-
var code2 = () => {
|
|
1062
|
-
const getDecorations = (view) => {
|
|
1063
|
-
const decorations = [];
|
|
1064
|
-
if (!view.hasFocus || view.state.readOnly) {
|
|
1065
|
-
const text = view.state.doc.sliceString(0);
|
|
1066
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1067
|
-
const blocks = view.viewportLineBlocks;
|
|
1068
|
-
for (const match of matches) {
|
|
1069
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1070
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1071
|
-
const block = blocks[i];
|
|
1072
|
-
decorations.push(Decoration2.line({
|
|
1073
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1074
|
-
}).range(block.from));
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
return Decoration2.set(decorations);
|
|
1079
|
-
};
|
|
1080
|
-
return [
|
|
1081
|
-
ViewPlugin3.fromClass(class {
|
|
1082
|
-
constructor(view) {
|
|
1083
|
-
this.hasFocus = false;
|
|
1084
|
-
this.decorations = getDecorations(view);
|
|
1085
|
-
}
|
|
1086
|
-
update(update2) {
|
|
1087
|
-
if (
|
|
1088
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1089
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1090
|
-
) {
|
|
1091
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1092
|
-
this.decorations = getDecorations(update2.view);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
}, {
|
|
1096
|
-
decorations: (value) => value.decorations
|
|
1097
|
-
}),
|
|
1098
|
-
styles2
|
|
1099
|
-
];
|
|
1100
|
-
};
|
|
1101
|
-
|
|
1102
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1103
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1104
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
1105
|
-
import sortBy from "lodash.sortby";
|
|
1106
|
-
import { debounce } from "@dxos/async";
|
|
1107
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1108
|
-
import { nonNullable } from "@dxos/util";
|
|
1109
|
-
|
|
1110
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1111
1041
|
import { log } from "@dxos/log";
|
|
1112
1042
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1113
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1114
1044
|
try {
|
|
1115
1045
|
return fn(...args);
|
|
1116
|
-
} catch (
|
|
1117
|
-
log.catch(
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1118
1048
|
F: __dxlog_file2,
|
|
1119
|
-
L:
|
|
1049
|
+
L: 18,
|
|
1120
1050
|
S: void 0,
|
|
1121
1051
|
C: (f, a) => f(...a)
|
|
1122
1052
|
});
|
|
1123
1053
|
}
|
|
1124
1054
|
};
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1059
|
+
}
|
|
1060
|
+
const changes2 = [];
|
|
1061
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1062
|
+
fromA,
|
|
1063
|
+
toA,
|
|
1064
|
+
fromB,
|
|
1065
|
+
toB,
|
|
1066
|
+
inserted: inserted.toString()
|
|
1067
|
+
})));
|
|
1068
|
+
return changes2;
|
|
1069
|
+
}).filter(Boolean);
|
|
1070
|
+
if (changes.length) {
|
|
1071
|
+
console.log("changes", changes);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1125
1074
|
|
|
1126
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1127
|
-
var
|
|
1128
|
-
var styles3 = EditorView5.baseTheme({
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1129
1077
|
"& .cm-comment": {
|
|
1130
1078
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1131
1079
|
},
|
|
1132
|
-
"& .cm-comment-
|
|
1080
|
+
"& .cm-comment-current": {
|
|
1133
1081
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1134
1082
|
}
|
|
1135
1083
|
});
|
|
1136
|
-
var
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1146
|
-
if (!range) {
|
|
1084
|
+
var commentMark = Decoration2.mark({
|
|
1085
|
+
class: "cm-comment"
|
|
1086
|
+
});
|
|
1087
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1088
|
+
class: "cm-comment-current"
|
|
1089
|
+
});
|
|
1090
|
+
var focusComment = (view, id, center = true) => {
|
|
1091
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1092
|
+
if (!comment?.comment.cursor) {
|
|
1147
1093
|
return;
|
|
1148
1094
|
}
|
|
1149
|
-
view.
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1095
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1096
|
+
if (range) {
|
|
1097
|
+
view.dispatch({
|
|
1098
|
+
selection: {
|
|
1099
|
+
anchor: range.from
|
|
1100
|
+
},
|
|
1101
|
+
effects: [
|
|
1102
|
+
//
|
|
1103
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1104
|
+
y: "center"
|
|
1105
|
+
} : void 0),
|
|
1106
|
+
setSelection.of({
|
|
1107
|
+
current: id
|
|
1108
|
+
})
|
|
1109
|
+
]
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1158
1112
|
};
|
|
1159
|
-
var
|
|
1113
|
+
var setComments = StateEffect2.define();
|
|
1160
1114
|
var setSelection = StateEffect2.define();
|
|
1161
1115
|
var setCommentState = StateEffect2.define();
|
|
1162
|
-
var
|
|
1116
|
+
var commentsState = StateField2.define({
|
|
1163
1117
|
create: () => ({
|
|
1164
|
-
|
|
1118
|
+
comments: [],
|
|
1119
|
+
selection: {}
|
|
1165
1120
|
}),
|
|
1166
1121
|
update: (value, tr) => {
|
|
1167
|
-
const cursorConverter3 = tr.state.facet(Cursor.converter);
|
|
1168
1122
|
for (const effect of tr.effects) {
|
|
1169
1123
|
if (effect.is(setSelection)) {
|
|
1170
1124
|
return {
|
|
1171
1125
|
...value,
|
|
1172
|
-
|
|
1126
|
+
selection: effect.value
|
|
1173
1127
|
};
|
|
1174
1128
|
}
|
|
1175
|
-
if (effect.is(
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
|
|
1129
|
+
if (effect.is(setComments)) {
|
|
1130
|
+
const comments2 = effect.value.map((comment) => {
|
|
1131
|
+
if (!comment.cursor) {
|
|
1132
|
+
return void 0;
|
|
1133
|
+
}
|
|
1134
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1179
1135
|
return range && {
|
|
1180
|
-
|
|
1181
|
-
|
|
1136
|
+
comment,
|
|
1137
|
+
range
|
|
1182
1138
|
};
|
|
1183
1139
|
}).filter(nonNullable);
|
|
1184
1140
|
return {
|
|
1185
1141
|
...value,
|
|
1186
|
-
|
|
1142
|
+
comments: comments2
|
|
1187
1143
|
};
|
|
1188
1144
|
}
|
|
1189
1145
|
if (effect.is(setCommentState)) {
|
|
@@ -1193,39 +1149,37 @@ var commentsStateField = StateField2.define({
|
|
|
1193
1149
|
return value;
|
|
1194
1150
|
}
|
|
1195
1151
|
});
|
|
1196
|
-
var
|
|
1197
|
-
|
|
1152
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1153
|
+
commentsState
|
|
1198
1154
|
], (state) => {
|
|
1199
|
-
const {
|
|
1200
|
-
const decorations = sortBy(
|
|
1201
|
-
|
|
1155
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1156
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1157
|
+
const range = comment.range;
|
|
1158
|
+
if (!range || range.from === range.to) {
|
|
1159
|
+
console.warn("Invalid range:", range);
|
|
1202
1160
|
return void 0;
|
|
1203
1161
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
to: selection.to
|
|
1207
|
-
};
|
|
1208
|
-
if (selection.id === active) {
|
|
1209
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1162
|
+
if (comment.comment.id === current) {
|
|
1163
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1210
1164
|
} else {
|
|
1211
|
-
return
|
|
1165
|
+
return commentMark.range(range.from, range.to);
|
|
1212
1166
|
}
|
|
1213
|
-
}).filter(nonNullable)
|
|
1214
|
-
return
|
|
1167
|
+
}).filter(nonNullable);
|
|
1168
|
+
return Decoration2.set(decorations);
|
|
1215
1169
|
});
|
|
1216
1170
|
var trackPastedComments = (onUpdate) => {
|
|
1217
1171
|
let tracked = null;
|
|
1218
1172
|
const handleTrack = (event, view) => {
|
|
1219
|
-
const comments2 = view.state.field(
|
|
1173
|
+
const comments2 = view.state.field(commentsState);
|
|
1220
1174
|
const { main } = view.state.selection;
|
|
1221
|
-
const selectedRanges = comments2.
|
|
1175
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1222
1176
|
if (!selectedRanges.length) {
|
|
1223
1177
|
tracked = null;
|
|
1224
1178
|
} else {
|
|
1225
1179
|
tracked = {
|
|
1226
1180
|
text: view.state.doc.slice(main.from, main.to),
|
|
1227
|
-
comments: selectedRanges.map((range) => ({
|
|
1228
|
-
id:
|
|
1181
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1182
|
+
id: comment.id,
|
|
1229
1183
|
from: range.from - main.from,
|
|
1230
1184
|
to: range.to - main.from
|
|
1231
1185
|
}))
|
|
@@ -1237,90 +1191,132 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1237
1191
|
cut: handleTrack,
|
|
1238
1192
|
copy: handleTrack
|
|
1239
1193
|
}),
|
|
1240
|
-
//
|
|
1241
|
-
|
|
1194
|
+
// Track deleted comments.
|
|
1195
|
+
invertedEffects2.of((tr) => {
|
|
1196
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1197
|
+
const effects = [];
|
|
1198
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1199
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1200
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1201
|
+
effects.push(restoreCommentEffect.of({
|
|
1202
|
+
id,
|
|
1203
|
+
from,
|
|
1204
|
+
to
|
|
1205
|
+
}));
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1209
|
+
return effects;
|
|
1210
|
+
}),
|
|
1211
|
+
// Handle paste or the undo of comment deletion.
|
|
1212
|
+
EditorView5.updateListener.of((update2) => {
|
|
1213
|
+
const restore = [];
|
|
1214
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1215
|
+
const tr = update2.transactions[i];
|
|
1216
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1217
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1218
|
+
}
|
|
1219
|
+
for (const effect of tr.effects) {
|
|
1220
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1221
|
+
restore.push(effect.value);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1242
1225
|
if (tracked) {
|
|
1243
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1226
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1244
1227
|
if (paste) {
|
|
1245
1228
|
let found = -1;
|
|
1246
1229
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1247
1230
|
if (text.eq(tracked.text)) {
|
|
1248
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1249
|
-
fromB = transactions[i].changes.mapPos(fromB);
|
|
1231
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1232
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1250
1233
|
}
|
|
1251
1234
|
found = fromB;
|
|
1252
1235
|
}
|
|
1253
1236
|
});
|
|
1254
1237
|
if (found > -1) {
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
from: found + moved.from,
|
|
1262
|
-
to: found + moved.to
|
|
1263
|
-
};
|
|
1264
|
-
const cursor = Cursor.getCursorFromRange(state.facet(Cursor.converter), range);
|
|
1265
|
-
onUpdate(moved.id, cursor);
|
|
1266
|
-
}
|
|
1238
|
+
for (const moved of tracked.comments) {
|
|
1239
|
+
restore.push({
|
|
1240
|
+
id: moved.id,
|
|
1241
|
+
from: found + moved.from,
|
|
1242
|
+
to: found + moved.to
|
|
1243
|
+
});
|
|
1267
1244
|
}
|
|
1268
1245
|
}
|
|
1269
1246
|
tracked = null;
|
|
1270
1247
|
}
|
|
1271
1248
|
}
|
|
1249
|
+
for (const comment of restore) {
|
|
1250
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1251
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1252
|
+
if (!exists) {
|
|
1253
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1254
|
+
onUpdate(comment.id, cursor);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1272
1257
|
})
|
|
1273
1258
|
];
|
|
1274
1259
|
};
|
|
1260
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1261
|
+
id: comment.id,
|
|
1262
|
+
from: changes.mapPos(comment.from, 1),
|
|
1263
|
+
to: changes.mapPos(comment.to, 1)
|
|
1264
|
+
});
|
|
1265
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1266
|
+
map: mapTrackedComment
|
|
1267
|
+
});
|
|
1268
|
+
var optionsFacet = Facet3.define({
|
|
1269
|
+
combine: (providers) => providers[0]
|
|
1270
|
+
});
|
|
1271
|
+
var createComment = (view) => {
|
|
1272
|
+
const options = view.state.facet(optionsFacet);
|
|
1273
|
+
const { from, to } = view.state.selection.main;
|
|
1274
|
+
if (from === to) {
|
|
1275
|
+
return false;
|
|
1276
|
+
}
|
|
1277
|
+
if (to === view.state.doc.length) {
|
|
1278
|
+
view.dispatch({
|
|
1279
|
+
changes: {
|
|
1280
|
+
from: to,
|
|
1281
|
+
insert: "\n"
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1286
|
+
from,
|
|
1287
|
+
to
|
|
1288
|
+
});
|
|
1289
|
+
if (cursor) {
|
|
1290
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1291
|
+
if (id) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
effects: setSelection.of({
|
|
1294
|
+
current: id
|
|
1295
|
+
}),
|
|
1296
|
+
selection: {
|
|
1297
|
+
anchor: to
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
return true;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return false;
|
|
1304
|
+
};
|
|
1275
1305
|
var comments = (options = {}) => {
|
|
1276
1306
|
const { key: shortcut = "meta-'" } = options;
|
|
1277
1307
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1278
|
-
const createCommentThread = (view) => {
|
|
1279
|
-
const cursorConverter3 = view.state.facet(Cursor.converter);
|
|
1280
|
-
invariant2(options.onCreate, void 0, {
|
|
1281
|
-
F: __dxlog_file3,
|
|
1282
|
-
L: 262,
|
|
1283
|
-
S: void 0,
|
|
1284
|
-
A: [
|
|
1285
|
-
"options.onCreate",
|
|
1286
|
-
""
|
|
1287
|
-
]
|
|
1288
|
-
});
|
|
1289
|
-
const { from, to } = view.state.selection.main;
|
|
1290
|
-
if (from === to) {
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
const cursor = Cursor.getCursorFromRange(cursorConverter3, {
|
|
1294
|
-
from,
|
|
1295
|
-
to
|
|
1296
|
-
});
|
|
1297
|
-
if (cursor) {
|
|
1298
|
-
const id = callbackWrapper(options.onCreate)(cursor, view.coordsAtPos(from));
|
|
1299
|
-
if (id) {
|
|
1300
|
-
view.dispatch({
|
|
1301
|
-
effects: setSelection.of({
|
|
1302
|
-
active: id
|
|
1303
|
-
}),
|
|
1304
|
-
selection: {
|
|
1305
|
-
anchor: from
|
|
1306
|
-
}
|
|
1307
|
-
});
|
|
1308
|
-
return true;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
return false;
|
|
1312
|
-
};
|
|
1313
1308
|
return [
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1309
|
+
optionsFacet.of(options),
|
|
1310
|
+
commentsState,
|
|
1311
|
+
commentsDecorations,
|
|
1312
|
+
styles2,
|
|
1317
1313
|
//
|
|
1318
1314
|
// Keymap.
|
|
1319
1315
|
//
|
|
1320
1316
|
options.onCreate ? keymap3.of([
|
|
1321
1317
|
{
|
|
1322
1318
|
key: shortcut,
|
|
1323
|
-
run: callbackWrapper(
|
|
1319
|
+
run: callbackWrapper(createComment)
|
|
1324
1320
|
}
|
|
1325
1321
|
]) : [],
|
|
1326
1322
|
//
|
|
@@ -1336,7 +1332,7 @@ var comments = (options = {}) => {
|
|
|
1336
1332
|
above: true,
|
|
1337
1333
|
create: () => {
|
|
1338
1334
|
const el = document.createElement("div");
|
|
1339
|
-
options.onHover
|
|
1335
|
+
options.onHover(el, shortcut);
|
|
1340
1336
|
return {
|
|
1341
1337
|
dom: el,
|
|
1342
1338
|
offset: {
|
|
@@ -1349,358 +1345,116 @@ var comments = (options = {}) => {
|
|
|
1349
1345
|
}
|
|
1350
1346
|
return null;
|
|
1351
1347
|
}, {
|
|
1352
|
-
|
|
1348
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1349
|
+
// hideOnChange: true,
|
|
1353
1350
|
hoverTime: 1e3
|
|
1354
1351
|
}) : [],
|
|
1355
1352
|
//
|
|
1356
|
-
//
|
|
1357
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1353
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1358
1354
|
//
|
|
1359
1355
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1360
|
-
|
|
1361
|
-
{
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
if (
|
|
1367
|
-
|
|
1368
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1369
|
-
options.onDelete?.(range.id);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
if (from <= range.to) {
|
|
1373
|
-
const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1374
|
-
Object.assign(range, newRange);
|
|
1375
|
-
mod = true;
|
|
1356
|
+
let mod = false;
|
|
1357
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1358
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1359
|
+
comments2.forEach(({ comment, range }) => {
|
|
1360
|
+
if (from2 === to2) {
|
|
1361
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1362
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1363
|
+
options.onDelete?.(comment.id);
|
|
1376
1364
|
}
|
|
1377
|
-
}
|
|
1365
|
+
}
|
|
1366
|
+
if (from <= range.to) {
|
|
1367
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1368
|
+
Object.assign(range, newRange);
|
|
1369
|
+
mod = true;
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
});
|
|
1373
|
+
if (mod) {
|
|
1374
|
+
view.dispatch({
|
|
1375
|
+
effects: setCommentState.of({
|
|
1376
|
+
comments: comments2,
|
|
1377
|
+
...value
|
|
1378
|
+
})
|
|
1378
1379
|
});
|
|
1379
|
-
if (mod) {
|
|
1380
|
-
view.dispatch({
|
|
1381
|
-
effects: setCommentState.of({
|
|
1382
|
-
active,
|
|
1383
|
-
ranges
|
|
1384
|
-
})
|
|
1385
|
-
});
|
|
1386
|
-
}
|
|
1387
1380
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1381
|
+
}),
|
|
1382
|
+
//
|
|
1383
|
+
// Track selection/proximity.
|
|
1384
|
+
//
|
|
1385
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1386
|
+
let min = Infinity;
|
|
1387
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1388
|
+
const { head } = state.selection.main;
|
|
1389
|
+
const selection = {};
|
|
1390
|
+
comments2.forEach(({ comment, range }) => {
|
|
1391
|
+
if (head >= range.from && head <= range.to) {
|
|
1392
|
+
selection.current = comment.id;
|
|
1393
|
+
selection.closest = void 0;
|
|
1394
|
+
}
|
|
1395
|
+
if (!selection.current) {
|
|
1396
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1401
1397
|
if (d < min) {
|
|
1402
|
-
|
|
1398
|
+
selection.closest = comment.id;
|
|
1403
1399
|
min = d;
|
|
1404
1400
|
}
|
|
1405
|
-
});
|
|
1406
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1407
|
-
view.dispatch({
|
|
1408
|
-
effects: setSelection.of(selected)
|
|
1409
|
-
});
|
|
1410
|
-
handleSelect({
|
|
1411
|
-
...selected,
|
|
1412
|
-
ranges: ranges.map((range) => ({
|
|
1413
|
-
...range,
|
|
1414
|
-
location: view.coordsAtPos(range.from)
|
|
1415
|
-
}))
|
|
1416
|
-
});
|
|
1417
1401
|
}
|
|
1402
|
+
});
|
|
1403
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1404
|
+
view.dispatch({
|
|
1405
|
+
effects: setSelection.of(selection)
|
|
1406
|
+
});
|
|
1407
|
+
handleSelect({
|
|
1408
|
+
selection,
|
|
1409
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1410
|
+
comment,
|
|
1411
|
+
range,
|
|
1412
|
+
location: view.coordsAtPos(range.from)
|
|
1413
|
+
}))
|
|
1414
|
+
});
|
|
1418
1415
|
}
|
|
1419
1416
|
}),
|
|
1420
1417
|
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1421
1418
|
];
|
|
1422
1419
|
};
|
|
1420
|
+
var useComments = (view, comments2 = []) => {
|
|
1421
|
+
useEffect(() => {
|
|
1422
|
+
if (view) {
|
|
1423
|
+
view.dispatch({
|
|
1424
|
+
effects: setComments.of(comments2)
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
}, [
|
|
1428
|
+
view,
|
|
1429
|
+
comments2
|
|
1430
|
+
]);
|
|
1431
|
+
};
|
|
1423
1432
|
|
|
1424
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1425
|
-
import {
|
|
1426
|
-
var
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
this._pos = _pos;
|
|
1437
|
-
}
|
|
1438
|
-
eq(other) {
|
|
1439
|
-
return this._pos === other._pos;
|
|
1440
|
-
}
|
|
1441
|
-
toDOM(view) {
|
|
1442
|
-
const el = document.createElement("div");
|
|
1443
|
-
el.className = "cm-hr";
|
|
1444
|
-
return el;
|
|
1445
|
-
}
|
|
1446
|
-
};
|
|
1447
|
-
var placeholderMatcher = new MatchDecorator({
|
|
1448
|
-
regexp: /^---$/g,
|
|
1449
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1450
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1451
|
-
})
|
|
1452
|
-
});
|
|
1453
|
-
var hr = () => [
|
|
1454
|
-
styles4,
|
|
1455
|
-
ViewPlugin4.fromClass(class {
|
|
1456
|
-
constructor(view) {
|
|
1457
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1458
|
-
}
|
|
1459
|
-
update(update2) {
|
|
1460
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1461
|
-
}
|
|
1462
|
-
}, {
|
|
1463
|
-
decorations: (instance) => instance.rules,
|
|
1464
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1465
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1466
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1467
|
-
})
|
|
1468
|
-
})
|
|
1469
|
-
];
|
|
1470
|
-
|
|
1471
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1472
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1473
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1474
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1475
|
-
var image = (options = {}) => {
|
|
1476
|
-
return StateField3.define({
|
|
1477
|
-
create: (state) => {
|
|
1478
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1479
|
-
},
|
|
1480
|
-
update: (value, tr) => {
|
|
1481
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1482
|
-
return value;
|
|
1483
|
-
}
|
|
1484
|
-
const cursor = tr.state.selection.main.head;
|
|
1485
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1486
|
-
let from = Math.min(cursor, oldCursor);
|
|
1487
|
-
let to = Math.max(cursor, oldCursor);
|
|
1488
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1489
|
-
from = Math.min(from, fromB);
|
|
1490
|
-
to = Math.max(to, toB);
|
|
1491
|
-
});
|
|
1492
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1493
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1494
|
-
return value.map(tr.changes).update({
|
|
1495
|
-
filterFrom: from,
|
|
1496
|
-
filterTo: to,
|
|
1497
|
-
filter: () => false,
|
|
1498
|
-
add: buildDecorations(from, to, tr.state)
|
|
1499
|
-
});
|
|
1500
|
-
},
|
|
1501
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1502
|
-
});
|
|
1503
|
-
};
|
|
1504
|
-
var buildDecorations = (from, to, state) => {
|
|
1505
|
-
const decorations = [];
|
|
1506
|
-
const cursor = state.selection.main.head;
|
|
1507
|
-
syntaxTree(state).iterate({
|
|
1508
|
-
enter: (node) => {
|
|
1509
|
-
if (node.name === "Image") {
|
|
1510
|
-
const urlNode = node.node.getChild("URL");
|
|
1511
|
-
if (urlNode) {
|
|
1512
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1513
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1514
|
-
decorations.push(Decoration5.replace({
|
|
1515
|
-
block: true,
|
|
1516
|
-
widget: new ImageWidget(url)
|
|
1517
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
},
|
|
1521
|
-
from,
|
|
1522
|
-
to
|
|
1523
|
-
});
|
|
1524
|
-
return decorations;
|
|
1525
|
-
};
|
|
1526
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1527
|
-
constructor(_url) {
|
|
1528
|
-
super();
|
|
1529
|
-
this._url = _url;
|
|
1530
|
-
}
|
|
1531
|
-
eq(other) {
|
|
1532
|
-
return this._url === other._url;
|
|
1533
|
-
}
|
|
1534
|
-
toDOM(view) {
|
|
1535
|
-
const img = document.createElement("img");
|
|
1536
|
-
img.setAttribute("src", this._url);
|
|
1537
|
-
img.setAttribute("class", "cm-image");
|
|
1538
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1539
|
-
return img;
|
|
1540
|
-
}
|
|
1541
|
-
};
|
|
1542
|
-
|
|
1543
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1544
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1545
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1546
|
-
import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1547
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1548
|
-
var link = (options = {}) => {
|
|
1549
|
-
const extensions = [
|
|
1550
|
-
ViewPlugin5.fromClass(class {
|
|
1551
|
-
constructor(view) {
|
|
1552
|
-
this.decorations = buildDecorations2(view, options);
|
|
1553
|
-
}
|
|
1554
|
-
update(update2) {
|
|
1555
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1556
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
}, {
|
|
1560
|
-
decorations: (v) => v.decorations
|
|
1561
|
-
})
|
|
1562
|
-
];
|
|
1563
|
-
if (options.onHover) {
|
|
1564
|
-
extensions.push(
|
|
1565
|
-
// https://codemirror.net/examples/tooltip
|
|
1566
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1567
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1568
|
-
hoverTooltip2((view, pos, side) => {
|
|
1569
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1570
|
-
let link2 = null;
|
|
1571
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1572
|
-
link2 = node.name === "Link" ? node : null;
|
|
1573
|
-
}
|
|
1574
|
-
const url = link2 && link2.getChild("URL");
|
|
1575
|
-
if (!url || !link2) {
|
|
1576
|
-
return null;
|
|
1577
|
-
}
|
|
1578
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1579
|
-
return {
|
|
1580
|
-
pos: link2.from,
|
|
1581
|
-
end: link2.to,
|
|
1582
|
-
above: true,
|
|
1583
|
-
create: () => {
|
|
1584
|
-
const el = document.createElement("div");
|
|
1585
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1586
|
-
options.onHover(el, urlText);
|
|
1587
|
-
return {
|
|
1588
|
-
dom: el,
|
|
1589
|
-
offset: {
|
|
1590
|
-
x: 0,
|
|
1591
|
-
y: 4
|
|
1592
|
-
}
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1596
|
-
})
|
|
1597
|
-
);
|
|
1598
|
-
}
|
|
1599
|
-
return extensions;
|
|
1600
|
-
};
|
|
1601
|
-
var LinkButton = class extends WidgetType4 {
|
|
1602
|
-
constructor(_url, _onAttach) {
|
|
1603
|
-
super();
|
|
1604
|
-
this._url = _url;
|
|
1605
|
-
this._onAttach = _onAttach;
|
|
1606
|
-
}
|
|
1607
|
-
eq(other) {
|
|
1608
|
-
return this._url === other._url;
|
|
1609
|
-
}
|
|
1610
|
-
toDOM(view) {
|
|
1611
|
-
const el = document.createElement("span");
|
|
1612
|
-
this._onAttach(el, this._url);
|
|
1613
|
-
return el;
|
|
1614
|
-
}
|
|
1615
|
-
};
|
|
1616
|
-
var LinkText = class extends WidgetType4 {
|
|
1617
|
-
constructor(_text, _url) {
|
|
1618
|
-
super();
|
|
1619
|
-
this._text = _text;
|
|
1620
|
-
this._url = _url;
|
|
1621
|
-
}
|
|
1622
|
-
eq(other) {
|
|
1623
|
-
return this._url === other._url;
|
|
1624
|
-
}
|
|
1625
|
-
toDOM(view) {
|
|
1626
|
-
const link2 = document.createElement("a");
|
|
1627
|
-
link2.setAttribute("class", "cm-link");
|
|
1628
|
-
link2.textContent = this._text;
|
|
1629
|
-
if (this._url) {
|
|
1630
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1631
|
-
link2.setAttribute("target", "_blank");
|
|
1632
|
-
link2.href = this._url;
|
|
1633
|
-
} else {
|
|
1634
|
-
link2.onclick = () => {
|
|
1635
|
-
view.dispatch({
|
|
1636
|
-
selection: {
|
|
1637
|
-
anchor: view.posAtDOM(link2)
|
|
1638
|
-
}
|
|
1639
|
-
});
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
return link2;
|
|
1643
|
-
}
|
|
1644
|
-
};
|
|
1645
|
-
var buildDecorations2 = (view, options) => {
|
|
1646
|
-
const builder = new RangeSetBuilder();
|
|
1647
|
-
const { state } = view;
|
|
1648
|
-
const cursor = state.selection.main.head;
|
|
1649
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1650
|
-
syntaxTree2(state).iterate({
|
|
1651
|
-
enter: (node) => {
|
|
1652
|
-
if (node.name === "Link") {
|
|
1653
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1654
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1655
|
-
const urlNode = node.node.getChild("URL");
|
|
1656
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1657
|
-
if (!url) {
|
|
1658
|
-
return false;
|
|
1659
|
-
}
|
|
1660
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1661
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1662
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1663
|
-
}));
|
|
1664
|
-
}
|
|
1665
|
-
if (options.onRender) {
|
|
1666
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1667
|
-
widget: new LinkButton(url, options.onRender)
|
|
1668
|
-
}));
|
|
1669
|
-
}
|
|
1670
|
-
return false;
|
|
1671
|
-
}
|
|
1672
|
-
},
|
|
1673
|
-
from,
|
|
1674
|
-
to
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1677
|
-
return builder.finish();
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1681
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1682
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1683
|
-
const extensions = [];
|
|
1684
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1685
|
-
onFocus(focused);
|
|
1686
|
-
return null;
|
|
1687
|
-
}));
|
|
1688
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1689
|
-
onChange(update2.state.doc.toString());
|
|
1690
|
-
}));
|
|
1691
|
-
return extensions;
|
|
1433
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1434
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1435
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1436
|
+
const extensions = [];
|
|
1437
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1438
|
+
onFocus(focused);
|
|
1439
|
+
return null;
|
|
1440
|
+
}));
|
|
1441
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1442
|
+
onChange(update2.state.doc.toString());
|
|
1443
|
+
}));
|
|
1444
|
+
return extensions;
|
|
1692
1445
|
};
|
|
1693
1446
|
|
|
1694
1447
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1695
1448
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1696
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1449
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1697
1450
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1698
1451
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1699
1452
|
import { languages } from "@codemirror/language-data";
|
|
1700
1453
|
import { searchKeymap } from "@codemirror/search";
|
|
1701
1454
|
import { EditorState } from "@codemirror/state";
|
|
1702
1455
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1703
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1456
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1457
|
+
import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1704
1458
|
|
|
1705
1459
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1706
1460
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1797,7 +1551,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1797
1551
|
markdownTags.QuoteMark,
|
|
1798
1552
|
markdownTags.EmphasisMark
|
|
1799
1553
|
],
|
|
1800
|
-
class:
|
|
1554
|
+
class: mark
|
|
1801
1555
|
},
|
|
1802
1556
|
// E.g., code block language (after ```).
|
|
1803
1557
|
{
|
|
@@ -1805,7 +1559,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1805
1559
|
tags.function(tags.variableName),
|
|
1806
1560
|
tags.labelName
|
|
1807
1561
|
],
|
|
1808
|
-
class:
|
|
1562
|
+
class: codeMark
|
|
1809
1563
|
},
|
|
1810
1564
|
{
|
|
1811
1565
|
tag: [
|
|
@@ -1816,27 +1570,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1816
1570
|
// Headings.
|
|
1817
1571
|
{
|
|
1818
1572
|
tag: tags.heading1,
|
|
1819
|
-
class: heading(1
|
|
1573
|
+
class: heading(1)
|
|
1820
1574
|
},
|
|
1821
1575
|
{
|
|
1822
1576
|
tag: tags.heading2,
|
|
1823
|
-
class: heading(2
|
|
1577
|
+
class: heading(2)
|
|
1824
1578
|
},
|
|
1825
1579
|
{
|
|
1826
1580
|
tag: tags.heading3,
|
|
1827
|
-
class: heading(3
|
|
1581
|
+
class: heading(3)
|
|
1828
1582
|
},
|
|
1829
1583
|
{
|
|
1830
1584
|
tag: tags.heading4,
|
|
1831
|
-
class: heading(4
|
|
1585
|
+
class: heading(4)
|
|
1832
1586
|
},
|
|
1833
1587
|
{
|
|
1834
1588
|
tag: tags.heading5,
|
|
1835
|
-
class: heading(5
|
|
1589
|
+
class: heading(5)
|
|
1836
1590
|
},
|
|
1837
1591
|
{
|
|
1838
1592
|
tag: tags.heading6,
|
|
1839
|
-
class: heading(6
|
|
1593
|
+
class: heading(6)
|
|
1840
1594
|
},
|
|
1841
1595
|
// Emphasis.
|
|
1842
1596
|
{
|
|
@@ -1862,7 +1616,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1862
1616
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1863
1617
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1864
1618
|
// the code, but all other CSS properties will be inherited.
|
|
1865
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1619
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1866
1620
|
{
|
|
1867
1621
|
tag: [
|
|
1868
1622
|
markdownTags.CodeText,
|
|
@@ -1891,19 +1645,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1891
1645
|
};
|
|
1892
1646
|
|
|
1893
1647
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1894
|
-
var
|
|
1648
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1895
1649
|
return [
|
|
1650
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1896
1651
|
EditorState.allowMultipleSelections.of(true),
|
|
1897
1652
|
EditorState.tabSize.of(2),
|
|
1898
|
-
|
|
1899
|
-
customKeymap(),
|
|
1653
|
+
// https://github.com/codemirror/basic-setup
|
|
1900
1654
|
bracketMatching2(),
|
|
1901
1655
|
closeBrackets2(),
|
|
1902
1656
|
crosshairCursor(),
|
|
1903
1657
|
dropCursor(),
|
|
1904
1658
|
drawSelection2(),
|
|
1905
|
-
|
|
1906
|
-
|
|
1659
|
+
highlightActiveLine2(),
|
|
1660
|
+
history2(),
|
|
1907
1661
|
indentOnInput(),
|
|
1908
1662
|
_placeholder && placeholder2(_placeholder),
|
|
1909
1663
|
// Main extension.
|
|
@@ -1927,58 +1681,602 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1927
1681
|
// https://github.com/codemirror/theme-one-dark
|
|
1928
1682
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1929
1683
|
// Custom styles.
|
|
1930
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1684
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1685
|
+
keymap4.of([
|
|
1686
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1687
|
+
indentWithTab,
|
|
1688
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1689
|
+
...closeBracketsKeymap,
|
|
1690
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1691
|
+
...historyKeymap,
|
|
1692
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1693
|
+
...searchKeymap,
|
|
1694
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1695
|
+
...standardKeymap
|
|
1696
|
+
])
|
|
1697
|
+
].filter(isNotFalsy2);
|
|
1698
|
+
};
|
|
1945
1699
|
|
|
1946
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1947
|
-
import {
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1700
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1701
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1702
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1703
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1704
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1705
|
+
var styles3 = EditorView8.baseTheme({
|
|
1706
|
+
"& .cm-code": {
|
|
1707
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1708
|
+
},
|
|
1709
|
+
"& .cm-codeblock": {
|
|
1710
|
+
width: "100%",
|
|
1711
|
+
paddingInline: "1rem !important",
|
|
1712
|
+
position: "relative",
|
|
1713
|
+
"&::after": {
|
|
1714
|
+
content: '""',
|
|
1715
|
+
position: "absolute",
|
|
1716
|
+
inset: 0
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
"&light .cm-codeblock": {
|
|
1720
|
+
"&::after": {
|
|
1721
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1722
|
+
mixBlendMode: "darken"
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
"&dark .cm-codeblock": {
|
|
1726
|
+
"&::after": {
|
|
1727
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1728
|
+
mixBlendMode: "lighten"
|
|
1729
|
+
}
|
|
1730
|
+
},
|
|
1731
|
+
"& .cm-codeblock-first": {
|
|
1732
|
+
display: "inline-block",
|
|
1733
|
+
"&::after": {
|
|
1734
|
+
borderTopLeftRadius: ".5rem",
|
|
1735
|
+
borderTopRightRadius: ".5rem"
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
"& .cm-codeblock-last": {
|
|
1739
|
+
display: "inline-block",
|
|
1740
|
+
"&::after": {
|
|
1741
|
+
borderBottomLeftRadius: ".5rem",
|
|
1742
|
+
borderBottomRightRadius: ".5rem"
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
});
|
|
1746
|
+
var getLineRange = (lines, from, to) => {
|
|
1747
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1748
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1749
|
+
return [
|
|
1750
|
+
start,
|
|
1751
|
+
end
|
|
1752
|
+
];
|
|
1753
|
+
};
|
|
1754
|
+
var LineWidget = class extends WidgetType2 {
|
|
1755
|
+
constructor(_className) {
|
|
1756
|
+
super();
|
|
1757
|
+
this._className = _className;
|
|
1758
|
+
}
|
|
1759
|
+
toDOM() {
|
|
1760
|
+
const el = document.createElement("span");
|
|
1761
|
+
el.innerHTML = " ";
|
|
1762
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1763
|
+
return el;
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1767
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1768
|
+
var buildDecorations = (view) => {
|
|
1769
|
+
const builder = new RangeSetBuilder();
|
|
1770
|
+
const { state } = view;
|
|
1771
|
+
const blocks = view.viewportLineBlocks;
|
|
1772
|
+
const cursor = state.selection.main.head;
|
|
1773
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1774
|
+
syntaxTree(state).iterate({
|
|
1775
|
+
enter: (node) => {
|
|
1776
|
+
if (node.name === "FencedCode") {
|
|
1777
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1778
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1779
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1780
|
+
const block = blocks[i];
|
|
1781
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1782
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1783
|
+
widget: i === range[0] ? top : bottom
|
|
1784
|
+
}));
|
|
1785
|
+
} else {
|
|
1786
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1787
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1788
|
+
}));
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1956
1791
|
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1792
|
+
},
|
|
1793
|
+
from,
|
|
1794
|
+
to
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
return builder.finish();
|
|
1798
|
+
};
|
|
1799
|
+
var code2 = () => {
|
|
1800
|
+
return [
|
|
1801
|
+
ViewPlugin3.fromClass(class {
|
|
1802
|
+
constructor(view) {
|
|
1803
|
+
this.decorations = buildDecorations(view);
|
|
1964
1804
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1805
|
+
update(update2) {
|
|
1806
|
+
this.decorations = buildDecorations(update2.view);
|
|
1807
|
+
}
|
|
1808
|
+
}, {
|
|
1809
|
+
decorations: (value) => value.decorations
|
|
1810
|
+
}),
|
|
1811
|
+
styles3
|
|
1812
|
+
];
|
|
1967
1813
|
};
|
|
1968
1814
|
|
|
1969
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1970
|
-
import {
|
|
1971
|
-
import {
|
|
1972
|
-
import {
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1815
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1816
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1817
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1818
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1819
|
+
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1820
|
+
var setHeading = (level) => (view) => {
|
|
1821
|
+
const { selection: { ranges }, doc } = view.state;
|
|
1822
|
+
const changes = [];
|
|
1823
|
+
for (const range of ranges) {
|
|
1824
|
+
const { number } = doc.lineAt(range.anchor);
|
|
1825
|
+
const { from, to } = doc.line(number);
|
|
1826
|
+
const line = doc.sliceString(from, to);
|
|
1827
|
+
const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
|
|
1828
|
+
const current = marks?.length ?? 0;
|
|
1829
|
+
if (level !== current) {
|
|
1830
|
+
changes.push({
|
|
1831
|
+
from,
|
|
1832
|
+
to: from + current + (spaces?.length ?? 0),
|
|
1833
|
+
insert: "#".repeat(level) + (level > 0 ? " " : "")
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
if (changes.length) {
|
|
1838
|
+
view.dispatch({
|
|
1839
|
+
changes
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
return true;
|
|
1843
|
+
};
|
|
1844
|
+
var toggleStyle = (mark2) => (view) => {
|
|
1845
|
+
const { ranges } = view.state.selection;
|
|
1846
|
+
for (const range of ranges) {
|
|
1847
|
+
if (range.from === range.to) {
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
view.dispatch({
|
|
1851
|
+
changes: [
|
|
1852
|
+
{
|
|
1853
|
+
from: range.from,
|
|
1854
|
+
insert: mark2
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
from: range.to,
|
|
1858
|
+
insert: mark2
|
|
1859
|
+
}
|
|
1860
|
+
]
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
return true;
|
|
1864
|
+
};
|
|
1865
|
+
var snippets = {
|
|
1866
|
+
codeblock: snippet([
|
|
1867
|
+
"```#{lang}",
|
|
1868
|
+
" #{}",
|
|
1869
|
+
"```"
|
|
1870
|
+
].join("\n")),
|
|
1871
|
+
table: snippet([
|
|
1872
|
+
"| #{col1} | #{col2} |",
|
|
1873
|
+
"| ---- | ---- |",
|
|
1874
|
+
"| #{val1} | #{val2} |",
|
|
1875
|
+
"| #{val3} | #{val4} |"
|
|
1876
|
+
].join("\n"))
|
|
1877
|
+
};
|
|
1878
|
+
var insertCodeblock = (view) => {
|
|
1879
|
+
const { selection: { main }, doc } = view.state;
|
|
1880
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1881
|
+
const { from } = doc.line(number);
|
|
1882
|
+
snippets.codeblock(view, null, from, from);
|
|
1883
|
+
};
|
|
1884
|
+
var insertTable = (view) => {
|
|
1885
|
+
const { selection: { main }, doc } = view.state;
|
|
1886
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1887
|
+
const { from } = doc.line(number);
|
|
1888
|
+
snippets.table(view, null, from, from);
|
|
1889
|
+
};
|
|
1890
|
+
var toggleBold = toggleStyle("**");
|
|
1891
|
+
var toggleItalic = toggleStyle("_");
|
|
1892
|
+
var toggleStrikethrough = toggleStyle("~~");
|
|
1893
|
+
var toggleList = (view) => {
|
|
1894
|
+
};
|
|
1895
|
+
var formatting = (options = {}) => {
|
|
1896
|
+
return [
|
|
1897
|
+
keymap5.of([
|
|
1898
|
+
{
|
|
1899
|
+
key: "meta-b",
|
|
1900
|
+
run: toggleBold
|
|
1901
|
+
}
|
|
1902
|
+
]),
|
|
1903
|
+
styling()
|
|
1904
|
+
];
|
|
1905
|
+
};
|
|
1906
|
+
var styling = () => {
|
|
1907
|
+
const buildDecorations7 = (view) => {
|
|
1908
|
+
const builder = new RangeSetBuilder2();
|
|
1909
|
+
const { state } = view;
|
|
1910
|
+
const cursor = state.selection.main.head;
|
|
1911
|
+
const replace = (node, marks) => {
|
|
1912
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1913
|
+
for (const mark2 of marks) {
|
|
1914
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1919
|
+
syntaxTree2(state).iterate({
|
|
1920
|
+
enter: (node) => {
|
|
1921
|
+
switch (node.name) {
|
|
1922
|
+
case "Emphasis":
|
|
1923
|
+
case "StrongEmphasis": {
|
|
1924
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
1925
|
+
replace(node, marks);
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
case "Strikethrough": {
|
|
1929
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
1930
|
+
replace(node, marks);
|
|
1931
|
+
break;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
},
|
|
1935
|
+
from,
|
|
1936
|
+
to
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
return builder.finish();
|
|
1940
|
+
};
|
|
1941
|
+
return [
|
|
1942
|
+
ViewPlugin4.fromClass(class {
|
|
1943
|
+
constructor(view) {
|
|
1944
|
+
this.decorations = buildDecorations7(view);
|
|
1945
|
+
}
|
|
1946
|
+
update(update2) {
|
|
1947
|
+
this.decorations = buildDecorations7(update2.view);
|
|
1948
|
+
}
|
|
1949
|
+
}, {
|
|
1950
|
+
decorations: (value) => value.decorations
|
|
1951
|
+
})
|
|
1952
|
+
];
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1956
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1957
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1958
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1959
|
+
var buildDecorations2 = (view) => {
|
|
1960
|
+
const builder = new RangeSetBuilder3();
|
|
1961
|
+
const { state } = view;
|
|
1962
|
+
const cursor = state.selection.main.head;
|
|
1963
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1964
|
+
syntaxTree3(state).iterate({
|
|
1965
|
+
enter: (node) => {
|
|
1966
|
+
switch (node.name) {
|
|
1967
|
+
case "ATXHeading1":
|
|
1968
|
+
case "ATXHeading2":
|
|
1969
|
+
case "ATXHeading3":
|
|
1970
|
+
case "ATXHeading4":
|
|
1971
|
+
case "ATXHeading5":
|
|
1972
|
+
case "ATXHeading6": {
|
|
1973
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1974
|
+
if (mark2) {
|
|
1975
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1976
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
from,
|
|
1983
|
+
to
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
return builder.finish();
|
|
1987
|
+
};
|
|
1988
|
+
var heading2 = () => {
|
|
1989
|
+
return [
|
|
1990
|
+
ViewPlugin5.fromClass(class {
|
|
1991
|
+
constructor(view) {
|
|
1992
|
+
this.decorations = buildDecorations2(view);
|
|
1993
|
+
}
|
|
1994
|
+
update(update2) {
|
|
1995
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1996
|
+
}
|
|
1997
|
+
}, {
|
|
1998
|
+
decorations: (value) => value.decorations
|
|
1999
|
+
})
|
|
2000
|
+
];
|
|
2001
|
+
};
|
|
2002
|
+
|
|
2003
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2004
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2005
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2006
|
+
import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2007
|
+
var styles4 = EditorView9.baseTheme({
|
|
2008
|
+
"& .cm-hr": {
|
|
2009
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2010
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2014
|
+
toDOM() {
|
|
2015
|
+
const el = document.createElement("div");
|
|
2016
|
+
el.className = "cm-hr";
|
|
2017
|
+
return el;
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
var decoration = Decoration6.replace({
|
|
2021
|
+
widget: new HorizontalRuleWidget()
|
|
2022
|
+
});
|
|
2023
|
+
var buildDecorations3 = (view) => {
|
|
2024
|
+
const builder = new RangeSetBuilder4();
|
|
2025
|
+
const { state } = view;
|
|
2026
|
+
const cursor = state.selection.main.head;
|
|
2027
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2028
|
+
syntaxTree4(state).iterate({
|
|
2029
|
+
enter: (node) => {
|
|
2030
|
+
if (node.name === "HorizontalRule") {
|
|
2031
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2032
|
+
builder.add(node.from, node.to, decoration);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
from,
|
|
2037
|
+
to
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
return builder.finish();
|
|
2041
|
+
};
|
|
2042
|
+
var hr = () => {
|
|
2043
|
+
return [
|
|
2044
|
+
ViewPlugin6.fromClass(class {
|
|
2045
|
+
constructor(view) {
|
|
2046
|
+
this.decorations = buildDecorations3(view);
|
|
2047
|
+
}
|
|
2048
|
+
update(update2) {
|
|
2049
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2050
|
+
}
|
|
2051
|
+
}, {
|
|
2052
|
+
decorations: (value) => value.decorations
|
|
2053
|
+
}),
|
|
2054
|
+
styles4
|
|
2055
|
+
];
|
|
2056
|
+
};
|
|
2057
|
+
|
|
2058
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2059
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2060
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
2061
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2062
|
+
var image = (options = {}) => {
|
|
2063
|
+
return StateField3.define({
|
|
2064
|
+
create: (state) => {
|
|
2065
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
2066
|
+
},
|
|
2067
|
+
update: (value, tr) => {
|
|
2068
|
+
if (!tr.docChanged && !tr.selection) {
|
|
2069
|
+
return value;
|
|
2070
|
+
}
|
|
2071
|
+
const cursor = tr.state.selection.main.head;
|
|
2072
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
2073
|
+
let from = Math.min(cursor, oldCursor);
|
|
2074
|
+
let to = Math.max(cursor, oldCursor);
|
|
2075
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
2076
|
+
from = Math.min(from, fromB);
|
|
2077
|
+
to = Math.max(to, toB);
|
|
2078
|
+
});
|
|
2079
|
+
from = tr.state.doc.lineAt(from).from;
|
|
2080
|
+
to = tr.state.doc.lineAt(to).to;
|
|
2081
|
+
return value.map(tr.changes).update({
|
|
2082
|
+
filterFrom: from,
|
|
2083
|
+
filterTo: to,
|
|
2084
|
+
filter: () => false,
|
|
2085
|
+
add: buildDecorations4(from, to, tr.state)
|
|
2086
|
+
});
|
|
2087
|
+
},
|
|
1977
2088
|
provide: (field) => EditorView10.decorations.from(field)
|
|
1978
2089
|
});
|
|
1979
2090
|
};
|
|
2091
|
+
var buildDecorations4 = (from, to, state) => {
|
|
2092
|
+
const decorations = [];
|
|
2093
|
+
const cursor = state.selection.main.head;
|
|
2094
|
+
syntaxTree5(state).iterate({
|
|
2095
|
+
enter: (node) => {
|
|
2096
|
+
if (node.name === "Image") {
|
|
2097
|
+
const urlNode = node.node.getChild("URL");
|
|
2098
|
+
if (urlNode) {
|
|
2099
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
2100
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2101
|
+
decorations.push(Decoration7.replace({
|
|
2102
|
+
block: true,
|
|
2103
|
+
widget: new ImageWidget(url)
|
|
2104
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
from,
|
|
2109
|
+
to
|
|
2110
|
+
});
|
|
2111
|
+
return decorations;
|
|
2112
|
+
};
|
|
2113
|
+
var ImageWidget = class extends WidgetType4 {
|
|
2114
|
+
constructor(_url) {
|
|
2115
|
+
super();
|
|
2116
|
+
this._url = _url;
|
|
2117
|
+
}
|
|
2118
|
+
eq(other) {
|
|
2119
|
+
return this._url === other._url;
|
|
2120
|
+
}
|
|
2121
|
+
toDOM(view) {
|
|
2122
|
+
const img = document.createElement("img");
|
|
2123
|
+
img.setAttribute("src", this._url);
|
|
2124
|
+
img.setAttribute("class", "cm-image");
|
|
2125
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
2126
|
+
return img;
|
|
2127
|
+
}
|
|
2128
|
+
};
|
|
2129
|
+
|
|
2130
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
2131
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2132
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
2133
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
2134
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
2135
|
+
var link = (options = {}) => {
|
|
2136
|
+
const extensions = [
|
|
2137
|
+
ViewPlugin7.fromClass(class {
|
|
2138
|
+
constructor(view) {
|
|
2139
|
+
this.decorations = buildDecorations5(view, options);
|
|
2140
|
+
}
|
|
2141
|
+
update(update2) {
|
|
2142
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2143
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}, {
|
|
2147
|
+
decorations: (value) => value.decorations
|
|
2148
|
+
})
|
|
2149
|
+
];
|
|
2150
|
+
if (options.onHover) {
|
|
2151
|
+
extensions.push(
|
|
2152
|
+
// https://codemirror.net/examples/tooltip
|
|
2153
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
2154
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
2155
|
+
hoverTooltip2((view, pos, side) => {
|
|
2156
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
2157
|
+
let link2 = null;
|
|
2158
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
2159
|
+
link2 = node.name === "Link" ? node : null;
|
|
2160
|
+
}
|
|
2161
|
+
const url = link2 && link2.getChild("URL");
|
|
2162
|
+
if (!url || !link2) {
|
|
2163
|
+
return null;
|
|
2164
|
+
}
|
|
2165
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
2166
|
+
return {
|
|
2167
|
+
pos: link2.from,
|
|
2168
|
+
end: link2.to,
|
|
2169
|
+
above: true,
|
|
2170
|
+
create: () => {
|
|
2171
|
+
const el = document.createElement("div");
|
|
2172
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2173
|
+
options.onHover(el, urlText);
|
|
2174
|
+
return {
|
|
2175
|
+
dom: el,
|
|
2176
|
+
offset: {
|
|
2177
|
+
x: 0,
|
|
2178
|
+
y: 4
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
})
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2186
|
+
return extensions;
|
|
2187
|
+
};
|
|
2188
|
+
var LinkButton = class extends WidgetType5 {
|
|
2189
|
+
constructor(_url, _onAttach) {
|
|
2190
|
+
super();
|
|
2191
|
+
this._url = _url;
|
|
2192
|
+
this._onAttach = _onAttach;
|
|
2193
|
+
}
|
|
2194
|
+
eq(other) {
|
|
2195
|
+
return this._url === other._url;
|
|
2196
|
+
}
|
|
2197
|
+
toDOM(view) {
|
|
2198
|
+
const el = document.createElement("span");
|
|
2199
|
+
this._onAttach(el, this._url);
|
|
2200
|
+
return el;
|
|
2201
|
+
}
|
|
2202
|
+
};
|
|
2203
|
+
var LinkText = class extends WidgetType5 {
|
|
2204
|
+
constructor(_text, _url) {
|
|
2205
|
+
super();
|
|
2206
|
+
this._text = _text;
|
|
2207
|
+
this._url = _url;
|
|
2208
|
+
}
|
|
2209
|
+
eq(other) {
|
|
2210
|
+
return this._url === other._url;
|
|
2211
|
+
}
|
|
2212
|
+
toDOM(view) {
|
|
2213
|
+
const link2 = document.createElement("a");
|
|
2214
|
+
link2.setAttribute("class", "cm-link");
|
|
2215
|
+
link2.textContent = this._text;
|
|
2216
|
+
if (this._url) {
|
|
2217
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2218
|
+
link2.setAttribute("target", "_blank");
|
|
2219
|
+
link2.href = this._url;
|
|
2220
|
+
} else {
|
|
2221
|
+
link2.onclick = () => {
|
|
2222
|
+
view.dispatch({
|
|
2223
|
+
selection: {
|
|
2224
|
+
anchor: view.posAtDOM(link2)
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
return link2;
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
var buildDecorations5 = (view, options) => {
|
|
2233
|
+
const builder = new RangeSetBuilder5();
|
|
2234
|
+
const { state } = view;
|
|
2235
|
+
const cursor = state.selection.main.head;
|
|
2236
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2237
|
+
syntaxTree6(state).iterate({
|
|
2238
|
+
enter: (node) => {
|
|
2239
|
+
if (node.name === "Link") {
|
|
2240
|
+
const marks = node.node.getChildren("LinkMark");
|
|
2241
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2242
|
+
const urlNode = node.node.getChild("URL");
|
|
2243
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2244
|
+
if (!url) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2248
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2249
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2250
|
+
}));
|
|
2251
|
+
}
|
|
2252
|
+
if (options.onRender) {
|
|
2253
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2254
|
+
widget: new LinkButton(url, options.onRender)
|
|
2255
|
+
}));
|
|
2256
|
+
}
|
|
2257
|
+
return false;
|
|
2258
|
+
}
|
|
2259
|
+
},
|
|
2260
|
+
from,
|
|
2261
|
+
to
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
return builder.finish();
|
|
2265
|
+
};
|
|
2266
|
+
|
|
2267
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2268
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2269
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2270
|
+
import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
2271
|
+
var table = (options = {}) => {
|
|
2272
|
+
return StateField4.define({
|
|
2273
|
+
create: (state) => update(state, options),
|
|
2274
|
+
update: (_, tr) => update(tr.state, options),
|
|
2275
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
2276
|
+
});
|
|
2277
|
+
};
|
|
1980
2278
|
var update = (state, options) => {
|
|
1981
|
-
const builder = new
|
|
2279
|
+
const builder = new RangeSetBuilder6();
|
|
1982
2280
|
const cursor = state.selection.main.head;
|
|
1983
2281
|
const tables = [];
|
|
1984
2282
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1986,7 +2284,7 @@ var update = (state, options) => {
|
|
|
1986
2284
|
const table2 = getTable();
|
|
1987
2285
|
return table2.rows?.[table2.rows.length - 1];
|
|
1988
2286
|
};
|
|
1989
|
-
|
|
2287
|
+
syntaxTree7(state).iterate({
|
|
1990
2288
|
enter: (node) => {
|
|
1991
2289
|
switch (node.name) {
|
|
1992
2290
|
case "Table": {
|
|
@@ -2018,16 +2316,16 @@ var update = (state, options) => {
|
|
|
2018
2316
|
});
|
|
2019
2317
|
tables.forEach((table2) => {
|
|
2020
2318
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2021
|
-
hide && builder.add(table2.from, table2.to,
|
|
2319
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2022
2320
|
widget: new TableWidget(table2)
|
|
2023
2321
|
}));
|
|
2024
|
-
builder.add(table2.from, table2.to,
|
|
2322
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2025
2323
|
class: "cm-table"
|
|
2026
2324
|
}));
|
|
2027
2325
|
});
|
|
2028
2326
|
return builder.finish();
|
|
2029
2327
|
};
|
|
2030
|
-
var TableWidget = class extends
|
|
2328
|
+
var TableWidget = class extends WidgetType6 {
|
|
2031
2329
|
constructor(_table) {
|
|
2032
2330
|
super();
|
|
2033
2331
|
this._table = _table;
|
|
@@ -2064,11 +2362,20 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2064
2362
|
}
|
|
2065
2363
|
};
|
|
2066
2364
|
|
|
2067
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2068
|
-
import { syntaxTree as
|
|
2069
|
-
import { RangeSetBuilder as
|
|
2070
|
-
import { EditorView as
|
|
2071
|
-
var
|
|
2365
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2366
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2367
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2368
|
+
import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
2369
|
+
var styles5 = EditorView12.baseTheme({
|
|
2370
|
+
"& .cm-task": {
|
|
2371
|
+
color: getToken("extend.colors.blue.500")
|
|
2372
|
+
},
|
|
2373
|
+
"& .cm-task-checkbox": {
|
|
2374
|
+
marginLeft: "4px",
|
|
2375
|
+
marginRight: "4px"
|
|
2376
|
+
}
|
|
2377
|
+
});
|
|
2378
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2072
2379
|
constructor(_checked) {
|
|
2073
2380
|
super();
|
|
2074
2381
|
this._checked = _checked;
|
|
@@ -2078,6 +2385,7 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2078
2385
|
}
|
|
2079
2386
|
toDOM(view) {
|
|
2080
2387
|
const input = document.createElement("input");
|
|
2388
|
+
input.className = "cm-task-checkbox";
|
|
2081
2389
|
input.type = "checkbox";
|
|
2082
2390
|
input.checked = this._checked;
|
|
2083
2391
|
if (view.state.readOnly) {
|
|
@@ -2104,39 +2412,27 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2104
2412
|
return false;
|
|
2105
2413
|
}
|
|
2106
2414
|
};
|
|
2107
|
-
var
|
|
2415
|
+
var checkedDecoration = Decoration10.replace({
|
|
2108
2416
|
widget: new CheckboxWidget(true)
|
|
2109
2417
|
});
|
|
2110
|
-
var
|
|
2418
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2111
2419
|
widget: new CheckboxWidget(false)
|
|
2112
2420
|
});
|
|
2113
|
-
var
|
|
2114
|
-
|
|
2115
|
-
constructor(view) {
|
|
2116
|
-
this.decorations = buildDecorations3(view);
|
|
2117
|
-
}
|
|
2118
|
-
update(update2) {
|
|
2119
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2120
|
-
this.decorations = buildDecorations3(update2.view);
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
}, {
|
|
2124
|
-
decorations: (v) => v.decorations,
|
|
2125
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2126
|
-
return view.plugin(plugin)?.decorations || Decoration8.none;
|
|
2127
|
-
})
|
|
2128
|
-
});
|
|
2129
|
-
};
|
|
2130
|
-
var buildDecorations3 = (view) => {
|
|
2131
|
-
const builder = new RangeSetBuilder3();
|
|
2421
|
+
var buildDecorations6 = (view) => {
|
|
2422
|
+
const builder = new RangeSetBuilder7();
|
|
2132
2423
|
const { state } = view;
|
|
2133
2424
|
const cursor = state.selection.main.head;
|
|
2134
2425
|
for (const { from, to } of view.visibleRanges) {
|
|
2135
|
-
|
|
2426
|
+
syntaxTree8(state).iterate({
|
|
2136
2427
|
enter: (node) => {
|
|
2137
|
-
if (node.name === "TaskMarker"
|
|
2138
|
-
|
|
2139
|
-
|
|
2428
|
+
if (node.name === "TaskMarker") {
|
|
2429
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2430
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2431
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2432
|
+
class: "cm-task"
|
|
2433
|
+
}));
|
|
2434
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2435
|
+
}
|
|
2140
2436
|
}
|
|
2141
2437
|
},
|
|
2142
2438
|
from,
|
|
@@ -2145,9 +2441,60 @@ var buildDecorations3 = (view) => {
|
|
|
2145
2441
|
}
|
|
2146
2442
|
return builder.finish();
|
|
2147
2443
|
};
|
|
2444
|
+
var tasklist = (options = {}) => {
|
|
2445
|
+
return [
|
|
2446
|
+
ViewPlugin8.fromClass(class {
|
|
2447
|
+
constructor(view) {
|
|
2448
|
+
this.decorations = buildDecorations6(view);
|
|
2449
|
+
}
|
|
2450
|
+
update(update2) {
|
|
2451
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2452
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}, {
|
|
2456
|
+
decorations: (value) => value.decorations
|
|
2457
|
+
}),
|
|
2458
|
+
styles5
|
|
2459
|
+
];
|
|
2460
|
+
};
|
|
2461
|
+
|
|
2462
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2463
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2464
|
+
var mention = ({ onSearch }) => {
|
|
2465
|
+
return autocompletion2({
|
|
2466
|
+
// TODO(burdon): Not working.
|
|
2467
|
+
activateOnTyping: true,
|
|
2468
|
+
// activateOnTypingDelay: 100,
|
|
2469
|
+
// selectOnOpen: true,
|
|
2470
|
+
closeOnBlur: false,
|
|
2471
|
+
// defaultKeymap: false,
|
|
2472
|
+
icons: false,
|
|
2473
|
+
override: [
|
|
2474
|
+
(context) => {
|
|
2475
|
+
console.log(context);
|
|
2476
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2477
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2478
|
+
return null;
|
|
2479
|
+
}
|
|
2480
|
+
return {
|
|
2481
|
+
from: match.from,
|
|
2482
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2483
|
+
label: `@${value}`
|
|
2484
|
+
}))
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
]
|
|
2488
|
+
});
|
|
2489
|
+
};
|
|
2490
|
+
|
|
2491
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2492
|
+
var outliner = (options = {}) => {
|
|
2493
|
+
return [];
|
|
2494
|
+
};
|
|
2148
2495
|
|
|
2149
2496
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2150
|
-
import { keymap as
|
|
2497
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2151
2498
|
var defaultItems = [
|
|
2152
2499
|
"hello world!",
|
|
2153
2500
|
"this is a test.",
|
|
@@ -2157,7 +2504,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2157
2504
|
let t;
|
|
2158
2505
|
let idx = 0;
|
|
2159
2506
|
return [
|
|
2160
|
-
|
|
2507
|
+
keymap6.of([
|
|
2161
2508
|
{
|
|
2162
2509
|
// Reset.
|
|
2163
2510
|
key: "alt-meta-'",
|
|
@@ -2203,27 +2550,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2203
2550
|
];
|
|
2204
2551
|
};
|
|
2205
2552
|
|
|
2206
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2207
|
-
import { yCollab } from "y-codemirror.next";
|
|
2208
|
-
|
|
2209
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2210
|
-
import * as Y from "yjs";
|
|
2211
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2212
|
-
var cursorConverter2 = (text) => ({
|
|
2213
|
-
toCursor: (index, assoc) => {
|
|
2214
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2215
|
-
},
|
|
2216
|
-
fromCursor: (cursor) => {
|
|
2217
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2218
|
-
}
|
|
2219
|
-
});
|
|
2220
|
-
|
|
2221
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2222
|
-
var yjs = (content, awareness2) => [
|
|
2223
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2224
|
-
yCollab(content, awareness2)
|
|
2225
|
-
];
|
|
2226
|
-
|
|
2227
2553
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2228
2554
|
import get3 from "lodash.get";
|
|
2229
2555
|
var defaultTheme = {
|
|
@@ -2255,8 +2581,9 @@ var defaultTheme = {
|
|
|
2255
2581
|
outline: "none"
|
|
2256
2582
|
},
|
|
2257
2583
|
".cm-scroller": {
|
|
2258
|
-
overflow:
|
|
2259
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2584
|
+
// overflow: 'visible',
|
|
2585
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
2586
|
+
lineHeight: 1.4
|
|
2260
2587
|
},
|
|
2261
2588
|
".cm-content": {
|
|
2262
2589
|
padding: 0,
|
|
@@ -2280,8 +2607,11 @@ var defaultTheme = {
|
|
|
2280
2607
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2281
2608
|
borderLeft: "2px solid white"
|
|
2282
2609
|
},
|
|
2283
|
-
".cm-placeholder": {
|
|
2284
|
-
|
|
2610
|
+
"&light .cm-placeholder": {
|
|
2611
|
+
color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
|
|
2612
|
+
},
|
|
2613
|
+
"&dark .cm-placeholder": {
|
|
2614
|
+
color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
|
|
2285
2615
|
},
|
|
2286
2616
|
//
|
|
2287
2617
|
// line
|
|
@@ -2290,7 +2620,7 @@ var defaultTheme = {
|
|
|
2290
2620
|
paddingInline: 0
|
|
2291
2621
|
},
|
|
2292
2622
|
".cm-activeLine": {
|
|
2293
|
-
background: "
|
|
2623
|
+
background: "transparent"
|
|
2294
2624
|
},
|
|
2295
2625
|
//
|
|
2296
2626
|
// Selection
|
|
@@ -2461,90 +2791,88 @@ var codeTheme = {
|
|
|
2461
2791
|
};
|
|
2462
2792
|
|
|
2463
2793
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2794
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2464
2795
|
var EditorModes = [
|
|
2465
2796
|
"default",
|
|
2466
2797
|
"vim"
|
|
2467
2798
|
];
|
|
2468
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2469
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2470
|
-
tabBehavior: "limited"
|
|
2471
|
-
});
|
|
2799
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2472
2800
|
const { themeMode } = useThemeContext();
|
|
2473
2801
|
const rootRef = useRef(null);
|
|
2474
2802
|
const [view, setView] = useState(null);
|
|
2475
2803
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2476
2804
|
view
|
|
2477
2805
|
]);
|
|
2478
|
-
|
|
2479
|
-
if (
|
|
2806
|
+
useEffect2(() => {
|
|
2807
|
+
if (autoFocus && !view?.hasFocus) {
|
|
2808
|
+
if (view?.state.selection.main?.from === 0) {
|
|
2809
|
+
const { to } = view.state.doc.lineAt(0);
|
|
2810
|
+
view?.dispatch({
|
|
2811
|
+
selection: {
|
|
2812
|
+
anchor: to
|
|
2813
|
+
}
|
|
2814
|
+
});
|
|
2815
|
+
}
|
|
2480
2816
|
view?.focus();
|
|
2481
2817
|
}
|
|
2482
|
-
}, [
|
|
2483
|
-
autofocus,
|
|
2484
|
-
view
|
|
2485
|
-
]);
|
|
2486
|
-
const { awareness: awareness2, peer } = model;
|
|
2487
|
-
useEffect(() => {
|
|
2488
|
-
if (awareness2 && peer) {
|
|
2489
|
-
awareness2.setLocalStateField("user", {
|
|
2490
|
-
name: peer.name ?? generateName(peer.id),
|
|
2491
|
-
color: getColorForValue({
|
|
2492
|
-
value: peer.id,
|
|
2493
|
-
type: "color"
|
|
2494
|
-
}),
|
|
2495
|
-
colorLight: getColorForValue({
|
|
2496
|
-
value: peer.id,
|
|
2497
|
-
themeMode,
|
|
2498
|
-
type: "highlight"
|
|
2499
|
-
})
|
|
2500
|
-
});
|
|
2501
|
-
}
|
|
2502
|
-
}, [
|
|
2503
|
-
awareness2,
|
|
2504
|
-
peer,
|
|
2505
|
-
themeMode
|
|
2506
|
-
]);
|
|
2507
|
-
useEffect(() => {
|
|
2508
|
-
if (view && comments2 !== void 0) {
|
|
2509
|
-
view.dispatch({
|
|
2510
|
-
effects: setCommentRange.of({
|
|
2511
|
-
model,
|
|
2512
|
-
comments: comments2
|
|
2513
|
-
})
|
|
2514
|
-
});
|
|
2515
|
-
}
|
|
2516
2818
|
}, [
|
|
2517
2819
|
view,
|
|
2518
|
-
|
|
2820
|
+
autoFocus
|
|
2519
2821
|
]);
|
|
2520
|
-
|
|
2822
|
+
useEffect2(() => {
|
|
2521
2823
|
if (!model || !rootRef.current) {
|
|
2522
2824
|
return;
|
|
2523
2825
|
}
|
|
2524
2826
|
const state = EditorState2.create({
|
|
2525
2827
|
doc: model.text(),
|
|
2526
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2527
2828
|
selection,
|
|
2528
2829
|
extensions: [
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2830
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2831
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2832
|
+
log2.catch(err, void 0, {
|
|
2833
|
+
F: __dxlog_file3,
|
|
2834
|
+
L: 134,
|
|
2835
|
+
S: void 0,
|
|
2836
|
+
C: (f, a) => f(...a)
|
|
2837
|
+
});
|
|
2838
|
+
}),
|
|
2532
2839
|
// Theme.
|
|
2533
|
-
// TODO(burdon): Make
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2840
|
+
// TODO(burdon): Make configurable.
|
|
2841
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2842
|
+
EditorView13.theme(theme ?? {}),
|
|
2843
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2844
|
+
EditorView13.editorAttributes.of({
|
|
2845
|
+
class: slots.editor?.className ?? ""
|
|
2846
|
+
}),
|
|
2847
|
+
EditorView13.contentAttributes.of({
|
|
2848
|
+
class: slots.content?.className ?? ""
|
|
2849
|
+
}),
|
|
2850
|
+
// State.
|
|
2851
|
+
EditorView13.editable.of(!readonly),
|
|
2852
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2537
2853
|
// Storage and replication.
|
|
2854
|
+
// NOTE: This must come before user extensions.
|
|
2538
2855
|
model.extension,
|
|
2856
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2857
|
+
editorMode === "vim" && vim(),
|
|
2539
2858
|
// Custom.
|
|
2540
2859
|
...extensions
|
|
2541
|
-
].filter(
|
|
2860
|
+
].filter(isNotFalsy3)
|
|
2542
2861
|
});
|
|
2543
|
-
|
|
2544
|
-
|
|
2862
|
+
const newView = new EditorView13({
|
|
2863
|
+
state,
|
|
2545
2864
|
parent: rootRef.current,
|
|
2546
|
-
|
|
2865
|
+
scrollTo,
|
|
2866
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2867
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2868
|
+
dispatchTransactions: (trs, view2) => {
|
|
2869
|
+
if (debug) {
|
|
2870
|
+
logChanges(trs);
|
|
2871
|
+
}
|
|
2872
|
+
view2.update(trs);
|
|
2873
|
+
}
|
|
2547
2874
|
});
|
|
2875
|
+
view?.destroy();
|
|
2548
2876
|
setView(newView);
|
|
2549
2877
|
return () => {
|
|
2550
2878
|
newView?.destroy();
|
|
@@ -2560,8 +2888,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2560
2888
|
const handleKeyUp = useCallback((event) => {
|
|
2561
2889
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2562
2890
|
switch (key) {
|
|
2891
|
+
case "Enter": {
|
|
2892
|
+
view?.focus();
|
|
2893
|
+
break;
|
|
2894
|
+
}
|
|
2563
2895
|
case "Escape": {
|
|
2564
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2896
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2897
|
+
view?.focus();
|
|
2898
|
+
}
|
|
2565
2899
|
break;
|
|
2566
2900
|
}
|
|
2567
2901
|
}
|
|
@@ -2573,23 +2907,23 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2573
2907
|
key: model.id,
|
|
2574
2908
|
role: "none",
|
|
2575
2909
|
tabIndex: 0,
|
|
2576
|
-
onKeyUp: handleKeyUp,
|
|
2577
2910
|
...slots.root,
|
|
2578
|
-
...editorMode !==
|
|
2911
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2912
|
+
onKeyUp: handleKeyUp,
|
|
2579
2913
|
ref: rootRef
|
|
2580
2914
|
});
|
|
2581
2915
|
});
|
|
2582
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2916
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2583
2917
|
const { themeMode } = useThemeContext();
|
|
2584
2918
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2585
2919
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2586
2920
|
ref: forwardedRef,
|
|
2587
2921
|
readonly,
|
|
2588
2922
|
extensions: [
|
|
2589
|
-
|
|
2590
|
-
readonly,
|
|
2923
|
+
createBasicBundle({
|
|
2591
2924
|
themeMode,
|
|
2592
|
-
placeholder: placeholder3
|
|
2925
|
+
placeholder: placeholder3,
|
|
2926
|
+
lineWrapping
|
|
2593
2927
|
}),
|
|
2594
2928
|
...extensions
|
|
2595
2929
|
],
|
|
@@ -2598,15 +2932,14 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2598
2932
|
...props
|
|
2599
2933
|
});
|
|
2600
2934
|
});
|
|
2601
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2935
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2602
2936
|
const { themeMode } = useThemeContext();
|
|
2603
2937
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2604
2938
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2605
2939
|
ref: forwardedRef,
|
|
2606
2940
|
readonly,
|
|
2607
2941
|
extensions: [
|
|
2608
|
-
|
|
2609
|
-
readonly,
|
|
2942
|
+
createMarkdownExtensions({
|
|
2610
2943
|
themeMode,
|
|
2611
2944
|
placeholder: placeholder3
|
|
2612
2945
|
}),
|
|
@@ -2619,7 +2952,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2619
2952
|
});
|
|
2620
2953
|
var defaultSlots = {
|
|
2621
2954
|
root: {
|
|
2622
|
-
className: mx3("
|
|
2955
|
+
className: mx3("grow", focusRing)
|
|
2956
|
+
},
|
|
2957
|
+
editor: {
|
|
2958
|
+
className: "bs-full"
|
|
2623
2959
|
}
|
|
2624
2960
|
};
|
|
2625
2961
|
var defaultTextSlots = {
|
|
@@ -2629,22 +2965,178 @@ var defaultMarkdownSlots = {
|
|
|
2629
2965
|
...defaultSlots
|
|
2630
2966
|
};
|
|
2631
2967
|
|
|
2632
|
-
// packages/ui/react-ui-editor/src/
|
|
2633
|
-
import
|
|
2634
|
-
import {
|
|
2635
|
-
import
|
|
2968
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
2969
|
+
import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, ListNumbers, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
|
|
2970
|
+
import { createContext } from "@radix-ui/react-context";
|
|
2971
|
+
import React2 from "react";
|
|
2972
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
2973
|
+
import { getSize } from "@dxos/react-ui-theme";
|
|
2974
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
2975
|
+
var ToolbarRoot = ({ children, onAction }) => {
|
|
2976
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
2977
|
+
onAction
|
|
2978
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
2979
|
+
density: "fine"
|
|
2980
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
2981
|
+
role: "toolbar",
|
|
2982
|
+
className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
|
|
2983
|
+
}, children)));
|
|
2984
|
+
};
|
|
2985
|
+
var ToolbarButton = ({ Icon, onClick, title }) => {
|
|
2986
|
+
const { onAction } = useToolbarContext("ToolbarButton");
|
|
2987
|
+
const handleClick = () => {
|
|
2988
|
+
const action = onClick();
|
|
2989
|
+
if (action) {
|
|
2990
|
+
onAction?.(action);
|
|
2991
|
+
}
|
|
2992
|
+
};
|
|
2993
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
2994
|
+
variant: "ghost",
|
|
2995
|
+
classNames: "p-2",
|
|
2996
|
+
onClick: handleClick,
|
|
2997
|
+
title
|
|
2998
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
2999
|
+
className: getSize(5)
|
|
3000
|
+
}));
|
|
3001
|
+
};
|
|
3002
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3003
|
+
className: "grow"
|
|
3004
|
+
});
|
|
3005
|
+
var MarkdownHeading = () => {
|
|
3006
|
+
const { onAction } = useToolbarContext("MarkdownFormatting");
|
|
3007
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3008
|
+
defaultValue: "0",
|
|
3009
|
+
onValueChange: (value) => onAction?.({
|
|
3010
|
+
type: "heading",
|
|
3011
|
+
data: parseInt(value)
|
|
3012
|
+
})
|
|
3013
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
|
|
3014
|
+
classNames: "w-[8rem]"
|
|
3015
|
+
}), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3016
|
+
value: "0"
|
|
3017
|
+
}, "Paragraph"), [
|
|
3018
|
+
1,
|
|
3019
|
+
2,
|
|
3020
|
+
3,
|
|
3021
|
+
4,
|
|
3022
|
+
5,
|
|
3023
|
+
6
|
|
3024
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3025
|
+
key: level,
|
|
3026
|
+
value: String(level)
|
|
3027
|
+
}, "Heading ", level))))));
|
|
3028
|
+
};
|
|
3029
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3030
|
+
role: "none"
|
|
3031
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3032
|
+
Icon: TextB,
|
|
3033
|
+
title: "Bold",
|
|
3034
|
+
onClick: () => ({
|
|
3035
|
+
type: "bold"
|
|
3036
|
+
})
|
|
3037
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3038
|
+
Icon: TextItalic,
|
|
3039
|
+
title: "Italic",
|
|
3040
|
+
onClick: () => ({
|
|
3041
|
+
type: "italic"
|
|
3042
|
+
})
|
|
3043
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3044
|
+
Icon: TextStrikethrough,
|
|
3045
|
+
title: "Strike-through",
|
|
3046
|
+
onClick: () => ({
|
|
3047
|
+
type: "strikethrough"
|
|
3048
|
+
})
|
|
3049
|
+
}));
|
|
3050
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3051
|
+
role: "none"
|
|
3052
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3053
|
+
Icon: ListBullets,
|
|
3054
|
+
title: "Bullet list",
|
|
3055
|
+
onClick: () => ({
|
|
3056
|
+
type: "list"
|
|
3057
|
+
})
|
|
3058
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3059
|
+
Icon: ListNumbers,
|
|
3060
|
+
title: "Numbered list",
|
|
3061
|
+
onClick: () => ({
|
|
3062
|
+
type: "list-ordered"
|
|
3063
|
+
})
|
|
3064
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3065
|
+
Icon: ListChecks,
|
|
3066
|
+
title: "Task list",
|
|
3067
|
+
onClick: () => ({
|
|
3068
|
+
type: "list-tasks"
|
|
3069
|
+
})
|
|
3070
|
+
}));
|
|
3071
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3072
|
+
role: "none"
|
|
3073
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3074
|
+
Icon: CaretRight,
|
|
3075
|
+
title: "Block quite",
|
|
3076
|
+
onClick: () => ({
|
|
3077
|
+
type: "blockquote"
|
|
3078
|
+
})
|
|
3079
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3080
|
+
Icon: Code,
|
|
3081
|
+
title: "Code block",
|
|
3082
|
+
onClick: () => ({
|
|
3083
|
+
type: "codeblock"
|
|
3084
|
+
})
|
|
3085
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3086
|
+
Icon: Table2,
|
|
3087
|
+
title: "Table",
|
|
3088
|
+
onClick: () => ({
|
|
3089
|
+
type: "table"
|
|
3090
|
+
})
|
|
3091
|
+
}));
|
|
3092
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3093
|
+
role: "none"
|
|
3094
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3095
|
+
Icon: Link,
|
|
3096
|
+
title: "Link",
|
|
3097
|
+
onClick: () => ({
|
|
3098
|
+
type: "link"
|
|
3099
|
+
})
|
|
3100
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3101
|
+
Icon: At,
|
|
3102
|
+
title: "Mention",
|
|
3103
|
+
onClick: () => ({
|
|
3104
|
+
type: "mention"
|
|
3105
|
+
})
|
|
3106
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3107
|
+
Icon: Image,
|
|
3108
|
+
title: "Image",
|
|
3109
|
+
onClick: () => ({
|
|
3110
|
+
type: "image"
|
|
3111
|
+
})
|
|
3112
|
+
}));
|
|
3113
|
+
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));
|
|
3114
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
3115
|
+
Icon: ChatText,
|
|
3116
|
+
title: "Create comment",
|
|
3117
|
+
onClick: () => ({
|
|
3118
|
+
type: "comment"
|
|
3119
|
+
})
|
|
3120
|
+
});
|
|
3121
|
+
var Toolbar = {
|
|
3122
|
+
Root: ToolbarRoot,
|
|
3123
|
+
Button: ToolbarButton,
|
|
3124
|
+
Separator: ToolbarSeparator,
|
|
3125
|
+
Markdown: MarkdownStandard,
|
|
3126
|
+
Extended: MarkdownExtended
|
|
3127
|
+
};
|
|
2636
3128
|
|
|
2637
3129
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2638
3130
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2639
3131
|
import { Context as Context2 } from "@dxos/context";
|
|
2640
|
-
import { invariant as
|
|
2641
|
-
import { log as
|
|
3132
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
3133
|
+
import { log as log3 } from "@dxos/log";
|
|
2642
3134
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2643
3135
|
var DEBOUNCE_INTERVAL = 100;
|
|
2644
3136
|
var SpaceAwarenessProvider = class {
|
|
2645
3137
|
constructor(params) {
|
|
2646
|
-
this.remoteStateChange = new Event2();
|
|
2647
3138
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
3139
|
+
this.remoteStateChange = new Event2();
|
|
2648
3140
|
this._space = params.space;
|
|
2649
3141
|
this._channel = params.channel;
|
|
2650
3142
|
this._peerId = params.peerId;
|
|
@@ -2661,7 +3153,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2661
3153
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2662
3154
|
}
|
|
2663
3155
|
});
|
|
2664
|
-
|
|
3156
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2665
3157
|
switch (message.payload.kind) {
|
|
2666
3158
|
case "query": {
|
|
2667
3159
|
this._handleQueryMessage();
|
|
@@ -2672,16 +3164,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2672
3164
|
break;
|
|
2673
3165
|
}
|
|
2674
3166
|
}
|
|
2675
|
-
});
|
|
2676
|
-
this._ctx.onDispose(unsubscribe);
|
|
3167
|
+
}));
|
|
2677
3168
|
void this._space.postMessage(this._channel, {
|
|
2678
3169
|
kind: "query"
|
|
2679
3170
|
}).catch((err) => {
|
|
2680
|
-
|
|
3171
|
+
log3.debug("failed to query awareness", {
|
|
2681
3172
|
err
|
|
2682
3173
|
}, {
|
|
2683
3174
|
F: __dxlog_file4,
|
|
2684
|
-
L:
|
|
3175
|
+
L: 89,
|
|
2685
3176
|
S: this,
|
|
2686
3177
|
C: (f, a) => f(...a)
|
|
2687
3178
|
});
|
|
@@ -2692,10 +3183,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2692
3183
|
this._ctx = void 0;
|
|
2693
3184
|
this._postTask = void 0;
|
|
2694
3185
|
}
|
|
3186
|
+
getRemoteStates() {
|
|
3187
|
+
return Array.from(this._remoteStates.values());
|
|
3188
|
+
}
|
|
2695
3189
|
update(position) {
|
|
2696
|
-
|
|
3190
|
+
invariant2(this._postTask, void 0, {
|
|
2697
3191
|
F: __dxlog_file4,
|
|
2698
|
-
L:
|
|
3192
|
+
L: 104,
|
|
2699
3193
|
S: this,
|
|
2700
3194
|
A: [
|
|
2701
3195
|
"this._postTask",
|
|
@@ -2709,13 +3203,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2709
3203
|
};
|
|
2710
3204
|
this._postTask.schedule();
|
|
2711
3205
|
}
|
|
2712
|
-
getRemoteStates() {
|
|
2713
|
-
return Array.from(this._remoteStates.values());
|
|
2714
|
-
}
|
|
2715
3206
|
_handleQueryMessage() {
|
|
2716
|
-
|
|
3207
|
+
invariant2(this._postTask, void 0, {
|
|
2717
3208
|
F: __dxlog_file4,
|
|
2718
|
-
L:
|
|
3209
|
+
L: 115,
|
|
2719
3210
|
S: this,
|
|
2720
3211
|
A: [
|
|
2721
3212
|
"this._postTask",
|
|
@@ -2725,9 +3216,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2725
3216
|
this._postTask.schedule();
|
|
2726
3217
|
}
|
|
2727
3218
|
_handlePostMessage(message) {
|
|
2728
|
-
|
|
3219
|
+
invariant2(message.kind === "post", void 0, {
|
|
2729
3220
|
F: __dxlog_file4,
|
|
2730
|
-
L:
|
|
3221
|
+
L: 120,
|
|
2731
3222
|
S: this,
|
|
2732
3223
|
A: [
|
|
2733
3224
|
"message.kind === 'post'",
|
|
@@ -2739,199 +3230,240 @@ var SpaceAwarenessProvider = class {
|
|
|
2739
3230
|
}
|
|
2740
3231
|
};
|
|
2741
3232
|
|
|
2742
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
3233
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2743
3234
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2744
|
-
|
|
2745
|
-
|
|
3235
|
+
var modelState = StateField5.define({
|
|
3236
|
+
create: () => void 0,
|
|
3237
|
+
update: (model) => model
|
|
3238
|
+
});
|
|
2746
3239
|
|
|
2747
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2753
|
-
import { log as log3 } from "@dxos/log";
|
|
2754
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2755
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2756
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2757
|
-
F: __dxlog_file5,
|
|
2758
|
-
L: 21,
|
|
2759
|
-
S: void 0,
|
|
2760
|
-
A: [
|
|
2761
|
-
"text?.doc && text?.content",
|
|
2762
|
-
""
|
|
2763
|
-
]
|
|
2764
|
-
});
|
|
2765
|
-
const provider = space ? new YAwarenessProvider({
|
|
2766
|
-
space,
|
|
2767
|
-
doc: text.doc,
|
|
2768
|
-
channel: `yjs.awareness.${text.id}`
|
|
2769
|
-
}) : void 0;
|
|
2770
|
-
const model = {
|
|
2771
|
-
id: text.doc.guid,
|
|
2772
|
-
content: text.content,
|
|
2773
|
-
text: () => text.content.toString(),
|
|
2774
|
-
extension: [
|
|
2775
|
-
modelState.init(() => model),
|
|
2776
|
-
yjs(text.content, provider?.awareness)
|
|
2777
|
-
],
|
|
2778
|
-
awareness: provider?.awareness,
|
|
2779
|
-
peer: identity ? {
|
|
2780
|
-
id: identity.identityKey.toHex(),
|
|
2781
|
-
name: identity.profile?.displayName
|
|
2782
|
-
} : void 0
|
|
2783
|
-
};
|
|
2784
|
-
return model;
|
|
2785
|
-
};
|
|
2786
|
-
var messageAwareness = 1;
|
|
2787
|
-
var messageQueryAwareness = 3;
|
|
2788
|
-
var YAwarenessProvider = class extends Observable {
|
|
2789
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2790
|
-
super();
|
|
2791
|
-
this._space = space;
|
|
2792
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2793
|
-
this._channel = channel;
|
|
2794
|
-
this._clientId = doc.clientID;
|
|
2795
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2796
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2797
|
-
if (typeof window !== "undefined") {
|
|
2798
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2799
|
-
} else if (typeof process !== "undefined") {
|
|
2800
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
3240
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3241
|
+
var useActionHandler = (view) => {
|
|
3242
|
+
return (action) => {
|
|
3243
|
+
if (!view) {
|
|
3244
|
+
return;
|
|
2801
3245
|
}
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
_handleSpaceMessage({ payload }) {
|
|
2834
|
-
log3("space message", payload, {
|
|
2835
|
-
F: __dxlog_file5,
|
|
2836
|
-
L: 109,
|
|
2837
|
-
S: this,
|
|
2838
|
-
C: (f, a) => f(...a)
|
|
3246
|
+
switch (action.type) {
|
|
3247
|
+
case "heading":
|
|
3248
|
+
setHeading(parseInt(action.data))(view);
|
|
3249
|
+
break;
|
|
3250
|
+
case "bold":
|
|
3251
|
+
toggleBold(view);
|
|
3252
|
+
break;
|
|
3253
|
+
case "italic":
|
|
3254
|
+
toggleItalic(view);
|
|
3255
|
+
break;
|
|
3256
|
+
case "strikethrough":
|
|
3257
|
+
toggleStrikethrough(view);
|
|
3258
|
+
break;
|
|
3259
|
+
case "list":
|
|
3260
|
+
toggleList(view);
|
|
3261
|
+
break;
|
|
3262
|
+
case "codeblock":
|
|
3263
|
+
insertCodeblock(view);
|
|
3264
|
+
break;
|
|
3265
|
+
case "table":
|
|
3266
|
+
insertTable(view);
|
|
3267
|
+
break;
|
|
3268
|
+
case "comment":
|
|
3269
|
+
createComment(view);
|
|
3270
|
+
break;
|
|
3271
|
+
}
|
|
3272
|
+
setTimeout(() => {
|
|
3273
|
+
view.focus();
|
|
3274
|
+
view.dispatch({
|
|
3275
|
+
selection: view.state.selection
|
|
3276
|
+
});
|
|
2839
3277
|
});
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
3278
|
+
};
|
|
3279
|
+
};
|
|
3280
|
+
|
|
3281
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
3282
|
+
import { useState as useState2 } from "react";
|
|
3283
|
+
var useEditorView = () => {
|
|
3284
|
+
const [view, setView] = useState2(null);
|
|
3285
|
+
return [
|
|
3286
|
+
(ref) => {
|
|
3287
|
+
setView(ref);
|
|
3288
|
+
},
|
|
3289
|
+
view
|
|
3290
|
+
];
|
|
3291
|
+
};
|
|
3292
|
+
|
|
3293
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3294
|
+
import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
|
|
3295
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
3296
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
3297
|
+
import { log as log4 } from "@dxos/log";
|
|
3298
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
3299
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
3300
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
3301
|
+
const onUpdate = useRef2();
|
|
3302
|
+
const [view, setView] = useState3();
|
|
3303
|
+
const parentRef = useRef2(null);
|
|
3304
|
+
useEffect3(() => {
|
|
3305
|
+
if (parentRef.current) {
|
|
3306
|
+
const state = EditorState3.create({
|
|
3307
|
+
doc,
|
|
3308
|
+
selection,
|
|
3309
|
+
extensions: [
|
|
3310
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3311
|
+
EditorView14.exceptionSink.of((err) => {
|
|
3312
|
+
log4.catch(err, void 0, {
|
|
3313
|
+
F: __dxlog_file5,
|
|
3314
|
+
L: 57,
|
|
3315
|
+
S: void 0,
|
|
3316
|
+
C: (f, a) => f(...a)
|
|
3317
|
+
});
|
|
3318
|
+
}),
|
|
3319
|
+
extensions,
|
|
3320
|
+
EditorView14.updateListener.of(() => {
|
|
3321
|
+
onUpdate.current?.();
|
|
3322
|
+
})
|
|
3323
|
+
].filter(isNotFalsy4)
|
|
3324
|
+
});
|
|
3325
|
+
const view2 = new EditorView14({
|
|
3326
|
+
parent: parentRef.current,
|
|
3327
|
+
scrollTo,
|
|
3328
|
+
state,
|
|
3329
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
3330
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
3331
|
+
dispatchTransactions: (trs, view3) => {
|
|
3332
|
+
if (debug) {
|
|
3333
|
+
logChanges(trs);
|
|
3334
|
+
}
|
|
3335
|
+
view3.update(trs);
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3338
|
+
setView(view2);
|
|
2844
3339
|
}
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3340
|
+
return () => {
|
|
3341
|
+
view?.destroy();
|
|
3342
|
+
};
|
|
3343
|
+
}, [
|
|
3344
|
+
parentRef
|
|
3345
|
+
]);
|
|
3346
|
+
useEffect3(() => {
|
|
3347
|
+
if (view) {
|
|
3348
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
3349
|
+
selection = EditorSelection.single(view.state.doc.line(1).to);
|
|
2855
3350
|
}
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3351
|
+
if (selection || scrollTo) {
|
|
3352
|
+
onUpdate.current = () => {
|
|
3353
|
+
onUpdate.current = void 0;
|
|
3354
|
+
view.dispatch({
|
|
3355
|
+
selection,
|
|
3356
|
+
effects: scrollTo && [
|
|
3357
|
+
scrollTo
|
|
3358
|
+
],
|
|
3359
|
+
scrollIntoView: !scrollTo
|
|
3360
|
+
});
|
|
3361
|
+
};
|
|
2861
3362
|
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
return encoder;
|
|
3363
|
+
if (autoFocus) {
|
|
3364
|
+
view.focus();
|
|
2865
3365
|
}
|
|
2866
3366
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
}
|
|
3367
|
+
}, [
|
|
3368
|
+
view,
|
|
3369
|
+
autoFocus,
|
|
3370
|
+
selection,
|
|
3371
|
+
scrollTo
|
|
3372
|
+
]);
|
|
3373
|
+
return {
|
|
3374
|
+
parentRef,
|
|
3375
|
+
view
|
|
3376
|
+
};
|
|
3377
|
+
};
|
|
3378
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
3379
|
+
return [
|
|
3380
|
+
//
|
|
3381
|
+
EditorState3.readOnly.of(readonly),
|
|
3382
|
+
EditorView14.editable.of(!readonly)
|
|
3383
|
+
];
|
|
3384
|
+
};
|
|
3385
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
3386
|
+
return [
|
|
3387
|
+
//
|
|
3388
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3389
|
+
theme && EditorView14.theme(theme),
|
|
3390
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3391
|
+
EditorView14.editorAttributes.of({
|
|
3392
|
+
class: slots?.editor?.className ?? ""
|
|
3393
|
+
}),
|
|
3394
|
+
EditorView14.contentAttributes.of({
|
|
3395
|
+
class: slots?.content?.className ?? ""
|
|
3396
|
+
})
|
|
3397
|
+
].filter(isNotFalsy4);
|
|
2877
3398
|
};
|
|
2878
3399
|
|
|
2879
3400
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
}
|
|
3401
|
+
import get4 from "lodash.get";
|
|
3402
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
3403
|
+
import { generateName } from "@dxos/display-name";
|
|
3404
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
3405
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
3406
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3407
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2884
3408
|
var useTextModel = (props) => {
|
|
2885
3409
|
const { identity, space, text } = props;
|
|
2886
|
-
const [model, setModel] =
|
|
2887
|
-
|
|
3410
|
+
const [model, setModel] = useState4();
|
|
3411
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2888
3412
|
identity,
|
|
2889
3413
|
space,
|
|
2890
3414
|
text
|
|
2891
3415
|
]);
|
|
2892
3416
|
return model;
|
|
2893
3417
|
};
|
|
2894
|
-
var
|
|
2895
|
-
const
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
}
|
|
3418
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
3419
|
+
const [content, setContent] = useState4(defaultContent ?? "");
|
|
3420
|
+
return {
|
|
3421
|
+
id,
|
|
3422
|
+
content,
|
|
3423
|
+
setContent,
|
|
3424
|
+
text: () => content
|
|
3425
|
+
};
|
|
2903
3426
|
};
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
3427
|
+
var createModel = ({ space, identity, text }) => {
|
|
3428
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
3429
|
+
F: __dxlog_file6,
|
|
3430
|
+
L: 50,
|
|
3431
|
+
S: void 0,
|
|
3432
|
+
A: [
|
|
3433
|
+
"isAutomergeObject(text)",
|
|
3434
|
+
""
|
|
3435
|
+
]
|
|
3436
|
+
});
|
|
2907
3437
|
const obj = text;
|
|
2908
3438
|
const doc = getRawDoc(obj, [
|
|
2909
3439
|
obj.field
|
|
2910
3440
|
]);
|
|
2911
|
-
const
|
|
3441
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2912
3442
|
space,
|
|
2913
3443
|
channel: `automerge.awareness.${obj.id}`,
|
|
2914
3444
|
info: {
|
|
2915
|
-
displayName: identity
|
|
3445
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2916
3446
|
color: cursorColor.color,
|
|
2917
3447
|
lightColor: cursorColor.light
|
|
2918
3448
|
},
|
|
2919
3449
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2920
3450
|
});
|
|
3451
|
+
const extensions = [
|
|
3452
|
+
//
|
|
3453
|
+
modelState.init(() => model),
|
|
3454
|
+
automerge({
|
|
3455
|
+
handle: doc.handle,
|
|
3456
|
+
path: doc.path
|
|
3457
|
+
})
|
|
3458
|
+
];
|
|
3459
|
+
if (awarenessProvider2) {
|
|
3460
|
+
extensions.push(awareness(awarenessProvider2));
|
|
3461
|
+
}
|
|
2921
3462
|
const model = {
|
|
2922
3463
|
id: obj.id,
|
|
2923
3464
|
content: doc,
|
|
2924
3465
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2925
|
-
|
|
2926
|
-
extension: [
|
|
2927
|
-
modelState.init(() => model),
|
|
2928
|
-
automerge3({
|
|
2929
|
-
handle: doc.handle,
|
|
2930
|
-
path: doc.path
|
|
2931
|
-
}),
|
|
2932
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2933
|
-
awareness()
|
|
2934
|
-
].filter(isNotNullOrUndefined),
|
|
3466
|
+
extension: extensions,
|
|
2935
3467
|
peer: identity ? {
|
|
2936
3468
|
id: identity.identityKey.toHex(),
|
|
2937
3469
|
name: identity.profile?.displayName
|
|
@@ -2940,7 +3472,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
2940
3472
|
return model;
|
|
2941
3473
|
};
|
|
2942
3474
|
export {
|
|
2943
|
-
AwarenessProvider,
|
|
2944
3475
|
BaseTextEditor,
|
|
2945
3476
|
Cursor,
|
|
2946
3477
|
Doc,
|
|
@@ -2950,46 +3481,66 @@ export {
|
|
|
2950
3481
|
SpaceAwarenessProvider,
|
|
2951
3482
|
TextEditor,
|
|
2952
3483
|
TextKind,
|
|
2953
|
-
|
|
3484
|
+
Toolbar,
|
|
2954
3485
|
YText,
|
|
2955
3486
|
YXmlFragment,
|
|
2956
3487
|
autocomplete,
|
|
2957
|
-
|
|
3488
|
+
automerge,
|
|
2958
3489
|
awareness,
|
|
2959
|
-
|
|
3490
|
+
awarenessProvider,
|
|
2960
3491
|
blast,
|
|
2961
3492
|
callbackWrapper,
|
|
2962
3493
|
code2 as code,
|
|
2963
3494
|
codeTheme,
|
|
2964
3495
|
comments,
|
|
2965
|
-
|
|
2966
|
-
|
|
3496
|
+
createBasicBundle,
|
|
3497
|
+
createComment,
|
|
3498
|
+
createDataExtensions,
|
|
3499
|
+
createMarkdownExtensions,
|
|
3500
|
+
createThemeExtensions,
|
|
2967
3501
|
defaultMarkdownSlots,
|
|
2968
3502
|
defaultOptions,
|
|
2969
3503
|
defaultSlots,
|
|
2970
3504
|
defaultTextSlots,
|
|
2971
3505
|
defaultTheme,
|
|
3506
|
+
focusComment,
|
|
3507
|
+
formatting,
|
|
2972
3508
|
getToken,
|
|
3509
|
+
heading2 as heading,
|
|
2973
3510
|
hr,
|
|
2974
3511
|
image,
|
|
3512
|
+
insertCodeblock,
|
|
3513
|
+
insertTable,
|
|
3514
|
+
keymap7 as keymap,
|
|
2975
3515
|
link,
|
|
2976
3516
|
listener,
|
|
2977
|
-
|
|
3517
|
+
logChanges,
|
|
2978
3518
|
markdownHighlightStyle,
|
|
2979
3519
|
markdownTags,
|
|
2980
3520
|
markdownTagsExtensions,
|
|
2981
3521
|
markdownTheme,
|
|
2982
3522
|
mention,
|
|
2983
3523
|
modelState,
|
|
2984
|
-
|
|
2985
|
-
|
|
3524
|
+
outliner,
|
|
3525
|
+
setComments,
|
|
3526
|
+
setHeading,
|
|
2986
3527
|
setSelection,
|
|
2987
3528
|
table,
|
|
2988
3529
|
tags2 as tags,
|
|
2989
3530
|
tasklist,
|
|
2990
3531
|
textTheme,
|
|
3532
|
+
toggleBold,
|
|
3533
|
+
toggleItalic,
|
|
3534
|
+
toggleList,
|
|
3535
|
+
toggleStrikethrough,
|
|
3536
|
+
toggleStyle,
|
|
2991
3537
|
typewriter,
|
|
3538
|
+
useActionHandler,
|
|
3539
|
+
useComments,
|
|
3540
|
+
useEditorView,
|
|
3541
|
+
useInMemoryTextModel,
|
|
3542
|
+
useTextEditor,
|
|
2992
3543
|
useTextModel,
|
|
2993
|
-
|
|
3544
|
+
useToolbarContext
|
|
2994
3545
|
};
|
|
2995
3546
|
//# sourceMappingURL=index.mjs.map
|