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