@dxos/react-ui-editor 0.3.11-main.5a4849d → 0.3.11-main.5e1976a
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 +1830 -1513
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +16 -13
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts +9 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +5 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +24 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts +14 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- 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/code.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +32 -19
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor.d.ts +25 -0
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/image.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +4 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -5
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
- package/dist/types/src/hooks/awareness-provider.d.ts +31 -0
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +3 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- 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 +2 -31
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +33 -34
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +77 -80
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +122 -93
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/extensions/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.ts +88 -0
- package/src/extensions/automerge/cursor.ts +52 -0
- package/src/extensions/automerge/defs.ts +41 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +34 -29
- package/src/{hooks → extensions}/automerge/update-automerge.ts +5 -6
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +13 -5
- package/src/extensions/awareness.ts +310 -0
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/code.ts +28 -23
- package/src/extensions/comments.ts +252 -229
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/hr.ts +50 -52
- package/src/extensions/image.ts +40 -22
- package/src/extensions/index.ts +4 -1
- package/src/extensions/link.ts +86 -88
- package/src/extensions/markdown/bundle.ts +18 -24
- package/src/extensions/markdown/highlight.ts +3 -12
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/extensions/table.ts +10 -4
- package/src/extensions/tasklist.ts +78 -88
- package/src/hooks/awareness-provider.ts +124 -0
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +4 -1
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +30 -116
- package/src/index.ts +3 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/markdown.ts +0 -2
- package/src/styles/tokens.ts +3 -0
- package/src/themes/default.ts +51 -78
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/extensions/util.d.ts +0 -5
- package/dist/types/src/extensions/util.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/handle.d.ts +0 -9
- package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/index.d.ts +0 -3
- package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts +0 -26
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/semaphore.d.ts +0 -19
- package/dist/types/src/hooks/automerge/semaphore.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-automerge.d.ts +0 -6
- package/dist/types/src/hooks/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/index.d.ts +0 -3
- package/dist/types/src/hooks/yjs/index.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/space-provider.d.ts +0 -27
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts +0 -12
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/hooks/yjs/yjs.test.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 -114
- package/src/extensions/mermaid.ts +0 -11
- package/src/extensions/util.ts +0 -18
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -132
- package/src/hooks/yjs/index.ts +0 -6
- package/src/hooks/yjs/space-provider.ts +0 -126
- package/src/hooks/yjs/yjs.stories.tsx +0 -56
- package/src/hooks/yjs/yjs.test.ts +0 -59
- 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 -189
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.d.ts +0 -0
- /package/dist/types/src/{hooks/yjs → styles}/cursors.d.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
|
@@ -7,784 +7,951 @@ 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
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
11
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState
|
|
15
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
18
|
|
|
19
19
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
21
22
|
import { keymap } from "@codemirror/view";
|
|
22
23
|
var autocomplete = ({ onSearch }) => {
|
|
23
24
|
return [
|
|
24
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
25
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
26
28
|
keymap.of(completionKeymap),
|
|
27
29
|
// https://codemirror.net/examples/autocompletion
|
|
28
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
29
31
|
autocompletion({
|
|
30
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
31
34
|
// defaultKeymap: false,
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
from: match.from,
|
|
44
|
-
options: onSearch(match.text.toLowerCase())
|
|
45
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
46
45
|
}
|
|
47
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
48
51
|
})
|
|
49
52
|
];
|
|
50
53
|
};
|
|
51
54
|
|
|
52
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
57
|
-
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
58
|
-
EditorView.lineWrapping,
|
|
59
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
60
|
-
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
61
|
-
bracketMatching(),
|
|
62
|
-
closeBrackets(),
|
|
63
|
-
drawSelection(),
|
|
64
|
-
_placeholder && placeholder(_placeholder),
|
|
65
|
-
// TODO(burdon): Is this required?
|
|
66
|
-
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
67
|
-
].filter(Boolean);
|
|
68
|
-
|
|
69
|
-
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
70
|
-
import { EditorView as EditorView2, keymap as keymap2 } from "@codemirror/view";
|
|
71
|
-
import defaultsDeep from "lodash.defaultsdeep";
|
|
55
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
58
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
72
59
|
import { invariant } from "@dxos/invariant";
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-1,
|
|
90
|
-
1
|
|
91
|
-
],
|
|
92
|
-
y: [
|
|
93
|
-
-3.5,
|
|
94
|
-
-1.5
|
|
95
|
-
]
|
|
60
|
+
|
|
61
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
62
|
+
import get from "lodash.get";
|
|
63
|
+
import { next as automerge } from "@dxos/automerge/automerge";
|
|
64
|
+
var cursorConverter = (handle, path) => ({
|
|
65
|
+
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
66
|
+
toCursor: (pos) => {
|
|
67
|
+
const doc = handle.docSync();
|
|
68
|
+
if (!doc) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
const value = get(doc, path);
|
|
72
|
+
if (typeof value === "string" && value.length <= pos) {
|
|
73
|
+
return "end";
|
|
74
|
+
}
|
|
75
|
+
return automerge.getCursor(doc, path.slice(), pos);
|
|
96
76
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
y: y - top
|
|
110
|
-
};
|
|
111
|
-
return {
|
|
112
|
-
element,
|
|
113
|
-
point
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
return [
|
|
117
|
-
// Cursor moved.
|
|
118
|
-
EditorView2.updateListener.of((update4) => {
|
|
119
|
-
if (blaster?.node !== update4.view.scrollDOM) {
|
|
120
|
-
if (blaster) {
|
|
121
|
-
blaster.destroy();
|
|
122
|
-
}
|
|
123
|
-
blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
|
|
124
|
-
particleGravity: 0.2,
|
|
125
|
-
particleShrinkRate: 0.995,
|
|
126
|
-
color: () => [
|
|
127
|
-
100 + Math.random() * 100,
|
|
128
|
-
0,
|
|
129
|
-
0
|
|
130
|
-
]
|
|
131
|
-
}, options, defaultOptions));
|
|
132
|
-
blaster.initialize();
|
|
133
|
-
blaster.start();
|
|
77
|
+
fromCursor: (cursor) => {
|
|
78
|
+
if (cursor === "") {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
const doc = handle.docSync();
|
|
82
|
+
if (!doc) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (cursor === "end") {
|
|
86
|
+
const value = get(doc, path);
|
|
87
|
+
if (typeof value === "string") {
|
|
88
|
+
return value.length;
|
|
134
89
|
} else {
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
const current = update4.state.selection.main.head;
|
|
138
|
-
if (current !== last) {
|
|
139
|
-
last = current;
|
|
140
|
-
const { element, point } = getPoint(update4.view, current - 1);
|
|
141
|
-
if (element && point) {
|
|
142
|
-
blaster.spawn({
|
|
143
|
-
element,
|
|
144
|
-
point
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}),
|
|
149
|
-
keymap2.of([
|
|
150
|
-
{
|
|
151
|
-
any: (_, event) => {
|
|
152
|
-
if (blaster) {
|
|
153
|
-
if (event.key === "Enter" && event.shiftKey) {
|
|
154
|
-
blaster.shake({
|
|
155
|
-
time: 0.8
|
|
156
|
-
});
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
])
|
|
164
|
-
];
|
|
165
|
-
};
|
|
166
|
-
var Blaster = class {
|
|
167
|
-
constructor(_node, _options) {
|
|
168
|
-
this._node = _node;
|
|
169
|
-
this._options = _options;
|
|
170
|
-
this._running = false;
|
|
171
|
-
this._shakeTime = 0;
|
|
172
|
-
this._shakeTimeMax = 0;
|
|
173
|
-
this._particles = [];
|
|
174
|
-
this._particlePointer = 0;
|
|
175
|
-
this._lastPoint = {
|
|
176
|
-
x: 0,
|
|
177
|
-
y: 0
|
|
178
|
-
};
|
|
179
|
-
this.shake = throttle(({ time }) => {
|
|
180
|
-
this._shakeTime = this._shakeTimeMax || time;
|
|
181
|
-
this._shakeTimeMax = time;
|
|
182
|
-
}, 100);
|
|
183
|
-
this.spawn = throttle(({ element, point }) => {
|
|
184
|
-
const color = getRGBComponents(element, this._options.color);
|
|
185
|
-
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
186
|
-
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
187
|
-
this._lastPoint = point;
|
|
188
|
-
for (let i = numParticles; i--; i > 0) {
|
|
189
|
-
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
190
|
-
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
90
|
+
return 0;
|
|
191
91
|
}
|
|
192
|
-
}, 100);
|
|
193
|
-
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
194
|
-
}
|
|
195
|
-
get node() {
|
|
196
|
-
return this._node;
|
|
197
|
-
}
|
|
198
|
-
initialize() {
|
|
199
|
-
invariant(!this._canvas && !this._ctx, void 0, {
|
|
200
|
-
F: __dxlog_file,
|
|
201
|
-
L: 138,
|
|
202
|
-
S: this,
|
|
203
|
-
A: [
|
|
204
|
-
"!this._canvas && !this._ctx",
|
|
205
|
-
""
|
|
206
|
-
]
|
|
207
|
-
});
|
|
208
|
-
this._canvas = document.createElement("canvas");
|
|
209
|
-
this._canvas.id = "code-blast-canvas";
|
|
210
|
-
this._canvas.style.position = "absolute";
|
|
211
|
-
this._canvas.style.zIndex = "0";
|
|
212
|
-
this._canvas.style.pointerEvents = "none";
|
|
213
|
-
this._ctx = this._canvas.getContext("2d");
|
|
214
|
-
const parent = this._node.parentElement?.parentElement;
|
|
215
|
-
parent?.appendChild(this._canvas);
|
|
216
|
-
this.resize();
|
|
217
|
-
}
|
|
218
|
-
destroy() {
|
|
219
|
-
this.stop();
|
|
220
|
-
if (this._canvas) {
|
|
221
|
-
this._canvas.remove();
|
|
222
|
-
this._canvas = void 0;
|
|
223
|
-
this._ctx = void 0;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
resize() {
|
|
227
|
-
if (this._node.parentElement && this._canvas) {
|
|
228
|
-
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
229
|
-
this._canvas.style.top = `${y}px`;
|
|
230
|
-
this._canvas.style.left = `${x}px`;
|
|
231
|
-
this._canvas.width = width;
|
|
232
|
-
this._canvas.height = height;
|
|
233
92
|
}
|
|
93
|
+
return automerge.getCursorPosition(doc, path.slice(), cursor);
|
|
234
94
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
98
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
99
|
+
var effectType = StateEffect.define({});
|
|
100
|
+
var reconcileAnnotationType = Annotation.define();
|
|
101
|
+
var getPath = (state, field) => state.field(field).path;
|
|
102
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
103
|
+
var updateHeads = (newHeads) => effectType.of({
|
|
104
|
+
newHeads
|
|
105
|
+
});
|
|
106
|
+
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
107
|
+
|
|
108
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
+
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
110
|
+
|
|
111
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
+
import { next as am } from "@dxos/automerge/automerge";
|
|
113
|
+
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
|
+
const { lastHeads, path } = state.field(field);
|
|
115
|
+
let hasChanges = false;
|
|
116
|
+
for (const tr of transactions) {
|
|
117
|
+
tr.changes.iterChanges(() => {
|
|
118
|
+
hasChanges = true;
|
|
244
119
|
});
|
|
245
|
-
this._running = true;
|
|
246
|
-
this.loop();
|
|
247
120
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this._node.style.transform = "translate(0px, 0px)";
|
|
121
|
+
if (!hasChanges) {
|
|
122
|
+
return void 0;
|
|
251
123
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
124
|
+
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
125
|
+
for (const tr of transactions) {
|
|
126
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
127
|
+
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
128
|
+
});
|
|
255
129
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
for (let i = this._particles.length; i--; i > 0) {
|
|
273
|
-
const particle = this._particles[i];
|
|
274
|
-
if (!particle) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
this._effect.update(this._ctx, particle);
|
|
130
|
+
});
|
|
131
|
+
return newHeads ?? void 0;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-codemirror.ts
|
|
135
|
+
import { ChangeSet } from "@codemirror/state";
|
|
136
|
+
var updateCodeMirror = (view, selection, target, patches) => {
|
|
137
|
+
for (const patch of patches) {
|
|
138
|
+
const changeSpec = handlePatch(patch, target, view.state);
|
|
139
|
+
if (changeSpec != null) {
|
|
140
|
+
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
141
|
+
selection = selection.map(changeSet, 1);
|
|
142
|
+
view.dispatch({
|
|
143
|
+
changes: changeSet,
|
|
144
|
+
annotations: reconcileAnnotationType.of({})
|
|
145
|
+
});
|
|
281
146
|
}
|
|
282
147
|
}
|
|
148
|
+
view.dispatch({
|
|
149
|
+
selection,
|
|
150
|
+
annotations: reconcileAnnotationType.of({})
|
|
151
|
+
});
|
|
283
152
|
};
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
|
|
153
|
+
var handlePatch = (patch, target, state) => {
|
|
154
|
+
if (patch.action === "insert") {
|
|
155
|
+
return handleInsert(target, patch);
|
|
156
|
+
} else if (patch.action === "splice") {
|
|
157
|
+
return handleSplice(target, patch);
|
|
158
|
+
} else if (patch.action === "del") {
|
|
159
|
+
return handleDel(target, patch);
|
|
160
|
+
} else if (patch.action === "put") {
|
|
161
|
+
return handlePut(target, patch, state);
|
|
162
|
+
} else {
|
|
163
|
+
return null;
|
|
287
164
|
}
|
|
288
165
|
};
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
y: y + 10,
|
|
294
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
295
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
296
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
297
|
-
color,
|
|
298
|
-
alpha: 1
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
update(ctx, particle) {
|
|
302
|
-
particle.vy += this._options.particleGravity;
|
|
303
|
-
particle.x += particle.vx;
|
|
304
|
-
particle.y += particle.vy;
|
|
305
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
306
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
307
|
-
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
166
|
+
var handleInsert = (target, patch) => {
|
|
167
|
+
const index = charPath(target, patch.path);
|
|
168
|
+
if (index == null) {
|
|
169
|
+
return [];
|
|
308
170
|
}
|
|
171
|
+
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
from: index,
|
|
175
|
+
to: index,
|
|
176
|
+
insert: text
|
|
177
|
+
}
|
|
178
|
+
];
|
|
309
179
|
};
|
|
310
|
-
var
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
y: y + 10,
|
|
315
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
316
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
317
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
318
|
-
color,
|
|
319
|
-
alpha: 1,
|
|
320
|
-
theta: random(0, 360) * Math.PI / 180,
|
|
321
|
-
drag: 0.92,
|
|
322
|
-
wander: 0.15
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
update(ctx, particle) {
|
|
326
|
-
particle.vy += this._options.particleGravity;
|
|
327
|
-
particle.x += particle.vx;
|
|
328
|
-
particle.y += particle.vy;
|
|
329
|
-
particle.vx *= particle.drag;
|
|
330
|
-
particle.vy *= particle.drag;
|
|
331
|
-
particle.theta += random(-0.5, 0.5);
|
|
332
|
-
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
333
|
-
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
334
|
-
particle.size *= this._options.particleShrinkRate;
|
|
335
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
336
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
337
|
-
ctx.beginPath();
|
|
338
|
-
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
339
|
-
ctx.fill();
|
|
180
|
+
var handleSplice = (target, patch) => {
|
|
181
|
+
const index = charPath(target, patch.path);
|
|
182
|
+
if (index == null) {
|
|
183
|
+
return [];
|
|
340
184
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (!wait) {
|
|
346
|
-
callback.apply(this, args);
|
|
347
|
-
wait = true;
|
|
348
|
-
setTimeout(() => {
|
|
349
|
-
wait = false;
|
|
350
|
-
}, limit);
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
from: index,
|
|
188
|
+
insert: patch.value
|
|
351
189
|
}
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
var
|
|
355
|
-
|
|
356
|
-
|
|
190
|
+
];
|
|
191
|
+
};
|
|
192
|
+
var handleDel = (target, patch) => {
|
|
193
|
+
const index = charPath(target, patch.path);
|
|
194
|
+
if (index == null) {
|
|
195
|
+
return [];
|
|
357
196
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
197
|
+
const length = patch.length || 1;
|
|
198
|
+
return [
|
|
199
|
+
{
|
|
200
|
+
from: index,
|
|
201
|
+
to: index + length
|
|
363
202
|
}
|
|
203
|
+
];
|
|
204
|
+
};
|
|
205
|
+
var handlePut = (target, patch, state) => {
|
|
206
|
+
const index = charPath(target, [
|
|
207
|
+
...patch.path,
|
|
208
|
+
0
|
|
209
|
+
]);
|
|
210
|
+
if (index == null) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
const length = state.doc.length;
|
|
214
|
+
if (typeof patch.value !== "string") {
|
|
215
|
+
return [];
|
|
364
216
|
}
|
|
365
217
|
return [
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
218
|
+
{
|
|
219
|
+
from: 0,
|
|
220
|
+
to: length,
|
|
221
|
+
insert: patch.value
|
|
222
|
+
}
|
|
369
223
|
];
|
|
370
224
|
};
|
|
371
|
-
var
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
min = 0;
|
|
225
|
+
var charPath = (textPath, candidatePath) => {
|
|
226
|
+
if (candidatePath.length !== textPath.length + 1) {
|
|
227
|
+
return null;
|
|
375
228
|
}
|
|
376
|
-
|
|
229
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
230
|
+
if (textPath[i] !== candidatePath[i]) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
235
|
+
if (typeof index === "number") {
|
|
236
|
+
return index;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
377
239
|
};
|
|
378
240
|
|
|
379
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
241
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
|
+
var PatchSemaphore = class {
|
|
243
|
+
// prettier-ignore
|
|
244
|
+
constructor(_handle, _state) {
|
|
245
|
+
this._handle = _handle;
|
|
246
|
+
this._state = _state;
|
|
247
|
+
this._inReconcile = false;
|
|
248
|
+
}
|
|
249
|
+
// NOTE: Cannot destruct view.state.
|
|
250
|
+
reconcile(view) {
|
|
251
|
+
if (this._inReconcile) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this._inReconcile = true;
|
|
255
|
+
const path = getPath(view.state, this._state);
|
|
256
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
257
|
+
let selection = view.state.selection;
|
|
258
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
259
|
+
const toInvert = transactions.slice().reverse();
|
|
260
|
+
for (const tx of toInvert) {
|
|
261
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
262
|
+
selection = selection.map(inverted);
|
|
263
|
+
view.dispatch({
|
|
264
|
+
changes: inverted,
|
|
265
|
+
annotations: reconcileAnnotationType.of(true)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
269
|
+
if (newHeads === null || newHeads === void 0) {
|
|
270
|
+
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
271
|
+
}
|
|
272
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
273
|
+
updateCodeMirror(view, selection, path, diff);
|
|
274
|
+
view.dispatch({
|
|
275
|
+
effects: updateHeads(newHeads),
|
|
276
|
+
annotations: reconcileAnnotationType.of({})
|
|
277
|
+
});
|
|
278
|
+
this._inReconcile = false;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
383
281
|
|
|
384
|
-
// packages/ui/react-ui-editor/src/
|
|
385
|
-
import {
|
|
386
|
-
var
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"-ml-[10px]"
|
|
390
|
-
],
|
|
391
|
-
2: [
|
|
392
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
393
|
-
"-ml-[8px]"
|
|
394
|
-
],
|
|
395
|
-
3: [
|
|
396
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
397
|
-
"-ml-[7px]"
|
|
398
|
-
],
|
|
399
|
-
4: [
|
|
400
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
401
|
-
"-ml-[6px]"
|
|
402
|
-
],
|
|
403
|
-
5: [
|
|
404
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
405
|
-
"-ml-[5px]"
|
|
406
|
-
],
|
|
407
|
-
6: [
|
|
408
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
409
|
-
"-ml-[4px]"
|
|
410
|
-
]
|
|
282
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
283
|
+
import { Facet } from "@codemirror/state";
|
|
284
|
+
var defaultCursorConverter = {
|
|
285
|
+
toCursor: (position) => position.toString(),
|
|
286
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
411
287
|
};
|
|
412
|
-
var
|
|
413
|
-
|
|
414
|
-
|
|
288
|
+
var Cursor = class _Cursor {
|
|
289
|
+
static {
|
|
290
|
+
this.converter = Facet.define({
|
|
291
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
static {
|
|
295
|
+
this.getCursorFromRange = (state, range) => {
|
|
296
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
297
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
298
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
299
|
+
return [
|
|
300
|
+
from,
|
|
301
|
+
to
|
|
302
|
+
].join(":");
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
static {
|
|
306
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
|
+
const parts = cursor.split(":");
|
|
309
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
310
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
311
|
+
return from !== void 0 && to !== void 0 ? {
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
} : void 0;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
415
317
|
};
|
|
416
|
-
var light = "text-neutral-200 dark:text-neutral-800";
|
|
417
|
-
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
418
|
-
var bold = "font-bold";
|
|
419
|
-
var italic = "italic";
|
|
420
|
-
var strikethrough = "line-through";
|
|
421
|
-
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
422
|
-
var codeMark = "font-mono text-primary-500";
|
|
423
|
-
var inlineUrl = mx(code, "px-1");
|
|
424
|
-
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
425
|
-
|
|
426
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
427
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
428
|
-
var tokens = tailwindConfig({}).theme;
|
|
429
318
|
|
|
430
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
431
|
-
var
|
|
432
|
-
var
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
var getLineRange = (lines, from, to) => {
|
|
458
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
459
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
460
|
-
return [
|
|
461
|
-
start,
|
|
462
|
-
end
|
|
463
|
-
];
|
|
464
|
-
};
|
|
465
|
-
var code2 = () => {
|
|
466
|
-
const getDecorations = (view) => {
|
|
467
|
-
const decorations = [];
|
|
468
|
-
if (view.state.readOnly) {
|
|
469
|
-
const text = view.state.doc.sliceString(0);
|
|
470
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
471
|
-
const blocks = view.viewportLineBlocks;
|
|
472
|
-
for (const match of matches) {
|
|
473
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
474
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
475
|
-
const block = blocks[i];
|
|
476
|
-
decorations.push(Decoration.line({
|
|
477
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
478
|
-
}).range(block.from));
|
|
319
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
320
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
|
|
321
|
+
var automerge3 = ({ handle, path }) => {
|
|
322
|
+
const state = StateField.define({
|
|
323
|
+
create: () => ({
|
|
324
|
+
path: path.slice(),
|
|
325
|
+
lastHeads: A.getHeads(handle.docSync()),
|
|
326
|
+
unreconciledTransactions: []
|
|
327
|
+
}),
|
|
328
|
+
update: (value, tr) => {
|
|
329
|
+
const result = {
|
|
330
|
+
path: path.slice(),
|
|
331
|
+
lastHeads: value.lastHeads,
|
|
332
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
333
|
+
};
|
|
334
|
+
let clearUnreconciled = false;
|
|
335
|
+
for (const effect of tr.effects) {
|
|
336
|
+
if (effect.is(effectType)) {
|
|
337
|
+
result.lastHeads = effect.value.newHeads;
|
|
338
|
+
clearUnreconciled = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (clearUnreconciled) {
|
|
342
|
+
result.unreconciledTransactions = [];
|
|
343
|
+
} else {
|
|
344
|
+
if (!isReconcileTx(tr)) {
|
|
345
|
+
result.unreconciledTransactions.push(tr);
|
|
479
346
|
}
|
|
480
347
|
}
|
|
348
|
+
return result;
|
|
481
349
|
}
|
|
482
|
-
|
|
483
|
-
|
|
350
|
+
});
|
|
351
|
+
const semaphore = new PatchSemaphore(handle, state);
|
|
484
352
|
return [
|
|
353
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
354
|
+
// Reconcile external updates.
|
|
485
355
|
ViewPlugin.fromClass(class {
|
|
486
|
-
constructor(
|
|
487
|
-
this.
|
|
356
|
+
constructor(_view) {
|
|
357
|
+
this._view = _view;
|
|
358
|
+
invariant(this._view, void 0, {
|
|
359
|
+
F: __dxlog_file,
|
|
360
|
+
L: 66,
|
|
361
|
+
S: this,
|
|
362
|
+
A: [
|
|
363
|
+
"this._view",
|
|
364
|
+
""
|
|
365
|
+
]
|
|
366
|
+
});
|
|
367
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
488
368
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
369
|
+
destroy() {
|
|
370
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
_handleChange() {
|
|
373
|
+
semaphore.reconcile(this._view);
|
|
493
374
|
}
|
|
494
|
-
}, {
|
|
495
|
-
decorations: (value) => value.decorations
|
|
496
375
|
}),
|
|
497
|
-
|
|
376
|
+
// Reconcile local updates.
|
|
377
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
378
|
+
if (!changes.empty) {
|
|
379
|
+
semaphore.reconcile(view);
|
|
380
|
+
}
|
|
381
|
+
}),
|
|
382
|
+
state
|
|
498
383
|
];
|
|
499
384
|
};
|
|
500
385
|
|
|
501
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
502
|
-
import {
|
|
503
|
-
import {
|
|
504
|
-
import
|
|
505
|
-
import
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
515
|
-
try {
|
|
516
|
-
return fn(...args);
|
|
517
|
-
} catch (error) {
|
|
518
|
-
log.catch(error, void 0, {
|
|
519
|
-
F: __dxlog_file2,
|
|
520
|
-
L: 16,
|
|
521
|
-
S: void 0,
|
|
522
|
-
C: (f, a) => f(...a)
|
|
523
|
-
});
|
|
386
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
387
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
388
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
389
|
+
import { Event } from "@dxos/async";
|
|
390
|
+
import { Context } from "@dxos/context";
|
|
391
|
+
var dummyProvider = {
|
|
392
|
+
remoteStateChange: new Event(),
|
|
393
|
+
open: () => {
|
|
394
|
+
},
|
|
395
|
+
close: () => {
|
|
396
|
+
},
|
|
397
|
+
getRemoteStates: () => [],
|
|
398
|
+
update: () => {
|
|
524
399
|
}
|
|
525
400
|
};
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
401
|
+
var AwarenessProvider = Facet2.define({
|
|
402
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
403
|
+
});
|
|
404
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
405
|
+
var awareness = (provider = dummyProvider) => {
|
|
406
|
+
return [
|
|
407
|
+
AwarenessProvider.of(provider),
|
|
408
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
409
|
+
decorations: (value) => value.decorations
|
|
410
|
+
}),
|
|
411
|
+
styles
|
|
412
|
+
];
|
|
413
|
+
};
|
|
414
|
+
var RemoteSelectionsDecorator = class {
|
|
415
|
+
constructor(view) {
|
|
416
|
+
this.decorations = RangeSet.of([]);
|
|
417
|
+
this._ctx = new Context();
|
|
418
|
+
this._lastAnchor = void 0;
|
|
419
|
+
this._lastHead = void 0;
|
|
420
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
421
|
+
this._provider = view.state.facet(AwarenessProvider);
|
|
422
|
+
this._provider.open();
|
|
423
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
424
|
+
view.dispatch({
|
|
425
|
+
annotations: [
|
|
426
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
427
|
+
]
|
|
428
|
+
});
|
|
553
429
|
});
|
|
554
430
|
}
|
|
555
|
-
|
|
556
|
-
|
|
431
|
+
destroy() {
|
|
432
|
+
void this._ctx.dispose();
|
|
433
|
+
this._provider.close();
|
|
557
434
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
435
|
+
update(update2) {
|
|
436
|
+
this._updateLocalSelection(update2);
|
|
437
|
+
this._updateRemoteSelections(update2);
|
|
438
|
+
}
|
|
439
|
+
_updateLocalSelection(update2) {
|
|
440
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
441
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
442
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
443
|
+
return;
|
|
563
444
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
445
|
+
this._lastAnchor = anchor;
|
|
446
|
+
this._lastHead = head;
|
|
447
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
448
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
449
|
+
head: this._cursorConverter.toCursor(head)
|
|
450
|
+
} : void 0);
|
|
451
|
+
}
|
|
452
|
+
_updateRemoteSelections(update2) {
|
|
453
|
+
const decorations = [];
|
|
454
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
455
|
+
for (const state of awarenessStates) {
|
|
456
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
457
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
458
|
+
if (anchor == null || head == null) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
462
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
463
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
464
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
465
|
+
const color = state.info.color ?? "#30bced";
|
|
466
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
467
|
+
if (startLine.number === endLine.number) {
|
|
468
|
+
decorations.push({
|
|
469
|
+
from: start,
|
|
470
|
+
to: end,
|
|
471
|
+
value: Decoration.mark({
|
|
472
|
+
attributes: {
|
|
473
|
+
style: `background-color: ${lightColor}`
|
|
474
|
+
},
|
|
475
|
+
class: "cm-collab-selection"
|
|
476
|
+
})
|
|
477
|
+
});
|
|
478
|
+
} else {
|
|
479
|
+
decorations.push({
|
|
480
|
+
from: start,
|
|
481
|
+
to: startLine.from + startLine.length,
|
|
482
|
+
value: Decoration.mark({
|
|
483
|
+
attributes: {
|
|
484
|
+
style: `background-color: ${color}`
|
|
485
|
+
},
|
|
486
|
+
class: "cm-collab-selection"
|
|
487
|
+
})
|
|
488
|
+
});
|
|
489
|
+
decorations.push({
|
|
490
|
+
from: endLine.from,
|
|
491
|
+
to: end,
|
|
492
|
+
value: Decoration.mark({
|
|
493
|
+
attributes: {
|
|
494
|
+
style: `background-color: ${color}`
|
|
495
|
+
},
|
|
496
|
+
class: "cm-collab-selection"
|
|
497
|
+
})
|
|
498
|
+
});
|
|
499
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
500
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
501
|
+
decorations.push({
|
|
502
|
+
from: linePos,
|
|
503
|
+
to: linePos,
|
|
504
|
+
value: Decoration.line({
|
|
505
|
+
attributes: {
|
|
506
|
+
style: `background-color: ${color}`,
|
|
507
|
+
class: "cm-collab-selectionLine"
|
|
508
|
+
}
|
|
509
|
+
})
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
decorations.push({
|
|
514
|
+
from: head,
|
|
515
|
+
to: head,
|
|
516
|
+
value: Decoration.widget({
|
|
517
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
518
|
+
block: false,
|
|
519
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
520
|
+
})
|
|
579
521
|
});
|
|
580
522
|
}
|
|
523
|
+
this.decorations = Decoration.set(decorations, true);
|
|
581
524
|
}
|
|
582
|
-
view.dispatch({
|
|
583
|
-
selection,
|
|
584
|
-
annotations: reconcileAnnotationType.of({})
|
|
585
|
-
});
|
|
586
525
|
};
|
|
587
|
-
var
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
526
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
527
|
+
constructor(_name, _color) {
|
|
528
|
+
super();
|
|
529
|
+
this._name = _name;
|
|
530
|
+
this._color = _color;
|
|
531
|
+
}
|
|
532
|
+
toDOM() {
|
|
533
|
+
const span = document.createElement("span");
|
|
534
|
+
span.className = "cm-collab-selectionCaret";
|
|
535
|
+
span.style.backgroundColor = this._color;
|
|
536
|
+
span.style.borderColor = this._color;
|
|
537
|
+
const dot = document.createElement("div");
|
|
538
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
539
|
+
const info = document.createElement("div");
|
|
540
|
+
info.className = "cm-collab-selectionInfo";
|
|
541
|
+
info.innerText = this._name;
|
|
542
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
543
|
+
span.appendChild(dot);
|
|
544
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
545
|
+
span.appendChild(info);
|
|
546
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
547
|
+
return span;
|
|
548
|
+
}
|
|
549
|
+
updateDOM() {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
eq(widget) {
|
|
553
|
+
return widget._color === this._color;
|
|
554
|
+
}
|
|
555
|
+
get estimatedHeight() {
|
|
556
|
+
return -1;
|
|
557
|
+
}
|
|
558
|
+
ignoreEvent() {
|
|
559
|
+
return true;
|
|
598
560
|
}
|
|
599
561
|
};
|
|
600
|
-
var
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
562
|
+
var styles = EditorView2.baseTheme({
|
|
563
|
+
".cm-collab-selection": {},
|
|
564
|
+
".cm-collab-selectionLine": {
|
|
565
|
+
padding: 0,
|
|
566
|
+
margin: "0px 2px 0px 4px"
|
|
567
|
+
},
|
|
568
|
+
".cm-collab-selectionCaret": {
|
|
569
|
+
position: "relative",
|
|
570
|
+
borderLeft: "1px solid black",
|
|
571
|
+
borderRight: "1px solid black",
|
|
572
|
+
marginLeft: "-1px",
|
|
573
|
+
marginRight: "-1px",
|
|
574
|
+
boxSizing: "border-box",
|
|
575
|
+
display: "inline",
|
|
576
|
+
cursor: "pointer"
|
|
577
|
+
},
|
|
578
|
+
".cm-collab-selectionCaretDot": {
|
|
579
|
+
borderRadius: "50%",
|
|
580
|
+
position: "absolute",
|
|
581
|
+
width: ".5em",
|
|
582
|
+
height: ".5em",
|
|
583
|
+
top: "-.25em",
|
|
584
|
+
left: "-.25em",
|
|
585
|
+
backgroundColor: "inherit",
|
|
586
|
+
transition: "transform .3s ease-in-out",
|
|
587
|
+
boxSizing: "border-box"
|
|
588
|
+
},
|
|
589
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
590
|
+
transform: "scale(0)",
|
|
591
|
+
transformOrigin: "center"
|
|
592
|
+
},
|
|
593
|
+
".cm-collab-selectionInfo": {
|
|
594
|
+
position: "absolute",
|
|
595
|
+
transform: "translate(-50%, 0)",
|
|
596
|
+
top: "-20px",
|
|
597
|
+
left: 0,
|
|
598
|
+
fontSize: ".75em",
|
|
599
|
+
fontFamily: "sans-serif",
|
|
600
|
+
fontStyle: "normal",
|
|
601
|
+
fontWeight: "normal",
|
|
602
|
+
lineHeight: "normal",
|
|
603
|
+
userSelect: "none",
|
|
604
|
+
color: "white",
|
|
605
|
+
padding: "2px",
|
|
606
|
+
zIndex: 101,
|
|
607
|
+
transition: "opacity .3s ease-in-out",
|
|
608
|
+
backgroundColor: "inherit",
|
|
609
|
+
borderRadius: "2px",
|
|
610
|
+
// These should be separate.
|
|
611
|
+
opacity: 0,
|
|
612
|
+
transitionDelay: "0s",
|
|
613
|
+
whiteSpace: "nowrap"
|
|
614
|
+
},
|
|
615
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
616
|
+
opacity: 1,
|
|
617
|
+
transitionDelay: "0s"
|
|
604
618
|
}
|
|
605
|
-
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
622
|
+
import { closeBrackets } from "@codemirror/autocomplete";
|
|
623
|
+
import { history } from "@codemirror/commands";
|
|
624
|
+
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
625
|
+
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
626
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
628
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
629
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
630
|
+
bracketMatching(),
|
|
631
|
+
closeBrackets(),
|
|
632
|
+
drawSelection(),
|
|
633
|
+
highlightActiveLine(),
|
|
634
|
+
history(),
|
|
635
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
636
|
+
// https://github.com/codemirror/theme-one-dark
|
|
637
|
+
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
638
|
+
];
|
|
639
|
+
|
|
640
|
+
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
641
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
642
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
643
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
644
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
645
|
+
var defaultOptions = {
|
|
646
|
+
effect: 2,
|
|
647
|
+
maxParticles: 200,
|
|
648
|
+
particleGravity: 0.08,
|
|
649
|
+
particleAlphaFadeout: 0.996,
|
|
650
|
+
particleSize: {
|
|
651
|
+
min: 2,
|
|
652
|
+
max: 8
|
|
653
|
+
},
|
|
654
|
+
particleNumRange: {
|
|
655
|
+
min: 5,
|
|
656
|
+
max: 10
|
|
657
|
+
},
|
|
658
|
+
particleVelocityRange: {
|
|
659
|
+
x: [
|
|
660
|
+
-1,
|
|
661
|
+
1
|
|
662
|
+
],
|
|
663
|
+
y: [
|
|
664
|
+
-3.5,
|
|
665
|
+
-1.5
|
|
666
|
+
]
|
|
667
|
+
},
|
|
668
|
+
particleShrinkRate: 0.95,
|
|
669
|
+
shakeIntensity: 5
|
|
670
|
+
};
|
|
671
|
+
var blast = (options = defaultOptions) => {
|
|
672
|
+
let blaster;
|
|
673
|
+
let last = 0;
|
|
674
|
+
const getPoint = (view, pos) => {
|
|
675
|
+
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
676
|
+
const element = document.elementFromPoint(x, y);
|
|
677
|
+
const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
|
|
678
|
+
const point = {
|
|
679
|
+
x: x - left,
|
|
680
|
+
y: y - top
|
|
681
|
+
};
|
|
682
|
+
return {
|
|
683
|
+
element,
|
|
684
|
+
point
|
|
685
|
+
};
|
|
686
|
+
};
|
|
606
687
|
return [
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
688
|
+
// Cursor moved.
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
690
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
691
|
+
if (blaster) {
|
|
692
|
+
blaster.destroy();
|
|
693
|
+
}
|
|
694
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
695
|
+
particleGravity: 0.2,
|
|
696
|
+
particleShrinkRate: 0.995,
|
|
697
|
+
color: () => [
|
|
698
|
+
100 + Math.random() * 100,
|
|
699
|
+
0,
|
|
700
|
+
0
|
|
701
|
+
]
|
|
702
|
+
}, options, defaultOptions));
|
|
703
|
+
blaster.initialize();
|
|
704
|
+
blaster.start();
|
|
705
|
+
} else {
|
|
706
|
+
blaster.resize();
|
|
707
|
+
}
|
|
708
|
+
const current = update2.state.selection.main.head;
|
|
709
|
+
if (current !== last) {
|
|
710
|
+
last = current;
|
|
711
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
712
|
+
if (element && point) {
|
|
713
|
+
blaster.spawn({
|
|
714
|
+
element,
|
|
715
|
+
point
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}),
|
|
720
|
+
keymap2.of([
|
|
721
|
+
{
|
|
722
|
+
any: (_, event) => {
|
|
723
|
+
if (blaster) {
|
|
724
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
725
|
+
blaster.shake({
|
|
726
|
+
time: 0.8
|
|
727
|
+
});
|
|
728
|
+
return true;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
])
|
|
612
735
|
];
|
|
613
736
|
};
|
|
614
|
-
var
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
737
|
+
var Blaster = class {
|
|
738
|
+
constructor(_node, _options) {
|
|
739
|
+
this._node = _node;
|
|
740
|
+
this._options = _options;
|
|
741
|
+
this._running = false;
|
|
742
|
+
this._shakeTime = 0;
|
|
743
|
+
this._shakeTimeMax = 0;
|
|
744
|
+
this._particles = [];
|
|
745
|
+
this._particlePointer = 0;
|
|
746
|
+
this._lastPoint = {
|
|
747
|
+
x: 0,
|
|
748
|
+
y: 0
|
|
749
|
+
};
|
|
750
|
+
this.shake = throttle(({ time }) => {
|
|
751
|
+
this._shakeTime = this._shakeTimeMax || time;
|
|
752
|
+
this._shakeTimeMax = time;
|
|
753
|
+
}, 100);
|
|
754
|
+
this.spawn = throttle(({ element, point }) => {
|
|
755
|
+
const color = getRGBComponents(element, this._options.color);
|
|
756
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
757
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
758
|
+
this._lastPoint = point;
|
|
759
|
+
for (let i = numParticles; i--; i > 0) {
|
|
760
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
761
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
762
|
+
}
|
|
763
|
+
}, 100);
|
|
764
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
618
765
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
766
|
+
get node() {
|
|
767
|
+
return this._node;
|
|
768
|
+
}
|
|
769
|
+
initialize() {
|
|
770
|
+
invariant2(!this._canvas && !this._ctx, void 0, {
|
|
771
|
+
F: __dxlog_file2,
|
|
772
|
+
L: 138,
|
|
773
|
+
S: this,
|
|
774
|
+
A: [
|
|
775
|
+
"!this._canvas && !this._ctx",
|
|
776
|
+
""
|
|
777
|
+
]
|
|
778
|
+
});
|
|
779
|
+
this._canvas = document.createElement("canvas");
|
|
780
|
+
this._canvas.id = "code-blast-canvas";
|
|
781
|
+
this._canvas.style.position = "absolute";
|
|
782
|
+
this._canvas.style.zIndex = "0";
|
|
783
|
+
this._canvas.style.pointerEvents = "none";
|
|
784
|
+
this._ctx = this._canvas.getContext("2d");
|
|
785
|
+
const parent = this._node.parentElement?.parentElement;
|
|
786
|
+
parent?.appendChild(this._canvas);
|
|
787
|
+
this.resize();
|
|
788
|
+
}
|
|
789
|
+
destroy() {
|
|
790
|
+
this.stop();
|
|
791
|
+
if (this._canvas) {
|
|
792
|
+
this._canvas.remove();
|
|
793
|
+
this._canvas = void 0;
|
|
794
|
+
this._ctx = void 0;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
resize() {
|
|
798
|
+
if (this._node.parentElement && this._canvas) {
|
|
799
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
800
|
+
this._canvas.style.top = `${y}px`;
|
|
801
|
+
this._canvas.style.left = `${x}px`;
|
|
802
|
+
this._canvas.width = width;
|
|
803
|
+
this._canvas.height = height;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
start() {
|
|
807
|
+
invariant2(this._canvas && this._ctx, void 0, {
|
|
808
|
+
F: __dxlog_file2,
|
|
809
|
+
L: 177,
|
|
810
|
+
S: this,
|
|
811
|
+
A: [
|
|
812
|
+
"this._canvas && this._ctx",
|
|
813
|
+
""
|
|
814
|
+
]
|
|
815
|
+
});
|
|
816
|
+
this._running = true;
|
|
817
|
+
this.loop();
|
|
818
|
+
}
|
|
819
|
+
stop() {
|
|
820
|
+
this._running = false;
|
|
821
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
822
|
+
}
|
|
823
|
+
loop() {
|
|
824
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
828
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
829
|
+
this._lastTime ??= now;
|
|
830
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
831
|
+
this._lastTime = now;
|
|
832
|
+
if (this._shakeTime > 0) {
|
|
833
|
+
this._shakeTime -= dt;
|
|
834
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
835
|
+
const shakeX = random(-magnitude, magnitude);
|
|
836
|
+
const shakeY = random(-magnitude, magnitude);
|
|
837
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
838
|
+
}
|
|
839
|
+
this.drawParticles();
|
|
840
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
841
|
+
}
|
|
842
|
+
drawParticles() {
|
|
843
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
844
|
+
const particle = this._particles[i];
|
|
845
|
+
if (!particle) {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
this._effect.update(this._ctx, particle);
|
|
623
852
|
}
|
|
624
|
-
|
|
853
|
+
}
|
|
625
854
|
};
|
|
626
|
-
var
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
return [];
|
|
855
|
+
var Effect = class {
|
|
856
|
+
constructor(_options) {
|
|
857
|
+
this._options = _options;
|
|
630
858
|
}
|
|
631
|
-
const length = patch.length || 1;
|
|
632
|
-
return [
|
|
633
|
-
{
|
|
634
|
-
from: index,
|
|
635
|
-
to: index + length
|
|
636
|
-
}
|
|
637
|
-
];
|
|
638
859
|
};
|
|
639
|
-
var
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
860
|
+
var Effect1 = class extends Effect {
|
|
861
|
+
create(x, y, color) {
|
|
862
|
+
return {
|
|
863
|
+
x,
|
|
864
|
+
y: y + 10,
|
|
865
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
866
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
867
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
868
|
+
color,
|
|
869
|
+
alpha: 1
|
|
870
|
+
};
|
|
646
871
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
872
|
+
update(ctx, particle) {
|
|
873
|
+
particle.vy += this._options.particleGravity;
|
|
874
|
+
particle.x += particle.vx;
|
|
875
|
+
particle.y += particle.vy;
|
|
876
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
877
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
878
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
650
879
|
}
|
|
651
|
-
return [
|
|
652
|
-
{
|
|
653
|
-
from: 0,
|
|
654
|
-
to: length,
|
|
655
|
-
insert: patch.value
|
|
656
|
-
}
|
|
657
|
-
];
|
|
658
880
|
};
|
|
659
|
-
var
|
|
660
|
-
|
|
661
|
-
return
|
|
881
|
+
var Effect2 = class extends Effect {
|
|
882
|
+
create(x, y, color) {
|
|
883
|
+
return {
|
|
884
|
+
x,
|
|
885
|
+
y: y + 10,
|
|
886
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
887
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
888
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
889
|
+
color,
|
|
890
|
+
alpha: 1,
|
|
891
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
892
|
+
drag: 0.92,
|
|
893
|
+
wander: 0.15
|
|
894
|
+
};
|
|
662
895
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
896
|
+
update(ctx, particle) {
|
|
897
|
+
particle.vy += this._options.particleGravity;
|
|
898
|
+
particle.x += particle.vx;
|
|
899
|
+
particle.y += particle.vy;
|
|
900
|
+
particle.vx *= particle.drag;
|
|
901
|
+
particle.vy *= particle.drag;
|
|
902
|
+
particle.theta += random(-0.5, 0.5);
|
|
903
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
904
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
905
|
+
particle.size *= this._options.particleShrinkRate;
|
|
906
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
907
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
908
|
+
ctx.beginPath();
|
|
909
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
910
|
+
ctx.fill();
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
function throttle(callback, limit) {
|
|
914
|
+
let wait = false;
|
|
915
|
+
return function(...args) {
|
|
916
|
+
if (!wait) {
|
|
917
|
+
callback.apply(this, args);
|
|
918
|
+
wait = true;
|
|
919
|
+
setTimeout(() => {
|
|
920
|
+
wait = false;
|
|
921
|
+
}, limit);
|
|
666
922
|
}
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
var getRGBComponents = (node, color) => {
|
|
926
|
+
if (typeof color === "function") {
|
|
927
|
+
return color();
|
|
667
928
|
}
|
|
668
|
-
const
|
|
669
|
-
if (
|
|
670
|
-
|
|
929
|
+
const bgColor = getComputedStyle(node).color;
|
|
930
|
+
if (bgColor) {
|
|
931
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
932
|
+
if (x) {
|
|
933
|
+
return x;
|
|
934
|
+
}
|
|
671
935
|
}
|
|
672
|
-
return
|
|
936
|
+
return [
|
|
937
|
+
50,
|
|
938
|
+
50,
|
|
939
|
+
50
|
|
940
|
+
];
|
|
673
941
|
};
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
this._inReconcile = false;
|
|
679
|
-
this._queue = [];
|
|
680
|
-
this.reconcile = (handle, view) => {
|
|
681
|
-
if (this._inReconcile) {
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
this._inReconcile = true;
|
|
685
|
-
const path = getPath(view.state, this._field);
|
|
686
|
-
const oldHeads = getLastHeads(view.state, this._field);
|
|
687
|
-
let selection = view.state.selection;
|
|
688
|
-
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
689
|
-
const toInvert = transactions.slice().reverse();
|
|
690
|
-
for (const tx of toInvert) {
|
|
691
|
-
const inverted = tx.changes.invert(tx.startState.doc);
|
|
692
|
-
selection = selection.map(inverted);
|
|
693
|
-
view.dispatch({
|
|
694
|
-
changes: inverted,
|
|
695
|
-
annotations: reconcileAnnotationType.of(true)
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
699
|
-
if (newHeads === null || newHeads === void 0) {
|
|
700
|
-
newHeads = automerge.getHeads(handle.docSync());
|
|
701
|
-
}
|
|
702
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
703
|
-
updateCodeMirror(view, selection, path, diff);
|
|
704
|
-
view.dispatch({
|
|
705
|
-
effects: updateHeads(newHeads),
|
|
706
|
-
annotations: reconcileAnnotationType.of({})
|
|
707
|
-
});
|
|
708
|
-
this._inReconcile = false;
|
|
709
|
-
};
|
|
710
|
-
if (field !== void 0) {
|
|
711
|
-
this._field = field;
|
|
712
|
-
}
|
|
942
|
+
var random = (min, max) => {
|
|
943
|
+
if (!max) {
|
|
944
|
+
max = min;
|
|
945
|
+
min = 0;
|
|
713
946
|
}
|
|
947
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
714
948
|
};
|
|
715
949
|
|
|
716
|
-
// packages/ui/react-ui-editor/src/
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
newHeads
|
|
720
|
-
});
|
|
721
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
722
|
-
var getPath = (state, field) => state.field(field).path;
|
|
723
|
-
var semaphoreFacet = Facet.define({
|
|
724
|
-
combine: (values) => values.at(-1)
|
|
725
|
-
});
|
|
726
|
-
var automergePlugin = (handle, path) => {
|
|
727
|
-
const stateField = StateField.define({
|
|
728
|
-
create: () => ({
|
|
729
|
-
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
730
|
-
unreconciledTransactions: [],
|
|
731
|
-
path: path.slice()
|
|
732
|
-
}),
|
|
733
|
-
update: (value, tr) => {
|
|
734
|
-
const result = {
|
|
735
|
-
lastHeads: value.lastHeads,
|
|
736
|
-
unreconciledTransactions: value.unreconciledTransactions.slice(),
|
|
737
|
-
path: path.slice()
|
|
738
|
-
};
|
|
739
|
-
let clearUnreconciled = false;
|
|
740
|
-
for (const effect of tr.effects) {
|
|
741
|
-
if (effect.is(effectType)) {
|
|
742
|
-
result.lastHeads = effect.value.newHeads;
|
|
743
|
-
clearUnreconciled = true;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
if (clearUnreconciled) {
|
|
747
|
-
result.unreconciledTransactions = [];
|
|
748
|
-
} else {
|
|
749
|
-
if (!isReconcileTx(tr)) {
|
|
750
|
-
result.unreconciledTransactions.push(tr);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
return result;
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
const semaphore = new PatchSemaphore(stateField);
|
|
757
|
-
const viewPlugin = ViewPlugin2.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
758
|
-
constructor(_view) {
|
|
759
|
-
this._view = _view;
|
|
760
|
-
this._handleChange = () => {
|
|
761
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
762
|
-
};
|
|
763
|
-
handle.addListener("change", this._handleChange);
|
|
764
|
-
}
|
|
765
|
-
update(update4) {
|
|
766
|
-
if (update4.transactions.length > 0 && update4.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
767
|
-
queueMicrotask(() => {
|
|
768
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
destroy() {
|
|
773
|
-
handle.addListener("change", this._handleChange);
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
return {
|
|
777
|
-
extension: [
|
|
778
|
-
stateField,
|
|
779
|
-
semaphoreFacet.of(semaphore),
|
|
780
|
-
viewPlugin
|
|
781
|
-
]
|
|
782
|
-
};
|
|
783
|
-
};
|
|
784
|
-
var reconcileAnnotationType = Annotation.define();
|
|
785
|
-
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
950
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
951
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
|
|
952
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
786
953
|
|
|
787
|
-
// packages/ui/react-ui-editor/src/
|
|
954
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
788
955
|
import * as random2 from "lib0/random";
|
|
789
956
|
var cursorColors = [
|
|
790
957
|
{
|
|
@@ -799,305 +966,266 @@ var cursorColors = [
|
|
|
799
966
|
color: "#ffbc42",
|
|
800
967
|
light: "#ffbc4233"
|
|
801
968
|
},
|
|
802
|
-
{
|
|
803
|
-
color: "#ecd444",
|
|
804
|
-
light: "#ecd44433"
|
|
969
|
+
{
|
|
970
|
+
color: "#ecd444",
|
|
971
|
+
light: "#ecd44433"
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
color: "#ee6352",
|
|
975
|
+
light: "#ee635233"
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
color: "#9ac2c9",
|
|
979
|
+
light: "#9ac2c933"
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
color: "#8acb88",
|
|
983
|
+
light: "#8acb8833"
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
color: "#1be7ff",
|
|
987
|
+
light: "#1be7ff33"
|
|
988
|
+
}
|
|
989
|
+
];
|
|
990
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
991
|
+
|
|
992
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
993
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
994
|
+
var headings = {
|
|
995
|
+
1: [
|
|
996
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
997
|
+
"-ml-[10px]"
|
|
998
|
+
],
|
|
999
|
+
2: [
|
|
1000
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1001
|
+
"-ml-[8px]"
|
|
1002
|
+
],
|
|
1003
|
+
3: [
|
|
1004
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1005
|
+
"-ml-[7px]"
|
|
1006
|
+
],
|
|
1007
|
+
4: [
|
|
1008
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1009
|
+
"-ml-[6px]"
|
|
1010
|
+
],
|
|
1011
|
+
5: [
|
|
1012
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1013
|
+
"-ml-[5px]"
|
|
1014
|
+
],
|
|
1015
|
+
6: [
|
|
1016
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1017
|
+
"-ml-[4px]"
|
|
1018
|
+
]
|
|
1019
|
+
};
|
|
1020
|
+
var heading = (level, readonly) => {
|
|
1021
|
+
const [style, offset] = headings[level];
|
|
1022
|
+
return mx(style, readonly && offset);
|
|
1023
|
+
};
|
|
1024
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1025
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1026
|
+
var bold = "font-bold";
|
|
1027
|
+
var italic = "italic";
|
|
1028
|
+
var strikethrough = "line-through";
|
|
1029
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1030
|
+
var codeMark = "font-mono text-primary-500";
|
|
1031
|
+
var inlineUrl = mx(code, "px-1");
|
|
1032
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1033
|
+
|
|
1034
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1035
|
+
import get2 from "lodash.get";
|
|
1036
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1037
|
+
var tokens = tailwindConfig({}).theme;
|
|
1038
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1039
|
+
|
|
1040
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1041
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1042
|
+
var styles2 = EditorView5.baseTheme({
|
|
1043
|
+
"& .cm-codeblock": {
|
|
1044
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1045
|
+
},
|
|
1046
|
+
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1047
|
+
background: getToken("extend.colors.neutral.50")
|
|
805
1048
|
},
|
|
806
|
-
{
|
|
807
|
-
|
|
808
|
-
light: "#ee635233"
|
|
1049
|
+
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1050
|
+
background: getToken("extend.colors.neutral.850")
|
|
809
1051
|
},
|
|
810
|
-
{
|
|
811
|
-
|
|
812
|
-
|
|
1052
|
+
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1053
|
+
display: "block",
|
|
1054
|
+
paddingInline: "4px !important"
|
|
813
1055
|
},
|
|
814
|
-
{
|
|
815
|
-
|
|
816
|
-
|
|
1056
|
+
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1057
|
+
paddingTop: "4px !important",
|
|
1058
|
+
borderTopLeftRadius: "4px",
|
|
1059
|
+
borderTopRightRadius: "4px"
|
|
817
1060
|
},
|
|
818
|
-
{
|
|
819
|
-
|
|
820
|
-
|
|
1061
|
+
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1062
|
+
paddingBottom: "4px !important",
|
|
1063
|
+
borderBottomLeftRadius: "4px",
|
|
1064
|
+
borderBottomRightRadius: "4px"
|
|
821
1065
|
}
|
|
822
|
-
|
|
823
|
-
var
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
var
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
} else if (typeof process !== "undefined") {
|
|
846
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
1066
|
+
});
|
|
1067
|
+
var getLineRange = (lines, from, to) => {
|
|
1068
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1069
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1070
|
+
return [
|
|
1071
|
+
start,
|
|
1072
|
+
end
|
|
1073
|
+
];
|
|
1074
|
+
};
|
|
1075
|
+
var code2 = () => {
|
|
1076
|
+
const buildDecorations5 = (view) => {
|
|
1077
|
+
const decorations = [];
|
|
1078
|
+
const text = view.state.doc.sliceString(0);
|
|
1079
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1080
|
+
const blocks = view.viewportLineBlocks;
|
|
1081
|
+
for (const match of matches) {
|
|
1082
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1083
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1084
|
+
const block = blocks[i];
|
|
1085
|
+
decorations.push(Decoration2.line({
|
|
1086
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1087
|
+
}).range(block.from));
|
|
1088
|
+
}
|
|
847
1089
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
removed,
|
|
866
|
-
origin
|
|
1090
|
+
return Decoration2.set(decorations);
|
|
1091
|
+
};
|
|
1092
|
+
return [
|
|
1093
|
+
ViewPlugin3.fromClass(class {
|
|
1094
|
+
constructor(view) {
|
|
1095
|
+
this.hasFocus = false;
|
|
1096
|
+
this.decorations = buildDecorations5(view);
|
|
1097
|
+
}
|
|
1098
|
+
update(update2) {
|
|
1099
|
+
if (
|
|
1100
|
+
// TODO(burdon): Generalize for other extensions.
|
|
1101
|
+
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1102
|
+
) {
|
|
1103
|
+
this.hasFocus = update2.view.hasFocus;
|
|
1104
|
+
this.decorations = buildDecorations5(update2.view);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
867
1107
|
}, {
|
|
1108
|
+
decorations: (value) => value.decorations
|
|
1109
|
+
}),
|
|
1110
|
+
styles2
|
|
1111
|
+
];
|
|
1112
|
+
};
|
|
1113
|
+
|
|
1114
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1115
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1116
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1117
|
+
import sortBy from "lodash.sortby";
|
|
1118
|
+
import { useEffect } from "react";
|
|
1119
|
+
import { debounce } from "@dxos/async";
|
|
1120
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1121
|
+
import { nonNullable } from "@dxos/util";
|
|
1122
|
+
|
|
1123
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1124
|
+
import { log } from "@dxos/log";
|
|
1125
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1126
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1127
|
+
try {
|
|
1128
|
+
return fn(...args);
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
log.catch(err, void 0, {
|
|
868
1131
|
F: __dxlog_file3,
|
|
869
|
-
L:
|
|
870
|
-
S:
|
|
871
|
-
C: (f, a) => f(...a)
|
|
872
|
-
});
|
|
873
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
874
|
-
const encoderAwareness = encoding.createEncoder();
|
|
875
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
876
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
877
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
878
|
-
}
|
|
879
|
-
_handleSpaceMessage({ payload }) {
|
|
880
|
-
log2("space message", payload, {
|
|
881
|
-
F: __dxlog_file3,
|
|
882
|
-
L: 79,
|
|
883
|
-
S: this,
|
|
1132
|
+
L: 18,
|
|
1133
|
+
S: void 0,
|
|
884
1134
|
C: (f, a) => f(...a)
|
|
885
1135
|
});
|
|
886
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
887
|
-
const encoder = this._readMessage(data);
|
|
888
|
-
if (encoder) {
|
|
889
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
_readMessage(message) {
|
|
893
|
-
const decoder = decoding.createDecoder(message);
|
|
894
|
-
const encoder = encoding.createEncoder();
|
|
895
|
-
const messageType = decoding.readVarUint(decoder);
|
|
896
|
-
let sendReply = false;
|
|
897
|
-
switch (messageType) {
|
|
898
|
-
case messageAwareness: {
|
|
899
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
900
|
-
break;
|
|
901
|
-
}
|
|
902
|
-
case messageQueryAwareness: {
|
|
903
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
904
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
905
|
-
sendReply = true;
|
|
906
|
-
break;
|
|
907
|
-
}
|
|
908
|
-
default: {
|
|
909
|
-
console.error("Invalid message:", messageType);
|
|
910
|
-
return encoder;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
if (!sendReply) {
|
|
914
|
-
return null;
|
|
915
|
-
}
|
|
916
|
-
return encoder;
|
|
917
|
-
}
|
|
918
|
-
_handleBeforeUnload() {
|
|
919
|
-
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
920
|
-
this._clientId
|
|
921
|
-
], "window unload");
|
|
922
1136
|
}
|
|
923
1137
|
};
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
var modelState = StateField2.define({
|
|
928
|
-
create: () => void 0,
|
|
929
|
-
update: (model) => model
|
|
930
|
-
});
|
|
931
|
-
var useTextModel = (props) => {
|
|
932
|
-
const { identity, space, text } = props;
|
|
933
|
-
const [model, setModel] = useState(() => createModel(props));
|
|
934
|
-
useEffect(() => setModel(createModel(props)), [
|
|
935
|
-
identity,
|
|
936
|
-
space,
|
|
937
|
-
text
|
|
938
|
-
]);
|
|
939
|
-
return model;
|
|
940
|
-
};
|
|
941
|
-
var createModel = (props) => {
|
|
942
|
-
const { text } = props;
|
|
943
|
-
if (isActualAutomergeObject(text)) {
|
|
944
|
-
return createAutomergeModel(props);
|
|
945
|
-
} else {
|
|
946
|
-
if (!text?.doc) {
|
|
1138
|
+
var logChanges = (trs) => {
|
|
1139
|
+
const changes = trs.flatMap((tr) => {
|
|
1140
|
+
if (tr.changes.empty) {
|
|
947
1141
|
return void 0;
|
|
948
1142
|
}
|
|
949
|
-
|
|
1143
|
+
const changes2 = [];
|
|
1144
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1145
|
+
fromA,
|
|
1146
|
+
toA,
|
|
1147
|
+
fromB,
|
|
1148
|
+
toB,
|
|
1149
|
+
inserted: inserted.toString()
|
|
1150
|
+
})));
|
|
1151
|
+
return changes2;
|
|
1152
|
+
}).filter(Boolean);
|
|
1153
|
+
if (changes.length) {
|
|
1154
|
+
console.log("changes", changes);
|
|
950
1155
|
}
|
|
951
1156
|
};
|
|
952
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
953
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
954
|
-
F: __dxlog_file4,
|
|
955
|
-
L: 97,
|
|
956
|
-
S: void 0,
|
|
957
|
-
A: [
|
|
958
|
-
"text?.doc && text?.content",
|
|
959
|
-
""
|
|
960
|
-
]
|
|
961
|
-
});
|
|
962
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
963
|
-
space,
|
|
964
|
-
doc: text.doc,
|
|
965
|
-
channel: `yjs.awareness.${text.id}`
|
|
966
|
-
}) : void 0;
|
|
967
|
-
const model = {
|
|
968
|
-
id: text.doc.guid,
|
|
969
|
-
content: text.content,
|
|
970
|
-
text: () => text.content.toString(),
|
|
971
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
972
|
-
getCursorFromRange: (range) => {
|
|
973
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
974
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
975
|
-
return [
|
|
976
|
-
arrayToString(from),
|
|
977
|
-
arrayToString(to)
|
|
978
|
-
].join(":");
|
|
979
|
-
},
|
|
980
|
-
getRangeFromCursor: (cursor) => {
|
|
981
|
-
invariant2(text.doc, void 0, {
|
|
982
|
-
F: __dxlog_file4,
|
|
983
|
-
L: 113,
|
|
984
|
-
S: void 0,
|
|
985
|
-
A: [
|
|
986
|
-
"text.doc",
|
|
987
|
-
""
|
|
988
|
-
]
|
|
989
|
-
});
|
|
990
|
-
const parts = cursor.split(":");
|
|
991
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
992
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
993
|
-
return from && to ? {
|
|
994
|
-
from: from.index,
|
|
995
|
-
to: to.index
|
|
996
|
-
} : void 0;
|
|
997
|
-
},
|
|
998
|
-
extension: [
|
|
999
|
-
yCollab(text.content, provider?.awareness),
|
|
1000
|
-
modelState.init(() => model)
|
|
1001
|
-
],
|
|
1002
|
-
awareness: provider?.awareness,
|
|
1003
|
-
peer: identity ? {
|
|
1004
|
-
id: identity.identityKey.toHex(),
|
|
1005
|
-
name: identity.profile?.displayName
|
|
1006
|
-
} : void 0
|
|
1007
|
-
};
|
|
1008
|
-
return model;
|
|
1009
|
-
};
|
|
1010
|
-
var createAutomergeModel = ({ identity, text }) => {
|
|
1011
|
-
const obj = text;
|
|
1012
|
-
const doc = getRawDoc(obj, [
|
|
1013
|
-
obj.field
|
|
1014
|
-
]);
|
|
1015
|
-
const model = {
|
|
1016
|
-
id: obj.id,
|
|
1017
|
-
content: doc,
|
|
1018
|
-
text: () => get2(doc.handle.docSync(), doc.path),
|
|
1019
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
1020
|
-
extension: [
|
|
1021
|
-
automergePlugin(doc.handle, doc.path),
|
|
1022
|
-
modelState.init(() => model)
|
|
1023
|
-
],
|
|
1024
|
-
peer: identity ? {
|
|
1025
|
-
id: identity.identityKey.toHex(),
|
|
1026
|
-
name: identity.profile?.displayName
|
|
1027
|
-
} : void 0
|
|
1028
|
-
};
|
|
1029
|
-
return model;
|
|
1030
|
-
};
|
|
1031
1157
|
|
|
1032
1158
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1033
|
-
var
|
|
1034
|
-
var
|
|
1035
|
-
"& .cm-bookmark": {
|
|
1036
|
-
cursor: "pointer",
|
|
1037
|
-
margin: "4px",
|
|
1038
|
-
padding: "4px",
|
|
1039
|
-
backgroundColor: "yellow"
|
|
1040
|
-
},
|
|
1041
|
-
"& .cm-bookmark-selected": {
|
|
1042
|
-
backgroundColor: "orange"
|
|
1043
|
-
},
|
|
1159
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1160
|
+
var styles3 = EditorView6.baseTheme({
|
|
1044
1161
|
"& .cm-comment": {
|
|
1045
|
-
backgroundColor:
|
|
1162
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1046
1163
|
},
|
|
1047
|
-
"& .cm-comment-
|
|
1048
|
-
backgroundColor:
|
|
1164
|
+
"& .cm-comment-current": {
|
|
1165
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1049
1166
|
}
|
|
1050
1167
|
});
|
|
1051
1168
|
var marks = {
|
|
1052
|
-
highlight:
|
|
1169
|
+
highlight: Decoration3.mark({
|
|
1053
1170
|
class: "cm-comment"
|
|
1054
1171
|
}),
|
|
1055
|
-
highlightActive:
|
|
1056
|
-
class: "cm-comment-
|
|
1172
|
+
highlightActive: Decoration3.mark({
|
|
1173
|
+
class: "cm-comment-current"
|
|
1057
1174
|
})
|
|
1058
1175
|
};
|
|
1059
|
-
var setFocus = (view,
|
|
1060
|
-
const
|
|
1061
|
-
if (!
|
|
1176
|
+
var setFocus = (view, id, center = true) => {
|
|
1177
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1178
|
+
if (!comment?.comment.cursor) {
|
|
1062
1179
|
return;
|
|
1063
1180
|
}
|
|
1064
|
-
view.
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1181
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1182
|
+
if (range) {
|
|
1183
|
+
view.dispatch({
|
|
1184
|
+
selection: {
|
|
1185
|
+
anchor: range.from
|
|
1186
|
+
},
|
|
1187
|
+
effects: [
|
|
1188
|
+
//
|
|
1189
|
+
EditorView6.scrollIntoView(range.from, center ? {
|
|
1190
|
+
y: "center"
|
|
1191
|
+
} : void 0),
|
|
1192
|
+
setSelection.of({
|
|
1193
|
+
current: id
|
|
1194
|
+
})
|
|
1195
|
+
]
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1073
1198
|
};
|
|
1074
|
-
var
|
|
1199
|
+
var setComments = StateEffect2.define();
|
|
1075
1200
|
var setSelection = StateEffect2.define();
|
|
1076
1201
|
var setCommentState = StateEffect2.define();
|
|
1077
|
-
var
|
|
1202
|
+
var commentsState = StateField2.define({
|
|
1078
1203
|
create: () => ({
|
|
1079
|
-
|
|
1204
|
+
comments: [],
|
|
1205
|
+
selection: {}
|
|
1080
1206
|
}),
|
|
1081
1207
|
update: (value, tr) => {
|
|
1082
1208
|
for (const effect of tr.effects) {
|
|
1083
1209
|
if (effect.is(setSelection)) {
|
|
1084
1210
|
return {
|
|
1085
1211
|
...value,
|
|
1086
|
-
|
|
1212
|
+
selection: effect.value
|
|
1087
1213
|
};
|
|
1088
1214
|
}
|
|
1089
|
-
if (effect.is(
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1215
|
+
if (effect.is(setComments)) {
|
|
1216
|
+
const comments2 = effect.value.map((comment) => {
|
|
1217
|
+
if (!comment.cursor) {
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1093
1221
|
return range && {
|
|
1094
|
-
|
|
1095
|
-
|
|
1222
|
+
comment,
|
|
1223
|
+
range
|
|
1096
1224
|
};
|
|
1097
1225
|
}).filter(nonNullable);
|
|
1098
1226
|
return {
|
|
1099
1227
|
...value,
|
|
1100
|
-
|
|
1228
|
+
comments: comments2
|
|
1101
1229
|
};
|
|
1102
1230
|
}
|
|
1103
1231
|
if (effect.is(setCommentState)) {
|
|
@@ -1107,142 +1235,133 @@ var commentsStateField = StateField3.define({
|
|
|
1107
1235
|
return value;
|
|
1108
1236
|
}
|
|
1109
1237
|
});
|
|
1110
|
-
var highlightDecorations =
|
|
1111
|
-
|
|
1238
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1239
|
+
commentsState
|
|
1112
1240
|
], (state) => {
|
|
1113
|
-
const {
|
|
1114
|
-
const decorations = sortBy(
|
|
1115
|
-
|
|
1241
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1242
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1243
|
+
const range = comment.range;
|
|
1244
|
+
if (!range || range.from === range.to) {
|
|
1245
|
+
console.warn("Invalid range:", range);
|
|
1116
1246
|
return void 0;
|
|
1117
1247
|
}
|
|
1118
|
-
|
|
1119
|
-
from: selection.from,
|
|
1120
|
-
to: selection.to
|
|
1121
|
-
};
|
|
1122
|
-
if (selection.id === active) {
|
|
1248
|
+
if (comment.comment.id === current) {
|
|
1123
1249
|
return marks.highlightActive.range(range.from, range.to);
|
|
1124
1250
|
} else {
|
|
1125
1251
|
return marks.highlight.range(range.from, range.to);
|
|
1126
1252
|
}
|
|
1127
|
-
}).filter(nonNullable)
|
|
1128
|
-
return
|
|
1253
|
+
}).filter(nonNullable);
|
|
1254
|
+
return Decoration3.set(decorations);
|
|
1129
1255
|
});
|
|
1130
|
-
var
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1148
|
-
}
|
|
1149
|
-
toDOM() {
|
|
1150
|
-
const span = document.createElement("span");
|
|
1151
|
-
span.className = "cm-bookmark";
|
|
1152
|
-
span.textContent = "\u203B";
|
|
1153
|
-
if (this._handleClick) {
|
|
1154
|
-
span.onclick = () => this._handleClick();
|
|
1256
|
+
var trackPastedComments = (onUpdate) => {
|
|
1257
|
+
let tracked = null;
|
|
1258
|
+
const handleTrack = (event, view) => {
|
|
1259
|
+
const comments2 = view.state.field(commentsState);
|
|
1260
|
+
const { main } = view.state.selection;
|
|
1261
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1262
|
+
if (!selectedRanges.length) {
|
|
1263
|
+
tracked = null;
|
|
1264
|
+
} else {
|
|
1265
|
+
tracked = {
|
|
1266
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1267
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1268
|
+
id: comment.id,
|
|
1269
|
+
from: range.from - main.from,
|
|
1270
|
+
to: range.to - main.from
|
|
1271
|
+
}))
|
|
1272
|
+
};
|
|
1155
1273
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1274
|
+
};
|
|
1275
|
+
return [
|
|
1276
|
+
EditorView6.domEventHandlers({
|
|
1277
|
+
cut: handleTrack,
|
|
1278
|
+
copy: handleTrack
|
|
1279
|
+
}),
|
|
1280
|
+
// Handle paste.
|
|
1281
|
+
EditorView6.updateListener.of(({ view, state, transactions }) => {
|
|
1282
|
+
if (tracked) {
|
|
1283
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1284
|
+
if (paste) {
|
|
1285
|
+
let found = -1;
|
|
1286
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1287
|
+
if (text.eq(tracked.text)) {
|
|
1288
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1289
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1290
|
+
}
|
|
1291
|
+
found = fromB;
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
if (found > -1) {
|
|
1295
|
+
for (const moved of tracked.comments) {
|
|
1296
|
+
const range = {
|
|
1297
|
+
from: found + moved.from,
|
|
1298
|
+
to: found + moved.to
|
|
1299
|
+
};
|
|
1300
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1301
|
+
onUpdate(moved.id, cursor);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
tracked = null;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
})
|
|
1308
|
+
];
|
|
1158
1309
|
};
|
|
1159
1310
|
var comments = (options = {}) => {
|
|
1311
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1160
1312
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1161
1313
|
const createCommentThread = (view) => {
|
|
1162
1314
|
invariant3(options.onCreate, void 0, {
|
|
1163
|
-
F:
|
|
1164
|
-
L:
|
|
1315
|
+
F: __dxlog_file4,
|
|
1316
|
+
L: 259,
|
|
1165
1317
|
S: void 0,
|
|
1166
1318
|
A: [
|
|
1167
1319
|
"options.onCreate",
|
|
1168
1320
|
""
|
|
1169
1321
|
]
|
|
1170
1322
|
});
|
|
1171
|
-
const {
|
|
1323
|
+
const { from, to } = view.state.selection.main;
|
|
1172
1324
|
if (from === to) {
|
|
1173
1325
|
return false;
|
|
1174
1326
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1327
|
+
if (to === view.state.doc.length) {
|
|
1328
|
+
view.dispatch({
|
|
1329
|
+
changes: {
|
|
1330
|
+
from: to,
|
|
1331
|
+
insert: "\n"
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1177
1336
|
from,
|
|
1178
1337
|
to
|
|
1179
1338
|
});
|
|
1180
|
-
if (
|
|
1181
|
-
const id =
|
|
1339
|
+
if (cursor) {
|
|
1340
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1182
1341
|
if (id) {
|
|
1183
1342
|
view.dispatch({
|
|
1184
1343
|
effects: setSelection.of({
|
|
1185
|
-
|
|
1344
|
+
current: id
|
|
1186
1345
|
}),
|
|
1187
1346
|
selection: {
|
|
1188
1347
|
anchor: from
|
|
1189
1348
|
}
|
|
1190
1349
|
});
|
|
1191
|
-
if (options.footnote) {
|
|
1192
|
-
const tag = `[^${id}]`;
|
|
1193
|
-
view.dispatch({
|
|
1194
|
-
changes: {
|
|
1195
|
-
from: head,
|
|
1196
|
-
insert: tag
|
|
1197
|
-
},
|
|
1198
|
-
selection: {
|
|
1199
|
-
anchor: head + tag.length
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
1350
|
return true;
|
|
1204
1351
|
}
|
|
1205
1352
|
}
|
|
1206
1353
|
return false;
|
|
1207
1354
|
};
|
|
1208
|
-
const bookmarksViewPlugin = ViewPlugin3.fromClass(class BookmarkViewPlugin {
|
|
1209
|
-
static {
|
|
1210
|
-
// Match markdown footnotes (option).
|
|
1211
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1212
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1213
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1214
|
-
decoration: (match, view, pos) => {
|
|
1215
|
-
const id = match[1];
|
|
1216
|
-
return Decoration2.replace({
|
|
1217
|
-
id,
|
|
1218
|
-
widget: new BookmarkWidget(pos, id)
|
|
1219
|
-
});
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
|
-
constructor(view) {
|
|
1224
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1225
|
-
}
|
|
1226
|
-
update(update4) {
|
|
1227
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
1228
|
-
}
|
|
1229
|
-
}, {
|
|
1230
|
-
decorations: (instance) => instance.bookmarks,
|
|
1231
|
-
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
1232
|
-
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
1233
|
-
})
|
|
1234
|
-
});
|
|
1235
1355
|
return [
|
|
1236
|
-
|
|
1237
|
-
commentsStateField,
|
|
1356
|
+
commentsState,
|
|
1238
1357
|
highlightDecorations,
|
|
1239
|
-
|
|
1358
|
+
styles3,
|
|
1240
1359
|
//
|
|
1241
1360
|
// Keymap.
|
|
1242
1361
|
//
|
|
1243
1362
|
options.onCreate ? keymap3.of([
|
|
1244
1363
|
{
|
|
1245
|
-
key:
|
|
1364
|
+
key: shortcut,
|
|
1246
1365
|
run: callbackWrapper(createCommentThread)
|
|
1247
1366
|
}
|
|
1248
1367
|
]) : [],
|
|
@@ -1259,7 +1378,7 @@ var comments = (options = {}) => {
|
|
|
1259
1378
|
above: true,
|
|
1260
1379
|
create: () => {
|
|
1261
1380
|
const el = document.createElement("div");
|
|
1262
|
-
options.onHover
|
|
1381
|
+
options.onHover(el, shortcut);
|
|
1263
1382
|
return {
|
|
1264
1383
|
dom: el,
|
|
1265
1384
|
offset: {
|
|
@@ -1272,178 +1391,206 @@ var comments = (options = {}) => {
|
|
|
1272
1391
|
}
|
|
1273
1392
|
return null;
|
|
1274
1393
|
}, {
|
|
1275
|
-
|
|
1394
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1395
|
+
// hideOnChange: true,
|
|
1276
1396
|
hoverTime: 1e3
|
|
1277
1397
|
}) : [],
|
|
1278
1398
|
//
|
|
1279
|
-
//
|
|
1280
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1399
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1281
1400
|
//
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
S: void 0,
|
|
1292
|
-
A: [
|
|
1293
|
-
"model",
|
|
1294
|
-
""
|
|
1295
|
-
]
|
|
1296
|
-
});
|
|
1297
|
-
ranges.forEach((range) => {
|
|
1298
|
-
if (from2 === to2) {
|
|
1299
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1300
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1301
|
-
log3.info("deleted comment", {
|
|
1302
|
-
thread: range.id
|
|
1303
|
-
}, {
|
|
1304
|
-
F: __dxlog_file5,
|
|
1305
|
-
L: 356,
|
|
1306
|
-
S: void 0,
|
|
1307
|
-
C: (f, a) => f(...a)
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1401
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1402
|
+
let mod = false;
|
|
1403
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1404
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1405
|
+
comments2.forEach(({ comment, range }) => {
|
|
1406
|
+
if (from2 === to2) {
|
|
1407
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1408
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1409
|
+
options.onDelete?.(comment.id);
|
|
1310
1410
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1411
|
+
}
|
|
1412
|
+
if (from <= range.to) {
|
|
1413
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1414
|
+
Object.assign(range, newRange);
|
|
1415
|
+
mod = true;
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1419
|
+
if (mod) {
|
|
1420
|
+
view.dispatch({
|
|
1421
|
+
effects: setCommentState.of({
|
|
1422
|
+
comments: comments2,
|
|
1423
|
+
...value
|
|
1424
|
+
})
|
|
1317
1425
|
});
|
|
1318
|
-
if (mod) {
|
|
1319
|
-
view.dispatch({
|
|
1320
|
-
effects: setCommentState.of({
|
|
1321
|
-
active,
|
|
1322
|
-
ranges
|
|
1323
|
-
})
|
|
1324
|
-
});
|
|
1325
|
-
}
|
|
1326
1426
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1427
|
+
}),
|
|
1428
|
+
//
|
|
1429
|
+
// Track selection/proximity.
|
|
1430
|
+
//
|
|
1431
|
+
EditorView6.updateListener.of(({ view, state }) => {
|
|
1432
|
+
let min = Infinity;
|
|
1433
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1434
|
+
const { head } = state.selection.main;
|
|
1435
|
+
const selection = {};
|
|
1436
|
+
comments2.forEach(({ comment, range }) => {
|
|
1437
|
+
if (head >= range.from && head <= range.to) {
|
|
1438
|
+
selection.current = comment.id;
|
|
1439
|
+
selection.closest = void 0;
|
|
1440
|
+
}
|
|
1441
|
+
if (!selection.current) {
|
|
1442
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1340
1443
|
if (d < min) {
|
|
1341
|
-
|
|
1444
|
+
selection.closest = comment.id;
|
|
1342
1445
|
min = d;
|
|
1343
1446
|
}
|
|
1344
|
-
});
|
|
1345
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1346
|
-
view.dispatch({
|
|
1347
|
-
effects: setSelection.of(selected)
|
|
1348
|
-
});
|
|
1349
|
-
handleSelect({
|
|
1350
|
-
...selected,
|
|
1351
|
-
ranges: ranges.map((range) => ({
|
|
1352
|
-
...range,
|
|
1353
|
-
location: view.coordsAtPos(range.from)
|
|
1354
|
-
}))
|
|
1355
|
-
});
|
|
1356
1447
|
}
|
|
1448
|
+
});
|
|
1449
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1450
|
+
view.dispatch({
|
|
1451
|
+
effects: setSelection.of(selection)
|
|
1452
|
+
});
|
|
1453
|
+
handleSelect({
|
|
1454
|
+
selection,
|
|
1455
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1456
|
+
comment,
|
|
1457
|
+
range,
|
|
1458
|
+
location: view.coordsAtPos(range.from)
|
|
1459
|
+
}))
|
|
1460
|
+
});
|
|
1357
1461
|
}
|
|
1358
|
-
})
|
|
1462
|
+
}),
|
|
1463
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1359
1464
|
];
|
|
1360
1465
|
};
|
|
1466
|
+
var useComments = (view, comments2 = []) => {
|
|
1467
|
+
useEffect(() => {
|
|
1468
|
+
if (view) {
|
|
1469
|
+
view.dispatch({
|
|
1470
|
+
effects: setComments.of(comments2)
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}, [
|
|
1474
|
+
view,
|
|
1475
|
+
comments2
|
|
1476
|
+
]);
|
|
1477
|
+
};
|
|
1361
1478
|
|
|
1362
1479
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1363
|
-
import {
|
|
1364
|
-
import
|
|
1365
|
-
|
|
1480
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1481
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1482
|
+
import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1483
|
+
var styles4 = EditorView7.baseTheme({
|
|
1366
1484
|
"& .cm-hr": {
|
|
1367
|
-
// TODO(burdon): ???
|
|
1368
1485
|
// Note that block-level decorations should not have vertical margins,
|
|
1369
|
-
|
|
1486
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1370
1487
|
}
|
|
1371
1488
|
});
|
|
1372
1489
|
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1373
|
-
|
|
1374
|
-
super();
|
|
1375
|
-
this._pos = _pos;
|
|
1376
|
-
}
|
|
1377
|
-
eq(other) {
|
|
1378
|
-
return this._pos === other._pos;
|
|
1379
|
-
}
|
|
1380
|
-
toDOM(view) {
|
|
1490
|
+
toDOM() {
|
|
1381
1491
|
const el = document.createElement("div");
|
|
1382
1492
|
el.className = "cm-hr";
|
|
1383
1493
|
return el;
|
|
1384
1494
|
}
|
|
1385
1495
|
};
|
|
1386
|
-
var
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1496
|
+
var decoration = Decoration4.replace({
|
|
1497
|
+
widget: new HorizontalRuleWidget()
|
|
1498
|
+
});
|
|
1499
|
+
var buildDecorations = (view) => {
|
|
1500
|
+
const builder = new RangeSetBuilder();
|
|
1501
|
+
const { state } = view;
|
|
1502
|
+
const cursor = state.selection.main.head;
|
|
1503
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1504
|
+
syntaxTree(state).iterate({
|
|
1505
|
+
enter: (node) => {
|
|
1506
|
+
if (node.name === "HorizontalRule") {
|
|
1507
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1508
|
+
builder.add(node.from, node.to, decoration);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
from,
|
|
1513
|
+
to
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return builder.finish();
|
|
1517
|
+
};
|
|
1518
|
+
var hr = () => {
|
|
1519
|
+
return [
|
|
1520
|
+
styles4,
|
|
1521
|
+
ViewPlugin4.fromClass(class {
|
|
1522
|
+
constructor(view) {
|
|
1523
|
+
this.decorations = buildDecorations(view);
|
|
1524
|
+
}
|
|
1525
|
+
update(update2) {
|
|
1526
|
+
this.decorations = buildDecorations(update2.view);
|
|
1527
|
+
}
|
|
1528
|
+
}, {
|
|
1529
|
+
decorations: (v) => v.decorations
|
|
1406
1530
|
})
|
|
1407
|
-
|
|
1408
|
-
|
|
1531
|
+
];
|
|
1532
|
+
};
|
|
1409
1533
|
|
|
1410
1534
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1411
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1412
|
-
import {
|
|
1413
|
-
import { Decoration as
|
|
1535
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1536
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1537
|
+
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1414
1538
|
var image = (options = {}) => {
|
|
1415
|
-
return
|
|
1416
|
-
create: (state) =>
|
|
1417
|
-
|
|
1418
|
-
|
|
1539
|
+
return StateField3.define({
|
|
1540
|
+
create: (state) => {
|
|
1541
|
+
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1542
|
+
},
|
|
1543
|
+
update: (value, tr) => {
|
|
1544
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1545
|
+
return value;
|
|
1546
|
+
}
|
|
1547
|
+
const cursor = tr.state.selection.main.head;
|
|
1548
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1549
|
+
let from = Math.min(cursor, oldCursor);
|
|
1550
|
+
let to = Math.max(cursor, oldCursor);
|
|
1551
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1552
|
+
from = Math.min(from, fromB);
|
|
1553
|
+
to = Math.max(to, toB);
|
|
1554
|
+
});
|
|
1555
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1556
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1557
|
+
return value.map(tr.changes).update({
|
|
1558
|
+
filterFrom: from,
|
|
1559
|
+
filterTo: to,
|
|
1560
|
+
filter: () => false,
|
|
1561
|
+
add: buildDecorations2(from, to, tr.state)
|
|
1562
|
+
});
|
|
1563
|
+
},
|
|
1564
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1419
1565
|
});
|
|
1420
1566
|
};
|
|
1421
|
-
var
|
|
1422
|
-
const
|
|
1567
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1568
|
+
const decorations = [];
|
|
1423
1569
|
const cursor = state.selection.main.head;
|
|
1424
|
-
|
|
1570
|
+
syntaxTree2(state).iterate({
|
|
1425
1571
|
enter: (node) => {
|
|
1426
1572
|
if (node.name === "Image") {
|
|
1427
1573
|
const urlNode = node.node.getChild("URL");
|
|
1428
1574
|
if (urlNode) {
|
|
1429
1575
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1430
1576
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1431
|
-
|
|
1577
|
+
decorations.push(Decoration5.replace({
|
|
1432
1578
|
block: true,
|
|
1433
1579
|
widget: new ImageWidget(url)
|
|
1434
|
-
}));
|
|
1580
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1435
1581
|
}
|
|
1436
1582
|
}
|
|
1437
|
-
}
|
|
1583
|
+
},
|
|
1584
|
+
from,
|
|
1585
|
+
to
|
|
1438
1586
|
});
|
|
1439
|
-
return
|
|
1587
|
+
return decorations;
|
|
1440
1588
|
};
|
|
1441
1589
|
var ImageWidget = class extends WidgetType3 {
|
|
1442
1590
|
constructor(_url) {
|
|
1443
1591
|
super();
|
|
1444
1592
|
this._url = _url;
|
|
1445
1593
|
}
|
|
1446
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1447
1594
|
eq(other) {
|
|
1448
1595
|
return this._url === other._url;
|
|
1449
1596
|
}
|
|
@@ -1451,22 +1598,29 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1451
1598
|
const img = document.createElement("img");
|
|
1452
1599
|
img.setAttribute("src", this._url);
|
|
1453
1600
|
img.setAttribute("class", "cm-image");
|
|
1601
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1454
1602
|
return img;
|
|
1455
1603
|
}
|
|
1456
1604
|
};
|
|
1457
1605
|
|
|
1458
1606
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1459
|
-
import { syntaxTree as
|
|
1460
|
-
import { RangeSetBuilder as RangeSetBuilder2
|
|
1461
|
-
import {
|
|
1607
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1608
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1609
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1462
1610
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1463
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1464
1611
|
var link = (options = {}) => {
|
|
1465
1612
|
const extensions = [
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1613
|
+
ViewPlugin5.fromClass(class {
|
|
1614
|
+
constructor(view) {
|
|
1615
|
+
this.decorations = buildDecorations3(view, options);
|
|
1616
|
+
}
|
|
1617
|
+
update(update2) {
|
|
1618
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1619
|
+
this.decorations = buildDecorations3(update2.view, options);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}, {
|
|
1623
|
+
decorations: (v) => v.decorations
|
|
1470
1624
|
})
|
|
1471
1625
|
];
|
|
1472
1626
|
if (options.onHover) {
|
|
@@ -1474,35 +1628,25 @@ var link = (options = {}) => {
|
|
|
1474
1628
|
// https://codemirror.net/examples/tooltip
|
|
1475
1629
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1476
1630
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1477
|
-
hoverTooltip2((view, pos) => {
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
let
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
match = void 0;
|
|
1486
|
-
break;
|
|
1487
|
-
}
|
|
1488
|
-
idx = text.indexOf(match[0]);
|
|
1489
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1490
|
-
break;
|
|
1491
|
-
}
|
|
1492
|
-
idx += match[0].length;
|
|
1493
|
-
} while (true);
|
|
1494
|
-
if (!match) {
|
|
1631
|
+
hoverTooltip2((view, pos, side) => {
|
|
1632
|
+
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1633
|
+
let link2 = null;
|
|
1634
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1635
|
+
link2 = node.name === "Link" ? node : null;
|
|
1636
|
+
}
|
|
1637
|
+
const url = link2 && link2.getChild("URL");
|
|
1638
|
+
if (!url || !link2) {
|
|
1495
1639
|
return null;
|
|
1496
1640
|
}
|
|
1497
|
-
const
|
|
1641
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1498
1642
|
return {
|
|
1499
|
-
pos:
|
|
1500
|
-
end:
|
|
1643
|
+
pos: link2.from,
|
|
1644
|
+
end: link2.to,
|
|
1501
1645
|
above: true,
|
|
1502
1646
|
create: () => {
|
|
1503
1647
|
const el = document.createElement("div");
|
|
1504
1648
|
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1505
|
-
options.onHover(el,
|
|
1649
|
+
options.onHover(el, urlText);
|
|
1506
1650
|
return {
|
|
1507
1651
|
dom: el,
|
|
1508
1652
|
offset: {
|
|
@@ -1518,14 +1662,13 @@ var link = (options = {}) => {
|
|
|
1518
1662
|
return extensions;
|
|
1519
1663
|
};
|
|
1520
1664
|
var LinkButton = class extends WidgetType4 {
|
|
1521
|
-
constructor(
|
|
1665
|
+
constructor(_url, _onAttach) {
|
|
1522
1666
|
super();
|
|
1523
|
-
this._pos = _pos;
|
|
1524
1667
|
this._url = _url;
|
|
1525
1668
|
this._onAttach = _onAttach;
|
|
1526
1669
|
}
|
|
1527
1670
|
eq(other) {
|
|
1528
|
-
return this.
|
|
1671
|
+
return this._url === other._url;
|
|
1529
1672
|
}
|
|
1530
1673
|
toDOM(view) {
|
|
1531
1674
|
const el = document.createElement("span");
|
|
@@ -1562,74 +1705,77 @@ var LinkText = class extends WidgetType4 {
|
|
|
1562
1705
|
return link2;
|
|
1563
1706
|
}
|
|
1564
1707
|
};
|
|
1565
|
-
var
|
|
1708
|
+
var buildDecorations3 = (view, options) => {
|
|
1566
1709
|
const builder = new RangeSetBuilder2();
|
|
1710
|
+
const { state } = view;
|
|
1567
1711
|
const cursor = state.selection.main.head;
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1712
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1713
|
+
syntaxTree3(state).iterate({
|
|
1714
|
+
enter: (node) => {
|
|
1715
|
+
if (node.name === "Link") {
|
|
1716
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
1717
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1718
|
+
const urlNode = node.node.getChild("URL");
|
|
1719
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1720
|
+
if (!url) {
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1724
|
+
builder.add(node.from, node.to, Decoration6.replace({
|
|
1725
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
1726
|
+
}));
|
|
1727
|
+
}
|
|
1728
|
+
if (options.onRender) {
|
|
1729
|
+
builder.add(node.to, node.to, Decoration6.replace({
|
|
1730
|
+
widget: new LinkButton(url, options.onRender)
|
|
1731
|
+
}));
|
|
1732
|
+
}
|
|
1576
1733
|
return false;
|
|
1577
1734
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
if (options.onRender) {
|
|
1584
|
-
builder.add(node.to, node.to, Decoration5.replace({
|
|
1585
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1586
|
-
}));
|
|
1587
|
-
}
|
|
1588
|
-
return false;
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
});
|
|
1735
|
+
},
|
|
1736
|
+
from,
|
|
1737
|
+
to
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1592
1740
|
return builder.finish();
|
|
1593
1741
|
};
|
|
1594
1742
|
|
|
1595
1743
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1596
|
-
import { EditorView as
|
|
1744
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1597
1745
|
var listener = ({ onFocus, onChange }) => {
|
|
1598
1746
|
const extensions = [];
|
|
1599
|
-
onFocus && extensions.push(
|
|
1747
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1600
1748
|
onFocus(focused);
|
|
1601
1749
|
return null;
|
|
1602
1750
|
}));
|
|
1603
|
-
onChange && extensions.push(
|
|
1604
|
-
onChange(
|
|
1751
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1752
|
+
onChange(update2.state.doc.toString());
|
|
1605
1753
|
}));
|
|
1606
1754
|
return extensions;
|
|
1607
1755
|
};
|
|
1608
1756
|
|
|
1609
1757
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1610
1758
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1611
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1612
|
-
import { markdownLanguage as
|
|
1759
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1760
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1613
1761
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1614
1762
|
import { languages } from "@codemirror/language-data";
|
|
1615
1763
|
import { searchKeymap } from "@codemirror/search";
|
|
1616
1764
|
import { EditorState } from "@codemirror/state";
|
|
1617
1765
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1618
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1766
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1619
1767
|
|
|
1620
1768
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1621
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1769
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1622
1770
|
import { HighlightStyle } from "@codemirror/language";
|
|
1623
1771
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1624
1772
|
import { Table } from "@lezer/markdown";
|
|
1625
|
-
import get5 from "lodash.get";
|
|
1626
1773
|
var markdownTags = {
|
|
1627
1774
|
Blockquote: Tag.define(),
|
|
1628
1775
|
CodeMark: Tag.define(),
|
|
1629
1776
|
CodeText: Tag.define(),
|
|
1630
1777
|
EmphasisMark: Tag.define(),
|
|
1631
1778
|
HeaderMark: Tag.define(),
|
|
1632
|
-
// HorizontalRule: Tag.define(),
|
|
1633
1779
|
InlineCode: Tag.define(),
|
|
1634
1780
|
LinkLabel: Tag.define(),
|
|
1635
1781
|
LinkReference: Tag.define(),
|
|
@@ -1793,12 +1939,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1793
1939
|
],
|
|
1794
1940
|
class: blockquote
|
|
1795
1941
|
},
|
|
1796
|
-
// TODO(burdon): Replace with extension.
|
|
1797
|
-
// {
|
|
1798
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1799
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1800
|
-
// },
|
|
1801
|
-
// TODO(burdon): Only if being edited.
|
|
1802
1942
|
{
|
|
1803
1943
|
tag: [
|
|
1804
1944
|
markdownTags.TableCell
|
|
@@ -1806,9 +1946,9 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1806
1946
|
class: "font-mono"
|
|
1807
1947
|
}
|
|
1808
1948
|
], {
|
|
1809
|
-
scope:
|
|
1949
|
+
scope: markdownLanguage2,
|
|
1810
1950
|
all: {
|
|
1811
|
-
fontFamily:
|
|
1951
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1812
1952
|
}
|
|
1813
1953
|
});
|
|
1814
1954
|
};
|
|
@@ -1818,17 +1958,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1818
1958
|
return [
|
|
1819
1959
|
EditorState.allowMultipleSelections.of(true),
|
|
1820
1960
|
EditorState.tabSize.of(2),
|
|
1821
|
-
|
|
1822
|
-
|
|
1961
|
+
EditorView10.lineWrapping,
|
|
1962
|
+
// https://github.com/codemirror/basic-setup
|
|
1823
1963
|
bracketMatching2(),
|
|
1824
1964
|
closeBrackets2(),
|
|
1825
1965
|
crosshairCursor(),
|
|
1826
1966
|
dropCursor(),
|
|
1827
1967
|
drawSelection2(),
|
|
1828
|
-
|
|
1829
|
-
|
|
1968
|
+
highlightActiveLine2(),
|
|
1969
|
+
history2(),
|
|
1830
1970
|
indentOnInput(),
|
|
1831
|
-
_placeholder
|
|
1971
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1832
1972
|
// Main extension.
|
|
1833
1973
|
// https://github.com/codemirror/lang-markdown
|
|
1834
1974
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1838,7 +1978,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1838
1978
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1839
1979
|
// https://github.github.com/gfm
|
|
1840
1980
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1841
|
-
base:
|
|
1981
|
+
base: markdownLanguage3,
|
|
1842
1982
|
// Languages for syntax highlighting fenced code blocks.
|
|
1843
1983
|
codeLanguages: languages,
|
|
1844
1984
|
// Parser extensions.
|
|
@@ -1850,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1850
1990
|
// https://github.com/codemirror/theme-one-dark
|
|
1851
1991
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1852
1992
|
// Custom styles.
|
|
1853
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1993
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly)),
|
|
1994
|
+
keymap4.of([
|
|
1995
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1996
|
+
indentWithTab,
|
|
1997
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1998
|
+
...closeBracketsKeymap,
|
|
1999
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2000
|
+
...historyKeymap,
|
|
2001
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2002
|
+
...searchKeymap,
|
|
2003
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2004
|
+
...standardKeymap
|
|
2005
|
+
])
|
|
2006
|
+
];
|
|
2007
|
+
};
|
|
1868
2008
|
|
|
1869
2009
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1870
2010
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1871
2011
|
var mention = ({ onSearch }) => {
|
|
1872
2012
|
return autocompletion2({
|
|
2013
|
+
// TODO(burdon): Not working.
|
|
2014
|
+
activateOnTyping: true,
|
|
2015
|
+
// activateOnTypingDelay: 100,
|
|
2016
|
+
// selectOnOpen: true,
|
|
1873
2017
|
closeOnBlur: false,
|
|
2018
|
+
// defaultKeymap: false,
|
|
2019
|
+
icons: false,
|
|
1874
2020
|
override: [
|
|
1875
2021
|
(context) => {
|
|
2022
|
+
console.log(context);
|
|
1876
2023
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1877
2024
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1878
2025
|
return null;
|
|
1879
2026
|
}
|
|
1880
|
-
console.log(match);
|
|
1881
2027
|
return {
|
|
1882
2028
|
from: match.from,
|
|
1883
2029
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1889,23 +2035,23 @@ var mention = ({ onSearch }) => {
|
|
|
1889
2035
|
});
|
|
1890
2036
|
};
|
|
1891
2037
|
|
|
1892
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1893
|
-
var
|
|
2038
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2039
|
+
var outliner = (options = {}) => {
|
|
1894
2040
|
return [];
|
|
1895
2041
|
};
|
|
1896
2042
|
|
|
1897
2043
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1898
|
-
import { syntaxTree as
|
|
1899
|
-
import { RangeSetBuilder as RangeSetBuilder3, StateField as
|
|
1900
|
-
import { Decoration as
|
|
2044
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2045
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
|
|
2046
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1901
2047
|
var table = (options = {}) => {
|
|
1902
|
-
return
|
|
1903
|
-
create: (state) =>
|
|
1904
|
-
update: (_, tr) =>
|
|
1905
|
-
provide: (field) =>
|
|
2048
|
+
return StateField4.define({
|
|
2049
|
+
create: (state) => update(state, options),
|
|
2050
|
+
update: (_, tr) => update(tr.state, options),
|
|
2051
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1906
2052
|
});
|
|
1907
2053
|
};
|
|
1908
|
-
var
|
|
2054
|
+
var update = (state, options) => {
|
|
1909
2055
|
const builder = new RangeSetBuilder3();
|
|
1910
2056
|
const cursor = state.selection.main.head;
|
|
1911
2057
|
const tables = [];
|
|
@@ -1914,7 +2060,7 @@ var update3 = (state, options) => {
|
|
|
1914
2060
|
const table2 = getTable();
|
|
1915
2061
|
return table2.rows?.[table2.rows.length - 1];
|
|
1916
2062
|
};
|
|
1917
|
-
|
|
2063
|
+
syntaxTree4(state).iterate({
|
|
1918
2064
|
enter: (node) => {
|
|
1919
2065
|
switch (node.name) {
|
|
1920
2066
|
case "Table": {
|
|
@@ -1946,11 +2092,10 @@ var update3 = (state, options) => {
|
|
|
1946
2092
|
});
|
|
1947
2093
|
tables.forEach((table2) => {
|
|
1948
2094
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1949
|
-
hide && builder.add(table2.from, table2.to,
|
|
1950
|
-
block: true,
|
|
2095
|
+
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
1951
2096
|
widget: new TableWidget(table2)
|
|
1952
2097
|
}));
|
|
1953
|
-
builder.add(table2.from, table2.to,
|
|
2098
|
+
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
1954
2099
|
class: "cm-table"
|
|
1955
2100
|
}));
|
|
1956
2101
|
});
|
|
@@ -1962,7 +2107,7 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1962
2107
|
this._table = _table;
|
|
1963
2108
|
}
|
|
1964
2109
|
eq(other) {
|
|
1965
|
-
return this._table.
|
|
2110
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1966
2111
|
}
|
|
1967
2112
|
toDOM(view) {
|
|
1968
2113
|
const table2 = document.createElement("table");
|
|
@@ -1988,90 +2133,105 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1988
2133
|
}
|
|
1989
2134
|
return table2;
|
|
1990
2135
|
}
|
|
2136
|
+
ignoreEvent(e) {
|
|
2137
|
+
return !/^mouse/.test(e.type);
|
|
2138
|
+
}
|
|
1991
2139
|
};
|
|
1992
2140
|
|
|
1993
2141
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
1994
|
-
import {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
2142
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2143
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2144
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
2145
|
+
var styles5 = EditorView12.baseTheme({
|
|
2146
|
+
"& .cm-task": {
|
|
2147
|
+
color: getToken("extend.colors.blue.500")
|
|
2148
|
+
},
|
|
2149
|
+
"& .cm-task-checkbox": {
|
|
2150
|
+
marginLeft: "4px",
|
|
2151
|
+
marginRight: "4px"
|
|
1999
2152
|
}
|
|
2000
2153
|
});
|
|
2001
2154
|
var CheckboxWidget = class extends WidgetType6 {
|
|
2002
|
-
constructor(
|
|
2155
|
+
constructor(_checked) {
|
|
2003
2156
|
super();
|
|
2004
|
-
this._pos = _pos;
|
|
2005
2157
|
this._checked = _checked;
|
|
2006
|
-
this._indent = _indent;
|
|
2007
|
-
this._onCheck = _onCheck;
|
|
2008
2158
|
}
|
|
2009
2159
|
eq(other) {
|
|
2010
|
-
return this.
|
|
2160
|
+
return this._checked === other._checked;
|
|
2011
2161
|
}
|
|
2012
2162
|
toDOM(view) {
|
|
2013
|
-
const
|
|
2014
|
-
|
|
2015
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2016
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2017
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2163
|
+
const input = document.createElement("input");
|
|
2164
|
+
input.className = "cm-task-checkbox";
|
|
2018
2165
|
input.type = "checkbox";
|
|
2019
2166
|
input.checked = this._checked;
|
|
2020
|
-
if (
|
|
2167
|
+
if (view.state.readOnly) {
|
|
2021
2168
|
input.setAttribute("disabled", "true");
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2169
|
+
} else {
|
|
2170
|
+
input.onmousedown = (event) => {
|
|
2171
|
+
const pos = view.posAtDOM(input);
|
|
2172
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2173
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2174
|
+
view.dispatch({
|
|
2175
|
+
changes: {
|
|
2176
|
+
from: pos + 1,
|
|
2177
|
+
to: pos + 2,
|
|
2178
|
+
insert: this._checked ? " " : "x"
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
event.preventDefault();
|
|
2182
|
+
}
|
|
2027
2183
|
};
|
|
2028
2184
|
}
|
|
2029
|
-
return
|
|
2185
|
+
return input;
|
|
2030
2186
|
}
|
|
2031
2187
|
ignoreEvent() {
|
|
2032
2188
|
return false;
|
|
2033
2189
|
}
|
|
2034
2190
|
};
|
|
2191
|
+
var checkedDecoration = Decoration8.replace({
|
|
2192
|
+
widget: new CheckboxWidget(true)
|
|
2193
|
+
});
|
|
2194
|
+
var uncheckedDecoration = Decoration8.replace({
|
|
2195
|
+
widget: new CheckboxWidget(false)
|
|
2196
|
+
});
|
|
2197
|
+
var buildDecorations4 = (view) => {
|
|
2198
|
+
const builder = new RangeSetBuilder4();
|
|
2199
|
+
const { state } = view;
|
|
2200
|
+
const cursor = state.selection.main.head;
|
|
2201
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2202
|
+
syntaxTree5(state).iterate({
|
|
2203
|
+
enter: (node) => {
|
|
2204
|
+
if (node.name === "TaskMarker") {
|
|
2205
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2206
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2207
|
+
builder.add(node.from - 2, node.from - 1, Decoration8.mark({
|
|
2208
|
+
class: "cm-task"
|
|
2209
|
+
}));
|
|
2210
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
from,
|
|
2215
|
+
to
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
return builder.finish();
|
|
2219
|
+
};
|
|
2035
2220
|
var tasklist = (options = {}) => {
|
|
2036
|
-
const taskMatcher = new MatchDecorator3({
|
|
2037
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2038
|
-
decoration: (match, view, pos) => {
|
|
2039
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2040
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2041
|
-
return Decoration7.replace({
|
|
2042
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2043
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2044
|
-
view.dispatch({
|
|
2045
|
-
changes: {
|
|
2046
|
-
from: idx,
|
|
2047
|
-
to: idx + 1,
|
|
2048
|
-
insert: checked2 ? "x" : " "
|
|
2049
|
-
},
|
|
2050
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2051
|
-
selection: {
|
|
2052
|
-
anchor: idx + 3
|
|
2053
|
-
}
|
|
2054
|
-
});
|
|
2055
|
-
})
|
|
2056
|
-
});
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
const tasks = ViewPlugin5.fromClass(class {
|
|
2060
|
-
constructor(view) {
|
|
2061
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2062
|
-
}
|
|
2063
|
-
update(update4) {
|
|
2064
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
2065
|
-
}
|
|
2066
|
-
}, {
|
|
2067
|
-
decorations: (value) => value.tasks,
|
|
2068
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2069
|
-
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
2070
|
-
})
|
|
2071
|
-
});
|
|
2072
2221
|
return [
|
|
2073
|
-
|
|
2074
|
-
|
|
2222
|
+
ViewPlugin6.fromClass(class {
|
|
2223
|
+
constructor(view) {
|
|
2224
|
+
this.decorations = buildDecorations4(view);
|
|
2225
|
+
}
|
|
2226
|
+
update(update2) {
|
|
2227
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2228
|
+
this.decorations = buildDecorations4(update2.view);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}, {
|
|
2232
|
+
decorations: (v) => v.decorations
|
|
2233
|
+
}),
|
|
2234
|
+
styles5
|
|
2075
2235
|
];
|
|
2076
2236
|
};
|
|
2077
2237
|
|
|
@@ -2133,7 +2293,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2133
2293
|
};
|
|
2134
2294
|
|
|
2135
2295
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2136
|
-
import
|
|
2296
|
+
import get3 from "lodash.get";
|
|
2137
2297
|
var defaultTheme = {
|
|
2138
2298
|
//
|
|
2139
2299
|
// Main layout:
|
|
@@ -2162,21 +2322,21 @@ var defaultTheme = {
|
|
|
2162
2322
|
"&.cm-focused": {
|
|
2163
2323
|
outline: "none"
|
|
2164
2324
|
},
|
|
2165
|
-
"
|
|
2325
|
+
".cm-scroller": {
|
|
2166
2326
|
overflow: "visible",
|
|
2167
|
-
fontFamily:
|
|
2327
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2168
2328
|
},
|
|
2169
|
-
"
|
|
2329
|
+
".cm-content": {
|
|
2170
2330
|
padding: 0,
|
|
2171
2331
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2172
2332
|
fontSize: "16px"
|
|
2173
2333
|
},
|
|
2174
2334
|
"&light .cm-content": {
|
|
2175
|
-
color:
|
|
2335
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2176
2336
|
caretColor: "black"
|
|
2177
2337
|
},
|
|
2178
2338
|
"&dark .cm-content": {
|
|
2179
|
-
color:
|
|
2339
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2180
2340
|
caretColor: "white"
|
|
2181
2341
|
},
|
|
2182
2342
|
//
|
|
@@ -2188,158 +2348,120 @@ var defaultTheme = {
|
|
|
2188
2348
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2189
2349
|
borderLeft: "2px solid white"
|
|
2190
2350
|
},
|
|
2191
|
-
"
|
|
2351
|
+
".cm-placeholder": {
|
|
2192
2352
|
fontWeight: 100
|
|
2193
2353
|
},
|
|
2194
2354
|
//
|
|
2195
2355
|
// line
|
|
2196
2356
|
//
|
|
2197
|
-
"
|
|
2357
|
+
".cm-line": {
|
|
2198
2358
|
paddingInline: 0
|
|
2199
2359
|
},
|
|
2200
|
-
"
|
|
2360
|
+
".cm-activeLine": {
|
|
2201
2361
|
background: "inherit"
|
|
2202
2362
|
},
|
|
2203
2363
|
//
|
|
2204
2364
|
// Selection
|
|
2205
2365
|
//
|
|
2206
2366
|
"&light .cm-selectionBackground": {
|
|
2207
|
-
background:
|
|
2367
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2208
2368
|
},
|
|
2209
2369
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2210
|
-
background:
|
|
2370
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2211
2371
|
},
|
|
2212
2372
|
"&dark .cm-selectionBackground": {
|
|
2213
|
-
background:
|
|
2373
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2214
2374
|
},
|
|
2215
2375
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2216
|
-
background:
|
|
2376
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2217
2377
|
},
|
|
2218
2378
|
//
|
|
2219
2379
|
// Search
|
|
2220
2380
|
//
|
|
2221
2381
|
"&light .cm-searchMatch": {
|
|
2222
|
-
backgroundColor:
|
|
2382
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2223
2383
|
},
|
|
2224
2384
|
"&dark .cm-searchMatch": {
|
|
2225
|
-
backgroundColor:
|
|
2226
|
-
},
|
|
2227
|
-
//
|
|
2228
|
-
// collaboration
|
|
2229
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2230
|
-
//
|
|
2231
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2232
|
-
mixBlendMode: "multiply"
|
|
2233
|
-
},
|
|
2234
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2235
|
-
mixBlendMode: "screen"
|
|
2236
|
-
},
|
|
2237
|
-
"& .cm-ySelectionInfo": {
|
|
2238
|
-
padding: "2px 4px",
|
|
2239
|
-
marginBlockStart: "-4px"
|
|
2240
|
-
},
|
|
2241
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2242
|
-
paddingBlockStart: ".15em",
|
|
2243
|
-
paddingBlockEnd: ".15em"
|
|
2244
|
-
},
|
|
2245
|
-
"& .cm-ySelectionCaret": {
|
|
2246
|
-
display: "inline-block",
|
|
2247
|
-
insetBlockStart: ".1em",
|
|
2248
|
-
blockSize: "1.4em",
|
|
2249
|
-
verticalAlign: "top"
|
|
2250
|
-
},
|
|
2251
|
-
"& .cm-yLineSelection": {
|
|
2252
|
-
margin: 0
|
|
2385
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2253
2386
|
},
|
|
2254
2387
|
//
|
|
2255
2388
|
// link
|
|
2256
2389
|
//
|
|
2257
|
-
"
|
|
2258
|
-
color:
|
|
2390
|
+
".cm-link": {
|
|
2391
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2259
2392
|
textDecorationLine: "underline",
|
|
2260
2393
|
textDecorationThickness: "1px",
|
|
2261
2394
|
textUnderlineOffset: "2px",
|
|
2262
2395
|
borderRadius: ".125rem",
|
|
2263
|
-
fontFamily:
|
|
2396
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2264
2397
|
},
|
|
2265
2398
|
//
|
|
2266
2399
|
// tooltip
|
|
2267
2400
|
//
|
|
2268
|
-
"
|
|
2401
|
+
".cm-tooltip": {
|
|
2269
2402
|
border: "none"
|
|
2270
2403
|
},
|
|
2271
|
-
"
|
|
2404
|
+
".cm-tooltip-below": {},
|
|
2272
2405
|
//
|
|
2273
2406
|
// autocomplete
|
|
2274
2407
|
//
|
|
2275
|
-
"
|
|
2408
|
+
".cm-tooltip-autocomplete": {
|
|
2276
2409
|
marginTop: "4px",
|
|
2277
2410
|
marginLeft: "-3px"
|
|
2278
2411
|
},
|
|
2279
|
-
"
|
|
2280
|
-
"
|
|
2281
|
-
"
|
|
2412
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2413
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2414
|
+
".cm-completionIcon": {
|
|
2282
2415
|
display: "none"
|
|
2283
2416
|
},
|
|
2284
|
-
"
|
|
2285
|
-
fontFamily:
|
|
2417
|
+
".cm-completionLabel": {
|
|
2418
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2286
2419
|
},
|
|
2287
|
-
"
|
|
2420
|
+
".cm-completionMatchedText": {
|
|
2288
2421
|
textDecoration: "none"
|
|
2289
2422
|
},
|
|
2290
2423
|
//
|
|
2291
|
-
// widgets
|
|
2292
|
-
//
|
|
2293
|
-
"& .cm-widgetBuffer": {
|
|
2294
|
-
display: "none",
|
|
2295
|
-
height: 0
|
|
2296
|
-
},
|
|
2297
|
-
//
|
|
2298
2424
|
// table
|
|
2299
2425
|
//
|
|
2300
|
-
"
|
|
2301
|
-
fontFamily: `${
|
|
2426
|
+
".cm-table *": {
|
|
2427
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2302
2428
|
textDecoration: "none !important"
|
|
2303
2429
|
},
|
|
2304
|
-
"
|
|
2430
|
+
".cm-table-head": {
|
|
2305
2431
|
padding: "2px 16px 2px 0px",
|
|
2306
|
-
borderBottom: `1px solid ${
|
|
2432
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2307
2433
|
fontWeight: 100,
|
|
2308
2434
|
textAlign: "left",
|
|
2309
|
-
color:
|
|
2435
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2310
2436
|
},
|
|
2311
|
-
"
|
|
2437
|
+
".cm-table-cell": {
|
|
2312
2438
|
padding: "2px 16px 2px 0px"
|
|
2313
2439
|
},
|
|
2314
2440
|
//
|
|
2315
2441
|
// image
|
|
2316
2442
|
//
|
|
2317
|
-
"
|
|
2318
|
-
|
|
2443
|
+
".cm-image": {
|
|
2444
|
+
display: "block",
|
|
2445
|
+
height: "0"
|
|
2446
|
+
},
|
|
2447
|
+
".cm-image.cm-loaded-image": {
|
|
2448
|
+
height: "auto",
|
|
2449
|
+
borderTop: "0.5rem solid transparent",
|
|
2450
|
+
borderBottom: "0.5rem solid transparent"
|
|
2319
2451
|
},
|
|
2320
2452
|
//
|
|
2321
2453
|
// font size
|
|
2322
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2454
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2455
|
+
// but it's far more verbose than it needs to be.
|
|
2323
2456
|
//
|
|
2324
|
-
...Object.keys(
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2333
|
-
height
|
|
2334
|
-
};
|
|
2335
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2336
|
-
height
|
|
2337
|
-
};
|
|
2338
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2339
|
-
height
|
|
2340
|
-
};
|
|
2341
|
-
return acc;
|
|
2342
|
-
}, {}),
|
|
2457
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2458
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2459
|
+
//
|
|
2460
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2461
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2462
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2463
|
+
// return acc;
|
|
2464
|
+
// }, {}),
|
|
2343
2465
|
/**
|
|
2344
2466
|
* Panels
|
|
2345
2467
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2356,144 +2478,140 @@ var defaultTheme = {
|
|
|
2356
2478
|
* </div>
|
|
2357
2479
|
* </div
|
|
2358
2480
|
*/
|
|
2359
|
-
"
|
|
2360
|
-
border: `1px solid ${
|
|
2481
|
+
".cm-panels": {
|
|
2482
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2361
2483
|
},
|
|
2362
|
-
"
|
|
2363
|
-
background:
|
|
2364
|
-
fontFamily:
|
|
2484
|
+
".cm-panel": {
|
|
2485
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2486
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2365
2487
|
},
|
|
2366
|
-
"
|
|
2488
|
+
".cm-button": {
|
|
2367
2489
|
margin: "4px",
|
|
2368
|
-
fontFamily:
|
|
2369
|
-
background:
|
|
2490
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2491
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2370
2492
|
backgroundImage: "none",
|
|
2371
2493
|
border: "none",
|
|
2372
2494
|
"&:hover": {
|
|
2373
|
-
background:
|
|
2495
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2374
2496
|
},
|
|
2375
2497
|
"&:active": {
|
|
2376
|
-
background:
|
|
2498
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2377
2499
|
backgroundImage: "none"
|
|
2378
2500
|
}
|
|
2379
2501
|
},
|
|
2380
|
-
"
|
|
2502
|
+
".cm-panel input[type=checkbox]": {
|
|
2381
2503
|
marginRight: "0.4rem !important"
|
|
2382
2504
|
}
|
|
2383
2505
|
};
|
|
2384
2506
|
var textTheme = {
|
|
2385
|
-
"
|
|
2386
|
-
fontFamily:
|
|
2507
|
+
".cm-scroller": {
|
|
2508
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2387
2509
|
},
|
|
2388
|
-
"
|
|
2389
|
-
fontFamily:
|
|
2510
|
+
".cm-placeholder": {
|
|
2511
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2390
2512
|
}
|
|
2391
2513
|
};
|
|
2392
2514
|
var markdownTheme = {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2515
|
+
".cm-scroller": {
|
|
2516
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2517
|
+
},
|
|
2518
|
+
".cm-placeholder": {
|
|
2519
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2396
2520
|
}
|
|
2397
2521
|
};
|
|
2398
2522
|
var codeTheme = {
|
|
2399
|
-
"
|
|
2400
|
-
fontFamily:
|
|
2523
|
+
".cm-scroller": {
|
|
2524
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2401
2525
|
},
|
|
2402
|
-
"
|
|
2403
|
-
fontFamily:
|
|
2526
|
+
".cm-placeholder": {
|
|
2527
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2404
2528
|
}
|
|
2405
2529
|
};
|
|
2406
2530
|
|
|
2407
2531
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2532
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2408
2533
|
var EditorModes = [
|
|
2409
2534
|
"default",
|
|
2410
2535
|
"vim"
|
|
2411
2536
|
];
|
|
2412
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2413
|
-
const { themeMode } = useThemeContext();
|
|
2537
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2414
2538
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2415
2539
|
tabBehavior: "limited"
|
|
2416
2540
|
});
|
|
2417
|
-
const
|
|
2418
|
-
const
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
state,
|
|
2541
|
+
const { themeMode } = useThemeContext();
|
|
2542
|
+
const rootRef = useRef(null);
|
|
2543
|
+
const [view, setView] = useState(null);
|
|
2544
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2422
2545
|
view
|
|
2423
|
-
}), [
|
|
2424
|
-
view,
|
|
2425
|
-
state,
|
|
2426
|
-
root
|
|
2427
|
-
]);
|
|
2428
|
-
const { awareness, peer } = model;
|
|
2429
|
-
useEffect2(() => {
|
|
2430
|
-
if (awareness && peer) {
|
|
2431
|
-
awareness.setLocalStateField("user", {
|
|
2432
|
-
name: peer.name ?? generateName(peer.id),
|
|
2433
|
-
color: getColorForValue({
|
|
2434
|
-
value: peer.id,
|
|
2435
|
-
type: "color"
|
|
2436
|
-
}),
|
|
2437
|
-
colorLight: getColorForValue({
|
|
2438
|
-
value: peer.id,
|
|
2439
|
-
themeMode,
|
|
2440
|
-
type: "highlight"
|
|
2441
|
-
})
|
|
2442
|
-
});
|
|
2443
|
-
}
|
|
2444
|
-
}, [
|
|
2445
|
-
awareness,
|
|
2446
|
-
peer,
|
|
2447
|
-
themeMode
|
|
2448
2546
|
]);
|
|
2449
2547
|
useEffect2(() => {
|
|
2450
|
-
if (
|
|
2451
|
-
view
|
|
2452
|
-
effects: setCommentRange.of({
|
|
2453
|
-
model,
|
|
2454
|
-
comments: comments2
|
|
2455
|
-
})
|
|
2456
|
-
});
|
|
2548
|
+
if (autoFocus) {
|
|
2549
|
+
view?.focus();
|
|
2457
2550
|
}
|
|
2458
2551
|
}, [
|
|
2459
2552
|
view,
|
|
2460
|
-
|
|
2553
|
+
autoFocus
|
|
2461
2554
|
]);
|
|
2462
2555
|
useEffect2(() => {
|
|
2463
|
-
if (!
|
|
2556
|
+
if (!model || !rootRef.current) {
|
|
2464
2557
|
return;
|
|
2465
2558
|
}
|
|
2466
|
-
const
|
|
2559
|
+
const state = EditorState2.create({
|
|
2467
2560
|
doc: model.text(),
|
|
2561
|
+
selection,
|
|
2468
2562
|
extensions: [
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2563
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2564
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2565
|
+
log2.catch(err, void 0, {
|
|
2566
|
+
F: __dxlog_file5,
|
|
2567
|
+
L: 123,
|
|
2568
|
+
S: void 0,
|
|
2569
|
+
C: (f, a) => f(...a)
|
|
2570
|
+
});
|
|
2571
|
+
}),
|
|
2472
2572
|
// Theme.
|
|
2473
|
-
// TODO(burdon): Make
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2573
|
+
// TODO(burdon): Make configurable.
|
|
2574
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2575
|
+
EditorView13.theme(theme ?? {}),
|
|
2576
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2577
|
+
EditorView13.editorAttributes.of({
|
|
2578
|
+
class: slots.editor?.className ?? ""
|
|
2579
|
+
}),
|
|
2580
|
+
EditorView13.contentAttributes.of({
|
|
2581
|
+
class: slots.content?.className ?? ""
|
|
2582
|
+
}),
|
|
2583
|
+
// State.
|
|
2584
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2477
2585
|
// Storage and replication.
|
|
2586
|
+
// NOTE: This must come before user extensions.
|
|
2478
2587
|
model.extension,
|
|
2588
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2589
|
+
editorMode === "vim" && vim(),
|
|
2479
2590
|
// Custom.
|
|
2480
2591
|
...extensions
|
|
2481
2592
|
].filter(Boolean)
|
|
2482
2593
|
});
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2594
|
+
const newView = new EditorView13({
|
|
2595
|
+
state,
|
|
2596
|
+
parent: rootRef.current,
|
|
2597
|
+
scrollTo,
|
|
2598
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2599
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2600
|
+
dispatchTransactions: (trs, view2) => {
|
|
2601
|
+
if (debug) {
|
|
2602
|
+
logChanges(trs);
|
|
2603
|
+
}
|
|
2604
|
+
view2.update(trs);
|
|
2605
|
+
}
|
|
2490
2606
|
});
|
|
2607
|
+
view?.destroy();
|
|
2608
|
+
setView(newView);
|
|
2491
2609
|
return () => {
|
|
2492
|
-
|
|
2493
|
-
|
|
2610
|
+
newView?.destroy();
|
|
2611
|
+
setView(null);
|
|
2494
2612
|
};
|
|
2495
2613
|
}, [
|
|
2496
|
-
|
|
2614
|
+
rootRef,
|
|
2497
2615
|
model,
|
|
2498
2616
|
readonly,
|
|
2499
2617
|
editorMode,
|
|
@@ -2503,11 +2621,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2503
2621
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2504
2622
|
switch (key) {
|
|
2505
2623
|
case "Enter": {
|
|
2506
|
-
view?.
|
|
2624
|
+
view?.focus();
|
|
2507
2625
|
break;
|
|
2508
2626
|
}
|
|
2509
2627
|
case "Escape": {
|
|
2510
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2628
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2629
|
+
rootRef.current?.focus();
|
|
2630
|
+
}
|
|
2511
2631
|
break;
|
|
2512
2632
|
}
|
|
2513
2633
|
}
|
|
@@ -2517,101 +2637,296 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2517
2637
|
]);
|
|
2518
2638
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2519
2639
|
key: model.id,
|
|
2520
|
-
|
|
2640
|
+
role: "none",
|
|
2521
2641
|
tabIndex: 0,
|
|
2522
|
-
|
|
2642
|
+
onKeyUp: handleKeyUp,
|
|
2643
|
+
...slots.root,
|
|
2523
2644
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2524
|
-
|
|
2645
|
+
ref: rootRef
|
|
2525
2646
|
});
|
|
2526
2647
|
});
|
|
2527
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2648
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2528
2649
|
const { themeMode } = useThemeContext();
|
|
2529
|
-
const
|
|
2650
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2530
2651
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2531
2652
|
ref: forwardedRef,
|
|
2532
2653
|
readonly,
|
|
2533
2654
|
extensions: [
|
|
2534
2655
|
basicBundle({
|
|
2535
|
-
readonly,
|
|
2536
2656
|
themeMode,
|
|
2537
|
-
placeholder:
|
|
2657
|
+
placeholder: placeholder3,
|
|
2658
|
+
lineWrapping
|
|
2538
2659
|
}),
|
|
2539
2660
|
...extensions
|
|
2540
2661
|
],
|
|
2541
|
-
|
|
2662
|
+
theme,
|
|
2663
|
+
slots: updatedSlots,
|
|
2542
2664
|
...props
|
|
2543
2665
|
});
|
|
2544
2666
|
});
|
|
2545
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2667
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2546
2668
|
const { themeMode } = useThemeContext();
|
|
2547
|
-
const
|
|
2669
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2548
2670
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2549
2671
|
ref: forwardedRef,
|
|
2550
2672
|
readonly,
|
|
2551
2673
|
extensions: [
|
|
2552
2674
|
markdownBundle({
|
|
2553
|
-
readonly,
|
|
2554
2675
|
themeMode,
|
|
2555
|
-
|
|
2676
|
+
readonly,
|
|
2677
|
+
placeholder: placeholder3
|
|
2556
2678
|
}),
|
|
2557
2679
|
...extensions
|
|
2558
2680
|
],
|
|
2559
|
-
|
|
2681
|
+
theme,
|
|
2682
|
+
slots: updatedSlots,
|
|
2560
2683
|
...props
|
|
2561
2684
|
});
|
|
2562
2685
|
});
|
|
2563
2686
|
var defaultSlots = {
|
|
2564
2687
|
root: {
|
|
2565
|
-
|
|
2688
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2689
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2690
|
+
},
|
|
2691
|
+
editor: {
|
|
2692
|
+
className: "h-full p-2"
|
|
2566
2693
|
}
|
|
2567
2694
|
};
|
|
2568
2695
|
var defaultTextSlots = {
|
|
2569
|
-
...defaultSlots
|
|
2570
|
-
editor: {
|
|
2571
|
-
theme: textTheme
|
|
2572
|
-
}
|
|
2696
|
+
...defaultSlots
|
|
2573
2697
|
};
|
|
2574
2698
|
var defaultMarkdownSlots = {
|
|
2575
|
-
...defaultSlots
|
|
2576
|
-
|
|
2577
|
-
|
|
2699
|
+
...defaultSlots
|
|
2700
|
+
};
|
|
2701
|
+
|
|
2702
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2703
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2704
|
+
import { Context as Context2 } from "@dxos/context";
|
|
2705
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2706
|
+
import { log as log3 } from "@dxos/log";
|
|
2707
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2708
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
2709
|
+
var SpaceAwarenessProvider = class {
|
|
2710
|
+
constructor(params) {
|
|
2711
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2712
|
+
this.remoteStateChange = new Event2();
|
|
2713
|
+
this._space = params.space;
|
|
2714
|
+
this._channel = params.channel;
|
|
2715
|
+
this._peerId = params.peerId;
|
|
2716
|
+
this._info = params.info;
|
|
2717
|
+
}
|
|
2718
|
+
open() {
|
|
2719
|
+
this._ctx = new Context2();
|
|
2720
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
2721
|
+
if (this._localState) {
|
|
2722
|
+
await this._space.postMessage(this._channel, {
|
|
2723
|
+
kind: "post",
|
|
2724
|
+
state: this._localState
|
|
2725
|
+
});
|
|
2726
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
2727
|
+
}
|
|
2728
|
+
});
|
|
2729
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2730
|
+
switch (message.payload.kind) {
|
|
2731
|
+
case "query": {
|
|
2732
|
+
this._handleQueryMessage();
|
|
2733
|
+
break;
|
|
2734
|
+
}
|
|
2735
|
+
case "post": {
|
|
2736
|
+
this._handlePostMessage(message.payload);
|
|
2737
|
+
break;
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
}));
|
|
2741
|
+
void this._space.postMessage(this._channel, {
|
|
2742
|
+
kind: "query"
|
|
2743
|
+
}).catch((err) => {
|
|
2744
|
+
log3.debug("failed to query awareness", {
|
|
2745
|
+
err
|
|
2746
|
+
}, {
|
|
2747
|
+
F: __dxlog_file6,
|
|
2748
|
+
L: 89,
|
|
2749
|
+
S: this,
|
|
2750
|
+
C: (f, a) => f(...a)
|
|
2751
|
+
});
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2754
|
+
close() {
|
|
2755
|
+
void this._ctx?.dispose();
|
|
2756
|
+
this._ctx = void 0;
|
|
2757
|
+
this._postTask = void 0;
|
|
2758
|
+
}
|
|
2759
|
+
getRemoteStates() {
|
|
2760
|
+
return Array.from(this._remoteStates.values());
|
|
2761
|
+
}
|
|
2762
|
+
update(position) {
|
|
2763
|
+
invariant4(this._postTask, void 0, {
|
|
2764
|
+
F: __dxlog_file6,
|
|
2765
|
+
L: 104,
|
|
2766
|
+
S: this,
|
|
2767
|
+
A: [
|
|
2768
|
+
"this._postTask",
|
|
2769
|
+
""
|
|
2770
|
+
]
|
|
2771
|
+
});
|
|
2772
|
+
this._localState = {
|
|
2773
|
+
peerId: this._peerId,
|
|
2774
|
+
position,
|
|
2775
|
+
info: this._info
|
|
2776
|
+
};
|
|
2777
|
+
this._postTask.schedule();
|
|
2778
|
+
}
|
|
2779
|
+
_handleQueryMessage() {
|
|
2780
|
+
invariant4(this._postTask, void 0, {
|
|
2781
|
+
F: __dxlog_file6,
|
|
2782
|
+
L: 115,
|
|
2783
|
+
S: this,
|
|
2784
|
+
A: [
|
|
2785
|
+
"this._postTask",
|
|
2786
|
+
""
|
|
2787
|
+
]
|
|
2788
|
+
});
|
|
2789
|
+
this._postTask.schedule();
|
|
2790
|
+
}
|
|
2791
|
+
_handlePostMessage(message) {
|
|
2792
|
+
invariant4(message.kind === "post", void 0, {
|
|
2793
|
+
F: __dxlog_file6,
|
|
2794
|
+
L: 120,
|
|
2795
|
+
S: this,
|
|
2796
|
+
A: [
|
|
2797
|
+
"message.kind === 'post'",
|
|
2798
|
+
""
|
|
2799
|
+
]
|
|
2800
|
+
});
|
|
2801
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
2802
|
+
this.remoteStateChange.emit();
|
|
2578
2803
|
}
|
|
2579
2804
|
};
|
|
2805
|
+
|
|
2806
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2807
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
2808
|
+
var modelState = StateField5.define({
|
|
2809
|
+
create: () => void 0,
|
|
2810
|
+
update: (model) => model
|
|
2811
|
+
});
|
|
2812
|
+
|
|
2813
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
2814
|
+
import { useState as useState2 } from "react";
|
|
2815
|
+
var useTextEditor = () => {
|
|
2816
|
+
const [view, setView] = useState2(null);
|
|
2817
|
+
return [
|
|
2818
|
+
(ref) => {
|
|
2819
|
+
setView(ref);
|
|
2820
|
+
},
|
|
2821
|
+
view
|
|
2822
|
+
];
|
|
2823
|
+
};
|
|
2824
|
+
|
|
2825
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2826
|
+
import get4 from "lodash.get";
|
|
2827
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
2828
|
+
import { generateName } from "@dxos/display-name";
|
|
2829
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2830
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2831
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2832
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2833
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2834
|
+
var useTextModel = (props) => {
|
|
2835
|
+
const { identity, space, text } = props;
|
|
2836
|
+
const [model, setModel] = useState3();
|
|
2837
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2838
|
+
identity,
|
|
2839
|
+
space,
|
|
2840
|
+
text
|
|
2841
|
+
]);
|
|
2842
|
+
return model;
|
|
2843
|
+
};
|
|
2844
|
+
var createModel = ({ space, identity, text }) => {
|
|
2845
|
+
invariant5(isAutomergeObject(text), void 0, {
|
|
2846
|
+
F: __dxlog_file7,
|
|
2847
|
+
L: 35,
|
|
2848
|
+
S: void 0,
|
|
2849
|
+
A: [
|
|
2850
|
+
"isAutomergeObject(text)",
|
|
2851
|
+
""
|
|
2852
|
+
]
|
|
2853
|
+
});
|
|
2854
|
+
const obj = text;
|
|
2855
|
+
const doc = getRawDoc(obj, [
|
|
2856
|
+
obj.field
|
|
2857
|
+
]);
|
|
2858
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2859
|
+
space,
|
|
2860
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2861
|
+
info: {
|
|
2862
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2863
|
+
color: cursorColor.color,
|
|
2864
|
+
lightColor: cursorColor.light
|
|
2865
|
+
},
|
|
2866
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2867
|
+
});
|
|
2868
|
+
const model = {
|
|
2869
|
+
id: obj.id,
|
|
2870
|
+
content: doc,
|
|
2871
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2872
|
+
extension: [
|
|
2873
|
+
modelState.init(() => model),
|
|
2874
|
+
automerge3({
|
|
2875
|
+
handle: doc.handle,
|
|
2876
|
+
path: doc.path
|
|
2877
|
+
}),
|
|
2878
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2879
|
+
awareness()
|
|
2880
|
+
].filter(isNotNullOrUndefined),
|
|
2881
|
+
peer: identity ? {
|
|
2882
|
+
id: identity.identityKey.toHex(),
|
|
2883
|
+
name: identity.profile?.displayName
|
|
2884
|
+
} : void 0
|
|
2885
|
+
};
|
|
2886
|
+
return model;
|
|
2887
|
+
};
|
|
2580
2888
|
export {
|
|
2889
|
+
AwarenessProvider,
|
|
2581
2890
|
BaseTextEditor,
|
|
2891
|
+
Cursor,
|
|
2582
2892
|
Doc,
|
|
2583
2893
|
EditorModes,
|
|
2584
2894
|
MarkdownEditor,
|
|
2895
|
+
RemoteSelectionsDecorator,
|
|
2585
2896
|
SpaceAwarenessProvider,
|
|
2586
2897
|
TextEditor,
|
|
2587
2898
|
TextKind,
|
|
2588
2899
|
YText,
|
|
2589
2900
|
YXmlFragment,
|
|
2590
2901
|
autocomplete,
|
|
2902
|
+
automerge3 as automerge,
|
|
2903
|
+
awareness,
|
|
2591
2904
|
basicBundle,
|
|
2592
2905
|
blast,
|
|
2906
|
+
callbackWrapper,
|
|
2593
2907
|
code2 as code,
|
|
2594
2908
|
codeTheme,
|
|
2595
2909
|
comments,
|
|
2596
|
-
cursorColor,
|
|
2597
2910
|
defaultMarkdownSlots,
|
|
2598
2911
|
defaultOptions,
|
|
2599
2912
|
defaultSlots,
|
|
2600
2913
|
defaultTextSlots,
|
|
2601
2914
|
defaultTheme,
|
|
2915
|
+
getToken,
|
|
2602
2916
|
hr,
|
|
2603
2917
|
image,
|
|
2604
2918
|
link,
|
|
2605
2919
|
listener,
|
|
2920
|
+
logChanges,
|
|
2606
2921
|
markdownBundle,
|
|
2607
2922
|
markdownHighlightStyle,
|
|
2608
2923
|
markdownTags,
|
|
2609
2924
|
markdownTagsExtensions,
|
|
2610
2925
|
markdownTheme,
|
|
2611
2926
|
mention,
|
|
2612
|
-
mermaid,
|
|
2613
2927
|
modelState,
|
|
2614
|
-
|
|
2928
|
+
outliner,
|
|
2929
|
+
setComments,
|
|
2615
2930
|
setFocus,
|
|
2616
2931
|
setSelection,
|
|
2617
2932
|
table,
|
|
@@ -2619,6 +2934,8 @@ export {
|
|
|
2619
2934
|
tasklist,
|
|
2620
2935
|
textTheme,
|
|
2621
2936
|
typewriter,
|
|
2937
|
+
useComments,
|
|
2938
|
+
useTextEditor,
|
|
2622
2939
|
useTextModel
|
|
2623
2940
|
};
|
|
2624
2941
|
//# sourceMappingURL=index.mjs.map
|