@dxos/react-ui-editor 0.3.11-main.162de7b → 0.3.11-main.17ae201
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 +1754 -1305
- 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 +16 -14
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts +23 -0
- 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/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/index.d.ts +0 -1
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +8 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +37 -20
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/{util → extensions}/cursor.d.ts +10 -2
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +2 -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.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 -32
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- 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 +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +48 -37
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +84 -90
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +135 -95
- 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 +55 -46
- package/src/extensions/automerge/cursor.ts +5 -4
- package/src/extensions/automerge/defs.ts +13 -34
- package/src/extensions/automerge/index.ts +0 -1
- package/src/extensions/automerge/semaphore.ts +33 -32
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +46 -49
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +320 -264
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -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 -23
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/{image.ts → markdown/image.ts} +2 -2
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +20 -11
- package/src/extensions/{table.ts → markdown/table.ts} +2 -2
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +62 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +67 -60
- package/src/index.ts +1 -0
- package/src/styles/markdown.ts +9 -12
- package/src/themes/default.ts +24 -54
- package/src/util.ts +41 -0
- 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/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/dist/types/src/util/cursor.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -3
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/util.d.ts +0 -5
- package/dist/types/src/util/util.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -98
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/tasklist.ts +0 -119
- package/src/extensions/yjs/cursor.ts +0 -21
- 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 -178
- 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/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
|
@@ -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, useState } from "react";
|
|
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
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
57
61
|
|
|
58
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
59
63
|
import get from "lodash.get";
|
|
60
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
61
65
|
var cursorConverter = (handle, path) => ({
|
|
62
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
63
67
|
toCursor: (pos) => {
|
|
@@ -69,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
69
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
70
74
|
return "end";
|
|
71
75
|
}
|
|
72
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
73
77
|
},
|
|
74
78
|
fromCursor: (cursor) => {
|
|
75
79
|
if (cursor === "") {
|
|
@@ -87,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
87
91
|
return 0;
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
|
-
var
|
|
97
|
-
var
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
98
104
|
newHeads
|
|
99
105
|
});
|
|
100
|
-
var
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
104
110
|
|
|
105
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
106
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
107
113
|
|
|
108
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
109
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
110
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
111
117
|
const { lastHeads, path } = state.field(field);
|
|
112
118
|
let hasChanges = false;
|
|
@@ -119,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
119
125
|
return void 0;
|
|
120
126
|
}
|
|
121
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
122
129
|
for (const tr of transactions) {
|
|
123
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
124
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
125
136
|
});
|
|
126
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
127
141
|
});
|
|
128
142
|
return newHeads ?? void 0;
|
|
129
143
|
};
|
|
@@ -138,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
138
152
|
selection = selection.map(changeSet, 1);
|
|
139
153
|
view.dispatch({
|
|
140
154
|
changes: changeSet,
|
|
141
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
142
156
|
});
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
view.dispatch({
|
|
146
160
|
selection,
|
|
147
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
148
162
|
});
|
|
149
163
|
};
|
|
150
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -165,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
165
179
|
if (index == null) {
|
|
166
180
|
return [];
|
|
167
181
|
}
|
|
168
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
169
183
|
return [
|
|
170
184
|
{
|
|
171
185
|
from: index,
|
|
@@ -237,89 +251,100 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
251
|
|
|
238
252
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
239
253
|
var PatchSemaphore = class {
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
256
|
+
this._handle = _handle;
|
|
257
|
+
this._state = _state;
|
|
242
258
|
this._inReconcile = false;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
248
262
|
this._inReconcile = true;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
263
|
-
if (newHeads === null || newHeads === void 0) {
|
|
264
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
265
|
-
}
|
|
266
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
267
|
-
updateCodeMirror(view, selection, path, diff);
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
268
276
|
view.dispatch({
|
|
269
|
-
|
|
270
|
-
annotations:
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
271
279
|
});
|
|
272
|
-
|
|
273
|
-
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
274
291
|
}
|
|
275
292
|
};
|
|
276
293
|
|
|
277
|
-
// packages/ui/react-ui-editor/src/
|
|
294
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
278
295
|
import { Facet } from "@codemirror/state";
|
|
279
|
-
var
|
|
296
|
+
var defaultCursorConverter = {
|
|
280
297
|
toCursor: (position) => position.toString(),
|
|
281
298
|
fromCursor: (cursor) => parseInt(cursor)
|
|
282
299
|
};
|
|
283
|
-
var
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// packages/ui/react-ui-editor/src/util/util.ts
|
|
288
|
-
import { log } from "@dxos/log";
|
|
289
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
290
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
291
|
-
try {
|
|
292
|
-
return fn(...args);
|
|
293
|
-
} catch (error) {
|
|
294
|
-
log.catch(error, void 0, {
|
|
295
|
-
F: __dxlog_file,
|
|
296
|
-
L: 16,
|
|
297
|
-
S: void 0,
|
|
298
|
-
C: (f, a) => f(...a)
|
|
300
|
+
var Cursor = class _Cursor {
|
|
301
|
+
static {
|
|
302
|
+
this.converter = Facet.define({
|
|
303
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
299
304
|
});
|
|
300
305
|
}
|
|
306
|
+
static {
|
|
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);
|
|
311
|
+
return [
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
].join(":");
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
static {
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
320
|
+
const parts = cursor.split(":");
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
323
|
+
return from !== void 0 && to !== void 0 ? {
|
|
324
|
+
from,
|
|
325
|
+
to
|
|
326
|
+
} : void 0;
|
|
327
|
+
};
|
|
328
|
+
}
|
|
301
329
|
};
|
|
302
330
|
|
|
303
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
304
|
-
var
|
|
305
|
-
|
|
306
|
-
});
|
|
307
|
-
var automerge3 = ({ handle, path }) => {
|
|
308
|
-
const stateField = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
309
334
|
create: () => ({
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
313
338
|
}),
|
|
314
339
|
update: (value, tr) => {
|
|
315
340
|
const result = {
|
|
341
|
+
path: path.slice(),
|
|
316
342
|
lastHeads: value.lastHeads,
|
|
317
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
318
|
-
path: path.slice()
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
319
344
|
};
|
|
320
345
|
let clearUnreconciled = false;
|
|
321
346
|
for (const effect of tr.effects) {
|
|
322
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
323
348
|
result.lastHeads = effect.value.newHeads;
|
|
324
349
|
clearUnreconciled = true;
|
|
325
350
|
}
|
|
@@ -327,46 +352,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
327
352
|
if (clearUnreconciled) {
|
|
328
353
|
result.unreconciledTransactions = [];
|
|
329
354
|
} else {
|
|
330
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
331
356
|
result.unreconciledTransactions.push(tr);
|
|
332
357
|
}
|
|
333
358
|
}
|
|
334
359
|
return result;
|
|
335
360
|
}
|
|
336
361
|
});
|
|
337
|
-
const semaphore = new PatchSemaphore(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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) => {
|
|
350
392
|
});
|
|
351
393
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
return {
|
|
358
|
-
extension: [
|
|
359
|
-
CursorConverter.of(cursorConverter(handle, path)),
|
|
360
|
-
semaphoreFacet.of(semaphore),
|
|
361
|
-
stateField,
|
|
362
|
-
viewPlugin
|
|
363
|
-
]
|
|
364
|
-
};
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
396
|
+
];
|
|
365
397
|
};
|
|
366
398
|
|
|
367
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
368
|
-
import { Annotation as Annotation2, Facet as
|
|
369
|
-
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";
|
|
370
402
|
import { Event } from "@dxos/async";
|
|
371
403
|
import { Context } from "@dxos/context";
|
|
372
404
|
var dummyProvider = {
|
|
@@ -375,17 +407,17 @@ var dummyProvider = {
|
|
|
375
407
|
},
|
|
376
408
|
close: () => {
|
|
377
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
378
411
|
update: () => {
|
|
379
|
-
}
|
|
380
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
381
413
|
};
|
|
382
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
383
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
384
416
|
});
|
|
385
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
386
418
|
var awareness = (provider = dummyProvider) => {
|
|
387
419
|
return [
|
|
388
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
389
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
390
422
|
decorations: (value) => value.decorations
|
|
391
423
|
}),
|
|
@@ -398,8 +430,8 @@ var RemoteSelectionsDecorator = class {
|
|
|
398
430
|
this._ctx = new Context();
|
|
399
431
|
this._lastAnchor = void 0;
|
|
400
432
|
this._lastHead = void 0;
|
|
401
|
-
this._cursorConverter = view.state.facet(
|
|
402
|
-
this._provider = view.state.facet(
|
|
433
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
403
435
|
this._provider.open();
|
|
404
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
405
437
|
view.dispatch({
|
|
@@ -453,7 +485,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
453
485
|
attributes: {
|
|
454
486
|
style: `background-color: ${lightColor}`
|
|
455
487
|
},
|
|
456
|
-
class: "cm-
|
|
488
|
+
class: "cm-collab-selection"
|
|
457
489
|
})
|
|
458
490
|
});
|
|
459
491
|
} else {
|
|
@@ -464,7 +496,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
464
496
|
attributes: {
|
|
465
497
|
style: `background-color: ${color}`
|
|
466
498
|
},
|
|
467
|
-
class: "cm-
|
|
499
|
+
class: "cm-collab-selection"
|
|
468
500
|
})
|
|
469
501
|
});
|
|
470
502
|
decorations.push({
|
|
@@ -474,7 +506,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
474
506
|
attributes: {
|
|
475
507
|
style: `background-color: ${color}`
|
|
476
508
|
},
|
|
477
|
-
class: "cm-
|
|
509
|
+
class: "cm-collab-selection"
|
|
478
510
|
})
|
|
479
511
|
});
|
|
480
512
|
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
@@ -485,7 +517,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
485
517
|
value: Decoration.line({
|
|
486
518
|
attributes: {
|
|
487
519
|
style: `background-color: ${color}`,
|
|
488
|
-
class: "cm-
|
|
520
|
+
class: "cm-collab-selectionLine"
|
|
489
521
|
}
|
|
490
522
|
})
|
|
491
523
|
});
|
|
@@ -505,23 +537,21 @@ var RemoteSelectionsDecorator = class {
|
|
|
505
537
|
}
|
|
506
538
|
};
|
|
507
539
|
var RemoteCaretWidget = class extends WidgetType {
|
|
508
|
-
constructor(
|
|
540
|
+
constructor(_name, _color) {
|
|
509
541
|
super();
|
|
510
|
-
this.
|
|
511
|
-
this.
|
|
512
|
-
this.name = name;
|
|
513
|
-
this.color = color;
|
|
542
|
+
this._name = _name;
|
|
543
|
+
this._color = _color;
|
|
514
544
|
}
|
|
515
545
|
toDOM() {
|
|
516
546
|
const span = document.createElement("span");
|
|
517
|
-
span.className = "cm-
|
|
518
|
-
span.style.backgroundColor = this.
|
|
519
|
-
span.style.borderColor = this.
|
|
547
|
+
span.className = "cm-collab-selectionCaret";
|
|
548
|
+
span.style.backgroundColor = this._color;
|
|
549
|
+
span.style.borderColor = this._color;
|
|
520
550
|
const dot = document.createElement("div");
|
|
521
|
-
dot.className = "cm-
|
|
551
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
522
552
|
const info = document.createElement("div");
|
|
523
|
-
info.className = "cm-
|
|
524
|
-
info.innerText = this.
|
|
553
|
+
info.className = "cm-collab-selectionInfo";
|
|
554
|
+
info.innerText = this._name;
|
|
525
555
|
span.appendChild(document.createTextNode("\u2060"));
|
|
526
556
|
span.appendChild(dot);
|
|
527
557
|
span.appendChild(document.createTextNode("\u2060"));
|
|
@@ -529,15 +559,12 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
529
559
|
span.appendChild(document.createTextNode("\u2060"));
|
|
530
560
|
return span;
|
|
531
561
|
}
|
|
532
|
-
eq(widget) {
|
|
533
|
-
return widget.color === this.color;
|
|
534
|
-
}
|
|
535
|
-
compare(widget) {
|
|
536
|
-
return widget.color === this.color;
|
|
537
|
-
}
|
|
538
562
|
updateDOM() {
|
|
539
563
|
return false;
|
|
540
564
|
}
|
|
565
|
+
eq(widget) {
|
|
566
|
+
return widget._color === this._color;
|
|
567
|
+
}
|
|
541
568
|
get estimatedHeight() {
|
|
542
569
|
return -1;
|
|
543
570
|
}
|
|
@@ -545,58 +572,60 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
545
572
|
return true;
|
|
546
573
|
}
|
|
547
574
|
};
|
|
548
|
-
var styles =
|
|
549
|
-
".cm-
|
|
550
|
-
".cm-
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
576
|
+
".cm-collab-selection": {},
|
|
577
|
+
".cm-collab-selectionLine": {
|
|
551
578
|
padding: 0,
|
|
552
579
|
margin: "0px 2px 0px 4px"
|
|
553
580
|
},
|
|
554
|
-
".cm-
|
|
581
|
+
".cm-collab-selectionCaret": {
|
|
555
582
|
position: "relative",
|
|
556
583
|
borderLeft: "1px solid black",
|
|
557
584
|
borderRight: "1px solid black",
|
|
558
585
|
marginLeft: "-1px",
|
|
559
586
|
marginRight: "-1px",
|
|
560
587
|
boxSizing: "border-box",
|
|
561
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
562
590
|
},
|
|
563
|
-
".cm-
|
|
591
|
+
".cm-collab-selectionCaretDot": {
|
|
564
592
|
borderRadius: "50%",
|
|
565
593
|
position: "absolute",
|
|
566
|
-
width: ".
|
|
567
|
-
height: ".
|
|
568
|
-
top: "-.
|
|
569
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
570
598
|
backgroundColor: "inherit",
|
|
571
599
|
transition: "transform .3s ease-in-out",
|
|
572
600
|
boxSizing: "border-box"
|
|
573
601
|
},
|
|
574
|
-
".cm-
|
|
575
|
-
|
|
576
|
-
|
|
602
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
577
605
|
},
|
|
578
|
-
".cm-
|
|
606
|
+
".cm-collab-selectionInfo": {
|
|
579
607
|
position: "absolute",
|
|
580
|
-
|
|
581
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
582
611
|
fontSize: ".75em",
|
|
583
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
584
613
|
fontStyle: "normal",
|
|
585
614
|
fontWeight: "normal",
|
|
586
615
|
lineHeight: "normal",
|
|
587
616
|
userSelect: "none",
|
|
588
617
|
color: "white",
|
|
589
|
-
|
|
590
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
591
619
|
zIndex: 101,
|
|
592
620
|
transition: "opacity .3s ease-in-out",
|
|
593
621
|
backgroundColor: "inherit",
|
|
594
|
-
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
595
624
|
opacity: 0,
|
|
596
625
|
transitionDelay: "0s",
|
|
597
626
|
whiteSpace: "nowrap"
|
|
598
627
|
},
|
|
599
|
-
".cm-
|
|
628
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
600
629
|
opacity: 1,
|
|
601
630
|
transitionDelay: "0s"
|
|
602
631
|
}
|
|
@@ -604,26 +633,29 @@ var styles = EditorView.baseTheme({
|
|
|
604
633
|
|
|
605
634
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
606
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
607
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
608
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
609
|
-
import { drawSelection, EditorView as
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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,
|
|
613
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
614
644
|
bracketMatching(),
|
|
615
645
|
closeBrackets(),
|
|
616
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
617
649
|
_placeholder && placeholder(_placeholder),
|
|
618
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
619
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
620
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
621
653
|
|
|
622
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
623
|
-
import { EditorView as
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
624
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
625
657
|
import { invariant } from "@dxos/invariant";
|
|
626
|
-
var
|
|
658
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
627
659
|
var defaultOptions = {
|
|
628
660
|
effect: 2,
|
|
629
661
|
maxParticles: 200,
|
|
@@ -656,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
656
688
|
const getPoint = (view, pos) => {
|
|
657
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
658
690
|
const element = document.elementFromPoint(x, y);
|
|
659
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
660
692
|
const point = {
|
|
661
693
|
x: x - left,
|
|
662
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
663
695
|
};
|
|
664
696
|
return {
|
|
665
697
|
element,
|
|
@@ -668,7 +700,7 @@ var blast = (options = defaultOptions) => {
|
|
|
668
700
|
};
|
|
669
701
|
return [
|
|
670
702
|
// Cursor moved.
|
|
671
|
-
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
672
704
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
673
705
|
if (blaster) {
|
|
674
706
|
blaster.destroy();
|
|
@@ -750,8 +782,8 @@ var Blaster = class {
|
|
|
750
782
|
}
|
|
751
783
|
initialize() {
|
|
752
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
753
|
-
F:
|
|
754
|
-
L:
|
|
785
|
+
F: __dxlog_file,
|
|
786
|
+
L: 141,
|
|
755
787
|
S: this,
|
|
756
788
|
A: [
|
|
757
789
|
"!this._canvas && !this._ctx",
|
|
@@ -787,8 +819,8 @@ var Blaster = class {
|
|
|
787
819
|
}
|
|
788
820
|
start() {
|
|
789
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
790
|
-
F:
|
|
791
|
-
L:
|
|
822
|
+
F: __dxlog_file,
|
|
823
|
+
L: 180,
|
|
792
824
|
S: this,
|
|
793
825
|
A: [
|
|
794
826
|
"this._canvas && this._ctx",
|
|
@@ -929,9 +961,14 @@ var random = (min, max) => {
|
|
|
929
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
930
962
|
};
|
|
931
963
|
|
|
932
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
933
|
-
import {
|
|
934
|
-
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";
|
|
935
972
|
|
|
936
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
974
|
import * as random2 from "lib0/random";
|
|
@@ -974,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
974
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
976
1013
|
var headings = {
|
|
977
|
-
1:
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
987
|
-
"-ml-[7px]"
|
|
988
|
-
],
|
|
989
|
-
4: [
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
991
|
-
"-ml-[6px]"
|
|
992
|
-
],
|
|
993
|
-
5: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
995
|
-
"-ml-[5px]"
|
|
996
|
-
],
|
|
997
|
-
6: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
999
|
-
"-ml-[4px]"
|
|
1000
|
-
]
|
|
1001
|
-
};
|
|
1002
|
-
var heading = (level, readonly) => {
|
|
1003
|
-
const [style, offset] = headings[level];
|
|
1004
|
-
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];
|
|
1005
1023
|
};
|
|
1006
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1019,154 +1037,109 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1019
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1020
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1021
1039
|
|
|
1022
|
-
// packages/ui/react-ui-editor/src/
|
|
1023
|
-
|
|
1024
|
-
var
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
display: "block",
|
|
1036
|
-
paddingInline: "4px !important"
|
|
1037
|
-
},
|
|
1038
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1039
|
-
paddingTop: "4px !important",
|
|
1040
|
-
borderTopLeftRadius: "4px",
|
|
1041
|
-
borderTopRightRadius: "4px"
|
|
1042
|
-
},
|
|
1043
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1044
|
-
paddingBottom: "4px !important",
|
|
1045
|
-
borderBottomLeftRadius: "4px",
|
|
1046
|
-
borderBottomRightRadius: "4px"
|
|
1040
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1041
|
+
import { log } from "@dxos/log";
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1043
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1044
|
+
try {
|
|
1045
|
+
return fn(...args);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1048
|
+
F: __dxlog_file2,
|
|
1049
|
+
L: 18,
|
|
1050
|
+
S: void 0,
|
|
1051
|
+
C: (f, a) => f(...a)
|
|
1052
|
+
});
|
|
1047
1053
|
}
|
|
1048
|
-
});
|
|
1049
|
-
var getLineRange = (lines, from, to) => {
|
|
1050
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1051
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1052
|
-
return [
|
|
1053
|
-
start,
|
|
1054
|
-
end
|
|
1055
|
-
];
|
|
1056
1054
|
};
|
|
1057
|
-
var
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
const text = view.state.doc.sliceString(0);
|
|
1062
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1063
|
-
const blocks = view.viewportLineBlocks;
|
|
1064
|
-
for (const match of matches) {
|
|
1065
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1066
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1067
|
-
const block = blocks[i];
|
|
1068
|
-
decorations.push(Decoration2.line({
|
|
1069
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1070
|
-
}).range(block.from));
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1073
1059
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
decorations: (value) => value.decorations
|
|
1088
|
-
}),
|
|
1089
|
-
styles2
|
|
1090
|
-
];
|
|
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
|
+
}
|
|
1091
1073
|
};
|
|
1092
1074
|
|
|
1093
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1094
|
-
|
|
1095
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1096
|
-
import sortBy from "lodash.sortby";
|
|
1097
|
-
import { debounce } from "@dxos/async";
|
|
1098
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1099
|
-
import { log as log2 } from "@dxos/log";
|
|
1100
|
-
import { nonNullable } from "@dxos/util";
|
|
1101
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1102
|
-
var styles3 = EditorView5.baseTheme({
|
|
1103
|
-
"& .cm-bookmark": {
|
|
1104
|
-
cursor: "pointer",
|
|
1105
|
-
margin: "4px",
|
|
1106
|
-
padding: "4px",
|
|
1107
|
-
backgroundColor: "yellow"
|
|
1108
|
-
},
|
|
1109
|
-
"& .cm-bookmark-selected": {
|
|
1110
|
-
backgroundColor: "orange"
|
|
1111
|
-
},
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1112
1077
|
"& .cm-comment": {
|
|
1113
1078
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1114
1079
|
},
|
|
1115
|
-
"& .cm-comment-
|
|
1080
|
+
"& .cm-comment-current": {
|
|
1116
1081
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1117
1082
|
}
|
|
1118
1083
|
});
|
|
1119
|
-
var
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1129
|
-
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) {
|
|
1130
1093
|
return;
|
|
1131
1094
|
}
|
|
1132
|
-
view.
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
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
|
+
}
|
|
1141
1112
|
};
|
|
1142
|
-
var
|
|
1113
|
+
var setComments = StateEffect2.define();
|
|
1143
1114
|
var setSelection = StateEffect2.define();
|
|
1144
1115
|
var setCommentState = StateEffect2.define();
|
|
1145
|
-
var
|
|
1116
|
+
var commentsState = StateField2.define({
|
|
1146
1117
|
create: () => ({
|
|
1147
|
-
|
|
1118
|
+
comments: [],
|
|
1119
|
+
selection: {}
|
|
1148
1120
|
}),
|
|
1149
1121
|
update: (value, tr) => {
|
|
1150
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1151
1122
|
for (const effect of tr.effects) {
|
|
1152
1123
|
if (effect.is(setSelection)) {
|
|
1153
1124
|
return {
|
|
1154
1125
|
...value,
|
|
1155
|
-
|
|
1126
|
+
selection: effect.value
|
|
1156
1127
|
};
|
|
1157
1128
|
}
|
|
1158
|
-
if (effect.is(
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
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);
|
|
1162
1135
|
return range && {
|
|
1163
|
-
|
|
1164
|
-
|
|
1136
|
+
comment,
|
|
1137
|
+
range
|
|
1165
1138
|
};
|
|
1166
1139
|
}).filter(nonNullable);
|
|
1167
1140
|
return {
|
|
1168
1141
|
...value,
|
|
1169
|
-
|
|
1142
|
+
comments: comments2
|
|
1170
1143
|
};
|
|
1171
1144
|
}
|
|
1172
1145
|
if (effect.is(setCommentState)) {
|
|
@@ -1176,143 +1149,174 @@ var commentsStateField = StateField2.define({
|
|
|
1176
1149
|
return value;
|
|
1177
1150
|
}
|
|
1178
1151
|
});
|
|
1179
|
-
var
|
|
1180
|
-
|
|
1152
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1153
|
+
commentsState
|
|
1181
1154
|
], (state) => {
|
|
1182
|
-
const {
|
|
1183
|
-
const decorations = sortBy(
|
|
1184
|
-
|
|
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);
|
|
1185
1160
|
return void 0;
|
|
1186
1161
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
to: selection.to
|
|
1190
|
-
};
|
|
1191
|
-
if (selection.id === active) {
|
|
1192
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1162
|
+
if (comment.comment.id === current) {
|
|
1163
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1193
1164
|
} else {
|
|
1194
|
-
return
|
|
1165
|
+
return commentMark.range(range.from, range.to);
|
|
1195
1166
|
}
|
|
1196
|
-
}).filter(nonNullable)
|
|
1197
|
-
return
|
|
1167
|
+
}).filter(nonNullable);
|
|
1168
|
+
return Decoration2.set(decorations);
|
|
1198
1169
|
});
|
|
1199
|
-
var
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1217
|
-
}
|
|
1218
|
-
toDOM() {
|
|
1219
|
-
const span = document.createElement("span");
|
|
1220
|
-
span.className = "cm-bookmark";
|
|
1221
|
-
span.textContent = "\u203B";
|
|
1222
|
-
if (this._handleClick) {
|
|
1223
|
-
span.onclick = () => this._handleClick();
|
|
1224
|
-
}
|
|
1225
|
-
return span;
|
|
1226
|
-
}
|
|
1227
|
-
};
|
|
1228
|
-
var comments = (options = {}) => {
|
|
1229
|
-
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1230
|
-
const createCommentThread = (view) => {
|
|
1231
|
-
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1232
|
-
invariant2(options.onCreate, void 0, {
|
|
1233
|
-
F: __dxlog_file3,
|
|
1234
|
-
L: 224,
|
|
1235
|
-
S: void 0,
|
|
1236
|
-
A: [
|
|
1237
|
-
"options.onCreate",
|
|
1238
|
-
""
|
|
1239
|
-
]
|
|
1240
|
-
});
|
|
1241
|
-
const { head, from, to } = view.state.selection.main;
|
|
1242
|
-
if (from === to) {
|
|
1243
|
-
return false;
|
|
1170
|
+
var trackPastedComments = (onUpdate) => {
|
|
1171
|
+
let tracked = null;
|
|
1172
|
+
const handleTrack = (event, view) => {
|
|
1173
|
+
const comments2 = view.state.field(commentsState);
|
|
1174
|
+
const { main } = view.state.selection;
|
|
1175
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1176
|
+
if (!selectedRanges.length) {
|
|
1177
|
+
tracked = null;
|
|
1178
|
+
} else {
|
|
1179
|
+
tracked = {
|
|
1180
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1181
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1182
|
+
id: comment.id,
|
|
1183
|
+
from: range.from - main.from,
|
|
1184
|
+
to: range.to - main.from
|
|
1185
|
+
}))
|
|
1186
|
+
};
|
|
1244
1187
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1188
|
+
};
|
|
1189
|
+
return [
|
|
1190
|
+
EditorView5.domEventHandlers({
|
|
1191
|
+
cut: handleTrack,
|
|
1192
|
+
copy: handleTrack
|
|
1193
|
+
}),
|
|
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
|
+
}));
|
|
1258
1206
|
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
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
|
+
}
|
|
1225
|
+
if (tracked) {
|
|
1226
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1227
|
+
if (paste) {
|
|
1228
|
+
let found = -1;
|
|
1229
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1230
|
+
if (text.eq(tracked.text)) {
|
|
1231
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1232
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1233
|
+
}
|
|
1234
|
+
found = fromB;
|
|
1269
1235
|
}
|
|
1270
1236
|
});
|
|
1237
|
+
if (found > -1) {
|
|
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
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
tracked = null;
|
|
1271
1247
|
}
|
|
1272
|
-
return true;
|
|
1273
1248
|
}
|
|
1274
|
-
|
|
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
|
+
}
|
|
1257
|
+
})
|
|
1258
|
+
];
|
|
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
1275
|
return false;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
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
|
|
1289
1298
|
}
|
|
1290
1299
|
});
|
|
1300
|
+
return true;
|
|
1291
1301
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}, {
|
|
1299
|
-
decorations: (instance) => instance.bookmarks,
|
|
1300
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1301
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1302
|
-
})
|
|
1303
|
-
});
|
|
1302
|
+
}
|
|
1303
|
+
return false;
|
|
1304
|
+
};
|
|
1305
|
+
var comments = (options = {}) => {
|
|
1306
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1307
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1304
1308
|
return [
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
+
optionsFacet.of(options),
|
|
1310
|
+
commentsState,
|
|
1311
|
+
commentsDecorations,
|
|
1312
|
+
styles2,
|
|
1309
1313
|
//
|
|
1310
1314
|
// Keymap.
|
|
1311
1315
|
//
|
|
1312
1316
|
options.onCreate ? keymap3.of([
|
|
1313
1317
|
{
|
|
1314
|
-
key:
|
|
1315
|
-
run: callbackWrapper(
|
|
1318
|
+
key: shortcut,
|
|
1319
|
+
run: callbackWrapper(createComment)
|
|
1316
1320
|
}
|
|
1317
1321
|
]) : [],
|
|
1318
1322
|
//
|
|
@@ -1328,7 +1332,7 @@ var comments = (options = {}) => {
|
|
|
1328
1332
|
above: true,
|
|
1329
1333
|
create: () => {
|
|
1330
1334
|
const el = document.createElement("div");
|
|
1331
|
-
options.onHover
|
|
1335
|
+
options.onHover(el, shortcut);
|
|
1332
1336
|
return {
|
|
1333
1337
|
dom: el,
|
|
1334
1338
|
offset: {
|
|
@@ -1341,366 +1345,100 @@ var comments = (options = {}) => {
|
|
|
1341
1345
|
}
|
|
1342
1346
|
return null;
|
|
1343
1347
|
}, {
|
|
1344
|
-
|
|
1348
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1349
|
+
// hideOnChange: true,
|
|
1345
1350
|
hoverTime: 1e3
|
|
1346
1351
|
}) : [],
|
|
1347
1352
|
//
|
|
1348
|
-
//
|
|
1349
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1353
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1350
1354
|
//
|
|
1351
1355
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1352
|
-
|
|
1353
|
-
{
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
if (
|
|
1359
|
-
|
|
1360
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1361
|
-
log2.info("deleted comment", {
|
|
1362
|
-
thread: range.id
|
|
1363
|
-
}, {
|
|
1364
|
-
F: __dxlog_file3,
|
|
1365
|
-
L: 358,
|
|
1366
|
-
S: void 0,
|
|
1367
|
-
C: (f, a) => f(...a)
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
if (from <= range.to) {
|
|
1372
|
-
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1373
|
-
Object.assign(range, newRange);
|
|
1374
|
-
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);
|
|
1375
1364
|
}
|
|
1376
|
-
}
|
|
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
|
+
})
|
|
1377
1379
|
});
|
|
1378
|
-
if (mod) {
|
|
1379
|
-
view.dispatch({
|
|
1380
|
-
effects: setCommentState.of({
|
|
1381
|
-
active,
|
|
1382
|
-
ranges
|
|
1383
|
-
})
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
1380
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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));
|
|
1400
1397
|
if (d < min) {
|
|
1401
|
-
|
|
1398
|
+
selection.closest = comment.id;
|
|
1402
1399
|
min = d;
|
|
1403
1400
|
}
|
|
1404
|
-
});
|
|
1405
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1406
|
-
view.dispatch({
|
|
1407
|
-
effects: setSelection.of(selected)
|
|
1408
|
-
});
|
|
1409
|
-
handleSelect({
|
|
1410
|
-
...selected,
|
|
1411
|
-
ranges: ranges.map((range) => ({
|
|
1412
|
-
...range,
|
|
1413
|
-
location: view.coordsAtPos(range.from)
|
|
1414
|
-
}))
|
|
1415
|
-
});
|
|
1416
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
|
+
});
|
|
1417
1415
|
}
|
|
1418
|
-
})
|
|
1416
|
+
}),
|
|
1417
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1419
1418
|
];
|
|
1420
1419
|
};
|
|
1421
|
-
var
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
to
|
|
1427
|
-
].join(":");
|
|
1428
|
-
};
|
|
1429
|
-
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1430
|
-
const parts = cursor.split(":");
|
|
1431
|
-
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1432
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1433
|
-
return from !== void 0 && to !== void 0 ? {
|
|
1434
|
-
from,
|
|
1435
|
-
to
|
|
1436
|
-
} : void 0;
|
|
1437
|
-
};
|
|
1438
|
-
|
|
1439
|
-
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1440
|
-
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1441
|
-
var styles4 = EditorView6.baseTheme({
|
|
1442
|
-
"& .cm-hr": {
|
|
1443
|
-
// TODO(burdon): ???
|
|
1444
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1445
|
-
borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1449
|
-
constructor(_pos) {
|
|
1450
|
-
super();
|
|
1451
|
-
this._pos = _pos;
|
|
1452
|
-
}
|
|
1453
|
-
eq(other) {
|
|
1454
|
-
return this._pos === other._pos;
|
|
1455
|
-
}
|
|
1456
|
-
toDOM(view) {
|
|
1457
|
-
const el = document.createElement("div");
|
|
1458
|
-
el.className = "cm-hr";
|
|
1459
|
-
return el;
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1463
|
-
regexp: /^---$/g,
|
|
1464
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1465
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1466
|
-
})
|
|
1467
|
-
});
|
|
1468
|
-
var hr = () => [
|
|
1469
|
-
styles4,
|
|
1470
|
-
ViewPlugin5.fromClass(class {
|
|
1471
|
-
constructor(view) {
|
|
1472
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1473
|
-
}
|
|
1474
|
-
update(update2) {
|
|
1475
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1476
|
-
}
|
|
1477
|
-
}, {
|
|
1478
|
-
decorations: (instance) => instance.rules,
|
|
1479
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1480
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1482
|
-
})
|
|
1483
|
-
})
|
|
1484
|
-
];
|
|
1485
|
-
|
|
1486
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1487
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1488
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1490
|
-
var image = (options = {}) => {
|
|
1491
|
-
return StateField3.define({
|
|
1492
|
-
create: (state) => {
|
|
1493
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1494
|
-
},
|
|
1495
|
-
update: (value, tr) => {
|
|
1496
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1497
|
-
return value;
|
|
1498
|
-
}
|
|
1499
|
-
const cursor = tr.state.selection.main.head;
|
|
1500
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1501
|
-
let from = Math.min(cursor, oldCursor);
|
|
1502
|
-
let to = Math.max(cursor, oldCursor);
|
|
1503
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1504
|
-
from = Math.min(from, fromB);
|
|
1505
|
-
to = Math.max(to, toB);
|
|
1506
|
-
});
|
|
1507
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1508
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1509
|
-
return value.map(tr.changes).update({
|
|
1510
|
-
filterFrom: from,
|
|
1511
|
-
filterTo: to,
|
|
1512
|
-
filter: () => false,
|
|
1513
|
-
add: buildDecorations(from, to, tr.state)
|
|
1420
|
+
var useComments = (view, comments2 = []) => {
|
|
1421
|
+
useEffect(() => {
|
|
1422
|
+
if (view) {
|
|
1423
|
+
view.dispatch({
|
|
1424
|
+
effects: setComments.of(comments2)
|
|
1514
1425
|
});
|
|
1515
|
-
},
|
|
1516
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1517
|
-
});
|
|
1518
|
-
};
|
|
1519
|
-
var buildDecorations = (from, to, state) => {
|
|
1520
|
-
const decorations = [];
|
|
1521
|
-
const cursor = state.selection.main.head;
|
|
1522
|
-
syntaxTree(state).iterate({
|
|
1523
|
-
enter: (node) => {
|
|
1524
|
-
if (node.name === "Image") {
|
|
1525
|
-
const urlNode = node.node.getChild("URL");
|
|
1526
|
-
if (urlNode) {
|
|
1527
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1528
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1529
|
-
decorations.push(Decoration5.replace({
|
|
1530
|
-
block: true,
|
|
1531
|
-
widget: new ImageWidget(url)
|
|
1532
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
},
|
|
1536
|
-
from,
|
|
1537
|
-
to
|
|
1538
|
-
});
|
|
1539
|
-
return decorations;
|
|
1540
|
-
};
|
|
1541
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1542
|
-
constructor(_url) {
|
|
1543
|
-
super();
|
|
1544
|
-
this._url = _url;
|
|
1545
|
-
}
|
|
1546
|
-
eq(other) {
|
|
1547
|
-
return this._url === other._url;
|
|
1548
|
-
}
|
|
1549
|
-
toDOM(view) {
|
|
1550
|
-
const img = document.createElement("img");
|
|
1551
|
-
img.setAttribute("src", this._url);
|
|
1552
|
-
img.setAttribute("class", "cm-image");
|
|
1553
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1554
|
-
return img;
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
|
|
1558
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1559
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1560
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1561
|
-
import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
1562
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1563
|
-
var link = (options = {}) => {
|
|
1564
|
-
const extensions = [
|
|
1565
|
-
ViewPlugin6.fromClass(class {
|
|
1566
|
-
constructor(view) {
|
|
1567
|
-
this.decorations = buildDecorations2(view, options);
|
|
1568
|
-
}
|
|
1569
|
-
update(update2) {
|
|
1570
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1571
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
}, {
|
|
1575
|
-
decorations: (v) => v.decorations
|
|
1576
|
-
})
|
|
1577
|
-
];
|
|
1578
|
-
if (options.onHover) {
|
|
1579
|
-
extensions.push(
|
|
1580
|
-
// https://codemirror.net/examples/tooltip
|
|
1581
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1582
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1583
|
-
hoverTooltip2((view, pos, side) => {
|
|
1584
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1585
|
-
let link2 = null;
|
|
1586
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1587
|
-
link2 = node.name === "Link" ? node : null;
|
|
1588
|
-
}
|
|
1589
|
-
const url = link2 && link2.getChild("URL");
|
|
1590
|
-
if (!url || !link2) {
|
|
1591
|
-
return null;
|
|
1592
|
-
}
|
|
1593
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1594
|
-
return {
|
|
1595
|
-
pos: link2.from,
|
|
1596
|
-
end: link2.to,
|
|
1597
|
-
above: true,
|
|
1598
|
-
create: () => {
|
|
1599
|
-
const el = document.createElement("div");
|
|
1600
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1601
|
-
options.onHover(el, urlText);
|
|
1602
|
-
return {
|
|
1603
|
-
dom: el,
|
|
1604
|
-
offset: {
|
|
1605
|
-
x: 0,
|
|
1606
|
-
y: 4
|
|
1607
|
-
}
|
|
1608
|
-
};
|
|
1609
|
-
}
|
|
1610
|
-
};
|
|
1611
|
-
})
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
return extensions;
|
|
1615
|
-
};
|
|
1616
|
-
var LinkButton = class extends WidgetType5 {
|
|
1617
|
-
constructor(_url, _onAttach) {
|
|
1618
|
-
super();
|
|
1619
|
-
this._url = _url;
|
|
1620
|
-
this._onAttach = _onAttach;
|
|
1621
|
-
}
|
|
1622
|
-
eq(other) {
|
|
1623
|
-
return this._url === other._url;
|
|
1624
|
-
}
|
|
1625
|
-
toDOM(view) {
|
|
1626
|
-
const el = document.createElement("span");
|
|
1627
|
-
this._onAttach(el, this._url);
|
|
1628
|
-
return el;
|
|
1629
|
-
}
|
|
1630
|
-
};
|
|
1631
|
-
var LinkText = class extends WidgetType5 {
|
|
1632
|
-
constructor(_text, _url) {
|
|
1633
|
-
super();
|
|
1634
|
-
this._text = _text;
|
|
1635
|
-
this._url = _url;
|
|
1636
|
-
}
|
|
1637
|
-
eq(other) {
|
|
1638
|
-
return this._url === other._url;
|
|
1639
|
-
}
|
|
1640
|
-
toDOM(view) {
|
|
1641
|
-
const link2 = document.createElement("a");
|
|
1642
|
-
link2.setAttribute("class", "cm-link");
|
|
1643
|
-
link2.textContent = this._text;
|
|
1644
|
-
if (this._url) {
|
|
1645
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1646
|
-
link2.setAttribute("target", "_blank");
|
|
1647
|
-
link2.href = this._url;
|
|
1648
|
-
} else {
|
|
1649
|
-
link2.onclick = () => {
|
|
1650
|
-
view.dispatch({
|
|
1651
|
-
selection: {
|
|
1652
|
-
anchor: view.posAtDOM(link2)
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
};
|
|
1656
1426
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
const builder = new RangeSetBuilder();
|
|
1662
|
-
const { state } = view;
|
|
1663
|
-
const cursor = state.selection.main.head;
|
|
1664
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1665
|
-
syntaxTree2(state).iterate({
|
|
1666
|
-
enter: (node) => {
|
|
1667
|
-
if (node.name === "Link") {
|
|
1668
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1669
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1670
|
-
const urlNode = node.node.getChild("URL");
|
|
1671
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1672
|
-
if (!url) {
|
|
1673
|
-
return false;
|
|
1674
|
-
}
|
|
1675
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1676
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1677
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1678
|
-
}));
|
|
1679
|
-
}
|
|
1680
|
-
if (options.onRender) {
|
|
1681
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1682
|
-
widget: new LinkButton(url, options.onRender)
|
|
1683
|
-
}));
|
|
1684
|
-
}
|
|
1685
|
-
return false;
|
|
1686
|
-
}
|
|
1687
|
-
},
|
|
1688
|
-
from,
|
|
1689
|
-
to
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
return builder.finish();
|
|
1427
|
+
}, [
|
|
1428
|
+
view,
|
|
1429
|
+
comments2
|
|
1430
|
+
]);
|
|
1693
1431
|
};
|
|
1694
1432
|
|
|
1695
1433
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1696
|
-
import { EditorView as
|
|
1434
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1697
1435
|
var listener = ({ onFocus, onChange }) => {
|
|
1698
1436
|
const extensions = [];
|
|
1699
|
-
onFocus && extensions.push(
|
|
1437
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1700
1438
|
onFocus(focused);
|
|
1701
1439
|
return null;
|
|
1702
1440
|
}));
|
|
1703
|
-
onChange && extensions.push(
|
|
1441
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1704
1442
|
onChange(update2.state.doc.toString());
|
|
1705
1443
|
}));
|
|
1706
1444
|
return extensions;
|
|
@@ -1708,14 +1446,15 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1708
1446
|
|
|
1709
1447
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1710
1448
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1711
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1449
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1712
1450
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1713
1451
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1714
1452
|
import { languages } from "@codemirror/language-data";
|
|
1715
1453
|
import { searchKeymap } from "@codemirror/search";
|
|
1716
1454
|
import { EditorState } from "@codemirror/state";
|
|
1717
1455
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1718
|
-
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";
|
|
1719
1458
|
|
|
1720
1459
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1721
1460
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1728,7 +1467,6 @@ var markdownTags = {
|
|
|
1728
1467
|
CodeText: Tag.define(),
|
|
1729
1468
|
EmphasisMark: Tag.define(),
|
|
1730
1469
|
HeaderMark: Tag.define(),
|
|
1731
|
-
// HorizontalRule: Tag.define(),
|
|
1732
1470
|
InlineCode: Tag.define(),
|
|
1733
1471
|
LinkLabel: Tag.define(),
|
|
1734
1472
|
LinkReference: Tag.define(),
|
|
@@ -1813,7 +1551,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1813
1551
|
markdownTags.QuoteMark,
|
|
1814
1552
|
markdownTags.EmphasisMark
|
|
1815
1553
|
],
|
|
1816
|
-
class:
|
|
1554
|
+
class: mark
|
|
1817
1555
|
},
|
|
1818
1556
|
// E.g., code block language (after ```).
|
|
1819
1557
|
{
|
|
@@ -1821,7 +1559,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1821
1559
|
tags.function(tags.variableName),
|
|
1822
1560
|
tags.labelName
|
|
1823
1561
|
],
|
|
1824
|
-
class:
|
|
1562
|
+
class: codeMark
|
|
1825
1563
|
},
|
|
1826
1564
|
{
|
|
1827
1565
|
tag: [
|
|
@@ -1832,27 +1570,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1832
1570
|
// Headings.
|
|
1833
1571
|
{
|
|
1834
1572
|
tag: tags.heading1,
|
|
1835
|
-
class: heading(1
|
|
1573
|
+
class: heading(1)
|
|
1836
1574
|
},
|
|
1837
1575
|
{
|
|
1838
1576
|
tag: tags.heading2,
|
|
1839
|
-
class: heading(2
|
|
1577
|
+
class: heading(2)
|
|
1840
1578
|
},
|
|
1841
1579
|
{
|
|
1842
1580
|
tag: tags.heading3,
|
|
1843
|
-
class: heading(3
|
|
1581
|
+
class: heading(3)
|
|
1844
1582
|
},
|
|
1845
1583
|
{
|
|
1846
1584
|
tag: tags.heading4,
|
|
1847
|
-
class: heading(4
|
|
1585
|
+
class: heading(4)
|
|
1848
1586
|
},
|
|
1849
1587
|
{
|
|
1850
1588
|
tag: tags.heading5,
|
|
1851
|
-
class: heading(5
|
|
1589
|
+
class: heading(5)
|
|
1852
1590
|
},
|
|
1853
1591
|
{
|
|
1854
1592
|
tag: tags.heading6,
|
|
1855
|
-
class: heading(6
|
|
1593
|
+
class: heading(6)
|
|
1856
1594
|
},
|
|
1857
1595
|
// Emphasis.
|
|
1858
1596
|
{
|
|
@@ -1878,7 +1616,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1878
1616
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1879
1617
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1880
1618
|
// the code, but all other CSS properties will be inherited.
|
|
1881
|
-
// 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.
|
|
1882
1620
|
{
|
|
1883
1621
|
tag: [
|
|
1884
1622
|
markdownTags.CodeText,
|
|
@@ -1892,12 +1630,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1892
1630
|
],
|
|
1893
1631
|
class: blockquote
|
|
1894
1632
|
},
|
|
1895
|
-
// TODO(burdon): Replace with extension.
|
|
1896
|
-
// {
|
|
1897
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1898
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1899
|
-
// },
|
|
1900
|
-
// TODO(burdon): Only if being edited.
|
|
1901
1633
|
{
|
|
1902
1634
|
tag: [
|
|
1903
1635
|
markdownTags.TableCell
|
|
@@ -1913,19 +1645,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1913
1645
|
};
|
|
1914
1646
|
|
|
1915
1647
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1916
|
-
var
|
|
1648
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1917
1649
|
return [
|
|
1650
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1918
1651
|
EditorState.allowMultipleSelections.of(true),
|
|
1919
1652
|
EditorState.tabSize.of(2),
|
|
1920
|
-
|
|
1921
|
-
customKeymap(),
|
|
1653
|
+
// https://github.com/codemirror/basic-setup
|
|
1922
1654
|
bracketMatching2(),
|
|
1923
1655
|
closeBrackets2(),
|
|
1924
1656
|
crosshairCursor(),
|
|
1925
1657
|
dropCursor(),
|
|
1926
1658
|
drawSelection2(),
|
|
1927
|
-
|
|
1928
|
-
|
|
1659
|
+
highlightActiveLine2(),
|
|
1660
|
+
history2(),
|
|
1929
1661
|
indentOnInput(),
|
|
1930
1662
|
_placeholder && placeholder2(_placeholder),
|
|
1931
1663
|
// Main extension.
|
|
@@ -1949,66 +1681,610 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1949
1681
|
// https://github.com/codemirror/theme-one-dark
|
|
1950
1682
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1951
1683
|
// Custom styles.
|
|
1952
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
]);
|
|
1967
|
-
|
|
1968
|
-
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1969
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1970
|
-
var mention = ({ onSearch }) => {
|
|
1971
|
-
return autocompletion2({
|
|
1972
|
-
closeOnBlur: false,
|
|
1973
|
-
override: [
|
|
1974
|
-
(context) => {
|
|
1975
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1976
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
1977
|
-
return null;
|
|
1978
|
-
}
|
|
1979
|
-
console.log(match);
|
|
1980
|
-
return {
|
|
1981
|
-
from: match.from,
|
|
1982
|
-
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1983
|
-
label: `@${value}`
|
|
1984
|
-
}))
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
]
|
|
1988
|
-
});
|
|
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);
|
|
1989
1698
|
};
|
|
1990
1699
|
|
|
1991
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1992
|
-
import { syntaxTree
|
|
1993
|
-
import { RangeSetBuilder
|
|
1994
|
-
import {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
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
|
+
}
|
|
1791
|
+
}
|
|
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);
|
|
1804
|
+
}
|
|
1805
|
+
update(update2) {
|
|
1806
|
+
this.decorations = buildDecorations(update2.view);
|
|
1807
|
+
}
|
|
1808
|
+
}, {
|
|
1809
|
+
decorations: (value) => value.decorations
|
|
1810
|
+
}),
|
|
1811
|
+
styles3
|
|
1812
|
+
];
|
|
1813
|
+
};
|
|
1814
|
+
|
|
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
|
+
},
|
|
2088
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
2089
|
+
});
|
|
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
|
+
};
|
|
2278
|
+
var update = (state, options) => {
|
|
2279
|
+
const builder = new RangeSetBuilder6();
|
|
2280
|
+
const cursor = state.selection.main.head;
|
|
2281
|
+
const tables = [];
|
|
2282
|
+
const getTable = () => tables[tables.length - 1];
|
|
2007
2283
|
const getRow = () => {
|
|
2008
2284
|
const table2 = getTable();
|
|
2009
2285
|
return table2.rows?.[table2.rows.length - 1];
|
|
2010
2286
|
};
|
|
2011
|
-
|
|
2287
|
+
syntaxTree7(state).iterate({
|
|
2012
2288
|
enter: (node) => {
|
|
2013
2289
|
switch (node.name) {
|
|
2014
2290
|
case "Table": {
|
|
@@ -2040,10 +2316,10 @@ var update = (state, options) => {
|
|
|
2040
2316
|
});
|
|
2041
2317
|
tables.forEach((table2) => {
|
|
2042
2318
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2043
|
-
hide && builder.add(table2.from, table2.to,
|
|
2319
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2044
2320
|
widget: new TableWidget(table2)
|
|
2045
2321
|
}));
|
|
2046
|
-
builder.add(table2.from, table2.to,
|
|
2322
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2047
2323
|
class: "cm-table"
|
|
2048
2324
|
}));
|
|
2049
2325
|
});
|
|
@@ -2086,92 +2362,139 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2086
2362
|
}
|
|
2087
2363
|
};
|
|
2088
2364
|
|
|
2089
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2090
|
-
import {
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
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"
|
|
2095
2376
|
}
|
|
2096
2377
|
});
|
|
2097
2378
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2098
|
-
constructor(_checked
|
|
2379
|
+
constructor(_checked) {
|
|
2099
2380
|
super();
|
|
2100
2381
|
this._checked = _checked;
|
|
2101
|
-
this._indent = _indent;
|
|
2102
|
-
this._onCheck = _onCheck;
|
|
2103
2382
|
}
|
|
2104
2383
|
eq(other) {
|
|
2105
|
-
return this._checked === other._checked
|
|
2384
|
+
return this._checked === other._checked;
|
|
2106
2385
|
}
|
|
2107
2386
|
toDOM(view) {
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2111
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2112
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2387
|
+
const input = document.createElement("input");
|
|
2388
|
+
input.className = "cm-task-checkbox";
|
|
2113
2389
|
input.type = "checkbox";
|
|
2114
2390
|
input.checked = this._checked;
|
|
2115
|
-
if (
|
|
2391
|
+
if (view.state.readOnly) {
|
|
2116
2392
|
input.setAttribute("disabled", "true");
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2393
|
+
} else {
|
|
2394
|
+
input.onmousedown = (event) => {
|
|
2395
|
+
const pos = view.posAtDOM(input);
|
|
2396
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2397
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2398
|
+
view.dispatch({
|
|
2399
|
+
changes: {
|
|
2400
|
+
from: pos + 1,
|
|
2401
|
+
to: pos + 2,
|
|
2402
|
+
insert: this._checked ? " " : "x"
|
|
2403
|
+
}
|
|
2404
|
+
});
|
|
2405
|
+
event.preventDefault();
|
|
2406
|
+
}
|
|
2122
2407
|
};
|
|
2123
2408
|
}
|
|
2124
|
-
return
|
|
2409
|
+
return input;
|
|
2125
2410
|
}
|
|
2126
2411
|
ignoreEvent() {
|
|
2127
2412
|
return false;
|
|
2128
2413
|
}
|
|
2129
2414
|
};
|
|
2415
|
+
var checkedDecoration = Decoration10.replace({
|
|
2416
|
+
widget: new CheckboxWidget(true)
|
|
2417
|
+
});
|
|
2418
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2419
|
+
widget: new CheckboxWidget(false)
|
|
2420
|
+
});
|
|
2421
|
+
var buildDecorations6 = (view) => {
|
|
2422
|
+
const builder = new RangeSetBuilder7();
|
|
2423
|
+
const { state } = view;
|
|
2424
|
+
const cursor = state.selection.main.head;
|
|
2425
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2426
|
+
syntaxTree8(state).iterate({
|
|
2427
|
+
enter: (node) => {
|
|
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
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
},
|
|
2438
|
+
from,
|
|
2439
|
+
to
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
return builder.finish();
|
|
2443
|
+
};
|
|
2130
2444
|
var tasklist = (options = {}) => {
|
|
2131
|
-
const taskMatcher = new MatchDecorator3({
|
|
2132
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2133
|
-
decoration: (match, view, pos) => {
|
|
2134
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2135
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2136
|
-
return Decoration8.replace({
|
|
2137
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2138
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2139
|
-
view.dispatch({
|
|
2140
|
-
changes: {
|
|
2141
|
-
from: idx,
|
|
2142
|
-
to: idx + 1,
|
|
2143
|
-
insert: checked2 ? "x" : " "
|
|
2144
|
-
},
|
|
2145
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2146
|
-
selection: {
|
|
2147
|
-
anchor: idx + 3
|
|
2148
|
-
}
|
|
2149
|
-
});
|
|
2150
|
-
})
|
|
2151
|
-
});
|
|
2152
|
-
}
|
|
2153
|
-
});
|
|
2154
|
-
const tasks = ViewPlugin7.fromClass(class {
|
|
2155
|
-
constructor(view) {
|
|
2156
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2157
|
-
}
|
|
2158
|
-
update(update2) {
|
|
2159
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2160
|
-
}
|
|
2161
|
-
}, {
|
|
2162
|
-
decorations: (value) => value.tasks,
|
|
2163
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2164
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2165
|
-
})
|
|
2166
|
-
});
|
|
2167
2445
|
return [
|
|
2168
|
-
|
|
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
|
+
}),
|
|
2169
2458
|
styles5
|
|
2170
2459
|
];
|
|
2171
2460
|
};
|
|
2172
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
|
+
};
|
|
2495
|
+
|
|
2173
2496
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2174
|
-
import { keymap as
|
|
2497
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2175
2498
|
var defaultItems = [
|
|
2176
2499
|
"hello world!",
|
|
2177
2500
|
"this is a test.",
|
|
@@ -2181,7 +2504,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2181
2504
|
let t;
|
|
2182
2505
|
let idx = 0;
|
|
2183
2506
|
return [
|
|
2184
|
-
|
|
2507
|
+
keymap6.of([
|
|
2185
2508
|
{
|
|
2186
2509
|
// Reset.
|
|
2187
2510
|
key: "alt-meta-'",
|
|
@@ -2227,27 +2550,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2227
2550
|
];
|
|
2228
2551
|
};
|
|
2229
2552
|
|
|
2230
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2231
|
-
import { yCollab } from "y-codemirror.next";
|
|
2232
|
-
|
|
2233
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2234
|
-
import * as Y from "yjs";
|
|
2235
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2236
|
-
var cursorConverter2 = (text) => ({
|
|
2237
|
-
toCursor: (index, assoc) => {
|
|
2238
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2239
|
-
},
|
|
2240
|
-
fromCursor: (cursor) => {
|
|
2241
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2242
|
-
}
|
|
2243
|
-
});
|
|
2244
|
-
|
|
2245
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2246
|
-
var yjs = (content, awareness2) => [
|
|
2247
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2248
|
-
yCollab(content, awareness2)
|
|
2249
|
-
];
|
|
2250
|
-
|
|
2251
2553
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2252
2554
|
import get3 from "lodash.get";
|
|
2253
2555
|
var defaultTheme = {
|
|
@@ -2279,8 +2581,9 @@ var defaultTheme = {
|
|
|
2279
2581
|
outline: "none"
|
|
2280
2582
|
},
|
|
2281
2583
|
".cm-scroller": {
|
|
2282
|
-
overflow:
|
|
2283
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2584
|
+
// overflow: 'visible',
|
|
2585
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
2586
|
+
lineHeight: 1.4
|
|
2284
2587
|
},
|
|
2285
2588
|
".cm-content": {
|
|
2286
2589
|
padding: 0,
|
|
@@ -2304,8 +2607,11 @@ var defaultTheme = {
|
|
|
2304
2607
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2305
2608
|
borderLeft: "2px solid white"
|
|
2306
2609
|
},
|
|
2307
|
-
".cm-placeholder": {
|
|
2308
|
-
|
|
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)")
|
|
2309
2615
|
},
|
|
2310
2616
|
//
|
|
2311
2617
|
// line
|
|
@@ -2314,7 +2620,7 @@ var defaultTheme = {
|
|
|
2314
2620
|
paddingInline: 0
|
|
2315
2621
|
},
|
|
2316
2622
|
".cm-activeLine": {
|
|
2317
|
-
background: "
|
|
2623
|
+
background: "transparent"
|
|
2318
2624
|
},
|
|
2319
2625
|
//
|
|
2320
2626
|
// Selection
|
|
@@ -2341,33 +2647,6 @@ var defaultTheme = {
|
|
|
2341
2647
|
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2342
2648
|
},
|
|
2343
2649
|
//
|
|
2344
|
-
// collaboration
|
|
2345
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2346
|
-
//
|
|
2347
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2348
|
-
mixBlendMode: "multiply"
|
|
2349
|
-
},
|
|
2350
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2351
|
-
mixBlendMode: "screen"
|
|
2352
|
-
},
|
|
2353
|
-
".cm-ySelectionInfo": {
|
|
2354
|
-
padding: "2px 4px",
|
|
2355
|
-
marginBlockStart: "-4px"
|
|
2356
|
-
},
|
|
2357
|
-
".cm-ySelection, & .cm-selectionMatch": {
|
|
2358
|
-
paddingBlockStart: ".15em",
|
|
2359
|
-
paddingBlockEnd: ".15em"
|
|
2360
|
-
},
|
|
2361
|
-
".cm-ySelectionCaret": {
|
|
2362
|
-
display: "inline-block",
|
|
2363
|
-
insetBlockStart: ".1em",
|
|
2364
|
-
blockSize: "1.4em",
|
|
2365
|
-
verticalAlign: "top"
|
|
2366
|
-
},
|
|
2367
|
-
".cm-yLineSelection": {
|
|
2368
|
-
margin: 0
|
|
2369
|
-
},
|
|
2370
|
-
//
|
|
2371
2650
|
// link
|
|
2372
2651
|
//
|
|
2373
2652
|
".cm-link": {
|
|
@@ -2404,13 +2683,6 @@ var defaultTheme = {
|
|
|
2404
2683
|
textDecoration: "none"
|
|
2405
2684
|
},
|
|
2406
2685
|
//
|
|
2407
|
-
// widgets
|
|
2408
|
-
//
|
|
2409
|
-
".cm-widgetBuffer": {
|
|
2410
|
-
display: "none",
|
|
2411
|
-
height: 0
|
|
2412
|
-
},
|
|
2413
|
-
//
|
|
2414
2686
|
// table
|
|
2415
2687
|
//
|
|
2416
2688
|
".cm-table *": {
|
|
@@ -2441,27 +2713,17 @@ var defaultTheme = {
|
|
|
2441
2713
|
},
|
|
2442
2714
|
//
|
|
2443
2715
|
// font size
|
|
2444
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2716
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2717
|
+
// but it's far more verbose than it needs to be.
|
|
2445
2718
|
//
|
|
2446
|
-
...Object.keys(
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2455
|
-
height
|
|
2456
|
-
};
|
|
2457
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2458
|
-
height
|
|
2459
|
-
};
|
|
2460
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2461
|
-
height
|
|
2462
|
-
};
|
|
2463
|
-
return acc;
|
|
2464
|
-
}, {}),
|
|
2719
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2720
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2721
|
+
//
|
|
2722
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2723
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2724
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2725
|
+
// return acc;
|
|
2726
|
+
// }, {}),
|
|
2465
2727
|
/**
|
|
2466
2728
|
* Panels
|
|
2467
2729
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2512,7 +2774,9 @@ var textTheme = {
|
|
|
2512
2774
|
}
|
|
2513
2775
|
};
|
|
2514
2776
|
var markdownTheme = {
|
|
2515
|
-
|
|
2777
|
+
".cm-scroller": {
|
|
2778
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2779
|
+
},
|
|
2516
2780
|
".cm-placeholder": {
|
|
2517
2781
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2518
2782
|
}
|
|
@@ -2527,95 +2791,95 @@ var codeTheme = {
|
|
|
2527
2791
|
};
|
|
2528
2792
|
|
|
2529
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";
|
|
2530
2795
|
var EditorModes = [
|
|
2531
2796
|
"default",
|
|
2532
2797
|
"vim"
|
|
2533
2798
|
];
|
|
2534
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2799
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2535
2800
|
const { themeMode } = useThemeContext();
|
|
2536
|
-
const
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
const [root, setRoot] = useState(null);
|
|
2540
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2541
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2542
|
-
root,
|
|
2543
|
-
state,
|
|
2801
|
+
const rootRef = useRef(null);
|
|
2802
|
+
const [view, setView] = useState(null);
|
|
2803
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2544
2804
|
view
|
|
2545
|
-
}), [
|
|
2546
|
-
view,
|
|
2547
|
-
state,
|
|
2548
|
-
root
|
|
2549
|
-
]);
|
|
2550
|
-
const { awareness: awareness2, peer } = model;
|
|
2551
|
-
useEffect(() => {
|
|
2552
|
-
if (awareness2 && peer) {
|
|
2553
|
-
awareness2.setLocalStateField("user", {
|
|
2554
|
-
name: peer.name ?? generateName(peer.id),
|
|
2555
|
-
color: getColorForValue({
|
|
2556
|
-
value: peer.id,
|
|
2557
|
-
type: "color"
|
|
2558
|
-
}),
|
|
2559
|
-
colorLight: getColorForValue({
|
|
2560
|
-
value: peer.id,
|
|
2561
|
-
themeMode,
|
|
2562
|
-
type: "highlight"
|
|
2563
|
-
})
|
|
2564
|
-
});
|
|
2565
|
-
}
|
|
2566
|
-
}, [
|
|
2567
|
-
awareness2,
|
|
2568
|
-
peer,
|
|
2569
|
-
themeMode
|
|
2570
2805
|
]);
|
|
2571
|
-
|
|
2572
|
-
if (
|
|
2573
|
-
view.
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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
|
+
}
|
|
2816
|
+
view?.focus();
|
|
2579
2817
|
}
|
|
2580
2818
|
}, [
|
|
2581
2819
|
view,
|
|
2582
|
-
|
|
2820
|
+
autoFocus
|
|
2583
2821
|
]);
|
|
2584
|
-
|
|
2585
|
-
if (!
|
|
2822
|
+
useEffect2(() => {
|
|
2823
|
+
if (!model || !rootRef.current) {
|
|
2586
2824
|
return;
|
|
2587
2825
|
}
|
|
2588
|
-
const
|
|
2826
|
+
const state = EditorState2.create({
|
|
2589
2827
|
doc: model.text(),
|
|
2828
|
+
selection,
|
|
2590
2829
|
extensions: [
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
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
|
+
}),
|
|
2594
2839
|
// Theme.
|
|
2595
|
-
// TODO(burdon): Make
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
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),
|
|
2599
2853
|
// Storage and replication.
|
|
2854
|
+
// NOTE: This must come before user extensions.
|
|
2600
2855
|
model.extension,
|
|
2856
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2857
|
+
editorMode === "vim" && vim(),
|
|
2601
2858
|
// Custom.
|
|
2602
2859
|
...extensions
|
|
2603
|
-
].filter(
|
|
2860
|
+
].filter(isNotFalsy3)
|
|
2604
2861
|
});
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2862
|
+
const newView = new EditorView13({
|
|
2863
|
+
state,
|
|
2864
|
+
parent: rootRef.current,
|
|
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
|
+
}
|
|
2612
2874
|
});
|
|
2875
|
+
view?.destroy();
|
|
2876
|
+
setView(newView);
|
|
2613
2877
|
return () => {
|
|
2614
|
-
|
|
2615
|
-
|
|
2878
|
+
newView?.destroy();
|
|
2879
|
+
setView(null);
|
|
2616
2880
|
};
|
|
2617
2881
|
}, [
|
|
2618
|
-
|
|
2882
|
+
rootRef,
|
|
2619
2883
|
model,
|
|
2620
2884
|
readonly,
|
|
2621
2885
|
editorMode,
|
|
@@ -2625,11 +2889,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2625
2889
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2626
2890
|
switch (key) {
|
|
2627
2891
|
case "Enter": {
|
|
2628
|
-
view?.
|
|
2892
|
+
view?.focus();
|
|
2629
2893
|
break;
|
|
2630
2894
|
}
|
|
2631
2895
|
case "Escape": {
|
|
2632
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2896
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2897
|
+
view?.focus();
|
|
2898
|
+
}
|
|
2633
2899
|
break;
|
|
2634
2900
|
}
|
|
2635
2901
|
}
|
|
@@ -2639,83 +2905,238 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2639
2905
|
]);
|
|
2640
2906
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2641
2907
|
key: model.id,
|
|
2642
|
-
|
|
2908
|
+
role: "none",
|
|
2643
2909
|
tabIndex: 0,
|
|
2644
|
-
...slots
|
|
2645
|
-
...editorMode !==
|
|
2646
|
-
onKeyUp: handleKeyUp
|
|
2910
|
+
...slots.root,
|
|
2911
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2912
|
+
onKeyUp: handleKeyUp,
|
|
2913
|
+
ref: rootRef
|
|
2647
2914
|
});
|
|
2648
2915
|
});
|
|
2649
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2916
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2650
2917
|
const { themeMode } = useThemeContext();
|
|
2651
|
-
const
|
|
2918
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2652
2919
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2653
2920
|
ref: forwardedRef,
|
|
2654
2921
|
readonly,
|
|
2655
2922
|
extensions: [
|
|
2656
|
-
|
|
2657
|
-
readonly,
|
|
2923
|
+
createBasicBundle({
|
|
2658
2924
|
themeMode,
|
|
2659
|
-
placeholder:
|
|
2925
|
+
placeholder: placeholder3,
|
|
2926
|
+
lineWrapping
|
|
2660
2927
|
}),
|
|
2661
2928
|
...extensions
|
|
2662
2929
|
],
|
|
2663
|
-
|
|
2930
|
+
theme,
|
|
2931
|
+
slots: updatedSlots,
|
|
2664
2932
|
...props
|
|
2665
2933
|
});
|
|
2666
2934
|
});
|
|
2667
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2935
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2668
2936
|
const { themeMode } = useThemeContext();
|
|
2669
|
-
const
|
|
2937
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2670
2938
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2671
2939
|
ref: forwardedRef,
|
|
2672
2940
|
readonly,
|
|
2673
2941
|
extensions: [
|
|
2674
|
-
|
|
2675
|
-
readonly,
|
|
2942
|
+
createMarkdownExtensions({
|
|
2676
2943
|
themeMode,
|
|
2677
|
-
placeholder:
|
|
2944
|
+
placeholder: placeholder3
|
|
2678
2945
|
}),
|
|
2679
2946
|
...extensions
|
|
2680
2947
|
],
|
|
2681
|
-
|
|
2948
|
+
theme,
|
|
2949
|
+
slots: updatedSlots,
|
|
2682
2950
|
...props
|
|
2683
2951
|
});
|
|
2684
2952
|
});
|
|
2685
2953
|
var defaultSlots = {
|
|
2686
2954
|
root: {
|
|
2687
|
-
className: mx3("
|
|
2955
|
+
className: mx3("grow", focusRing)
|
|
2956
|
+
},
|
|
2957
|
+
editor: {
|
|
2958
|
+
className: "bs-full"
|
|
2688
2959
|
}
|
|
2689
2960
|
};
|
|
2690
2961
|
var defaultTextSlots = {
|
|
2691
|
-
...defaultSlots
|
|
2692
|
-
editor: {
|
|
2693
|
-
theme: textTheme
|
|
2694
|
-
}
|
|
2962
|
+
...defaultSlots
|
|
2695
2963
|
};
|
|
2696
2964
|
var defaultMarkdownSlots = {
|
|
2697
|
-
...defaultSlots
|
|
2698
|
-
editor: {
|
|
2699
|
-
theme: markdownTheme
|
|
2700
|
-
}
|
|
2965
|
+
...defaultSlots
|
|
2701
2966
|
};
|
|
2702
2967
|
|
|
2703
|
-
// packages/ui/react-ui-editor/src/
|
|
2704
|
-
import
|
|
2705
|
-
import {
|
|
2706
|
-
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
|
+
};
|
|
2707
3128
|
|
|
2708
3129
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2709
3130
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2710
3131
|
import { Context as Context2 } from "@dxos/context";
|
|
2711
|
-
import { invariant as
|
|
3132
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2712
3133
|
import { log as log3 } from "@dxos/log";
|
|
2713
3134
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2714
3135
|
var DEBOUNCE_INTERVAL = 100;
|
|
2715
3136
|
var SpaceAwarenessProvider = class {
|
|
2716
3137
|
constructor(params) {
|
|
2717
|
-
this.remoteStateChange = new Event2();
|
|
2718
3138
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
3139
|
+
this.remoteStateChange = new Event2();
|
|
2719
3140
|
this._space = params.space;
|
|
2720
3141
|
this._channel = params.channel;
|
|
2721
3142
|
this._peerId = params.peerId;
|
|
@@ -2732,7 +3153,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2732
3153
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2733
3154
|
}
|
|
2734
3155
|
});
|
|
2735
|
-
|
|
3156
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2736
3157
|
switch (message.payload.kind) {
|
|
2737
3158
|
case "query": {
|
|
2738
3159
|
this._handleQueryMessage();
|
|
@@ -2743,8 +3164,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2743
3164
|
break;
|
|
2744
3165
|
}
|
|
2745
3166
|
}
|
|
2746
|
-
});
|
|
2747
|
-
this._ctx.onDispose(unsubscribe);
|
|
3167
|
+
}));
|
|
2748
3168
|
void this._space.postMessage(this._channel, {
|
|
2749
3169
|
kind: "query"
|
|
2750
3170
|
}).catch((err) => {
|
|
@@ -2752,7 +3172,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2752
3172
|
err
|
|
2753
3173
|
}, {
|
|
2754
3174
|
F: __dxlog_file4,
|
|
2755
|
-
L:
|
|
3175
|
+
L: 89,
|
|
2756
3176
|
S: this,
|
|
2757
3177
|
C: (f, a) => f(...a)
|
|
2758
3178
|
});
|
|
@@ -2763,10 +3183,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2763
3183
|
this._ctx = void 0;
|
|
2764
3184
|
this._postTask = void 0;
|
|
2765
3185
|
}
|
|
3186
|
+
getRemoteStates() {
|
|
3187
|
+
return Array.from(this._remoteStates.values());
|
|
3188
|
+
}
|
|
2766
3189
|
update(position) {
|
|
2767
|
-
|
|
3190
|
+
invariant2(this._postTask, void 0, {
|
|
2768
3191
|
F: __dxlog_file4,
|
|
2769
|
-
L:
|
|
3192
|
+
L: 104,
|
|
2770
3193
|
S: this,
|
|
2771
3194
|
A: [
|
|
2772
3195
|
"this._postTask",
|
|
@@ -2780,13 +3203,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2780
3203
|
};
|
|
2781
3204
|
this._postTask.schedule();
|
|
2782
3205
|
}
|
|
2783
|
-
getRemoteStates() {
|
|
2784
|
-
return Array.from(this._remoteStates.values());
|
|
2785
|
-
}
|
|
2786
3206
|
_handleQueryMessage() {
|
|
2787
|
-
|
|
3207
|
+
invariant2(this._postTask, void 0, {
|
|
2788
3208
|
F: __dxlog_file4,
|
|
2789
|
-
L:
|
|
3209
|
+
L: 115,
|
|
2790
3210
|
S: this,
|
|
2791
3211
|
A: [
|
|
2792
3212
|
"this._postTask",
|
|
@@ -2796,9 +3216,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2796
3216
|
this._postTask.schedule();
|
|
2797
3217
|
}
|
|
2798
3218
|
_handlePostMessage(message) {
|
|
2799
|
-
|
|
3219
|
+
invariant2(message.kind === "post", void 0, {
|
|
2800
3220
|
F: __dxlog_file4,
|
|
2801
|
-
L:
|
|
3221
|
+
L: 120,
|
|
2802
3222
|
S: this,
|
|
2803
3223
|
A: [
|
|
2804
3224
|
"message.kind === 'post'",
|
|
@@ -2810,229 +3230,240 @@ var SpaceAwarenessProvider = class {
|
|
|
2810
3230
|
}
|
|
2811
3231
|
};
|
|
2812
3232
|
|
|
2813
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
3233
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2814
3234
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2815
|
-
|
|
2816
|
-
|
|
3235
|
+
var modelState = StateField5.define({
|
|
3236
|
+
create: () => void 0,
|
|
3237
|
+
update: (model) => model
|
|
3238
|
+
});
|
|
2817
3239
|
|
|
2818
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
arrayToString2(to)
|
|
2855
|
-
].join(":");
|
|
2856
|
-
},
|
|
2857
|
-
getRangeFromCursor: (cursor) => {
|
|
2858
|
-
invariant4(text.doc, void 0, {
|
|
2859
|
-
F: __dxlog_file5,
|
|
2860
|
-
L: 40,
|
|
2861
|
-
S: void 0,
|
|
2862
|
-
A: [
|
|
2863
|
-
"text.doc",
|
|
2864
|
-
""
|
|
2865
|
-
]
|
|
3240
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3241
|
+
var useActionHandler = (view) => {
|
|
3242
|
+
return (action) => {
|
|
3243
|
+
if (!view) {
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
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
|
|
2866
3276
|
});
|
|
2867
|
-
|
|
2868
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2869
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2870
|
-
return from && to ? {
|
|
2871
|
-
from: from.index,
|
|
2872
|
-
to: to.index
|
|
2873
|
-
} : void 0;
|
|
2874
|
-
},
|
|
2875
|
-
extension: [
|
|
2876
|
-
modelState.init(() => model),
|
|
2877
|
-
yjs(text.content, provider?.awareness)
|
|
2878
|
-
],
|
|
2879
|
-
awareness: provider?.awareness,
|
|
2880
|
-
peer: identity ? {
|
|
2881
|
-
id: identity.identityKey.toHex(),
|
|
2882
|
-
name: identity.profile?.displayName
|
|
2883
|
-
} : void 0
|
|
3277
|
+
});
|
|
2884
3278
|
};
|
|
2885
|
-
return model;
|
|
2886
3279
|
};
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
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);
|
|
2945
3339
|
}
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
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);
|
|
2956
3350
|
}
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
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
|
+
};
|
|
2962
3362
|
}
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
return encoder;
|
|
3363
|
+
if (autoFocus) {
|
|
3364
|
+
view.focus();
|
|
2966
3365
|
}
|
|
2967
3366
|
}
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
}
|
|
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);
|
|
2978
3398
|
};
|
|
2979
3399
|
|
|
2980
3400
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
}
|
|
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";
|
|
2985
3408
|
var useTextModel = (props) => {
|
|
2986
3409
|
const { identity, space, text } = props;
|
|
2987
|
-
const [model, setModel] =
|
|
2988
|
-
|
|
3410
|
+
const [model, setModel] = useState4();
|
|
3411
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2989
3412
|
identity,
|
|
2990
3413
|
space,
|
|
2991
3414
|
text
|
|
2992
3415
|
]);
|
|
2993
3416
|
return model;
|
|
2994
3417
|
};
|
|
2995
|
-
var
|
|
2996
|
-
const
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
}
|
|
3418
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
3419
|
+
const [content, setContent] = useState4(defaultContent ?? "");
|
|
3420
|
+
return {
|
|
3421
|
+
id,
|
|
3422
|
+
content,
|
|
3423
|
+
setContent,
|
|
3424
|
+
text: () => content
|
|
3425
|
+
};
|
|
3004
3426
|
};
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
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
|
+
});
|
|
3008
3437
|
const obj = text;
|
|
3009
3438
|
const doc = getRawDoc(obj, [
|
|
3010
3439
|
obj.field
|
|
3011
3440
|
]);
|
|
3012
|
-
const
|
|
3441
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
3013
3442
|
space,
|
|
3014
3443
|
channel: `automerge.awareness.${obj.id}`,
|
|
3015
3444
|
info: {
|
|
3016
|
-
displayName: identity
|
|
3445
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
3017
3446
|
color: cursorColor.color,
|
|
3018
3447
|
lightColor: cursorColor.light
|
|
3019
3448
|
},
|
|
3020
3449
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3021
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
|
+
}
|
|
3022
3462
|
const model = {
|
|
3023
3463
|
id: obj.id,
|
|
3024
3464
|
content: doc,
|
|
3025
3465
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3026
|
-
|
|
3027
|
-
extension: [
|
|
3028
|
-
modelState.init(() => model),
|
|
3029
|
-
automerge3({
|
|
3030
|
-
handle: doc.handle,
|
|
3031
|
-
path: doc.path
|
|
3032
|
-
}),
|
|
3033
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3034
|
-
awareness()
|
|
3035
|
-
].filter(isNotNullOrUndefined),
|
|
3466
|
+
extension: extensions,
|
|
3036
3467
|
peer: identity ? {
|
|
3037
3468
|
id: identity.identityKey.toHex(),
|
|
3038
3469
|
name: identity.profile?.displayName
|
|
@@ -3041,9 +3472,8 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3041
3472
|
return model;
|
|
3042
3473
|
};
|
|
3043
3474
|
export {
|
|
3044
|
-
AwarenessProvider,
|
|
3045
3475
|
BaseTextEditor,
|
|
3046
|
-
|
|
3476
|
+
Cursor,
|
|
3047
3477
|
Doc,
|
|
3048
3478
|
EditorModes,
|
|
3049
3479
|
MarkdownEditor,
|
|
@@ -3051,47 +3481,66 @@ export {
|
|
|
3051
3481
|
SpaceAwarenessProvider,
|
|
3052
3482
|
TextEditor,
|
|
3053
3483
|
TextKind,
|
|
3054
|
-
|
|
3484
|
+
Toolbar,
|
|
3055
3485
|
YText,
|
|
3056
3486
|
YXmlFragment,
|
|
3057
3487
|
autocomplete,
|
|
3058
|
-
|
|
3488
|
+
automerge,
|
|
3059
3489
|
awareness,
|
|
3060
|
-
|
|
3490
|
+
awarenessProvider,
|
|
3061
3491
|
blast,
|
|
3062
3492
|
callbackWrapper,
|
|
3063
3493
|
code2 as code,
|
|
3064
3494
|
codeTheme,
|
|
3065
3495
|
comments,
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3496
|
+
createBasicBundle,
|
|
3497
|
+
createComment,
|
|
3498
|
+
createDataExtensions,
|
|
3499
|
+
createMarkdownExtensions,
|
|
3500
|
+
createThemeExtensions,
|
|
3069
3501
|
defaultMarkdownSlots,
|
|
3070
3502
|
defaultOptions,
|
|
3071
3503
|
defaultSlots,
|
|
3072
3504
|
defaultTextSlots,
|
|
3073
3505
|
defaultTheme,
|
|
3506
|
+
focusComment,
|
|
3507
|
+
formatting,
|
|
3074
3508
|
getToken,
|
|
3509
|
+
heading2 as heading,
|
|
3075
3510
|
hr,
|
|
3076
3511
|
image,
|
|
3512
|
+
insertCodeblock,
|
|
3513
|
+
insertTable,
|
|
3514
|
+
keymap7 as keymap,
|
|
3077
3515
|
link,
|
|
3078
3516
|
listener,
|
|
3079
|
-
|
|
3517
|
+
logChanges,
|
|
3080
3518
|
markdownHighlightStyle,
|
|
3081
3519
|
markdownTags,
|
|
3082
3520
|
markdownTagsExtensions,
|
|
3083
3521
|
markdownTheme,
|
|
3084
3522
|
mention,
|
|
3085
3523
|
modelState,
|
|
3086
|
-
|
|
3087
|
-
|
|
3524
|
+
outliner,
|
|
3525
|
+
setComments,
|
|
3526
|
+
setHeading,
|
|
3088
3527
|
setSelection,
|
|
3089
3528
|
table,
|
|
3090
3529
|
tags2 as tags,
|
|
3091
3530
|
tasklist,
|
|
3092
3531
|
textTheme,
|
|
3532
|
+
toggleBold,
|
|
3533
|
+
toggleItalic,
|
|
3534
|
+
toggleList,
|
|
3535
|
+
toggleStrikethrough,
|
|
3536
|
+
toggleStyle,
|
|
3093
3537
|
typewriter,
|
|
3538
|
+
useActionHandler,
|
|
3539
|
+
useComments,
|
|
3540
|
+
useEditorView,
|
|
3541
|
+
useInMemoryTextModel,
|
|
3542
|
+
useTextEditor,
|
|
3094
3543
|
useTextModel,
|
|
3095
|
-
|
|
3544
|
+
useToolbarContext
|
|
3096
3545
|
};
|
|
3097
3546
|
//# sourceMappingURL=index.mjs.map
|