@dxos/react-ui-editor 0.3.11-main.08776d7 → 0.3.11-main.0999ea0
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 +1211 -1005
- 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 +12 -17
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +13 -7
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +9 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +14 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +6 -6
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +6 -6
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +11 -3
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +0 -8
- 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 +11 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +8 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts +3 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/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 +1 -4
- package/dist/types/src/hooks/defs.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -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/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- 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 +2 -0
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +45 -36
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +61 -72
- package/src/components/TextEditor/TextEditor.tsx +101 -77
- package/src/components/TextEditor/comments.stories.tsx +16 -21
- package/src/components/Toolbar/Toolbar.stories.tsx +86 -0
- package/src/components/Toolbar/Toolbar.tsx +115 -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 +53 -13
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +9 -29
- package/src/extensions/automerge/semaphore.ts +24 -28
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +17 -17
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/comments.ts +149 -92
- package/src/extensions/index.ts +0 -8
- package/src/extensions/markdown/bundle.ts +20 -30
- package/src/extensions/markdown/code.ts +142 -0
- package/src/extensions/markdown/formatting.ts +159 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -15
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +5 -2
- package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +48 -34
- package/src/extensions/mention.ts +9 -2
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +1 -6
- package/src/hooks/index.ts +2 -2
- package/src/hooks/useActionHandler.ts +45 -0
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +48 -11
- package/src/styles/markdown.ts +9 -10
- package/src/themes/default.ts +1 -3
- package/src/util.ts +26 -3
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/sync.d.ts +0 -7
- package/dist/types/src/extensions/sync.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts +0 -7
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -4
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -28
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -104
- package/src/extensions/hr.ts +0 -72
- package/src/extensions/sync.ts +0 -15
- package/src/extensions/yjs/cursor.ts +0 -22
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -53
- package/src/hooks/yjs.ts +0 -157
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
- /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
|
@@ -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 } 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,12 +53,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
56
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
54
57
|
import { StateField } from "@codemirror/state";
|
|
55
|
-
import {
|
|
58
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
59
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
56
60
|
|
|
57
61
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
58
62
|
import get from "lodash.get";
|
|
59
|
-
import { next as
|
|
63
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
60
64
|
var cursorConverter = (handle, path) => ({
|
|
61
65
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
62
66
|
toCursor: (pos) => {
|
|
@@ -68,7 +72,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
68
72
|
if (typeof value === "string" && value.length <= pos) {
|
|
69
73
|
return "end";
|
|
70
74
|
}
|
|
71
|
-
return
|
|
75
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
72
76
|
},
|
|
73
77
|
fromCursor: (cursor) => {
|
|
74
78
|
if (cursor === "") {
|
|
@@ -86,26 +90,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
86
90
|
return 0;
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
|
-
return
|
|
93
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
90
94
|
}
|
|
91
95
|
});
|
|
92
96
|
|
|
93
97
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
94
98
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
95
|
-
var effectType = StateEffect.define({});
|
|
96
|
-
var reconcileAnnotationType = Annotation.define();
|
|
97
99
|
var getPath = (state, field) => state.field(field).path;
|
|
98
100
|
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
99
|
-
var
|
|
101
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
102
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
100
103
|
newHeads
|
|
101
104
|
});
|
|
102
|
-
var
|
|
105
|
+
var reconcileAnnotation = Annotation.define();
|
|
106
|
+
var isReconcile = (tr) => {
|
|
107
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
108
|
+
};
|
|
103
109
|
|
|
104
110
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
105
|
-
import { next as
|
|
111
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
106
112
|
|
|
107
113
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
108
|
-
import { next as
|
|
114
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
109
115
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
110
116
|
const { lastHeads, path } = state.field(field);
|
|
111
117
|
let hasChanges = false;
|
|
@@ -118,11 +124,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
118
124
|
return void 0;
|
|
119
125
|
}
|
|
120
126
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
127
|
+
const invertedTransactions = [];
|
|
121
128
|
for (const tr of transactions) {
|
|
122
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
123
|
-
|
|
129
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
130
|
+
invertedTransactions.push({
|
|
131
|
+
from: fromA,
|
|
132
|
+
del: toA - fromA,
|
|
133
|
+
insert
|
|
134
|
+
});
|
|
124
135
|
});
|
|
125
136
|
}
|
|
137
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
138
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
139
|
+
});
|
|
126
140
|
});
|
|
127
141
|
return newHeads ?? void 0;
|
|
128
142
|
};
|
|
@@ -137,13 +151,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
137
151
|
selection = selection.map(changeSet, 1);
|
|
138
152
|
view.dispatch({
|
|
139
153
|
changes: changeSet,
|
|
140
|
-
annotations:
|
|
154
|
+
annotations: reconcileAnnotation.of(false)
|
|
141
155
|
});
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
view.dispatch({
|
|
145
159
|
selection,
|
|
146
|
-
annotations:
|
|
160
|
+
annotations: reconcileAnnotation.of(false)
|
|
147
161
|
});
|
|
148
162
|
};
|
|
149
163
|
var handlePatch = (patch, target, state) => {
|
|
@@ -164,7 +178,7 @@ var handleInsert = (target, patch) => {
|
|
|
164
178
|
if (index == null) {
|
|
165
179
|
return [];
|
|
166
180
|
}
|
|
167
|
-
const text = patch.values.map((
|
|
181
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
168
182
|
return [
|
|
169
183
|
{
|
|
170
184
|
from: index,
|
|
@@ -237,41 +251,42 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
251
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
238
252
|
var PatchSemaphore = class {
|
|
239
253
|
// prettier-ignore
|
|
240
|
-
constructor(_handle,
|
|
254
|
+
constructor(_handle, _state) {
|
|
241
255
|
this._handle = _handle;
|
|
242
|
-
this.
|
|
256
|
+
this._state = _state;
|
|
243
257
|
this._inReconcile = false;
|
|
244
258
|
}
|
|
245
|
-
// NOTE: Cannot destruct view.state.
|
|
246
259
|
reconcile(view) {
|
|
247
|
-
if (this._inReconcile) {
|
|
248
|
-
|
|
260
|
+
if (!this._inReconcile) {
|
|
261
|
+
this._inReconcile = true;
|
|
262
|
+
this.doReconcile(view);
|
|
263
|
+
this._inReconcile = false;
|
|
249
264
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
265
|
+
}
|
|
266
|
+
doReconcile(view) {
|
|
267
|
+
const path = getPath(view.state, this._state);
|
|
268
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
253
269
|
let selection = view.state.selection;
|
|
254
|
-
const transactions = view.state.field(this.
|
|
270
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
255
271
|
const toInvert = transactions.slice().reverse();
|
|
256
|
-
for (const
|
|
257
|
-
const inverted =
|
|
272
|
+
for (const tr of toInvert) {
|
|
273
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
258
274
|
selection = selection.map(inverted);
|
|
259
275
|
view.dispatch({
|
|
260
276
|
changes: inverted,
|
|
261
|
-
annotations:
|
|
277
|
+
annotations: reconcileAnnotation.of(true)
|
|
262
278
|
});
|
|
263
279
|
}
|
|
264
|
-
let newHeads = updateAutomerge(this.
|
|
280
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
265
281
|
if (newHeads === null || newHeads === void 0) {
|
|
266
|
-
newHeads =
|
|
282
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
267
283
|
}
|
|
268
|
-
const diff =
|
|
284
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
269
285
|
updateCodeMirror(view, selection, path, diff);
|
|
270
286
|
view.dispatch({
|
|
271
287
|
effects: updateHeads(newHeads),
|
|
272
|
-
annotations:
|
|
288
|
+
annotations: reconcileAnnotation.of(false)
|
|
273
289
|
});
|
|
274
|
-
this._inReconcile = false;
|
|
275
290
|
}
|
|
276
291
|
};
|
|
277
292
|
|
|
@@ -289,9 +304,9 @@ var Cursor = class _Cursor {
|
|
|
289
304
|
}
|
|
290
305
|
static {
|
|
291
306
|
this.getCursorFromRange = (state, range) => {
|
|
292
|
-
const
|
|
293
|
-
const from =
|
|
294
|
-
const to =
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
309
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
295
310
|
return [
|
|
296
311
|
from,
|
|
297
312
|
to
|
|
@@ -300,10 +315,10 @@ var Cursor = class _Cursor {
|
|
|
300
315
|
}
|
|
301
316
|
static {
|
|
302
317
|
this.getRangeFromCursor = (state, cursor) => {
|
|
303
|
-
const
|
|
318
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
304
319
|
const parts = cursor.split(":");
|
|
305
|
-
const from =
|
|
306
|
-
const to =
|
|
320
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
321
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
307
322
|
return from !== void 0 && to !== void 0 ? {
|
|
308
323
|
from,
|
|
309
324
|
to
|
|
@@ -312,18 +327,12 @@ var Cursor = class _Cursor {
|
|
|
312
327
|
}
|
|
313
328
|
};
|
|
314
329
|
|
|
315
|
-
// packages/ui/react-ui-editor/src/extensions/sync.ts
|
|
316
|
-
import { Facet as Facet2 } from "@codemirror/state";
|
|
317
|
-
var syncFacet = Facet2.define({
|
|
318
|
-
combine: (values) => values.at(-1)
|
|
319
|
-
});
|
|
320
|
-
|
|
321
330
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
322
|
-
var
|
|
323
|
-
const
|
|
331
|
+
var automerge = ({ handle, path }) => {
|
|
332
|
+
const syncState = StateField.define({
|
|
324
333
|
create: () => ({
|
|
325
334
|
path: path.slice(),
|
|
326
|
-
lastHeads:
|
|
335
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
327
336
|
unreconciledTransactions: []
|
|
328
337
|
}),
|
|
329
338
|
update: (value, tr) => {
|
|
@@ -334,7 +343,7 @@ var automerge3 = ({ handle, path }) => {
|
|
|
334
343
|
};
|
|
335
344
|
let clearUnreconciled = false;
|
|
336
345
|
for (const effect of tr.effects) {
|
|
337
|
-
if (effect.is(
|
|
346
|
+
if (effect.is(updateHeadsEffect)) {
|
|
338
347
|
result.lastHeads = effect.value.newHeads;
|
|
339
348
|
clearUnreconciled = true;
|
|
340
349
|
}
|
|
@@ -342,26 +351,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
342
351
|
if (clearUnreconciled) {
|
|
343
352
|
result.unreconciledTransactions = [];
|
|
344
353
|
} else {
|
|
345
|
-
if (!
|
|
354
|
+
if (!isReconcile(tr)) {
|
|
346
355
|
result.unreconciledTransactions.push(tr);
|
|
347
356
|
}
|
|
348
357
|
}
|
|
349
358
|
return result;
|
|
350
359
|
}
|
|
351
360
|
});
|
|
352
|
-
const semaphore = new PatchSemaphore(handle,
|
|
353
|
-
return
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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) => {
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return effects;
|
|
394
|
+
})
|
|
395
|
+
];
|
|
360
396
|
};
|
|
361
397
|
|
|
362
398
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
363
|
-
import { Annotation as Annotation2, Facet as
|
|
364
|
-
import { Decoration, EditorView, ViewPlugin, 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";
|
|
365
401
|
import { Event } from "@dxos/async";
|
|
366
402
|
import { Context } from "@dxos/context";
|
|
367
403
|
var dummyProvider = {
|
|
@@ -370,18 +406,18 @@ var dummyProvider = {
|
|
|
370
406
|
},
|
|
371
407
|
close: () => {
|
|
372
408
|
},
|
|
409
|
+
getRemoteStates: () => [],
|
|
373
410
|
update: () => {
|
|
374
|
-
}
|
|
375
|
-
getRemoteStates: () => []
|
|
411
|
+
}
|
|
376
412
|
};
|
|
377
|
-
var
|
|
413
|
+
var awarenessProvider = Facet2.define({
|
|
378
414
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
379
415
|
});
|
|
380
416
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
381
417
|
var awareness = (provider = dummyProvider) => {
|
|
382
418
|
return [
|
|
383
|
-
|
|
384
|
-
|
|
419
|
+
awarenessProvider.of(provider),
|
|
420
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
385
421
|
decorations: (value) => value.decorations
|
|
386
422
|
}),
|
|
387
423
|
styles
|
|
@@ -394,7 +430,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
394
430
|
this._lastAnchor = void 0;
|
|
395
431
|
this._lastHead = void 0;
|
|
396
432
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
397
|
-
this._provider = view.state.facet(
|
|
433
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
398
434
|
this._provider.open();
|
|
399
435
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
400
436
|
view.dispatch({
|
|
@@ -535,7 +571,7 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
535
571
|
return true;
|
|
536
572
|
}
|
|
537
573
|
};
|
|
538
|
-
var styles =
|
|
574
|
+
var styles = EditorView2.baseTheme({
|
|
539
575
|
".cm-collab-selection": {},
|
|
540
576
|
".cm-collab-selectionLine": {
|
|
541
577
|
padding: 0,
|
|
@@ -548,39 +584,41 @@ var styles = EditorView.baseTheme({
|
|
|
548
584
|
marginLeft: "-1px",
|
|
549
585
|
marginRight: "-1px",
|
|
550
586
|
boxSizing: "border-box",
|
|
551
|
-
display: "inline"
|
|
587
|
+
display: "inline",
|
|
588
|
+
cursor: "pointer"
|
|
552
589
|
},
|
|
553
590
|
".cm-collab-selectionCaretDot": {
|
|
554
591
|
borderRadius: "50%",
|
|
555
592
|
position: "absolute",
|
|
556
|
-
width: ".
|
|
557
|
-
height: ".
|
|
558
|
-
top: "-.
|
|
559
|
-
left: "-.
|
|
593
|
+
width: ".5em",
|
|
594
|
+
height: ".5em",
|
|
595
|
+
top: "-.25em",
|
|
596
|
+
left: "-.25em",
|
|
560
597
|
backgroundColor: "inherit",
|
|
561
598
|
transition: "transform .3s ease-in-out",
|
|
562
599
|
boxSizing: "border-box"
|
|
563
600
|
},
|
|
564
601
|
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
565
|
-
|
|
566
|
-
|
|
602
|
+
transform: "scale(0)",
|
|
603
|
+
transformOrigin: "center"
|
|
567
604
|
},
|
|
568
605
|
".cm-collab-selectionInfo": {
|
|
569
606
|
position: "absolute",
|
|
570
|
-
|
|
571
|
-
|
|
607
|
+
transform: "translate(-50%, 0)",
|
|
608
|
+
top: "-20px",
|
|
609
|
+
left: 0,
|
|
572
610
|
fontSize: ".75em",
|
|
573
|
-
fontFamily: "serif",
|
|
611
|
+
fontFamily: "sans-serif",
|
|
574
612
|
fontStyle: "normal",
|
|
575
613
|
fontWeight: "normal",
|
|
576
614
|
lineHeight: "normal",
|
|
577
615
|
userSelect: "none",
|
|
578
616
|
color: "white",
|
|
579
|
-
|
|
580
|
-
paddingRight: "2px",
|
|
617
|
+
padding: "2px",
|
|
581
618
|
zIndex: 101,
|
|
582
619
|
transition: "opacity .3s ease-in-out",
|
|
583
620
|
backgroundColor: "inherit",
|
|
621
|
+
borderRadius: "2px",
|
|
584
622
|
// These should be separate.
|
|
585
623
|
opacity: 0,
|
|
586
624
|
transitionDelay: "0s",
|
|
@@ -594,23 +632,25 @@ var styles = EditorView.baseTheme({
|
|
|
594
632
|
|
|
595
633
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
596
634
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
635
|
+
import { history } from "@codemirror/commands";
|
|
597
636
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
598
637
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
599
|
-
import { drawSelection, EditorView as
|
|
600
|
-
var basicBundle = ({
|
|
601
|
-
|
|
602
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
638
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
639
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
640
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
603
641
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
604
642
|
bracketMatching(),
|
|
605
643
|
closeBrackets(),
|
|
606
644
|
drawSelection(),
|
|
607
|
-
|
|
608
|
-
|
|
645
|
+
highlightActiveLine(),
|
|
646
|
+
history(),
|
|
647
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
648
|
+
// https://github.com/codemirror/theme-one-dark
|
|
609
649
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
610
|
-
]
|
|
650
|
+
];
|
|
611
651
|
|
|
612
652
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
613
|
-
import { EditorView as
|
|
653
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
614
654
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
615
655
|
import { invariant } from "@dxos/invariant";
|
|
616
656
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
@@ -646,10 +686,10 @@ var blast = (options = defaultOptions) => {
|
|
|
646
686
|
const getPoint = (view, pos) => {
|
|
647
687
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
648
688
|
const element = document.elementFromPoint(x, y);
|
|
649
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
689
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
650
690
|
const point = {
|
|
651
691
|
x: x - left,
|
|
652
|
-
y: y -
|
|
692
|
+
y: y - top2
|
|
653
693
|
};
|
|
654
694
|
return {
|
|
655
695
|
element,
|
|
@@ -658,7 +698,7 @@ var blast = (options = defaultOptions) => {
|
|
|
658
698
|
};
|
|
659
699
|
return [
|
|
660
700
|
// Cursor moved.
|
|
661
|
-
|
|
701
|
+
EditorView4.updateListener.of((update2) => {
|
|
662
702
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
663
703
|
if (blaster) {
|
|
664
704
|
blaster.destroy();
|
|
@@ -919,9 +959,14 @@ var random = (min, max) => {
|
|
|
919
959
|
return min + ~~(Math.random() * (max - min + 1));
|
|
920
960
|
};
|
|
921
961
|
|
|
922
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
923
|
-
import {
|
|
924
|
-
import {
|
|
962
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
963
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
964
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
965
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
966
|
+
import sortBy from "lodash.sortby";
|
|
967
|
+
import { useEffect } from "react";
|
|
968
|
+
import { debounce } from "@dxos/async";
|
|
969
|
+
import { nonNullable } from "@dxos/util";
|
|
925
970
|
|
|
926
971
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
927
972
|
import * as random2 from "lib0/random";
|
|
@@ -964,34 +1009,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
964
1009
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
965
1010
|
import { mx } from "@dxos/react-ui-theme";
|
|
966
1011
|
var headings = {
|
|
967
|
-
1:
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
977
|
-
"-ml-[7px]"
|
|
978
|
-
],
|
|
979
|
-
4: [
|
|
980
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
981
|
-
"-ml-[6px]"
|
|
982
|
-
],
|
|
983
|
-
5: [
|
|
984
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
985
|
-
"-ml-[5px]"
|
|
986
|
-
],
|
|
987
|
-
6: [
|
|
988
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
989
|
-
"-ml-[4px]"
|
|
990
|
-
]
|
|
991
|
-
};
|
|
992
|
-
var heading = (level, readonly) => {
|
|
993
|
-
const [style, offset] = headings[level];
|
|
994
|
-
return mx(style, readonly && offset);
|
|
1012
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1013
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1014
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1015
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1016
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1017
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1018
|
+
};
|
|
1019
|
+
var heading = (level) => {
|
|
1020
|
+
return headings[level];
|
|
995
1021
|
};
|
|
996
1022
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
997
1023
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1009,136 +1035,78 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1009
1035
|
var tokens = tailwindConfig({}).theme;
|
|
1010
1036
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1011
1037
|
|
|
1012
|
-
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1013
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1014
|
-
var styles2 = EditorView4.baseTheme({
|
|
1015
|
-
"& .cm-codeblock": {
|
|
1016
|
-
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1017
|
-
},
|
|
1018
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1019
|
-
background: getToken("extend.colors.neutral.50")
|
|
1020
|
-
},
|
|
1021
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1022
|
-
background: getToken("extend.colors.neutral.850")
|
|
1023
|
-
},
|
|
1024
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1025
|
-
display: "block",
|
|
1026
|
-
paddingInline: "4px !important"
|
|
1027
|
-
},
|
|
1028
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1029
|
-
paddingTop: "4px !important",
|
|
1030
|
-
borderTopLeftRadius: "4px",
|
|
1031
|
-
borderTopRightRadius: "4px"
|
|
1032
|
-
},
|
|
1033
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1034
|
-
paddingBottom: "4px !important",
|
|
1035
|
-
borderBottomLeftRadius: "4px",
|
|
1036
|
-
borderBottomRightRadius: "4px"
|
|
1037
|
-
}
|
|
1038
|
-
});
|
|
1039
|
-
var getLineRange = (lines, from, to) => {
|
|
1040
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1041
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1042
|
-
return [
|
|
1043
|
-
start,
|
|
1044
|
-
end
|
|
1045
|
-
];
|
|
1046
|
-
};
|
|
1047
|
-
var code2 = () => {
|
|
1048
|
-
const buildDecorations4 = (view) => {
|
|
1049
|
-
const decorations = [];
|
|
1050
|
-
const text = view.state.doc.sliceString(0);
|
|
1051
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1052
|
-
const blocks = view.viewportLineBlocks;
|
|
1053
|
-
for (const match of matches) {
|
|
1054
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1055
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1056
|
-
const block = blocks[i];
|
|
1057
|
-
decorations.push(Decoration2.line({
|
|
1058
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1059
|
-
}).range(block.from));
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
return Decoration2.set(decorations);
|
|
1063
|
-
};
|
|
1064
|
-
return [
|
|
1065
|
-
ViewPlugin2.fromClass(class {
|
|
1066
|
-
constructor(view) {
|
|
1067
|
-
this.hasFocus = false;
|
|
1068
|
-
this.decorations = buildDecorations4(view);
|
|
1069
|
-
}
|
|
1070
|
-
update(update2) {
|
|
1071
|
-
if (
|
|
1072
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1073
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1074
|
-
) {
|
|
1075
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1076
|
-
this.decorations = buildDecorations4(update2.view);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
}, {
|
|
1080
|
-
decorations: (value) => value.decorations
|
|
1081
|
-
}),
|
|
1082
|
-
styles2
|
|
1083
|
-
];
|
|
1084
|
-
};
|
|
1085
|
-
|
|
1086
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1087
|
-
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1088
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
1089
|
-
import sortBy from "lodash.sortby";
|
|
1090
|
-
import { debounce } from "@dxos/async";
|
|
1091
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1092
|
-
import { nonNullable } from "@dxos/util";
|
|
1093
|
-
|
|
1094
1038
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1095
1039
|
import { log } from "@dxos/log";
|
|
1096
1040
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1097
1041
|
var callbackWrapper = (fn) => (...args) => {
|
|
1098
1042
|
try {
|
|
1099
1043
|
return fn(...args);
|
|
1100
|
-
} catch (
|
|
1101
|
-
log.catch(
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
log.catch(err, void 0, {
|
|
1102
1046
|
F: __dxlog_file2,
|
|
1103
|
-
L:
|
|
1047
|
+
L: 18,
|
|
1104
1048
|
S: void 0,
|
|
1105
1049
|
C: (f, a) => f(...a)
|
|
1106
1050
|
});
|
|
1107
1051
|
}
|
|
1108
1052
|
};
|
|
1053
|
+
var logChanges = (trs) => {
|
|
1054
|
+
const changes = trs.flatMap((tr) => {
|
|
1055
|
+
if (tr.changes.empty) {
|
|
1056
|
+
return void 0;
|
|
1057
|
+
}
|
|
1058
|
+
const changes2 = [];
|
|
1059
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1060
|
+
fromA,
|
|
1061
|
+
toA,
|
|
1062
|
+
fromB,
|
|
1063
|
+
toB,
|
|
1064
|
+
inserted: inserted.toString()
|
|
1065
|
+
})));
|
|
1066
|
+
return changes2;
|
|
1067
|
+
}).filter(Boolean);
|
|
1068
|
+
if (changes.length) {
|
|
1069
|
+
console.log("changes", changes);
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1109
1072
|
|
|
1110
1073
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1111
|
-
var
|
|
1112
|
-
var styles3 = EditorView5.baseTheme({
|
|
1074
|
+
var styles2 = EditorView5.baseTheme({
|
|
1113
1075
|
"& .cm-comment": {
|
|
1114
1076
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1115
1077
|
},
|
|
1116
|
-
"& .cm-comment-
|
|
1078
|
+
"& .cm-comment-current": {
|
|
1117
1079
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1118
1080
|
}
|
|
1119
1081
|
});
|
|
1120
|
-
var
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
const comment = view.state.field(commentsState).comments.find((range) => range.comment.id === thread);
|
|
1130
|
-
if (!comment) {
|
|
1082
|
+
var commentMark = Decoration2.mark({
|
|
1083
|
+
class: "cm-comment"
|
|
1084
|
+
});
|
|
1085
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1086
|
+
class: "cm-comment-current"
|
|
1087
|
+
});
|
|
1088
|
+
var setFocus = (view, id, center = true) => {
|
|
1089
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1090
|
+
if (!comment?.comment.cursor) {
|
|
1131
1091
|
return;
|
|
1132
1092
|
}
|
|
1133
|
-
view.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1093
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1094
|
+
if (range) {
|
|
1095
|
+
view.dispatch({
|
|
1096
|
+
selection: {
|
|
1097
|
+
anchor: range.from
|
|
1098
|
+
},
|
|
1099
|
+
effects: [
|
|
1100
|
+
//
|
|
1101
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1102
|
+
y: "center"
|
|
1103
|
+
} : void 0),
|
|
1104
|
+
setSelection.of({
|
|
1105
|
+
current: id
|
|
1106
|
+
})
|
|
1107
|
+
]
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1142
1110
|
};
|
|
1143
1111
|
var setComments = StateEffect2.define();
|
|
1144
1112
|
var setSelection = StateEffect2.define();
|
|
@@ -1179,23 +1147,23 @@ var commentsState = StateField2.define({
|
|
|
1179
1147
|
return value;
|
|
1180
1148
|
}
|
|
1181
1149
|
});
|
|
1182
|
-
var
|
|
1150
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1183
1151
|
commentsState
|
|
1184
1152
|
], (state) => {
|
|
1185
|
-
const { selection: {
|
|
1153
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1186
1154
|
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1187
1155
|
const range = comment.range;
|
|
1188
1156
|
if (!range || range.from === range.to) {
|
|
1189
1157
|
console.warn("Invalid range:", range);
|
|
1190
1158
|
return void 0;
|
|
1191
1159
|
}
|
|
1192
|
-
if (comment.comment.id ===
|
|
1193
|
-
return
|
|
1160
|
+
if (comment.comment.id === current) {
|
|
1161
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1194
1162
|
} else {
|
|
1195
|
-
return
|
|
1163
|
+
return commentMark.range(range.from, range.to);
|
|
1196
1164
|
}
|
|
1197
1165
|
}).filter(nonNullable);
|
|
1198
|
-
return
|
|
1166
|
+
return Decoration2.set(decorations);
|
|
1199
1167
|
});
|
|
1200
1168
|
var trackPastedComments = (onUpdate) => {
|
|
1201
1169
|
let tracked = null;
|
|
@@ -1221,94 +1189,132 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1221
1189
|
cut: handleTrack,
|
|
1222
1190
|
copy: handleTrack
|
|
1223
1191
|
}),
|
|
1224
|
-
//
|
|
1225
|
-
|
|
1192
|
+
// Track deleted comments.
|
|
1193
|
+
invertedEffects2.of((tr) => {
|
|
1194
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1195
|
+
const effects = [];
|
|
1196
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1197
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1198
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1199
|
+
effects.push(restoreCommentEffect.of({
|
|
1200
|
+
id,
|
|
1201
|
+
from,
|
|
1202
|
+
to
|
|
1203
|
+
}));
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
return effects;
|
|
1208
|
+
}),
|
|
1209
|
+
// Handle paste or the undo of comment deletion.
|
|
1210
|
+
EditorView5.updateListener.of((update2) => {
|
|
1211
|
+
const restore = [];
|
|
1212
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1213
|
+
const tr = update2.transactions[i];
|
|
1214
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1215
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1216
|
+
}
|
|
1217
|
+
for (const effect of tr.effects) {
|
|
1218
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1219
|
+
restore.push(effect.value);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1226
1223
|
if (tracked) {
|
|
1227
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1224
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1228
1225
|
if (paste) {
|
|
1229
1226
|
let found = -1;
|
|
1230
1227
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1231
1228
|
if (text.eq(tracked.text)) {
|
|
1232
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1233
|
-
fromB = transactions[i].changes.mapPos(fromB);
|
|
1229
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1230
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1234
1231
|
}
|
|
1235
1232
|
found = fromB;
|
|
1236
1233
|
}
|
|
1237
1234
|
});
|
|
1238
1235
|
if (found > -1) {
|
|
1239
|
-
state.facet(syncFacet)?.reconcile(view);
|
|
1240
1236
|
for (const moved of tracked.comments) {
|
|
1241
|
-
|
|
1237
|
+
restore.push({
|
|
1238
|
+
id: moved.id,
|
|
1242
1239
|
from: found + moved.from,
|
|
1243
1240
|
to: found + moved.to
|
|
1244
|
-
};
|
|
1245
|
-
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1246
|
-
onUpdate(moved.id, cursor);
|
|
1241
|
+
});
|
|
1247
1242
|
}
|
|
1248
1243
|
}
|
|
1249
1244
|
tracked = null;
|
|
1250
1245
|
}
|
|
1251
1246
|
}
|
|
1247
|
+
for (const comment of restore) {
|
|
1248
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1249
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1250
|
+
if (!exists) {
|
|
1251
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1252
|
+
onUpdate(comment.id, cursor);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1252
1255
|
})
|
|
1253
1256
|
];
|
|
1254
1257
|
};
|
|
1255
|
-
var
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1258
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1259
|
+
id: comment.id,
|
|
1260
|
+
from: changes.mapPos(comment.from, 1),
|
|
1261
|
+
to: changes.mapPos(comment.to, 1)
|
|
1262
|
+
});
|
|
1263
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1264
|
+
map: mapTrackedComment
|
|
1265
|
+
});
|
|
1266
|
+
var optionsFacet = Facet3.define({
|
|
1267
|
+
combine: (providers) => providers[0]
|
|
1268
|
+
});
|
|
1269
|
+
var createComment = (view) => {
|
|
1270
|
+
const options = view.state.facet(optionsFacet);
|
|
1271
|
+
const { from, to } = view.state.selection.main;
|
|
1272
|
+
if (from === to) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
if (to === view.state.doc.length) {
|
|
1276
|
+
view.dispatch({
|
|
1277
|
+
changes: {
|
|
1278
|
+
from: to,
|
|
1279
|
+
insert: "\n"
|
|
1280
|
+
}
|
|
1267
1281
|
});
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1282
|
+
}
|
|
1283
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1284
|
+
from,
|
|
1285
|
+
to
|
|
1286
|
+
});
|
|
1287
|
+
if (cursor) {
|
|
1288
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1289
|
+
if (id) {
|
|
1273
1290
|
view.dispatch({
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1291
|
+
effects: setSelection.of({
|
|
1292
|
+
current: id
|
|
1293
|
+
}),
|
|
1294
|
+
selection: {
|
|
1295
|
+
anchor: to
|
|
1277
1296
|
}
|
|
1278
1297
|
});
|
|
1298
|
+
return true;
|
|
1279
1299
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
if (id) {
|
|
1287
|
-
view.dispatch({
|
|
1288
|
-
effects: setSelection.of({
|
|
1289
|
-
active: id
|
|
1290
|
-
}),
|
|
1291
|
-
selection: {
|
|
1292
|
-
anchor: from
|
|
1293
|
-
}
|
|
1294
|
-
});
|
|
1295
|
-
return true;
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
return false;
|
|
1299
|
-
};
|
|
1300
|
+
}
|
|
1301
|
+
return false;
|
|
1302
|
+
};
|
|
1303
|
+
var comments = (options = {}) => {
|
|
1304
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1305
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1300
1306
|
return [
|
|
1307
|
+
optionsFacet.of(options),
|
|
1301
1308
|
commentsState,
|
|
1302
|
-
|
|
1303
|
-
|
|
1309
|
+
commentsDecorations,
|
|
1310
|
+
styles2,
|
|
1304
1311
|
//
|
|
1305
1312
|
// Keymap.
|
|
1306
1313
|
//
|
|
1307
1314
|
options.onCreate ? keymap3.of([
|
|
1308
1315
|
{
|
|
1309
1316
|
key: shortcut,
|
|
1310
|
-
|
|
1311
|
-
run: callbackWrapper(createCommentThread)
|
|
1317
|
+
run: callbackWrapper(createComment)
|
|
1312
1318
|
}
|
|
1313
1319
|
]) : [],
|
|
1314
1320
|
//
|
|
@@ -1374,17 +1380,17 @@ var comments = (options = {}) => {
|
|
|
1374
1380
|
//
|
|
1375
1381
|
// Track selection/proximity.
|
|
1376
1382
|
//
|
|
1377
|
-
EditorView5.updateListener.of(({ view, state
|
|
1383
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1378
1384
|
let min = Infinity;
|
|
1379
|
-
const { selection: {
|
|
1385
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1380
1386
|
const { head } = state.selection.main;
|
|
1381
1387
|
const selection = {};
|
|
1382
1388
|
comments2.forEach(({ comment, range }) => {
|
|
1383
1389
|
if (head >= range.from && head <= range.to) {
|
|
1384
|
-
selection.
|
|
1390
|
+
selection.current = comment.id;
|
|
1385
1391
|
selection.closest = void 0;
|
|
1386
1392
|
}
|
|
1387
|
-
if (!selection.
|
|
1393
|
+
if (!selection.current) {
|
|
1388
1394
|
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1389
1395
|
if (d < min) {
|
|
1390
1396
|
selection.closest = comment.id;
|
|
@@ -1392,7 +1398,7 @@ var comments = (options = {}) => {
|
|
|
1392
1398
|
}
|
|
1393
1399
|
}
|
|
1394
1400
|
});
|
|
1395
|
-
if (selection.
|
|
1401
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1396
1402
|
view.dispatch({
|
|
1397
1403
|
effects: setSelection.of(selection)
|
|
1398
1404
|
});
|
|
@@ -1409,319 +1415,78 @@ var comments = (options = {}) => {
|
|
|
1409
1415
|
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1410
1416
|
];
|
|
1411
1417
|
};
|
|
1418
|
+
var useComments = (view, comments2 = []) => {
|
|
1419
|
+
useEffect(() => {
|
|
1420
|
+
if (view) {
|
|
1421
|
+
view.dispatch({
|
|
1422
|
+
effects: setComments.of(comments2)
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
}, [
|
|
1426
|
+
view,
|
|
1427
|
+
comments2
|
|
1428
|
+
]);
|
|
1429
|
+
};
|
|
1412
1430
|
|
|
1413
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1414
|
-
import {
|
|
1415
|
-
var
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1431
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1432
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1433
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1434
|
+
const extensions = [];
|
|
1435
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1436
|
+
onFocus(focused);
|
|
1437
|
+
return null;
|
|
1438
|
+
}));
|
|
1439
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1440
|
+
onChange(update2.state.doc.toString());
|
|
1441
|
+
}));
|
|
1442
|
+
return extensions;
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1445
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1446
|
+
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1447
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1448
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1449
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1450
|
+
import { languages } from "@codemirror/language-data";
|
|
1451
|
+
import { searchKeymap } from "@codemirror/search";
|
|
1452
|
+
import { EditorState } from "@codemirror/state";
|
|
1453
|
+
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1454
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1455
|
+
|
|
1456
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1457
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1458
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
1459
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1460
|
+
import { Table } from "@lezer/markdown";
|
|
1461
|
+
var markdownTags = {
|
|
1462
|
+
Blockquote: Tag.define(),
|
|
1463
|
+
CodeMark: Tag.define(),
|
|
1464
|
+
CodeText: Tag.define(),
|
|
1465
|
+
EmphasisMark: Tag.define(),
|
|
1466
|
+
HeaderMark: Tag.define(),
|
|
1467
|
+
InlineCode: Tag.define(),
|
|
1468
|
+
LinkLabel: Tag.define(),
|
|
1469
|
+
LinkReference: Tag.define(),
|
|
1470
|
+
ListMark: Tag.define(),
|
|
1471
|
+
QuoteMark: Tag.define(),
|
|
1472
|
+
URL: Tag.define(),
|
|
1473
|
+
// Custom.
|
|
1474
|
+
TableCell: Tag.define()
|
|
1475
|
+
};
|
|
1476
|
+
Table.defineNodes?.forEach((node) => {
|
|
1477
|
+
switch (node?.name) {
|
|
1478
|
+
case "TableCell": {
|
|
1479
|
+
node.style = markdownTags.TableCell;
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1420
1482
|
}
|
|
1421
1483
|
});
|
|
1422
|
-
var
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
return this._pos === other._pos;
|
|
1429
|
-
}
|
|
1430
|
-
toDOM(view) {
|
|
1431
|
-
const el = document.createElement("div");
|
|
1432
|
-
el.className = "cm-hr";
|
|
1433
|
-
return el;
|
|
1434
|
-
}
|
|
1435
|
-
};
|
|
1436
|
-
var placeholderMatcher = new MatchDecorator({
|
|
1437
|
-
// regexp: /(?<=\n\n)---/gs,
|
|
1438
|
-
regexp: /^---$/gs,
|
|
1439
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1440
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1441
|
-
})
|
|
1442
|
-
});
|
|
1443
|
-
var hr = () => [
|
|
1444
|
-
styles4,
|
|
1445
|
-
ViewPlugin3.fromClass(class {
|
|
1446
|
-
constructor(view) {
|
|
1447
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1448
|
-
}
|
|
1449
|
-
update(update2) {
|
|
1450
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1451
|
-
}
|
|
1452
|
-
}, {
|
|
1453
|
-
decorations: (instance) => instance.rules
|
|
1454
|
-
})
|
|
1455
|
-
];
|
|
1456
|
-
|
|
1457
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1458
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1459
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1460
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1461
|
-
var image = (options = {}) => {
|
|
1462
|
-
return StateField3.define({
|
|
1463
|
-
create: (state) => {
|
|
1464
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1465
|
-
},
|
|
1466
|
-
update: (value, tr) => {
|
|
1467
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1468
|
-
return value;
|
|
1469
|
-
}
|
|
1470
|
-
const cursor = tr.state.selection.main.head;
|
|
1471
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1472
|
-
let from = Math.min(cursor, oldCursor);
|
|
1473
|
-
let to = Math.max(cursor, oldCursor);
|
|
1474
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1475
|
-
from = Math.min(from, fromB);
|
|
1476
|
-
to = Math.max(to, toB);
|
|
1477
|
-
});
|
|
1478
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1479
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1480
|
-
return value.map(tr.changes).update({
|
|
1481
|
-
filterFrom: from,
|
|
1482
|
-
filterTo: to,
|
|
1483
|
-
filter: () => false,
|
|
1484
|
-
add: buildDecorations(from, to, tr.state)
|
|
1485
|
-
});
|
|
1486
|
-
},
|
|
1487
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1488
|
-
});
|
|
1489
|
-
};
|
|
1490
|
-
var buildDecorations = (from, to, state) => {
|
|
1491
|
-
const decorations = [];
|
|
1492
|
-
const cursor = state.selection.main.head;
|
|
1493
|
-
syntaxTree(state).iterate({
|
|
1494
|
-
enter: (node) => {
|
|
1495
|
-
if (node.name === "Image") {
|
|
1496
|
-
const urlNode = node.node.getChild("URL");
|
|
1497
|
-
if (urlNode) {
|
|
1498
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1499
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1500
|
-
decorations.push(Decoration5.replace({
|
|
1501
|
-
block: true,
|
|
1502
|
-
widget: new ImageWidget(url)
|
|
1503
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
},
|
|
1507
|
-
from,
|
|
1508
|
-
to
|
|
1509
|
-
});
|
|
1510
|
-
return decorations;
|
|
1511
|
-
};
|
|
1512
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1513
|
-
constructor(_url) {
|
|
1514
|
-
super();
|
|
1515
|
-
this._url = _url;
|
|
1516
|
-
}
|
|
1517
|
-
eq(other) {
|
|
1518
|
-
return this._url === other._url;
|
|
1519
|
-
}
|
|
1520
|
-
toDOM(view) {
|
|
1521
|
-
const img = document.createElement("img");
|
|
1522
|
-
img.setAttribute("src", this._url);
|
|
1523
|
-
img.setAttribute("class", "cm-image");
|
|
1524
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1525
|
-
return img;
|
|
1526
|
-
}
|
|
1527
|
-
};
|
|
1528
|
-
|
|
1529
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1530
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1531
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1532
|
-
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin4, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1533
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1534
|
-
var link = (options = {}) => {
|
|
1535
|
-
const extensions = [
|
|
1536
|
-
ViewPlugin4.fromClass(class {
|
|
1537
|
-
constructor(view) {
|
|
1538
|
-
this.decorations = buildDecorations2(view, options);
|
|
1539
|
-
}
|
|
1540
|
-
update(update2) {
|
|
1541
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1542
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}, {
|
|
1546
|
-
decorations: (v) => v.decorations
|
|
1547
|
-
})
|
|
1548
|
-
];
|
|
1549
|
-
if (options.onHover) {
|
|
1550
|
-
extensions.push(
|
|
1551
|
-
// https://codemirror.net/examples/tooltip
|
|
1552
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1553
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1554
|
-
hoverTooltip2((view, pos, side) => {
|
|
1555
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1556
|
-
let link2 = null;
|
|
1557
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1558
|
-
link2 = node.name === "Link" ? node : null;
|
|
1559
|
-
}
|
|
1560
|
-
const url = link2 && link2.getChild("URL");
|
|
1561
|
-
if (!url || !link2) {
|
|
1562
|
-
return null;
|
|
1563
|
-
}
|
|
1564
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1565
|
-
return {
|
|
1566
|
-
pos: link2.from,
|
|
1567
|
-
end: link2.to,
|
|
1568
|
-
above: true,
|
|
1569
|
-
create: () => {
|
|
1570
|
-
const el = document.createElement("div");
|
|
1571
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1572
|
-
options.onHover(el, urlText);
|
|
1573
|
-
return {
|
|
1574
|
-
dom: el,
|
|
1575
|
-
offset: {
|
|
1576
|
-
x: 0,
|
|
1577
|
-
y: 4
|
|
1578
|
-
}
|
|
1579
|
-
};
|
|
1580
|
-
}
|
|
1581
|
-
};
|
|
1582
|
-
})
|
|
1583
|
-
);
|
|
1584
|
-
}
|
|
1585
|
-
return extensions;
|
|
1586
|
-
};
|
|
1587
|
-
var LinkButton = class extends WidgetType4 {
|
|
1588
|
-
constructor(_url, _onAttach) {
|
|
1589
|
-
super();
|
|
1590
|
-
this._url = _url;
|
|
1591
|
-
this._onAttach = _onAttach;
|
|
1592
|
-
}
|
|
1593
|
-
eq(other) {
|
|
1594
|
-
return this._url === other._url;
|
|
1595
|
-
}
|
|
1596
|
-
toDOM(view) {
|
|
1597
|
-
const el = document.createElement("span");
|
|
1598
|
-
this._onAttach(el, this._url);
|
|
1599
|
-
return el;
|
|
1600
|
-
}
|
|
1601
|
-
};
|
|
1602
|
-
var LinkText = class extends WidgetType4 {
|
|
1603
|
-
constructor(_text, _url) {
|
|
1604
|
-
super();
|
|
1605
|
-
this._text = _text;
|
|
1606
|
-
this._url = _url;
|
|
1607
|
-
}
|
|
1608
|
-
eq(other) {
|
|
1609
|
-
return this._url === other._url;
|
|
1610
|
-
}
|
|
1611
|
-
toDOM(view) {
|
|
1612
|
-
const link2 = document.createElement("a");
|
|
1613
|
-
link2.setAttribute("class", "cm-link");
|
|
1614
|
-
link2.textContent = this._text;
|
|
1615
|
-
if (this._url) {
|
|
1616
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1617
|
-
link2.setAttribute("target", "_blank");
|
|
1618
|
-
link2.href = this._url;
|
|
1619
|
-
} else {
|
|
1620
|
-
link2.onclick = () => {
|
|
1621
|
-
view.dispatch({
|
|
1622
|
-
selection: {
|
|
1623
|
-
anchor: view.posAtDOM(link2)
|
|
1624
|
-
}
|
|
1625
|
-
});
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
return link2;
|
|
1629
|
-
}
|
|
1630
|
-
};
|
|
1631
|
-
var buildDecorations2 = (view, options) => {
|
|
1632
|
-
const builder = new RangeSetBuilder();
|
|
1633
|
-
const { state } = view;
|
|
1634
|
-
const cursor = state.selection.main.head;
|
|
1635
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1636
|
-
syntaxTree2(state).iterate({
|
|
1637
|
-
enter: (node) => {
|
|
1638
|
-
if (node.name === "Link") {
|
|
1639
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1640
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1641
|
-
const urlNode = node.node.getChild("URL");
|
|
1642
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1643
|
-
if (!url) {
|
|
1644
|
-
return false;
|
|
1645
|
-
}
|
|
1646
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1647
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1648
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1649
|
-
}));
|
|
1650
|
-
}
|
|
1651
|
-
if (options.onRender) {
|
|
1652
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1653
|
-
widget: new LinkButton(url, options.onRender)
|
|
1654
|
-
}));
|
|
1655
|
-
}
|
|
1656
|
-
return false;
|
|
1657
|
-
}
|
|
1658
|
-
},
|
|
1659
|
-
from,
|
|
1660
|
-
to
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
|
-
return builder.finish();
|
|
1664
|
-
};
|
|
1665
|
-
|
|
1666
|
-
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1667
|
-
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1668
|
-
var listener = ({ onFocus, onChange }) => {
|
|
1669
|
-
const extensions = [];
|
|
1670
|
-
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1671
|
-
onFocus(focused);
|
|
1672
|
-
return null;
|
|
1673
|
-
}));
|
|
1674
|
-
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1675
|
-
onChange(update2.state.doc.toString());
|
|
1676
|
-
}));
|
|
1677
|
-
return extensions;
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1681
|
-
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1682
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1683
|
-
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1684
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1685
|
-
import { languages } from "@codemirror/language-data";
|
|
1686
|
-
import { searchKeymap } from "@codemirror/search";
|
|
1687
|
-
import { EditorState } from "@codemirror/state";
|
|
1688
|
-
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1689
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1690
|
-
|
|
1691
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1692
|
-
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1693
|
-
import { HighlightStyle } from "@codemirror/language";
|
|
1694
|
-
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1695
|
-
import { Table } from "@lezer/markdown";
|
|
1696
|
-
var markdownTags = {
|
|
1697
|
-
Blockquote: Tag.define(),
|
|
1698
|
-
CodeMark: Tag.define(),
|
|
1699
|
-
CodeText: Tag.define(),
|
|
1700
|
-
EmphasisMark: Tag.define(),
|
|
1701
|
-
HeaderMark: Tag.define(),
|
|
1702
|
-
InlineCode: Tag.define(),
|
|
1703
|
-
LinkLabel: Tag.define(),
|
|
1704
|
-
LinkReference: Tag.define(),
|
|
1705
|
-
ListMark: Tag.define(),
|
|
1706
|
-
QuoteMark: Tag.define(),
|
|
1707
|
-
URL: Tag.define(),
|
|
1708
|
-
// Custom.
|
|
1709
|
-
TableCell: Tag.define()
|
|
1710
|
-
};
|
|
1711
|
-
Table.defineNodes?.forEach((node) => {
|
|
1712
|
-
switch (node?.name) {
|
|
1713
|
-
case "TableCell": {
|
|
1714
|
-
node.style = markdownTags.TableCell;
|
|
1715
|
-
break;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
});
|
|
1719
|
-
var markdownTagsExtensions = [
|
|
1720
|
-
Table,
|
|
1721
|
-
{
|
|
1722
|
-
props: [
|
|
1723
|
-
styleTags(markdownTags)
|
|
1724
|
-
]
|
|
1484
|
+
var markdownTagsExtensions = [
|
|
1485
|
+
Table,
|
|
1486
|
+
{
|
|
1487
|
+
props: [
|
|
1488
|
+
styleTags(markdownTags)
|
|
1489
|
+
]
|
|
1725
1490
|
}
|
|
1726
1491
|
];
|
|
1727
1492
|
var markdownHighlightStyle = (readonly) => {
|
|
@@ -1783,7 +1548,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1783
1548
|
markdownTags.QuoteMark,
|
|
1784
1549
|
markdownTags.EmphasisMark
|
|
1785
1550
|
],
|
|
1786
|
-
class:
|
|
1551
|
+
class: mark
|
|
1787
1552
|
},
|
|
1788
1553
|
// E.g., code block language (after ```).
|
|
1789
1554
|
{
|
|
@@ -1791,7 +1556,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1791
1556
|
tags.function(tags.variableName),
|
|
1792
1557
|
tags.labelName
|
|
1793
1558
|
],
|
|
1794
|
-
class:
|
|
1559
|
+
class: codeMark
|
|
1795
1560
|
},
|
|
1796
1561
|
{
|
|
1797
1562
|
tag: [
|
|
@@ -1802,27 +1567,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1802
1567
|
// Headings.
|
|
1803
1568
|
{
|
|
1804
1569
|
tag: tags.heading1,
|
|
1805
|
-
class: heading(1
|
|
1570
|
+
class: heading(1)
|
|
1806
1571
|
},
|
|
1807
1572
|
{
|
|
1808
1573
|
tag: tags.heading2,
|
|
1809
|
-
class: heading(2
|
|
1574
|
+
class: heading(2)
|
|
1810
1575
|
},
|
|
1811
1576
|
{
|
|
1812
1577
|
tag: tags.heading3,
|
|
1813
|
-
class: heading(3
|
|
1578
|
+
class: heading(3)
|
|
1814
1579
|
},
|
|
1815
1580
|
{
|
|
1816
1581
|
tag: tags.heading4,
|
|
1817
|
-
class: heading(4
|
|
1582
|
+
class: heading(4)
|
|
1818
1583
|
},
|
|
1819
1584
|
{
|
|
1820
1585
|
tag: tags.heading5,
|
|
1821
|
-
class: heading(5
|
|
1586
|
+
class: heading(5)
|
|
1822
1587
|
},
|
|
1823
1588
|
{
|
|
1824
1589
|
tag: tags.heading6,
|
|
1825
|
-
class: heading(6
|
|
1590
|
+
class: heading(6)
|
|
1826
1591
|
},
|
|
1827
1592
|
// Emphasis.
|
|
1828
1593
|
{
|
|
@@ -1848,7 +1613,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1848
1613
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1849
1614
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1850
1615
|
// the code, but all other CSS properties will be inherited.
|
|
1851
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1616
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1852
1617
|
{
|
|
1853
1618
|
tag: [
|
|
1854
1619
|
markdownTags.CodeText,
|
|
@@ -1877,21 +1642,21 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1877
1642
|
};
|
|
1878
1643
|
|
|
1879
1644
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1880
|
-
var markdownBundle = ({
|
|
1645
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1881
1646
|
return [
|
|
1882
1647
|
EditorState.allowMultipleSelections.of(true),
|
|
1883
1648
|
EditorState.tabSize.of(2),
|
|
1884
|
-
|
|
1885
|
-
|
|
1649
|
+
EditorView7.lineWrapping,
|
|
1650
|
+
// https://github.com/codemirror/basic-setup
|
|
1886
1651
|
bracketMatching2(),
|
|
1887
1652
|
closeBrackets2(),
|
|
1888
1653
|
crosshairCursor(),
|
|
1889
1654
|
dropCursor(),
|
|
1890
1655
|
drawSelection2(),
|
|
1891
|
-
|
|
1892
|
-
|
|
1656
|
+
highlightActiveLine2(),
|
|
1657
|
+
history2(),
|
|
1893
1658
|
indentOnInput(),
|
|
1894
|
-
_placeholder
|
|
1659
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1895
1660
|
// Main extension.
|
|
1896
1661
|
// https://github.com/codemirror/lang-markdown
|
|
1897
1662
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1913,63 +1678,575 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1913
1678
|
// https://github.com/codemirror/theme-one-dark
|
|
1914
1679
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1915
1680
|
// Custom styles.
|
|
1916
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1681
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1682
|
+
keymap4.of([
|
|
1683
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1684
|
+
indentWithTab,
|
|
1685
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1686
|
+
...closeBracketsKeymap,
|
|
1687
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1688
|
+
...historyKeymap,
|
|
1689
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1690
|
+
...searchKeymap,
|
|
1691
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1692
|
+
...standardKeymap
|
|
1693
|
+
])
|
|
1694
|
+
];
|
|
1695
|
+
};
|
|
1931
1696
|
|
|
1932
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1933
|
-
import {
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1697
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1698
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1699
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1700
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1701
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1702
|
+
var styles3 = EditorView8.baseTheme({
|
|
1703
|
+
"& .cm-code": {
|
|
1704
|
+
paddingInline: "1rem !important",
|
|
1705
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1706
|
+
},
|
|
1707
|
+
"& .cm-codeblock": {
|
|
1708
|
+
display: "inline-block",
|
|
1709
|
+
width: "100%",
|
|
1710
|
+
position: "relative",
|
|
1711
|
+
"&::after": {
|
|
1712
|
+
content: '""',
|
|
1713
|
+
position: "absolute",
|
|
1714
|
+
inset: 0
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
"&light .cm-codeblock": {
|
|
1718
|
+
"&::after": {
|
|
1719
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1720
|
+
mixBlendMode: "darken"
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
"&dark .cm-codeblock": {
|
|
1724
|
+
"&::after": {
|
|
1725
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1726
|
+
mixBlendMode: "lighten"
|
|
1727
|
+
}
|
|
1728
|
+
},
|
|
1729
|
+
"& .cm-codeblock-first": {
|
|
1730
|
+
"&::after": {
|
|
1731
|
+
borderTopLeftRadius: ".5rem",
|
|
1732
|
+
borderTopRightRadius: ".5rem"
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
"& .cm-codeblock-last": {
|
|
1736
|
+
"&::after": {
|
|
1737
|
+
borderBottomLeftRadius: ".5rem",
|
|
1738
|
+
borderBottomRightRadius: ".5rem"
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
var getLineRange = (lines, from, to) => {
|
|
1743
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1744
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1745
|
+
return [
|
|
1746
|
+
start,
|
|
1747
|
+
end
|
|
1748
|
+
];
|
|
1749
|
+
};
|
|
1750
|
+
var LineWidget = class extends WidgetType2 {
|
|
1751
|
+
constructor(_className) {
|
|
1752
|
+
super();
|
|
1753
|
+
this._className = _className;
|
|
1754
|
+
}
|
|
1755
|
+
toDOM() {
|
|
1756
|
+
const el = document.createElement("span");
|
|
1757
|
+
el.innerHTML = " ";
|
|
1758
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1759
|
+
return el;
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1763
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1764
|
+
var buildDecorations = (view) => {
|
|
1765
|
+
const builder = new RangeSetBuilder();
|
|
1766
|
+
const { state } = view;
|
|
1767
|
+
const blocks = view.viewportLineBlocks;
|
|
1768
|
+
const cursor = state.selection.main.head;
|
|
1769
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1770
|
+
syntaxTree(state).iterate({
|
|
1771
|
+
enter: (node) => {
|
|
1772
|
+
if (node.name === "FencedCode") {
|
|
1773
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1774
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1775
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1776
|
+
const block = blocks[i];
|
|
1777
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1778
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1779
|
+
widget: i === range[0] ? top : bottom
|
|
1780
|
+
}));
|
|
1781
|
+
} else {
|
|
1782
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1783
|
+
class: mx2("cm-code cm-codeblock")
|
|
1784
|
+
}));
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1789
|
+
from,
|
|
1790
|
+
to
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
return builder.finish();
|
|
1794
|
+
};
|
|
1795
|
+
var code2 = () => {
|
|
1796
|
+
return [
|
|
1797
|
+
ViewPlugin3.fromClass(class {
|
|
1798
|
+
constructor(view) {
|
|
1799
|
+
this.decorations = buildDecorations(view);
|
|
1800
|
+
}
|
|
1801
|
+
update(update2) {
|
|
1802
|
+
this.decorations = buildDecorations(update2.view);
|
|
1803
|
+
}
|
|
1804
|
+
}, {
|
|
1805
|
+
decorations: (value) => value.decorations
|
|
1806
|
+
}),
|
|
1807
|
+
styles3
|
|
1808
|
+
];
|
|
1809
|
+
};
|
|
1810
|
+
|
|
1811
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1812
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1813
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1814
|
+
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1815
|
+
var setHeading = (level) => (view) => {
|
|
1816
|
+
const { selection: { ranges }, doc } = view.state;
|
|
1817
|
+
const changes = [];
|
|
1818
|
+
for (const range of ranges) {
|
|
1819
|
+
const { number } = doc.lineAt(range.anchor);
|
|
1820
|
+
const { from } = doc.line(number);
|
|
1821
|
+
const line = doc.sliceString(from, from + 7);
|
|
1822
|
+
const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
|
|
1823
|
+
const current = marks?.length ?? 0;
|
|
1824
|
+
if (level !== current) {
|
|
1825
|
+
changes.push({
|
|
1826
|
+
from,
|
|
1827
|
+
to: from + current + (spaces?.length ?? 0),
|
|
1828
|
+
insert: "#".repeat(level) + (level > 0 ? " " : "")
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
if (changes.length) {
|
|
1833
|
+
view.dispatch({
|
|
1834
|
+
changes
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
return true;
|
|
1838
|
+
};
|
|
1839
|
+
var toggleStyle = (mark2) => (view) => {
|
|
1840
|
+
const { ranges } = view.state.selection;
|
|
1841
|
+
for (const range of ranges) {
|
|
1842
|
+
if (range.from === range.to) {
|
|
1843
|
+
return false;
|
|
1844
|
+
}
|
|
1845
|
+
view.dispatch({
|
|
1846
|
+
changes: [
|
|
1847
|
+
{
|
|
1848
|
+
from: range.from,
|
|
1849
|
+
insert: mark2
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
from: range.to,
|
|
1853
|
+
insert: mark2
|
|
1854
|
+
}
|
|
1855
|
+
]
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
return true;
|
|
1859
|
+
};
|
|
1860
|
+
var toggleBold = toggleStyle("**");
|
|
1861
|
+
var toggleItalic = toggleStyle("_");
|
|
1862
|
+
var toggleStrikethrough = toggleStyle("~~");
|
|
1863
|
+
var toggleList = (view) => {
|
|
1864
|
+
};
|
|
1865
|
+
var formatting = (options = {}) => {
|
|
1866
|
+
return [
|
|
1867
|
+
keymap5.of([
|
|
1868
|
+
{
|
|
1869
|
+
key: "meta-b",
|
|
1870
|
+
run: toggleBold
|
|
1871
|
+
}
|
|
1872
|
+
]),
|
|
1873
|
+
styling()
|
|
1874
|
+
];
|
|
1875
|
+
};
|
|
1876
|
+
var styling = () => {
|
|
1877
|
+
const buildDecorations7 = (view) => {
|
|
1878
|
+
const builder = new RangeSetBuilder2();
|
|
1879
|
+
const { state } = view;
|
|
1880
|
+
const cursor = state.selection.main.head;
|
|
1881
|
+
const replace = (node, marks) => {
|
|
1882
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1883
|
+
for (const mark2 of marks) {
|
|
1884
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1889
|
+
syntaxTree2(state).iterate({
|
|
1890
|
+
enter: (node) => {
|
|
1891
|
+
switch (node.name) {
|
|
1892
|
+
case "Emphasis":
|
|
1893
|
+
case "StrongEmphasis": {
|
|
1894
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
1895
|
+
replace(node, marks);
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
case "Strikethrough": {
|
|
1899
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
1900
|
+
replace(node, marks);
|
|
1901
|
+
break;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
},
|
|
1905
|
+
from,
|
|
1906
|
+
to
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
return builder.finish();
|
|
1910
|
+
};
|
|
1911
|
+
return [
|
|
1912
|
+
ViewPlugin4.fromClass(class {
|
|
1913
|
+
constructor(view) {
|
|
1914
|
+
this.decorations = buildDecorations7(view);
|
|
1915
|
+
}
|
|
1916
|
+
update(update2) {
|
|
1917
|
+
this.decorations = buildDecorations7(update2.view);
|
|
1918
|
+
}
|
|
1919
|
+
}, {
|
|
1920
|
+
decorations: (value) => value.decorations
|
|
1921
|
+
})
|
|
1922
|
+
];
|
|
1923
|
+
};
|
|
1924
|
+
|
|
1925
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1926
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1927
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1928
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1929
|
+
var buildDecorations2 = (view) => {
|
|
1930
|
+
const builder = new RangeSetBuilder3();
|
|
1931
|
+
const { state } = view;
|
|
1932
|
+
const cursor = state.selection.main.head;
|
|
1933
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1934
|
+
syntaxTree3(state).iterate({
|
|
1935
|
+
enter: (node) => {
|
|
1936
|
+
switch (node.name) {
|
|
1937
|
+
case "ATXHeading1":
|
|
1938
|
+
case "ATXHeading2":
|
|
1939
|
+
case "ATXHeading3":
|
|
1940
|
+
case "ATXHeading4":
|
|
1941
|
+
case "ATXHeading5":
|
|
1942
|
+
case "ATXHeading6": {
|
|
1943
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1944
|
+
if (mark2) {
|
|
1945
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1946
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1952
|
+
from,
|
|
1953
|
+
to
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
return builder.finish();
|
|
1957
|
+
};
|
|
1958
|
+
var heading2 = () => {
|
|
1959
|
+
return [
|
|
1960
|
+
ViewPlugin5.fromClass(class {
|
|
1961
|
+
constructor(view) {
|
|
1962
|
+
this.decorations = buildDecorations2(view);
|
|
1963
|
+
}
|
|
1964
|
+
update(update2) {
|
|
1965
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1966
|
+
}
|
|
1967
|
+
}, {
|
|
1968
|
+
decorations: (value) => value.decorations
|
|
1969
|
+
})
|
|
1970
|
+
];
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
1974
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
1975
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
1976
|
+
import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1977
|
+
var styles4 = EditorView9.baseTheme({
|
|
1978
|
+
"& .cm-hr": {
|
|
1979
|
+
// Note that block-level decorations should not have vertical margins,
|
|
1980
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1984
|
+
toDOM() {
|
|
1985
|
+
const el = document.createElement("div");
|
|
1986
|
+
el.className = "cm-hr";
|
|
1987
|
+
return el;
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1990
|
+
var decoration = Decoration6.replace({
|
|
1991
|
+
widget: new HorizontalRuleWidget()
|
|
1992
|
+
});
|
|
1993
|
+
var buildDecorations3 = (view) => {
|
|
1994
|
+
const builder = new RangeSetBuilder4();
|
|
1995
|
+
const { state } = view;
|
|
1996
|
+
const cursor = state.selection.main.head;
|
|
1997
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1998
|
+
syntaxTree4(state).iterate({
|
|
1999
|
+
enter: (node) => {
|
|
2000
|
+
if (node.name === "HorizontalRule") {
|
|
2001
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2002
|
+
builder.add(node.from, node.to, decoration);
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
from,
|
|
2007
|
+
to
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
return builder.finish();
|
|
2011
|
+
};
|
|
2012
|
+
var hr = () => {
|
|
2013
|
+
return [
|
|
2014
|
+
ViewPlugin6.fromClass(class {
|
|
2015
|
+
constructor(view) {
|
|
2016
|
+
this.decorations = buildDecorations3(view);
|
|
2017
|
+
}
|
|
2018
|
+
update(update2) {
|
|
2019
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2020
|
+
}
|
|
2021
|
+
}, {
|
|
2022
|
+
decorations: (value) => value.decorations
|
|
2023
|
+
}),
|
|
2024
|
+
styles4
|
|
2025
|
+
];
|
|
2026
|
+
};
|
|
2027
|
+
|
|
2028
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2029
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2030
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
2031
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2032
|
+
var image = (options = {}) => {
|
|
2033
|
+
return StateField3.define({
|
|
2034
|
+
create: (state) => {
|
|
2035
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
2036
|
+
},
|
|
2037
|
+
update: (value, tr) => {
|
|
2038
|
+
if (!tr.docChanged && !tr.selection) {
|
|
2039
|
+
return value;
|
|
2040
|
+
}
|
|
2041
|
+
const cursor = tr.state.selection.main.head;
|
|
2042
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
2043
|
+
let from = Math.min(cursor, oldCursor);
|
|
2044
|
+
let to = Math.max(cursor, oldCursor);
|
|
2045
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
2046
|
+
from = Math.min(from, fromB);
|
|
2047
|
+
to = Math.max(to, toB);
|
|
2048
|
+
});
|
|
2049
|
+
from = tr.state.doc.lineAt(from).from;
|
|
2050
|
+
to = tr.state.doc.lineAt(to).to;
|
|
2051
|
+
return value.map(tr.changes).update({
|
|
2052
|
+
filterFrom: from,
|
|
2053
|
+
filterTo: to,
|
|
2054
|
+
filter: () => false,
|
|
2055
|
+
add: buildDecorations4(from, to, tr.state)
|
|
2056
|
+
});
|
|
2057
|
+
},
|
|
2058
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
2059
|
+
});
|
|
2060
|
+
};
|
|
2061
|
+
var buildDecorations4 = (from, to, state) => {
|
|
2062
|
+
const decorations = [];
|
|
2063
|
+
const cursor = state.selection.main.head;
|
|
2064
|
+
syntaxTree5(state).iterate({
|
|
2065
|
+
enter: (node) => {
|
|
2066
|
+
if (node.name === "Image") {
|
|
2067
|
+
const urlNode = node.node.getChild("URL");
|
|
2068
|
+
if (urlNode) {
|
|
2069
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
2070
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2071
|
+
decorations.push(Decoration7.replace({
|
|
2072
|
+
block: true,
|
|
2073
|
+
widget: new ImageWidget(url)
|
|
2074
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
},
|
|
2078
|
+
from,
|
|
2079
|
+
to
|
|
2080
|
+
});
|
|
2081
|
+
return decorations;
|
|
2082
|
+
};
|
|
2083
|
+
var ImageWidget = class extends WidgetType4 {
|
|
2084
|
+
constructor(_url) {
|
|
2085
|
+
super();
|
|
2086
|
+
this._url = _url;
|
|
2087
|
+
}
|
|
2088
|
+
eq(other) {
|
|
2089
|
+
return this._url === other._url;
|
|
2090
|
+
}
|
|
2091
|
+
toDOM(view) {
|
|
2092
|
+
const img = document.createElement("img");
|
|
2093
|
+
img.setAttribute("src", this._url);
|
|
2094
|
+
img.setAttribute("class", "cm-image");
|
|
2095
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
2096
|
+
return img;
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
|
|
2100
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
2101
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2102
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
2103
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
2104
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
2105
|
+
var link = (options = {}) => {
|
|
2106
|
+
const extensions = [
|
|
2107
|
+
ViewPlugin7.fromClass(class {
|
|
2108
|
+
constructor(view) {
|
|
2109
|
+
this.decorations = buildDecorations5(view, options);
|
|
2110
|
+
}
|
|
2111
|
+
update(update2) {
|
|
2112
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2113
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}, {
|
|
2117
|
+
decorations: (value) => value.decorations
|
|
2118
|
+
})
|
|
2119
|
+
];
|
|
2120
|
+
if (options.onHover) {
|
|
2121
|
+
extensions.push(
|
|
2122
|
+
// https://codemirror.net/examples/tooltip
|
|
2123
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
2124
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
2125
|
+
hoverTooltip2((view, pos, side) => {
|
|
2126
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
2127
|
+
let link2 = null;
|
|
2128
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
2129
|
+
link2 = node.name === "Link" ? node : null;
|
|
2130
|
+
}
|
|
2131
|
+
const url = link2 && link2.getChild("URL");
|
|
2132
|
+
if (!url || !link2) {
|
|
2133
|
+
return null;
|
|
2134
|
+
}
|
|
2135
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
2136
|
+
return {
|
|
2137
|
+
pos: link2.from,
|
|
2138
|
+
end: link2.to,
|
|
2139
|
+
above: true,
|
|
2140
|
+
create: () => {
|
|
2141
|
+
const el = document.createElement("div");
|
|
2142
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2143
|
+
options.onHover(el, urlText);
|
|
2144
|
+
return {
|
|
2145
|
+
dom: el,
|
|
2146
|
+
offset: {
|
|
2147
|
+
x: 0,
|
|
2148
|
+
y: 4
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
};
|
|
2153
|
+
})
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
return extensions;
|
|
2157
|
+
};
|
|
2158
|
+
var LinkButton = class extends WidgetType5 {
|
|
2159
|
+
constructor(_url, _onAttach) {
|
|
2160
|
+
super();
|
|
2161
|
+
this._url = _url;
|
|
2162
|
+
this._onAttach = _onAttach;
|
|
2163
|
+
}
|
|
2164
|
+
eq(other) {
|
|
2165
|
+
return this._url === other._url;
|
|
2166
|
+
}
|
|
2167
|
+
toDOM(view) {
|
|
2168
|
+
const el = document.createElement("span");
|
|
2169
|
+
this._onAttach(el, this._url);
|
|
2170
|
+
return el;
|
|
2171
|
+
}
|
|
2172
|
+
};
|
|
2173
|
+
var LinkText = class extends WidgetType5 {
|
|
2174
|
+
constructor(_text, _url) {
|
|
2175
|
+
super();
|
|
2176
|
+
this._text = _text;
|
|
2177
|
+
this._url = _url;
|
|
2178
|
+
}
|
|
2179
|
+
eq(other) {
|
|
2180
|
+
return this._url === other._url;
|
|
2181
|
+
}
|
|
2182
|
+
toDOM(view) {
|
|
2183
|
+
const link2 = document.createElement("a");
|
|
2184
|
+
link2.setAttribute("class", "cm-link");
|
|
2185
|
+
link2.textContent = this._text;
|
|
2186
|
+
if (this._url) {
|
|
2187
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2188
|
+
link2.setAttribute("target", "_blank");
|
|
2189
|
+
link2.href = this._url;
|
|
2190
|
+
} else {
|
|
2191
|
+
link2.onclick = () => {
|
|
2192
|
+
view.dispatch({
|
|
2193
|
+
selection: {
|
|
2194
|
+
anchor: view.posAtDOM(link2)
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
return link2;
|
|
2200
|
+
}
|
|
1953
2201
|
};
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
2202
|
+
var buildDecorations5 = (view, options) => {
|
|
2203
|
+
const builder = new RangeSetBuilder5();
|
|
2204
|
+
const { state } = view;
|
|
2205
|
+
const cursor = state.selection.main.head;
|
|
2206
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2207
|
+
syntaxTree6(state).iterate({
|
|
2208
|
+
enter: (node) => {
|
|
2209
|
+
if (node.name === "Link") {
|
|
2210
|
+
const marks = node.node.getChildren("LinkMark");
|
|
2211
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2212
|
+
const urlNode = node.node.getChild("URL");
|
|
2213
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2214
|
+
if (!url) {
|
|
2215
|
+
return false;
|
|
2216
|
+
}
|
|
2217
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2218
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2219
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2220
|
+
}));
|
|
2221
|
+
}
|
|
2222
|
+
if (options.onRender) {
|
|
2223
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2224
|
+
widget: new LinkButton(url, options.onRender)
|
|
2225
|
+
}));
|
|
2226
|
+
}
|
|
2227
|
+
return false;
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
from,
|
|
2231
|
+
to
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
return builder.finish();
|
|
1958
2235
|
};
|
|
1959
2236
|
|
|
1960
|
-
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1961
|
-
import { syntaxTree as
|
|
1962
|
-
import { RangeSetBuilder as
|
|
1963
|
-
import { Decoration as
|
|
2237
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2238
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2239
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2240
|
+
import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1964
2241
|
var table = (options = {}) => {
|
|
1965
2242
|
return StateField4.define({
|
|
1966
2243
|
create: (state) => update(state, options),
|
|
1967
2244
|
update: (_, tr) => update(tr.state, options),
|
|
1968
|
-
provide: (field) =>
|
|
2245
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1969
2246
|
});
|
|
1970
2247
|
};
|
|
1971
2248
|
var update = (state, options) => {
|
|
1972
|
-
const builder = new
|
|
2249
|
+
const builder = new RangeSetBuilder6();
|
|
1973
2250
|
const cursor = state.selection.main.head;
|
|
1974
2251
|
const tables = [];
|
|
1975
2252
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1977,7 +2254,7 @@ var update = (state, options) => {
|
|
|
1977
2254
|
const table2 = getTable();
|
|
1978
2255
|
return table2.rows?.[table2.rows.length - 1];
|
|
1979
2256
|
};
|
|
1980
|
-
|
|
2257
|
+
syntaxTree7(state).iterate({
|
|
1981
2258
|
enter: (node) => {
|
|
1982
2259
|
switch (node.name) {
|
|
1983
2260
|
case "Table": {
|
|
@@ -2009,16 +2286,16 @@ var update = (state, options) => {
|
|
|
2009
2286
|
});
|
|
2010
2287
|
tables.forEach((table2) => {
|
|
2011
2288
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2012
|
-
hide && builder.add(table2.from, table2.to,
|
|
2289
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2013
2290
|
widget: new TableWidget(table2)
|
|
2014
2291
|
}));
|
|
2015
|
-
builder.add(table2.from, table2.to,
|
|
2292
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2016
2293
|
class: "cm-table"
|
|
2017
2294
|
}));
|
|
2018
2295
|
});
|
|
2019
2296
|
return builder.finish();
|
|
2020
2297
|
};
|
|
2021
|
-
var TableWidget = class extends
|
|
2298
|
+
var TableWidget = class extends WidgetType6 {
|
|
2022
2299
|
constructor(_table) {
|
|
2023
2300
|
super();
|
|
2024
2301
|
this._table = _table;
|
|
@@ -2055,11 +2332,20 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2055
2332
|
}
|
|
2056
2333
|
};
|
|
2057
2334
|
|
|
2058
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2059
|
-
import { syntaxTree as
|
|
2060
|
-
import { RangeSetBuilder as
|
|
2061
|
-
import { EditorView as
|
|
2062
|
-
var
|
|
2335
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2336
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2337
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2338
|
+
import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
2339
|
+
var styles5 = EditorView12.baseTheme({
|
|
2340
|
+
"& .cm-task": {
|
|
2341
|
+
color: getToken("extend.colors.blue.500")
|
|
2342
|
+
},
|
|
2343
|
+
"& .cm-task-checkbox": {
|
|
2344
|
+
marginLeft: "4px",
|
|
2345
|
+
marginRight: "4px"
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
2348
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2063
2349
|
constructor(_checked) {
|
|
2064
2350
|
super();
|
|
2065
2351
|
this._checked = _checked;
|
|
@@ -2069,6 +2355,7 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2069
2355
|
}
|
|
2070
2356
|
toDOM(view) {
|
|
2071
2357
|
const input = document.createElement("input");
|
|
2358
|
+
input.className = "cm-task-checkbox";
|
|
2072
2359
|
input.type = "checkbox";
|
|
2073
2360
|
input.checked = this._checked;
|
|
2074
2361
|
if (view.state.readOnly) {
|
|
@@ -2095,40 +2382,27 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2095
2382
|
return false;
|
|
2096
2383
|
}
|
|
2097
2384
|
};
|
|
2098
|
-
var
|
|
2385
|
+
var checkedDecoration = Decoration10.replace({
|
|
2099
2386
|
widget: new CheckboxWidget(true)
|
|
2100
2387
|
});
|
|
2101
|
-
var
|
|
2388
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2102
2389
|
widget: new CheckboxWidget(false)
|
|
2103
2390
|
});
|
|
2104
|
-
var
|
|
2105
|
-
|
|
2106
|
-
constructor(view) {
|
|
2107
|
-
this.decorations = buildDecorations3(view);
|
|
2108
|
-
}
|
|
2109
|
-
update(update2) {
|
|
2110
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2111
|
-
this.decorations = buildDecorations3(update2.view);
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
}, {
|
|
2115
|
-
decorations: (v) => v.decorations,
|
|
2116
|
-
// TODO(burdon): Is this still required?
|
|
2117
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2118
|
-
return view.plugin(plugin)?.decorations || Decoration8.none;
|
|
2119
|
-
})
|
|
2120
|
-
});
|
|
2121
|
-
};
|
|
2122
|
-
var buildDecorations3 = (view) => {
|
|
2123
|
-
const builder = new RangeSetBuilder3();
|
|
2391
|
+
var buildDecorations6 = (view) => {
|
|
2392
|
+
const builder = new RangeSetBuilder7();
|
|
2124
2393
|
const { state } = view;
|
|
2125
2394
|
const cursor = state.selection.main.head;
|
|
2126
2395
|
for (const { from, to } of view.visibleRanges) {
|
|
2127
|
-
|
|
2396
|
+
syntaxTree8(state).iterate({
|
|
2128
2397
|
enter: (node) => {
|
|
2129
|
-
if (node.name === "TaskMarker"
|
|
2130
|
-
|
|
2131
|
-
|
|
2398
|
+
if (node.name === "TaskMarker") {
|
|
2399
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2400
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2401
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2402
|
+
class: "cm-task"
|
|
2403
|
+
}));
|
|
2404
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2405
|
+
}
|
|
2132
2406
|
}
|
|
2133
2407
|
},
|
|
2134
2408
|
from,
|
|
@@ -2137,9 +2411,60 @@ var buildDecorations3 = (view) => {
|
|
|
2137
2411
|
}
|
|
2138
2412
|
return builder.finish();
|
|
2139
2413
|
};
|
|
2414
|
+
var tasklist = (options = {}) => {
|
|
2415
|
+
return [
|
|
2416
|
+
ViewPlugin8.fromClass(class {
|
|
2417
|
+
constructor(view) {
|
|
2418
|
+
this.decorations = buildDecorations6(view);
|
|
2419
|
+
}
|
|
2420
|
+
update(update2) {
|
|
2421
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2422
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}, {
|
|
2426
|
+
decorations: (value) => value.decorations
|
|
2427
|
+
}),
|
|
2428
|
+
styles5
|
|
2429
|
+
];
|
|
2430
|
+
};
|
|
2431
|
+
|
|
2432
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2433
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2434
|
+
var mention = ({ onSearch }) => {
|
|
2435
|
+
return autocompletion2({
|
|
2436
|
+
// TODO(burdon): Not working.
|
|
2437
|
+
activateOnTyping: true,
|
|
2438
|
+
// activateOnTypingDelay: 100,
|
|
2439
|
+
// selectOnOpen: true,
|
|
2440
|
+
closeOnBlur: false,
|
|
2441
|
+
// defaultKeymap: false,
|
|
2442
|
+
icons: false,
|
|
2443
|
+
override: [
|
|
2444
|
+
(context) => {
|
|
2445
|
+
console.log(context);
|
|
2446
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2447
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2448
|
+
return null;
|
|
2449
|
+
}
|
|
2450
|
+
return {
|
|
2451
|
+
from: match.from,
|
|
2452
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2453
|
+
label: `@${value}`
|
|
2454
|
+
}))
|
|
2455
|
+
};
|
|
2456
|
+
}
|
|
2457
|
+
]
|
|
2458
|
+
});
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2461
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2462
|
+
var outliner = (options = {}) => {
|
|
2463
|
+
return [];
|
|
2464
|
+
};
|
|
2140
2465
|
|
|
2141
2466
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2142
|
-
import { keymap as
|
|
2467
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2143
2468
|
var defaultItems = [
|
|
2144
2469
|
"hello world!",
|
|
2145
2470
|
"this is a test.",
|
|
@@ -2149,7 +2474,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2149
2474
|
let t;
|
|
2150
2475
|
let idx = 0;
|
|
2151
2476
|
return [
|
|
2152
|
-
|
|
2477
|
+
keymap6.of([
|
|
2153
2478
|
{
|
|
2154
2479
|
// Reset.
|
|
2155
2480
|
key: "alt-meta-'",
|
|
@@ -2195,27 +2520,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2195
2520
|
];
|
|
2196
2521
|
};
|
|
2197
2522
|
|
|
2198
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2199
|
-
import { yCollab } from "y-codemirror.next";
|
|
2200
|
-
|
|
2201
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2202
|
-
import * as Y from "yjs";
|
|
2203
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2204
|
-
var cursorConverter2 = (text) => ({
|
|
2205
|
-
toCursor: (index, assoc) => {
|
|
2206
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2207
|
-
},
|
|
2208
|
-
fromCursor: (cursor) => {
|
|
2209
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2210
|
-
}
|
|
2211
|
-
});
|
|
2212
|
-
|
|
2213
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2214
|
-
var yjs = (content, awareness2) => [
|
|
2215
|
-
Cursor.converter.of(cursorConverter2(content)),
|
|
2216
|
-
yCollab(content, awareness2)
|
|
2217
|
-
];
|
|
2218
|
-
|
|
2219
2523
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2220
2524
|
import get3 from "lodash.get";
|
|
2221
2525
|
var defaultTheme = {
|
|
@@ -2282,7 +2586,7 @@ var defaultTheme = {
|
|
|
2282
2586
|
paddingInline: 0
|
|
2283
2587
|
},
|
|
2284
2588
|
".cm-activeLine": {
|
|
2285
|
-
background: "
|
|
2589
|
+
background: "transparent"
|
|
2286
2590
|
},
|
|
2287
2591
|
//
|
|
2288
2592
|
// Selection
|
|
@@ -2453,101 +2757,80 @@ var codeTheme = {
|
|
|
2453
2757
|
};
|
|
2454
2758
|
|
|
2455
2759
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2760
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2456
2761
|
var EditorModes = [
|
|
2457
2762
|
"default",
|
|
2458
2763
|
"vim"
|
|
2459
2764
|
];
|
|
2460
|
-
var
|
|
2461
|
-
useEffect(() => {
|
|
2462
|
-
if (view && comments2 !== void 0) {
|
|
2463
|
-
view.dispatch({
|
|
2464
|
-
effects: setComments.of(comments2)
|
|
2465
|
-
});
|
|
2466
|
-
}
|
|
2467
|
-
}, [
|
|
2468
|
-
view,
|
|
2469
|
-
comments2
|
|
2470
|
-
]);
|
|
2471
|
-
};
|
|
2472
|
-
var useAwareness = ({ awareness: awareness2, peer }) => {
|
|
2473
|
-
const { themeMode } = useThemeContext();
|
|
2474
|
-
useEffect(() => {
|
|
2475
|
-
if (awareness2 && peer) {
|
|
2476
|
-
awareness2.setLocalStateField("user", {
|
|
2477
|
-
name: peer.name ?? generateName(peer.id),
|
|
2478
|
-
color: getColorForValue({
|
|
2479
|
-
value: peer.id,
|
|
2480
|
-
type: "color"
|
|
2481
|
-
}),
|
|
2482
|
-
colorLight: getColorForValue({
|
|
2483
|
-
value: peer.id,
|
|
2484
|
-
themeMode,
|
|
2485
|
-
type: "highlight"
|
|
2486
|
-
})
|
|
2487
|
-
});
|
|
2488
|
-
}
|
|
2489
|
-
}, [
|
|
2490
|
-
awareness2,
|
|
2491
|
-
peer,
|
|
2492
|
-
themeMode
|
|
2493
|
-
]);
|
|
2494
|
-
};
|
|
2495
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, selection, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
|
|
2496
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2497
|
-
tabBehavior: "limited"
|
|
2498
|
-
});
|
|
2765
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2499
2766
|
const { themeMode } = useThemeContext();
|
|
2500
2767
|
const rootRef = useRef(null);
|
|
2501
2768
|
const [view, setView] = useState(null);
|
|
2502
2769
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2503
2770
|
view
|
|
2504
2771
|
]);
|
|
2505
|
-
|
|
2506
|
-
if (
|
|
2772
|
+
useEffect2(() => {
|
|
2773
|
+
if (autoFocus) {
|
|
2507
2774
|
view?.focus();
|
|
2508
2775
|
}
|
|
2509
2776
|
}, [
|
|
2510
2777
|
view,
|
|
2511
|
-
|
|
2778
|
+
autoFocus
|
|
2512
2779
|
]);
|
|
2513
|
-
|
|
2514
|
-
useComments(view, comments2);
|
|
2515
|
-
useEffect(() => {
|
|
2780
|
+
useEffect2(() => {
|
|
2516
2781
|
if (!model || !rootRef.current) {
|
|
2517
2782
|
return;
|
|
2518
2783
|
}
|
|
2519
2784
|
const state = EditorState2.create({
|
|
2520
2785
|
doc: model.text(),
|
|
2521
|
-
// TODO(burdon): Composer should store and set selection when switching documents.
|
|
2522
2786
|
selection,
|
|
2523
2787
|
extensions: [
|
|
2524
|
-
|
|
2788
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2789
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2790
|
+
log2.catch(err, void 0, {
|
|
2791
|
+
F: __dxlog_file3,
|
|
2792
|
+
L: 129,
|
|
2793
|
+
S: void 0,
|
|
2794
|
+
C: (f, a) => f(...a)
|
|
2795
|
+
});
|
|
2796
|
+
}),
|
|
2525
2797
|
// Theme.
|
|
2526
|
-
// TODO(burdon): Make
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2798
|
+
// TODO(burdon): Make configurable.
|
|
2799
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2800
|
+
EditorView13.theme(theme ?? {}),
|
|
2801
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2802
|
+
EditorView13.editorAttributes.of({
|
|
2803
|
+
class: slots.editor?.className ?? ""
|
|
2804
|
+
}),
|
|
2805
|
+
EditorView13.contentAttributes.of({
|
|
2806
|
+
class: slots.content?.className ?? ""
|
|
2807
|
+
}),
|
|
2808
|
+
// State.
|
|
2809
|
+
EditorView13.editable.of(!readonly),
|
|
2810
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2811
|
+
// Storage and replication.
|
|
2812
|
+
// NOTE: This must come before user extensions.
|
|
2533
2813
|
model.extension,
|
|
2814
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2815
|
+
editorMode === "vim" && vim(),
|
|
2534
2816
|
// Custom.
|
|
2535
2817
|
...extensions
|
|
2536
|
-
].filter(
|
|
2818
|
+
].filter(isNotFalsy)
|
|
2537
2819
|
});
|
|
2538
|
-
|
|
2539
|
-
const newView = new EditorView12({
|
|
2540
|
-
parent: rootRef.current,
|
|
2820
|
+
const newView = new EditorView13({
|
|
2541
2821
|
state,
|
|
2542
|
-
|
|
2822
|
+
parent: rootRef.current,
|
|
2823
|
+
scrollTo,
|
|
2824
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2543
2825
|
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
view2.
|
|
2826
|
+
dispatchTransactions: (trs, view2) => {
|
|
2827
|
+
if (debug) {
|
|
2828
|
+
logChanges(trs);
|
|
2829
|
+
}
|
|
2830
|
+
view2.update(trs);
|
|
2549
2831
|
}
|
|
2550
2832
|
});
|
|
2833
|
+
view?.destroy();
|
|
2551
2834
|
setView(newView);
|
|
2552
2835
|
return () => {
|
|
2553
2836
|
newView?.destroy();
|
|
@@ -2563,9 +2846,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2563
2846
|
const handleKeyUp = useCallback((event) => {
|
|
2564
2847
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2565
2848
|
switch (key) {
|
|
2849
|
+
case "Enter": {
|
|
2850
|
+
view?.focus();
|
|
2851
|
+
break;
|
|
2852
|
+
}
|
|
2566
2853
|
case "Escape": {
|
|
2567
2854
|
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2568
|
-
|
|
2855
|
+
view?.focus();
|
|
2569
2856
|
}
|
|
2570
2857
|
break;
|
|
2571
2858
|
}
|
|
@@ -2578,13 +2865,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, s
|
|
|
2578
2865
|
key: model.id,
|
|
2579
2866
|
role: "none",
|
|
2580
2867
|
tabIndex: 0,
|
|
2581
|
-
onKeyUp: handleKeyUp,
|
|
2582
2868
|
...slots.root,
|
|
2583
|
-
...editorMode !==
|
|
2869
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2870
|
+
onKeyUp: handleKeyUp,
|
|
2584
2871
|
ref: rootRef
|
|
2585
2872
|
});
|
|
2586
2873
|
});
|
|
2587
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2874
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2588
2875
|
const { themeMode } = useThemeContext();
|
|
2589
2876
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2590
2877
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
@@ -2592,9 +2879,9 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2592
2879
|
readonly,
|
|
2593
2880
|
extensions: [
|
|
2594
2881
|
basicBundle({
|
|
2595
|
-
readonly,
|
|
2596
2882
|
themeMode,
|
|
2597
|
-
placeholder: placeholder3
|
|
2883
|
+
placeholder: placeholder3,
|
|
2884
|
+
lineWrapping
|
|
2598
2885
|
}),
|
|
2599
2886
|
...extensions
|
|
2600
2887
|
],
|
|
@@ -2603,7 +2890,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2603
2890
|
...props
|
|
2604
2891
|
});
|
|
2605
2892
|
});
|
|
2606
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3,
|
|
2893
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2607
2894
|
const { themeMode } = useThemeContext();
|
|
2608
2895
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2609
2896
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
@@ -2611,7 +2898,6 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2611
2898
|
readonly,
|
|
2612
2899
|
extensions: [
|
|
2613
2900
|
markdownBundle({
|
|
2614
|
-
readonly,
|
|
2615
2901
|
themeMode,
|
|
2616
2902
|
placeholder: placeholder3
|
|
2617
2903
|
}),
|
|
@@ -2624,7 +2910,11 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2624
2910
|
});
|
|
2625
2911
|
var defaultSlots = {
|
|
2626
2912
|
root: {
|
|
2627
|
-
|
|
2913
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2914
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2915
|
+
},
|
|
2916
|
+
editor: {
|
|
2917
|
+
className: "h-full p-2"
|
|
2628
2918
|
}
|
|
2629
2919
|
};
|
|
2630
2920
|
var defaultTextSlots = {
|
|
@@ -2634,22 +2924,17 @@ var defaultMarkdownSlots = {
|
|
|
2634
2924
|
...defaultSlots
|
|
2635
2925
|
};
|
|
2636
2926
|
|
|
2637
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2638
|
-
import get4 from "lodash.get";
|
|
2639
|
-
import { getRawDoc } from "@dxos/echo-schema";
|
|
2640
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2641
|
-
|
|
2642
2927
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2643
2928
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2644
2929
|
import { Context as Context2 } from "@dxos/context";
|
|
2645
|
-
import { invariant as
|
|
2646
|
-
import { log as
|
|
2930
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2931
|
+
import { log as log3 } from "@dxos/log";
|
|
2647
2932
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2648
2933
|
var DEBOUNCE_INTERVAL = 100;
|
|
2649
2934
|
var SpaceAwarenessProvider = class {
|
|
2650
2935
|
constructor(params) {
|
|
2651
|
-
this.remoteStateChange = new Event2();
|
|
2652
2936
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2937
|
+
this.remoteStateChange = new Event2();
|
|
2653
2938
|
this._space = params.space;
|
|
2654
2939
|
this._channel = params.channel;
|
|
2655
2940
|
this._peerId = params.peerId;
|
|
@@ -2666,7 +2951,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2666
2951
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2667
2952
|
}
|
|
2668
2953
|
});
|
|
2669
|
-
|
|
2954
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2670
2955
|
switch (message.payload.kind) {
|
|
2671
2956
|
case "query": {
|
|
2672
2957
|
this._handleQueryMessage();
|
|
@@ -2677,16 +2962,15 @@ var SpaceAwarenessProvider = class {
|
|
|
2677
2962
|
break;
|
|
2678
2963
|
}
|
|
2679
2964
|
}
|
|
2680
|
-
});
|
|
2681
|
-
this._ctx.onDispose(unsubscribe);
|
|
2965
|
+
}));
|
|
2682
2966
|
void this._space.postMessage(this._channel, {
|
|
2683
2967
|
kind: "query"
|
|
2684
2968
|
}).catch((err) => {
|
|
2685
|
-
|
|
2969
|
+
log3.debug("failed to query awareness", {
|
|
2686
2970
|
err
|
|
2687
2971
|
}, {
|
|
2688
2972
|
F: __dxlog_file4,
|
|
2689
|
-
L:
|
|
2973
|
+
L: 89,
|
|
2690
2974
|
S: this,
|
|
2691
2975
|
C: (f, a) => f(...a)
|
|
2692
2976
|
});
|
|
@@ -2697,10 +2981,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2697
2981
|
this._ctx = void 0;
|
|
2698
2982
|
this._postTask = void 0;
|
|
2699
2983
|
}
|
|
2984
|
+
getRemoteStates() {
|
|
2985
|
+
return Array.from(this._remoteStates.values());
|
|
2986
|
+
}
|
|
2700
2987
|
update(position) {
|
|
2701
|
-
|
|
2988
|
+
invariant2(this._postTask, void 0, {
|
|
2702
2989
|
F: __dxlog_file4,
|
|
2703
|
-
L:
|
|
2990
|
+
L: 104,
|
|
2704
2991
|
S: this,
|
|
2705
2992
|
A: [
|
|
2706
2993
|
"this._postTask",
|
|
@@ -2714,13 +3001,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2714
3001
|
};
|
|
2715
3002
|
this._postTask.schedule();
|
|
2716
3003
|
}
|
|
2717
|
-
getRemoteStates() {
|
|
2718
|
-
return Array.from(this._remoteStates.values());
|
|
2719
|
-
}
|
|
2720
3004
|
_handleQueryMessage() {
|
|
2721
|
-
|
|
3005
|
+
invariant2(this._postTask, void 0, {
|
|
2722
3006
|
F: __dxlog_file4,
|
|
2723
|
-
L:
|
|
3007
|
+
L: 115,
|
|
2724
3008
|
S: this,
|
|
2725
3009
|
A: [
|
|
2726
3010
|
"this._postTask",
|
|
@@ -2730,9 +3014,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2730
3014
|
this._postTask.schedule();
|
|
2731
3015
|
}
|
|
2732
3016
|
_handlePostMessage(message) {
|
|
2733
|
-
|
|
3017
|
+
invariant2(message.kind === "post", void 0, {
|
|
2734
3018
|
F: __dxlog_file4,
|
|
2735
|
-
L:
|
|
3019
|
+
L: 120,
|
|
2736
3020
|
S: this,
|
|
2737
3021
|
A: [
|
|
2738
3022
|
"message.kind === 'post'",
|
|
@@ -2751,76 +3035,108 @@ var modelState = StateField5.define({
|
|
|
2751
3035
|
update: (model) => model
|
|
2752
3036
|
});
|
|
2753
3037
|
|
|
2754
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2755
|
-
var
|
|
3038
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3039
|
+
var useActionHandler = (view) => {
|
|
3040
|
+
return (action) => {
|
|
3041
|
+
if (!view) {
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
switch (action.type) {
|
|
3045
|
+
case "heading":
|
|
3046
|
+
setHeading(parseInt(action.data))(view);
|
|
3047
|
+
break;
|
|
3048
|
+
case "bold":
|
|
3049
|
+
toggleBold(view);
|
|
3050
|
+
break;
|
|
3051
|
+
case "italic":
|
|
3052
|
+
toggleItalic(view);
|
|
3053
|
+
break;
|
|
3054
|
+
case "strikethrough":
|
|
3055
|
+
toggleStrikethrough(view);
|
|
3056
|
+
break;
|
|
3057
|
+
case "list":
|
|
3058
|
+
toggleList(view);
|
|
3059
|
+
break;
|
|
3060
|
+
case "comment":
|
|
3061
|
+
createComment(view);
|
|
3062
|
+
break;
|
|
3063
|
+
}
|
|
3064
|
+
setTimeout(() => {
|
|
3065
|
+
view.focus();
|
|
3066
|
+
});
|
|
3067
|
+
};
|
|
3068
|
+
};
|
|
3069
|
+
|
|
3070
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3071
|
+
import { useState as useState2 } from "react";
|
|
3072
|
+
var useTextEditor = () => {
|
|
3073
|
+
const [view, setView] = useState2(null);
|
|
3074
|
+
return [
|
|
3075
|
+
(ref) => {
|
|
3076
|
+
setView(ref);
|
|
3077
|
+
},
|
|
3078
|
+
view
|
|
3079
|
+
];
|
|
3080
|
+
};
|
|
3081
|
+
|
|
3082
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
3083
|
+
import get4 from "lodash.get";
|
|
3084
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
3085
|
+
import { generateName } from "@dxos/display-name";
|
|
3086
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
3087
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
3088
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3089
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
3090
|
+
var useTextModel = (props) => {
|
|
3091
|
+
const { identity, space, text } = props;
|
|
3092
|
+
const [model, setModel] = useState3();
|
|
3093
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
3094
|
+
identity,
|
|
3095
|
+
space,
|
|
3096
|
+
text
|
|
3097
|
+
]);
|
|
3098
|
+
return model;
|
|
3099
|
+
};
|
|
3100
|
+
var createModel = ({ space, identity, text }) => {
|
|
3101
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
3102
|
+
F: __dxlog_file5,
|
|
3103
|
+
L: 34,
|
|
3104
|
+
S: void 0,
|
|
3105
|
+
A: [
|
|
3106
|
+
"isAutomergeObject(text)",
|
|
3107
|
+
""
|
|
3108
|
+
]
|
|
3109
|
+
});
|
|
2756
3110
|
const obj = text;
|
|
2757
3111
|
const doc = getRawDoc(obj, [
|
|
2758
3112
|
obj.field
|
|
2759
3113
|
]);
|
|
2760
|
-
const
|
|
3114
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2761
3115
|
space,
|
|
2762
3116
|
channel: `automerge.awareness.${obj.id}`,
|
|
2763
3117
|
info: {
|
|
2764
|
-
displayName: identity
|
|
3118
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2765
3119
|
color: cursorColor.color,
|
|
2766
3120
|
lightColor: cursorColor.light
|
|
2767
3121
|
},
|
|
2768
3122
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2769
3123
|
});
|
|
3124
|
+
const extensions = [
|
|
3125
|
+
//
|
|
3126
|
+
modelState.init(() => model),
|
|
3127
|
+
automerge({
|
|
3128
|
+
handle: doc.handle,
|
|
3129
|
+
path: doc.path
|
|
3130
|
+
})
|
|
3131
|
+
];
|
|
3132
|
+
if (awarenessProvider2) {
|
|
3133
|
+
extensions.push(awareness(awarenessProvider2));
|
|
3134
|
+
}
|
|
2770
3135
|
const model = {
|
|
2771
3136
|
id: obj.id,
|
|
2772
3137
|
content: doc,
|
|
2773
3138
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2774
|
-
|
|
2775
|
-
extension: [
|
|
2776
|
-
modelState.init(() => model),
|
|
2777
|
-
automerge3({
|
|
2778
|
-
handle: doc.handle,
|
|
2779
|
-
path: doc.path
|
|
2780
|
-
}),
|
|
2781
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2782
|
-
awareness()
|
|
2783
|
-
].filter(isNotNullOrUndefined),
|
|
2784
|
-
peer: identity ? {
|
|
2785
|
-
id: identity.identityKey.toHex(),
|
|
2786
|
-
name: identity.profile?.displayName
|
|
2787
|
-
} : void 0
|
|
2788
|
-
};
|
|
2789
|
-
return model;
|
|
2790
|
-
};
|
|
2791
|
-
|
|
2792
|
-
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2793
|
-
import * as decoding from "lib0/decoding";
|
|
2794
|
-
import * as encoding from "lib0/encoding";
|
|
2795
|
-
import { Observable } from "lib0/observable";
|
|
2796
|
-
import * as YP from "y-protocols/awareness";
|
|
2797
|
-
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2798
|
-
import { log as log3 } from "@dxos/log";
|
|
2799
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2800
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2801
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2802
|
-
F: __dxlog_file5,
|
|
2803
|
-
L: 22,
|
|
2804
|
-
S: void 0,
|
|
2805
|
-
A: [
|
|
2806
|
-
"text?.doc && text?.content",
|
|
2807
|
-
""
|
|
2808
|
-
]
|
|
2809
|
-
});
|
|
2810
|
-
const provider = space ? new YAwarenessProvider({
|
|
2811
|
-
space,
|
|
2812
|
-
doc: text.doc,
|
|
2813
|
-
channel: `yjs.awareness.${text.id}`
|
|
2814
|
-
}) : void 0;
|
|
2815
|
-
const model = {
|
|
2816
|
-
id: text.doc.guid,
|
|
2817
|
-
content: text.content,
|
|
2818
|
-
text: () => text.content.toString(),
|
|
2819
|
-
extension: [
|
|
2820
|
-
modelState.init(() => model),
|
|
2821
|
-
yjs(text.content, provider?.awareness)
|
|
2822
|
-
],
|
|
2823
|
-
awareness: provider?.awareness,
|
|
3139
|
+
extension: extensions,
|
|
2824
3140
|
peer: identity ? {
|
|
2825
3141
|
id: identity.identityKey.toHex(),
|
|
2826
3142
|
name: identity.profile?.displayName
|
|
@@ -2828,124 +3144,7 @@ var createYjsModel = ({ identity, space, text }) => {
|
|
|
2828
3144
|
};
|
|
2829
3145
|
return model;
|
|
2830
3146
|
};
|
|
2831
|
-
var messageAwareness = 1;
|
|
2832
|
-
var messageQueryAwareness = 3;
|
|
2833
|
-
var YAwarenessProvider = class extends Observable {
|
|
2834
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2835
|
-
super();
|
|
2836
|
-
this._space = space;
|
|
2837
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2838
|
-
this._channel = channel;
|
|
2839
|
-
this._clientId = doc.clientID;
|
|
2840
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2841
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2842
|
-
if (typeof window !== "undefined") {
|
|
2843
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2844
|
-
} else if (typeof process !== "undefined") {
|
|
2845
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2846
|
-
}
|
|
2847
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2848
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2849
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2850
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2851
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2852
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2853
|
-
this._clientId
|
|
2854
|
-
]));
|
|
2855
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2856
|
-
}
|
|
2857
|
-
get awareness() {
|
|
2858
|
-
return this._awareness;
|
|
2859
|
-
}
|
|
2860
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2861
|
-
log3("awareness update", {
|
|
2862
|
-
added,
|
|
2863
|
-
updated,
|
|
2864
|
-
removed,
|
|
2865
|
-
origin
|
|
2866
|
-
}, {
|
|
2867
|
-
F: __dxlog_file5,
|
|
2868
|
-
L: 101,
|
|
2869
|
-
S: this,
|
|
2870
|
-
C: (f, a) => f(...a)
|
|
2871
|
-
});
|
|
2872
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2873
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2874
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2875
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2876
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2877
|
-
}
|
|
2878
|
-
_handleSpaceMessage({ payload }) {
|
|
2879
|
-
log3("space message", payload, {
|
|
2880
|
-
F: __dxlog_file5,
|
|
2881
|
-
L: 110,
|
|
2882
|
-
S: this,
|
|
2883
|
-
C: (f, a) => f(...a)
|
|
2884
|
-
});
|
|
2885
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2886
|
-
const encoder = this._readMessage(data);
|
|
2887
|
-
if (encoder) {
|
|
2888
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
_readMessage(message) {
|
|
2892
|
-
const decoder = decoding.createDecoder(message);
|
|
2893
|
-
const encoder = encoding.createEncoder();
|
|
2894
|
-
const messageType = decoding.readVarUint(decoder);
|
|
2895
|
-
let sendReply = false;
|
|
2896
|
-
switch (messageType) {
|
|
2897
|
-
case messageAwareness: {
|
|
2898
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2899
|
-
break;
|
|
2900
|
-
}
|
|
2901
|
-
case messageQueryAwareness: {
|
|
2902
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
2903
|
-
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2904
|
-
sendReply = true;
|
|
2905
|
-
break;
|
|
2906
|
-
}
|
|
2907
|
-
default: {
|
|
2908
|
-
console.error("Invalid message:", messageType);
|
|
2909
|
-
return encoder;
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
if (!sendReply) {
|
|
2913
|
-
return null;
|
|
2914
|
-
}
|
|
2915
|
-
return encoder;
|
|
2916
|
-
}
|
|
2917
|
-
_handleBeforeUnload() {
|
|
2918
|
-
YP.removeAwarenessStates(this._awareness, [
|
|
2919
|
-
this._clientId
|
|
2920
|
-
], "window unload");
|
|
2921
|
-
}
|
|
2922
|
-
};
|
|
2923
|
-
|
|
2924
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2925
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
2926
|
-
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2927
|
-
var useTextModel = (props) => {
|
|
2928
|
-
const { identity, space, text } = props;
|
|
2929
|
-
const [model, setModel] = useState2();
|
|
2930
|
-
useEffect2(() => setModel(createModel(props)), [
|
|
2931
|
-
identity,
|
|
2932
|
-
space,
|
|
2933
|
-
text
|
|
2934
|
-
]);
|
|
2935
|
-
return model;
|
|
2936
|
-
};
|
|
2937
|
-
var createModel = (props) => {
|
|
2938
|
-
const { text } = props;
|
|
2939
|
-
if (isAutomergeObject(text)) {
|
|
2940
|
-
return createAutomergeModel(props);
|
|
2941
|
-
} else if (text?.doc) {
|
|
2942
|
-
return createYjsModel(props);
|
|
2943
|
-
} else {
|
|
2944
|
-
return void 0;
|
|
2945
|
-
}
|
|
2946
|
-
};
|
|
2947
3147
|
export {
|
|
2948
|
-
AwarenessProvider,
|
|
2949
3148
|
BaseTextEditor,
|
|
2950
3149
|
Cursor,
|
|
2951
3150
|
Doc,
|
|
@@ -2955,30 +3154,32 @@ export {
|
|
|
2955
3154
|
SpaceAwarenessProvider,
|
|
2956
3155
|
TextEditor,
|
|
2957
3156
|
TextKind,
|
|
2958
|
-
YAwarenessProvider,
|
|
2959
3157
|
YText,
|
|
2960
3158
|
YXmlFragment,
|
|
2961
3159
|
autocomplete,
|
|
2962
|
-
|
|
3160
|
+
automerge,
|
|
2963
3161
|
awareness,
|
|
3162
|
+
awarenessProvider,
|
|
2964
3163
|
basicBundle,
|
|
2965
3164
|
blast,
|
|
2966
3165
|
callbackWrapper,
|
|
2967
3166
|
code2 as code,
|
|
2968
3167
|
codeTheme,
|
|
2969
3168
|
comments,
|
|
2970
|
-
|
|
2971
|
-
createYjsModel,
|
|
3169
|
+
createComment,
|
|
2972
3170
|
defaultMarkdownSlots,
|
|
2973
3171
|
defaultOptions,
|
|
2974
3172
|
defaultSlots,
|
|
2975
3173
|
defaultTextSlots,
|
|
2976
3174
|
defaultTheme,
|
|
3175
|
+
formatting,
|
|
2977
3176
|
getToken,
|
|
3177
|
+
heading2 as heading,
|
|
2978
3178
|
hr,
|
|
2979
3179
|
image,
|
|
2980
3180
|
link,
|
|
2981
3181
|
listener,
|
|
3182
|
+
logChanges,
|
|
2982
3183
|
markdownBundle,
|
|
2983
3184
|
markdownHighlightStyle,
|
|
2984
3185
|
markdownTags,
|
|
@@ -2989,16 +3190,21 @@ export {
|
|
|
2989
3190
|
outliner,
|
|
2990
3191
|
setComments,
|
|
2991
3192
|
setFocus,
|
|
3193
|
+
setHeading,
|
|
2992
3194
|
setSelection,
|
|
2993
|
-
syncFacet,
|
|
2994
3195
|
table,
|
|
2995
3196
|
tags2 as tags,
|
|
2996
3197
|
tasklist,
|
|
2997
3198
|
textTheme,
|
|
3199
|
+
toggleBold,
|
|
3200
|
+
toggleItalic,
|
|
3201
|
+
toggleList,
|
|
3202
|
+
toggleStrikethrough,
|
|
3203
|
+
toggleStyle,
|
|
2998
3204
|
typewriter,
|
|
2999
|
-
|
|
3205
|
+
useActionHandler,
|
|
3000
3206
|
useComments,
|
|
3001
|
-
|
|
3002
|
-
|
|
3207
|
+
useTextEditor,
|
|
3208
|
+
useTextModel
|
|
3003
3209
|
};
|
|
3004
3210
|
//# sourceMappingURL=index.mjs.map
|