@dxos/react-ui-editor 0.3.11-main.0e40963 → 0.3.11-main.108b22e
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 +1837 -1502
- 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 -3
- 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 +33 -18
- 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 +13 -34
- 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 +256 -219
- 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 -134
- 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,783 +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
|
-
try {
|
|
515
|
-
return fn(...args);
|
|
516
|
-
} catch (error) {
|
|
517
|
-
log.catch(error, void 0, {
|
|
518
|
-
F: __dxlog_file2,
|
|
519
|
-
L: 16,
|
|
520
|
-
S: void 0,
|
|
521
|
-
C: (f, a) => f(...a)
|
|
522
|
-
});
|
|
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: () => {
|
|
523
399
|
}
|
|
524
400
|
};
|
|
525
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
552
429
|
});
|
|
553
430
|
}
|
|
554
|
-
|
|
555
|
-
|
|
431
|
+
destroy() {
|
|
432
|
+
void this._ctx.dispose();
|
|
433
|
+
this._provider.close();
|
|
556
434
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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;
|
|
562
444
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
+
})
|
|
578
521
|
});
|
|
579
522
|
}
|
|
523
|
+
this.decorations = Decoration.set(decorations, true);
|
|
580
524
|
}
|
|
581
|
-
view.dispatch({
|
|
582
|
-
selection,
|
|
583
|
-
annotations: reconcileAnnotationType.of({})
|
|
584
|
-
});
|
|
585
525
|
};
|
|
586
|
-
var
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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;
|
|
597
560
|
}
|
|
598
561
|
};
|
|
599
|
-
var
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
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"
|
|
603
618
|
}
|
|
604
|
-
|
|
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
|
+
};
|
|
605
687
|
return [
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
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
|
+
])
|
|
735
|
+
];
|
|
736
|
+
};
|
|
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);
|
|
765
|
+
}
|
|
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);
|
|
610
852
|
}
|
|
611
|
-
];
|
|
612
|
-
};
|
|
613
|
-
var handleSplice = (target, patch) => {
|
|
614
|
-
const index = charPath(target, patch.path);
|
|
615
|
-
if (index == null) {
|
|
616
|
-
return [];
|
|
617
853
|
}
|
|
618
|
-
return [
|
|
619
|
-
{
|
|
620
|
-
from: index,
|
|
621
|
-
insert: patch.value
|
|
622
|
-
}
|
|
623
|
-
];
|
|
624
854
|
};
|
|
625
|
-
var
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return [];
|
|
855
|
+
var Effect = class {
|
|
856
|
+
constructor(_options) {
|
|
857
|
+
this._options = _options;
|
|
629
858
|
}
|
|
630
|
-
const length = patch.length || 1;
|
|
631
|
-
return [
|
|
632
|
-
{
|
|
633
|
-
from: index,
|
|
634
|
-
to: index + length
|
|
635
|
-
}
|
|
636
|
-
];
|
|
637
859
|
};
|
|
638
|
-
var
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
+
};
|
|
645
871
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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);
|
|
649
879
|
}
|
|
650
|
-
return [
|
|
651
|
-
{
|
|
652
|
-
from: 0,
|
|
653
|
-
to: length,
|
|
654
|
-
insert: patch.value
|
|
655
|
-
}
|
|
656
|
-
];
|
|
657
880
|
};
|
|
658
|
-
var
|
|
659
|
-
|
|
660
|
-
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
|
+
};
|
|
661
895
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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);
|
|
665
922
|
}
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
var getRGBComponents = (node, color) => {
|
|
926
|
+
if (typeof color === "function") {
|
|
927
|
+
return color();
|
|
666
928
|
}
|
|
667
|
-
const
|
|
668
|
-
if (
|
|
669
|
-
|
|
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
|
+
}
|
|
670
935
|
}
|
|
671
|
-
return
|
|
936
|
+
return [
|
|
937
|
+
50,
|
|
938
|
+
50,
|
|
939
|
+
50
|
|
940
|
+
];
|
|
672
941
|
};
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
this._inReconcile = false;
|
|
678
|
-
this._queue = [];
|
|
679
|
-
this.reconcile = (handle, view) => {
|
|
680
|
-
if (this._inReconcile) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
this._inReconcile = true;
|
|
684
|
-
const path = getPath(view.state, this._field);
|
|
685
|
-
const oldHeads = getLastHeads(view.state, this._field);
|
|
686
|
-
let selection = view.state.selection;
|
|
687
|
-
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
688
|
-
const toInvert = transactions.slice().reverse();
|
|
689
|
-
for (const tx of toInvert) {
|
|
690
|
-
const inverted = tx.changes.invert(tx.startState.doc);
|
|
691
|
-
selection = selection.map(inverted);
|
|
692
|
-
view.dispatch({
|
|
693
|
-
changes: inverted,
|
|
694
|
-
annotations: reconcileAnnotationType.of(true)
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
698
|
-
if (newHeads === null || newHeads === void 0) {
|
|
699
|
-
newHeads = automerge.getHeads(handle.docSync());
|
|
700
|
-
}
|
|
701
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
702
|
-
updateCodeMirror(view, selection, path, diff);
|
|
703
|
-
view.dispatch({
|
|
704
|
-
effects: updateHeads(newHeads),
|
|
705
|
-
annotations: reconcileAnnotationType.of({})
|
|
706
|
-
});
|
|
707
|
-
this._inReconcile = false;
|
|
708
|
-
};
|
|
709
|
-
if (field !== void 0) {
|
|
710
|
-
this._field = field;
|
|
711
|
-
}
|
|
942
|
+
var random = (min, max) => {
|
|
943
|
+
if (!max) {
|
|
944
|
+
max = min;
|
|
945
|
+
min = 0;
|
|
712
946
|
}
|
|
947
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
713
948
|
};
|
|
714
949
|
|
|
715
|
-
// packages/ui/react-ui-editor/src/
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
newHeads
|
|
719
|
-
});
|
|
720
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
721
|
-
var getPath = (state, field) => state.field(field).path;
|
|
722
|
-
var semaphoreFacet = Facet.define({
|
|
723
|
-
combine: (values) => values.at(-1)
|
|
724
|
-
});
|
|
725
|
-
var automergePlugin = (handle, path) => {
|
|
726
|
-
const stateField = StateField.define({
|
|
727
|
-
create: () => ({
|
|
728
|
-
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
729
|
-
unreconciledTransactions: [],
|
|
730
|
-
path: path.slice()
|
|
731
|
-
}),
|
|
732
|
-
update: (value, tr) => {
|
|
733
|
-
const result = {
|
|
734
|
-
lastHeads: value.lastHeads,
|
|
735
|
-
unreconciledTransactions: value.unreconciledTransactions.slice(),
|
|
736
|
-
path: path.slice()
|
|
737
|
-
};
|
|
738
|
-
let clearUnreconciled = false;
|
|
739
|
-
for (const effect of tr.effects) {
|
|
740
|
-
if (effect.is(effectType)) {
|
|
741
|
-
result.lastHeads = effect.value.newHeads;
|
|
742
|
-
clearUnreconciled = true;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
if (clearUnreconciled) {
|
|
746
|
-
result.unreconciledTransactions = [];
|
|
747
|
-
} else {
|
|
748
|
-
if (!isReconcileTx(tr)) {
|
|
749
|
-
result.unreconciledTransactions.push(tr);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
return result;
|
|
753
|
-
}
|
|
754
|
-
});
|
|
755
|
-
const semaphore = new PatchSemaphore(stateField);
|
|
756
|
-
const viewPlugin = ViewPlugin2.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
757
|
-
constructor(view) {
|
|
758
|
-
this._handleChange = () => {
|
|
759
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
760
|
-
};
|
|
761
|
-
this._view = view;
|
|
762
|
-
handle.addListener("change", this._handleChange);
|
|
763
|
-
}
|
|
764
|
-
update(update4) {
|
|
765
|
-
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
766
|
-
queueMicrotask(() => {
|
|
767
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
destroy() {
|
|
772
|
-
handle.addListener("change", this._handleChange);
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
|
-
return {
|
|
776
|
-
extension: [
|
|
777
|
-
stateField,
|
|
778
|
-
semaphoreFacet.of(semaphore),
|
|
779
|
-
viewPlugin
|
|
780
|
-
]
|
|
781
|
-
};
|
|
782
|
-
};
|
|
783
|
-
var reconcileAnnotationType = Annotation.define();
|
|
784
|
-
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";
|
|
785
953
|
|
|
786
|
-
// packages/ui/react-ui-editor/src/
|
|
954
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
787
955
|
import * as random2 from "lib0/random";
|
|
788
956
|
var cursorColors = [
|
|
789
957
|
{
|
|
@@ -798,290 +966,266 @@ var cursorColors = [
|
|
|
798
966
|
color: "#ffbc42",
|
|
799
967
|
light: "#ffbc4233"
|
|
800
968
|
},
|
|
801
|
-
{
|
|
802
|
-
color: "#ecd444",
|
|
803
|
-
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")
|
|
804
1048
|
},
|
|
805
|
-
{
|
|
806
|
-
|
|
807
|
-
light: "#ee635233"
|
|
1049
|
+
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1050
|
+
background: getToken("extend.colors.neutral.850")
|
|
808
1051
|
},
|
|
809
|
-
{
|
|
810
|
-
|
|
811
|
-
|
|
1052
|
+
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1053
|
+
display: "block",
|
|
1054
|
+
paddingInline: "4px !important"
|
|
812
1055
|
},
|
|
813
|
-
{
|
|
814
|
-
|
|
815
|
-
|
|
1056
|
+
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1057
|
+
paddingTop: "4px !important",
|
|
1058
|
+
borderTopLeftRadius: "4px",
|
|
1059
|
+
borderTopRightRadius: "4px"
|
|
816
1060
|
},
|
|
817
|
-
{
|
|
818
|
-
|
|
819
|
-
|
|
1061
|
+
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1062
|
+
paddingBottom: "4px !important",
|
|
1063
|
+
borderBottomLeftRadius: "4px",
|
|
1064
|
+
borderBottomRightRadius: "4px"
|
|
820
1065
|
}
|
|
821
|
-
|
|
822
|
-
var
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
var
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
} else if (typeof process !== "undefined") {
|
|
845
|
-
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
|
+
}
|
|
846
1089
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
removed,
|
|
865
|
-
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
|
+
}
|
|
866
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, {
|
|
867
1131
|
F: __dxlog_file3,
|
|
868
|
-
L:
|
|
869
|
-
S:
|
|
870
|
-
C: (f, a) => f(...a)
|
|
871
|
-
});
|
|
872
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
873
|
-
const encoderAwareness = encoding.createEncoder();
|
|
874
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
875
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
876
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
877
|
-
}
|
|
878
|
-
_handleSpaceMessage({ payload }) {
|
|
879
|
-
log2("space message", payload, {
|
|
880
|
-
F: __dxlog_file3,
|
|
881
|
-
L: 79,
|
|
882
|
-
S: this,
|
|
1132
|
+
L: 18,
|
|
1133
|
+
S: void 0,
|
|
883
1134
|
C: (f, a) => f(...a)
|
|
884
1135
|
});
|
|
885
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
886
|
-
const encoder = this._readMessage(data);
|
|
887
|
-
if (encoder) {
|
|
888
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
_readMessage(message) {
|
|
892
|
-
const decoder = decoding.createDecoder(message);
|
|
893
|
-
const encoder = encoding.createEncoder();
|
|
894
|
-
const messageType = decoding.readVarUint(decoder);
|
|
895
|
-
let sendReply = false;
|
|
896
|
-
switch (messageType) {
|
|
897
|
-
case messageAwareness: {
|
|
898
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
899
|
-
break;
|
|
900
|
-
}
|
|
901
|
-
case messageQueryAwareness: {
|
|
902
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
903
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
904
|
-
sendReply = true;
|
|
905
|
-
break;
|
|
906
|
-
}
|
|
907
|
-
default: {
|
|
908
|
-
console.error("Invalid message:", messageType);
|
|
909
|
-
return encoder;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (!sendReply) {
|
|
913
|
-
return null;
|
|
914
|
-
}
|
|
915
|
-
return encoder;
|
|
916
|
-
}
|
|
917
|
-
_handleBeforeUnload() {
|
|
918
|
-
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
919
|
-
this._clientId
|
|
920
|
-
], "window unload");
|
|
921
1136
|
}
|
|
922
1137
|
};
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
var modelState = StateField2.define({
|
|
927
|
-
create: () => void 0,
|
|
928
|
-
update: (model) => model
|
|
929
|
-
});
|
|
930
|
-
var useTextModel = (props) => {
|
|
931
|
-
const { identity, space, text } = props;
|
|
932
|
-
const [model, setModel] = useState(() => createModel(props));
|
|
933
|
-
useEffect(() => setModel(createModel(props)), [
|
|
934
|
-
identity,
|
|
935
|
-
space,
|
|
936
|
-
text
|
|
937
|
-
]);
|
|
938
|
-
return model;
|
|
939
|
-
};
|
|
940
|
-
var createModel = (props) => {
|
|
941
|
-
const { text } = props;
|
|
942
|
-
if (isActualAutomergeObject(text)) {
|
|
943
|
-
return createAutomergeModel(props);
|
|
944
|
-
} else {
|
|
945
|
-
if (!text?.doc) {
|
|
1138
|
+
var logChanges = (trs) => {
|
|
1139
|
+
const changes = trs.flatMap((tr) => {
|
|
1140
|
+
if (tr.changes.empty) {
|
|
946
1141
|
return void 0;
|
|
947
1142
|
}
|
|
948
|
-
|
|
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);
|
|
949
1155
|
}
|
|
950
1156
|
};
|
|
951
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
952
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
953
|
-
F: __dxlog_file4,
|
|
954
|
-
L: 97,
|
|
955
|
-
S: void 0,
|
|
956
|
-
A: [
|
|
957
|
-
"text?.doc && text?.content",
|
|
958
|
-
""
|
|
959
|
-
]
|
|
960
|
-
});
|
|
961
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
962
|
-
space,
|
|
963
|
-
doc: text.doc,
|
|
964
|
-
channel: `yjs.awareness.${text.id}`
|
|
965
|
-
}) : void 0;
|
|
966
|
-
const model = {
|
|
967
|
-
id: text.doc.guid,
|
|
968
|
-
content: text.content,
|
|
969
|
-
text: () => text.content.toString(),
|
|
970
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
971
|
-
getCursorFromRange: (range) => {
|
|
972
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
973
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
974
|
-
return [
|
|
975
|
-
arrayToString(from),
|
|
976
|
-
arrayToString(to)
|
|
977
|
-
].join(":");
|
|
978
|
-
},
|
|
979
|
-
getRangeFromCursor: (cursor) => {
|
|
980
|
-
invariant2(text.doc, void 0, {
|
|
981
|
-
F: __dxlog_file4,
|
|
982
|
-
L: 113,
|
|
983
|
-
S: void 0,
|
|
984
|
-
A: [
|
|
985
|
-
"text.doc",
|
|
986
|
-
""
|
|
987
|
-
]
|
|
988
|
-
});
|
|
989
|
-
const parts = cursor.split(":");
|
|
990
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
991
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
992
|
-
return from && to ? {
|
|
993
|
-
from: from.index,
|
|
994
|
-
to: to.index
|
|
995
|
-
} : void 0;
|
|
996
|
-
},
|
|
997
|
-
extension: [
|
|
998
|
-
yCollab(text.content, provider?.awareness),
|
|
999
|
-
modelState.init(() => model)
|
|
1000
|
-
],
|
|
1001
|
-
awareness: provider?.awareness,
|
|
1002
|
-
peer: identity ? {
|
|
1003
|
-
id: identity.identityKey.toHex(),
|
|
1004
|
-
name: identity.profile?.displayName
|
|
1005
|
-
} : void 0
|
|
1006
|
-
};
|
|
1007
|
-
return model;
|
|
1008
|
-
};
|
|
1009
|
-
var createAutomergeModel = ({ identity, text }) => {
|
|
1010
|
-
const obj = text;
|
|
1011
|
-
const doc = getRawDoc(obj, [
|
|
1012
|
-
obj.field
|
|
1013
|
-
]);
|
|
1014
|
-
const model = {
|
|
1015
|
-
id: obj.id,
|
|
1016
|
-
content: doc,
|
|
1017
|
-
text: () => get2(doc.handle.docSync(), doc.path),
|
|
1018
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
1019
|
-
extension: [
|
|
1020
|
-
automergePlugin(doc.handle, doc.path),
|
|
1021
|
-
modelState.init(() => model)
|
|
1022
|
-
],
|
|
1023
|
-
peer: identity ? {
|
|
1024
|
-
id: identity.identityKey.toHex(),
|
|
1025
|
-
name: identity.profile?.displayName
|
|
1026
|
-
} : void 0
|
|
1027
|
-
};
|
|
1028
|
-
return model;
|
|
1029
|
-
};
|
|
1030
1157
|
|
|
1031
1158
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1032
|
-
var
|
|
1033
|
-
var
|
|
1034
|
-
"& .cm-bookmark": {
|
|
1035
|
-
cursor: "pointer",
|
|
1036
|
-
margin: "4px",
|
|
1037
|
-
padding: "4px",
|
|
1038
|
-
backgroundColor: "yellow"
|
|
1039
|
-
},
|
|
1040
|
-
"& .cm-bookmark-selected": {
|
|
1041
|
-
backgroundColor: "orange"
|
|
1042
|
-
},
|
|
1159
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1160
|
+
var styles3 = EditorView6.baseTheme({
|
|
1043
1161
|
"& .cm-comment": {
|
|
1044
|
-
backgroundColor: "yellow"
|
|
1162
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1045
1163
|
},
|
|
1046
|
-
"& .cm-comment-
|
|
1047
|
-
backgroundColor: "
|
|
1164
|
+
"& .cm-comment-current": {
|
|
1165
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1048
1166
|
}
|
|
1049
1167
|
});
|
|
1050
1168
|
var marks = {
|
|
1051
|
-
highlight:
|
|
1169
|
+
highlight: Decoration3.mark({
|
|
1052
1170
|
class: "cm-comment"
|
|
1053
1171
|
}),
|
|
1054
|
-
highlightActive:
|
|
1055
|
-
class: "cm-comment-
|
|
1172
|
+
highlightActive: Decoration3.mark({
|
|
1173
|
+
class: "cm-comment-current"
|
|
1056
1174
|
})
|
|
1057
1175
|
};
|
|
1058
|
-
var
|
|
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) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
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
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
var setComments = StateEffect2.define();
|
|
1059
1200
|
var setSelection = StateEffect2.define();
|
|
1060
1201
|
var setCommentState = StateEffect2.define();
|
|
1061
|
-
var
|
|
1202
|
+
var commentsState = StateField2.define({
|
|
1062
1203
|
create: () => ({
|
|
1063
|
-
|
|
1204
|
+
comments: [],
|
|
1205
|
+
selection: {}
|
|
1064
1206
|
}),
|
|
1065
1207
|
update: (value, tr) => {
|
|
1066
1208
|
for (const effect of tr.effects) {
|
|
1067
1209
|
if (effect.is(setSelection)) {
|
|
1068
1210
|
return {
|
|
1069
1211
|
...value,
|
|
1070
|
-
|
|
1212
|
+
selection: effect.value
|
|
1071
1213
|
};
|
|
1072
1214
|
}
|
|
1073
|
-
if (effect.is(
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
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);
|
|
1077
1221
|
return range && {
|
|
1078
|
-
|
|
1079
|
-
|
|
1222
|
+
comment,
|
|
1223
|
+
range
|
|
1080
1224
|
};
|
|
1081
1225
|
}).filter(nonNullable);
|
|
1082
1226
|
return {
|
|
1083
1227
|
...value,
|
|
1084
|
-
|
|
1228
|
+
comments: comments2
|
|
1085
1229
|
};
|
|
1086
1230
|
}
|
|
1087
1231
|
if (effect.is(setCommentState)) {
|
|
@@ -1091,142 +1235,133 @@ var commentsStateField = StateField3.define({
|
|
|
1091
1235
|
return value;
|
|
1092
1236
|
}
|
|
1093
1237
|
});
|
|
1094
|
-
var highlightDecorations =
|
|
1095
|
-
|
|
1238
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1239
|
+
commentsState
|
|
1096
1240
|
], (state) => {
|
|
1097
|
-
const {
|
|
1098
|
-
const decorations = sortBy(
|
|
1099
|
-
|
|
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);
|
|
1100
1246
|
return void 0;
|
|
1101
1247
|
}
|
|
1102
|
-
|
|
1103
|
-
from: selection.from,
|
|
1104
|
-
to: selection.to
|
|
1105
|
-
};
|
|
1106
|
-
if (selection.id === active) {
|
|
1248
|
+
if (comment.comment.id === current) {
|
|
1107
1249
|
return marks.highlightActive.range(range.from, range.to);
|
|
1108
1250
|
} else {
|
|
1109
1251
|
return marks.highlight.range(range.from, range.to);
|
|
1110
1252
|
}
|
|
1111
|
-
}).filter(nonNullable)
|
|
1112
|
-
return
|
|
1253
|
+
}).filter(nonNullable);
|
|
1254
|
+
return Decoration3.set(decorations);
|
|
1113
1255
|
});
|
|
1114
|
-
var
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1132
|
-
}
|
|
1133
|
-
toDOM() {
|
|
1134
|
-
const span = document.createElement("span");
|
|
1135
|
-
span.className = "cm-bookmark";
|
|
1136
|
-
span.textContent = "\u203B";
|
|
1137
|
-
if (this._handleClick) {
|
|
1138
|
-
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
|
+
};
|
|
1139
1273
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
+
];
|
|
1142
1309
|
};
|
|
1143
1310
|
var comments = (options = {}) => {
|
|
1311
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1144
1312
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1145
1313
|
const createCommentThread = (view) => {
|
|
1146
1314
|
invariant3(options.onCreate, void 0, {
|
|
1147
|
-
F:
|
|
1148
|
-
L:
|
|
1315
|
+
F: __dxlog_file4,
|
|
1316
|
+
L: 259,
|
|
1149
1317
|
S: void 0,
|
|
1150
1318
|
A: [
|
|
1151
1319
|
"options.onCreate",
|
|
1152
1320
|
""
|
|
1153
1321
|
]
|
|
1154
1322
|
});
|
|
1155
|
-
const {
|
|
1323
|
+
const { from, to } = view.state.selection.main;
|
|
1156
1324
|
if (from === to) {
|
|
1157
1325
|
return false;
|
|
1158
1326
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
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, {
|
|
1161
1336
|
from,
|
|
1162
1337
|
to
|
|
1163
1338
|
});
|
|
1164
|
-
if (
|
|
1165
|
-
const id =
|
|
1339
|
+
if (cursor) {
|
|
1340
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1166
1341
|
if (id) {
|
|
1167
1342
|
view.dispatch({
|
|
1168
1343
|
effects: setSelection.of({
|
|
1169
|
-
|
|
1344
|
+
current: id
|
|
1170
1345
|
}),
|
|
1171
1346
|
selection: {
|
|
1172
1347
|
anchor: from
|
|
1173
1348
|
}
|
|
1174
1349
|
});
|
|
1175
|
-
if (options.footnote) {
|
|
1176
|
-
const tag = `[^${id}]`;
|
|
1177
|
-
view.dispatch({
|
|
1178
|
-
changes: {
|
|
1179
|
-
from: head,
|
|
1180
|
-
insert: tag
|
|
1181
|
-
},
|
|
1182
|
-
selection: {
|
|
1183
|
-
anchor: head + tag.length
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
}
|
|
1187
1350
|
return true;
|
|
1188
1351
|
}
|
|
1189
1352
|
}
|
|
1190
1353
|
return false;
|
|
1191
1354
|
};
|
|
1192
|
-
const bookmarksViewPlugin = ViewPlugin3.fromClass(class BookmarkViewPlugin {
|
|
1193
|
-
static {
|
|
1194
|
-
// Match markdown footnotes (option).
|
|
1195
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1196
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1197
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1198
|
-
decoration: (match, view, pos) => {
|
|
1199
|
-
const id = match[1];
|
|
1200
|
-
return Decoration2.replace({
|
|
1201
|
-
id,
|
|
1202
|
-
widget: new BookmarkWidget(pos, id)
|
|
1203
|
-
});
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
}
|
|
1207
|
-
constructor(view) {
|
|
1208
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1209
|
-
}
|
|
1210
|
-
update(update4) {
|
|
1211
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
1212
|
-
}
|
|
1213
|
-
}, {
|
|
1214
|
-
decorations: (instance) => instance.bookmarks,
|
|
1215
|
-
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
1216
|
-
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
1217
|
-
})
|
|
1218
|
-
});
|
|
1219
1355
|
return [
|
|
1220
|
-
|
|
1221
|
-
commentsStateField,
|
|
1356
|
+
commentsState,
|
|
1222
1357
|
highlightDecorations,
|
|
1223
|
-
|
|
1358
|
+
styles3,
|
|
1224
1359
|
//
|
|
1225
1360
|
// Keymap.
|
|
1226
1361
|
//
|
|
1227
1362
|
options.onCreate ? keymap3.of([
|
|
1228
1363
|
{
|
|
1229
|
-
key:
|
|
1364
|
+
key: shortcut,
|
|
1230
1365
|
run: callbackWrapper(createCommentThread)
|
|
1231
1366
|
}
|
|
1232
1367
|
]) : [],
|
|
@@ -1243,7 +1378,7 @@ var comments = (options = {}) => {
|
|
|
1243
1378
|
above: true,
|
|
1244
1379
|
create: () => {
|
|
1245
1380
|
const el = document.createElement("div");
|
|
1246
|
-
options.onHover
|
|
1381
|
+
options.onHover(el, shortcut);
|
|
1247
1382
|
return {
|
|
1248
1383
|
dom: el,
|
|
1249
1384
|
offset: {
|
|
@@ -1256,178 +1391,206 @@ var comments = (options = {}) => {
|
|
|
1256
1391
|
}
|
|
1257
1392
|
return null;
|
|
1258
1393
|
}, {
|
|
1259
|
-
|
|
1394
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1395
|
+
// hideOnChange: true,
|
|
1260
1396
|
hoverTime: 1e3
|
|
1261
1397
|
}) : [],
|
|
1262
1398
|
//
|
|
1263
|
-
//
|
|
1264
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1399
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1265
1400
|
//
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
S: void 0,
|
|
1276
|
-
A: [
|
|
1277
|
-
"model",
|
|
1278
|
-
""
|
|
1279
|
-
]
|
|
1280
|
-
});
|
|
1281
|
-
ranges.forEach((range) => {
|
|
1282
|
-
if (from2 === to2) {
|
|
1283
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1284
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1285
|
-
log3.info("deleted comment", {
|
|
1286
|
-
thread: range.id
|
|
1287
|
-
}, {
|
|
1288
|
-
F: __dxlog_file5,
|
|
1289
|
-
L: 342,
|
|
1290
|
-
S: void 0,
|
|
1291
|
-
C: (f, a) => f(...a)
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
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);
|
|
1294
1410
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
}
|
|
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
|
+
})
|
|
1301
1425
|
});
|
|
1302
|
-
if (mod) {
|
|
1303
|
-
view.dispatch({
|
|
1304
|
-
effects: setCommentState.of({
|
|
1305
|
-
active,
|
|
1306
|
-
ranges
|
|
1307
|
-
})
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
1426
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
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));
|
|
1324
1443
|
if (d < min) {
|
|
1325
|
-
|
|
1444
|
+
selection.closest = comment.id;
|
|
1326
1445
|
min = d;
|
|
1327
1446
|
}
|
|
1328
|
-
});
|
|
1329
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1330
|
-
view.dispatch({
|
|
1331
|
-
effects: setSelection.of(selected)
|
|
1332
|
-
});
|
|
1333
|
-
handleSelect({
|
|
1334
|
-
...selected,
|
|
1335
|
-
ranges: ranges.map((range) => ({
|
|
1336
|
-
...range,
|
|
1337
|
-
location: view.coordsAtPos(range.from)
|
|
1338
|
-
}))
|
|
1339
|
-
});
|
|
1340
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
|
+
});
|
|
1341
1461
|
}
|
|
1342
|
-
})
|
|
1462
|
+
}),
|
|
1463
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1343
1464
|
];
|
|
1344
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
|
+
};
|
|
1345
1478
|
|
|
1346
1479
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1347
|
-
import {
|
|
1348
|
-
import
|
|
1349
|
-
|
|
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({
|
|
1350
1484
|
"& .cm-hr": {
|
|
1351
|
-
// TODO(burdon): ???
|
|
1352
1485
|
// Note that block-level decorations should not have vertical margins,
|
|
1353
|
-
|
|
1486
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1354
1487
|
}
|
|
1355
1488
|
});
|
|
1356
1489
|
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1357
|
-
|
|
1358
|
-
super();
|
|
1359
|
-
this._pos = _pos;
|
|
1360
|
-
}
|
|
1361
|
-
eq(other) {
|
|
1362
|
-
return this._pos === other._pos;
|
|
1363
|
-
}
|
|
1364
|
-
toDOM(view) {
|
|
1490
|
+
toDOM() {
|
|
1365
1491
|
const el = document.createElement("div");
|
|
1366
1492
|
el.className = "cm-hr";
|
|
1367
1493
|
return el;
|
|
1368
1494
|
}
|
|
1369
1495
|
};
|
|
1370
|
-
var
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
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
|
|
1390
1530
|
})
|
|
1391
|
-
|
|
1392
|
-
|
|
1531
|
+
];
|
|
1532
|
+
};
|
|
1393
1533
|
|
|
1394
1534
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1395
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1396
|
-
import {
|
|
1397
|
-
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";
|
|
1398
1538
|
var image = (options = {}) => {
|
|
1399
|
-
return
|
|
1400
|
-
create: (state) =>
|
|
1401
|
-
|
|
1402
|
-
|
|
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)
|
|
1403
1565
|
});
|
|
1404
1566
|
};
|
|
1405
|
-
var
|
|
1406
|
-
const
|
|
1567
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1568
|
+
const decorations = [];
|
|
1407
1569
|
const cursor = state.selection.main.head;
|
|
1408
|
-
|
|
1570
|
+
syntaxTree2(state).iterate({
|
|
1409
1571
|
enter: (node) => {
|
|
1410
1572
|
if (node.name === "Image") {
|
|
1411
1573
|
const urlNode = node.node.getChild("URL");
|
|
1412
1574
|
if (urlNode) {
|
|
1413
1575
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1414
1576
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1415
|
-
|
|
1577
|
+
decorations.push(Decoration5.replace({
|
|
1416
1578
|
block: true,
|
|
1417
1579
|
widget: new ImageWidget(url)
|
|
1418
|
-
}));
|
|
1580
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1419
1581
|
}
|
|
1420
1582
|
}
|
|
1421
|
-
}
|
|
1583
|
+
},
|
|
1584
|
+
from,
|
|
1585
|
+
to
|
|
1422
1586
|
});
|
|
1423
|
-
return
|
|
1587
|
+
return decorations;
|
|
1424
1588
|
};
|
|
1425
1589
|
var ImageWidget = class extends WidgetType3 {
|
|
1426
1590
|
constructor(_url) {
|
|
1427
1591
|
super();
|
|
1428
1592
|
this._url = _url;
|
|
1429
1593
|
}
|
|
1430
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1431
1594
|
eq(other) {
|
|
1432
1595
|
return this._url === other._url;
|
|
1433
1596
|
}
|
|
@@ -1435,22 +1598,29 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1435
1598
|
const img = document.createElement("img");
|
|
1436
1599
|
img.setAttribute("src", this._url);
|
|
1437
1600
|
img.setAttribute("class", "cm-image");
|
|
1601
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1438
1602
|
return img;
|
|
1439
1603
|
}
|
|
1440
1604
|
};
|
|
1441
1605
|
|
|
1442
1606
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1443
|
-
import { syntaxTree as
|
|
1444
|
-
import { RangeSetBuilder as RangeSetBuilder2
|
|
1445
|
-
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";
|
|
1446
1610
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1447
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1448
1611
|
var link = (options = {}) => {
|
|
1449
1612
|
const extensions = [
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
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
|
|
1454
1624
|
})
|
|
1455
1625
|
];
|
|
1456
1626
|
if (options.onHover) {
|
|
@@ -1458,35 +1628,25 @@ var link = (options = {}) => {
|
|
|
1458
1628
|
// https://codemirror.net/examples/tooltip
|
|
1459
1629
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1460
1630
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1461
|
-
hoverTooltip2((view, pos) => {
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1464
|
-
let
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
match = void 0;
|
|
1470
|
-
break;
|
|
1471
|
-
}
|
|
1472
|
-
idx = text.indexOf(match[0]);
|
|
1473
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1474
|
-
break;
|
|
1475
|
-
}
|
|
1476
|
-
idx += match[0].length;
|
|
1477
|
-
} while (true);
|
|
1478
|
-
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) {
|
|
1479
1639
|
return null;
|
|
1480
1640
|
}
|
|
1481
|
-
const
|
|
1641
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1482
1642
|
return {
|
|
1483
|
-
pos:
|
|
1484
|
-
end:
|
|
1643
|
+
pos: link2.from,
|
|
1644
|
+
end: link2.to,
|
|
1485
1645
|
above: true,
|
|
1486
1646
|
create: () => {
|
|
1487
1647
|
const el = document.createElement("div");
|
|
1488
1648
|
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1489
|
-
options.onHover(el,
|
|
1649
|
+
options.onHover(el, urlText);
|
|
1490
1650
|
return {
|
|
1491
1651
|
dom: el,
|
|
1492
1652
|
offset: {
|
|
@@ -1502,14 +1662,13 @@ var link = (options = {}) => {
|
|
|
1502
1662
|
return extensions;
|
|
1503
1663
|
};
|
|
1504
1664
|
var LinkButton = class extends WidgetType4 {
|
|
1505
|
-
constructor(
|
|
1665
|
+
constructor(_url, _onAttach) {
|
|
1506
1666
|
super();
|
|
1507
|
-
this._pos = _pos;
|
|
1508
1667
|
this._url = _url;
|
|
1509
1668
|
this._onAttach = _onAttach;
|
|
1510
1669
|
}
|
|
1511
1670
|
eq(other) {
|
|
1512
|
-
return this.
|
|
1671
|
+
return this._url === other._url;
|
|
1513
1672
|
}
|
|
1514
1673
|
toDOM(view) {
|
|
1515
1674
|
const el = document.createElement("span");
|
|
@@ -1546,74 +1705,77 @@ var LinkText = class extends WidgetType4 {
|
|
|
1546
1705
|
return link2;
|
|
1547
1706
|
}
|
|
1548
1707
|
};
|
|
1549
|
-
var
|
|
1708
|
+
var buildDecorations3 = (view, options) => {
|
|
1550
1709
|
const builder = new RangeSetBuilder2();
|
|
1710
|
+
const { state } = view;
|
|
1551
1711
|
const cursor = state.selection.main.head;
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
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
|
+
}
|
|
1560
1733
|
return false;
|
|
1561
1734
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
if (options.onRender) {
|
|
1568
|
-
builder.add(node.to, node.to, Decoration5.replace({
|
|
1569
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1570
|
-
}));
|
|
1571
|
-
}
|
|
1572
|
-
return false;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1735
|
+
},
|
|
1736
|
+
from,
|
|
1737
|
+
to
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1576
1740
|
return builder.finish();
|
|
1577
1741
|
};
|
|
1578
1742
|
|
|
1579
1743
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1580
|
-
import { EditorView as
|
|
1744
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1581
1745
|
var listener = ({ onFocus, onChange }) => {
|
|
1582
1746
|
const extensions = [];
|
|
1583
|
-
onFocus && extensions.push(
|
|
1747
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1584
1748
|
onFocus(focused);
|
|
1585
1749
|
return null;
|
|
1586
1750
|
}));
|
|
1587
|
-
onChange && extensions.push(
|
|
1588
|
-
onChange(
|
|
1751
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1752
|
+
onChange(update2.state.doc.toString());
|
|
1589
1753
|
}));
|
|
1590
1754
|
return extensions;
|
|
1591
1755
|
};
|
|
1592
1756
|
|
|
1593
1757
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1594
1758
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1595
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1596
|
-
import { markdownLanguage as
|
|
1759
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1760
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1597
1761
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1598
1762
|
import { languages } from "@codemirror/language-data";
|
|
1599
1763
|
import { searchKeymap } from "@codemirror/search";
|
|
1600
1764
|
import { EditorState } from "@codemirror/state";
|
|
1601
1765
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1602
|
-
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";
|
|
1603
1767
|
|
|
1604
1768
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1605
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1769
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1606
1770
|
import { HighlightStyle } from "@codemirror/language";
|
|
1607
1771
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1608
1772
|
import { Table } from "@lezer/markdown";
|
|
1609
|
-
import get4 from "lodash.get";
|
|
1610
1773
|
var markdownTags = {
|
|
1611
1774
|
Blockquote: Tag.define(),
|
|
1612
1775
|
CodeMark: Tag.define(),
|
|
1613
1776
|
CodeText: Tag.define(),
|
|
1614
1777
|
EmphasisMark: Tag.define(),
|
|
1615
1778
|
HeaderMark: Tag.define(),
|
|
1616
|
-
// HorizontalRule: Tag.define(),
|
|
1617
1779
|
InlineCode: Tag.define(),
|
|
1618
1780
|
LinkLabel: Tag.define(),
|
|
1619
1781
|
LinkReference: Tag.define(),
|
|
@@ -1777,12 +1939,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1777
1939
|
],
|
|
1778
1940
|
class: blockquote
|
|
1779
1941
|
},
|
|
1780
|
-
// TODO(burdon): Replace with extension.
|
|
1781
|
-
// {
|
|
1782
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1783
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1784
|
-
// },
|
|
1785
|
-
// TODO(burdon): Only if being edited.
|
|
1786
1942
|
{
|
|
1787
1943
|
tag: [
|
|
1788
1944
|
markdownTags.TableCell
|
|
@@ -1790,9 +1946,9 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1790
1946
|
class: "font-mono"
|
|
1791
1947
|
}
|
|
1792
1948
|
], {
|
|
1793
|
-
scope:
|
|
1949
|
+
scope: markdownLanguage2,
|
|
1794
1950
|
all: {
|
|
1795
|
-
fontFamily:
|
|
1951
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1796
1952
|
}
|
|
1797
1953
|
});
|
|
1798
1954
|
};
|
|
@@ -1802,17 +1958,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1802
1958
|
return [
|
|
1803
1959
|
EditorState.allowMultipleSelections.of(true),
|
|
1804
1960
|
EditorState.tabSize.of(2),
|
|
1805
|
-
|
|
1806
|
-
|
|
1961
|
+
EditorView10.lineWrapping,
|
|
1962
|
+
// https://github.com/codemirror/basic-setup
|
|
1807
1963
|
bracketMatching2(),
|
|
1808
1964
|
closeBrackets2(),
|
|
1809
1965
|
crosshairCursor(),
|
|
1810
1966
|
dropCursor(),
|
|
1811
1967
|
drawSelection2(),
|
|
1812
|
-
|
|
1813
|
-
|
|
1968
|
+
highlightActiveLine2(),
|
|
1969
|
+
history2(),
|
|
1814
1970
|
indentOnInput(),
|
|
1815
|
-
_placeholder
|
|
1971
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1816
1972
|
// Main extension.
|
|
1817
1973
|
// https://github.com/codemirror/lang-markdown
|
|
1818
1974
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1822,7 +1978,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1822
1978
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1823
1979
|
// https://github.github.com/gfm
|
|
1824
1980
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1825
|
-
base:
|
|
1981
|
+
base: markdownLanguage3,
|
|
1826
1982
|
// Languages for syntax highlighting fenced code blocks.
|
|
1827
1983
|
codeLanguages: languages,
|
|
1828
1984
|
// Parser extensions.
|
|
@@ -1834,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1834
1990
|
// https://github.com/codemirror/theme-one-dark
|
|
1835
1991
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1836
1992
|
// Custom styles.
|
|
1837
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
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
|
+
};
|
|
1852
2008
|
|
|
1853
2009
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1854
2010
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1855
2011
|
var mention = ({ onSearch }) => {
|
|
1856
2012
|
return autocompletion2({
|
|
2013
|
+
// TODO(burdon): Not working.
|
|
2014
|
+
activateOnTyping: true,
|
|
2015
|
+
// activateOnTypingDelay: 100,
|
|
2016
|
+
// selectOnOpen: true,
|
|
1857
2017
|
closeOnBlur: false,
|
|
2018
|
+
// defaultKeymap: false,
|
|
2019
|
+
icons: false,
|
|
1858
2020
|
override: [
|
|
1859
2021
|
(context) => {
|
|
2022
|
+
console.log(context);
|
|
1860
2023
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1861
2024
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1862
2025
|
return null;
|
|
1863
2026
|
}
|
|
1864
|
-
console.log(match);
|
|
1865
2027
|
return {
|
|
1866
2028
|
from: match.from,
|
|
1867
2029
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1873,23 +2035,23 @@ var mention = ({ onSearch }) => {
|
|
|
1873
2035
|
});
|
|
1874
2036
|
};
|
|
1875
2037
|
|
|
1876
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1877
|
-
var
|
|
2038
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2039
|
+
var outliner = (options = {}) => {
|
|
1878
2040
|
return [];
|
|
1879
2041
|
};
|
|
1880
2042
|
|
|
1881
2043
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1882
|
-
import { syntaxTree as
|
|
1883
|
-
import { RangeSetBuilder as RangeSetBuilder3, StateField as
|
|
1884
|
-
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";
|
|
1885
2047
|
var table = (options = {}) => {
|
|
1886
|
-
return
|
|
1887
|
-
create: (state) =>
|
|
1888
|
-
update: (_, tr) =>
|
|
1889
|
-
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)
|
|
1890
2052
|
});
|
|
1891
2053
|
};
|
|
1892
|
-
var
|
|
2054
|
+
var update = (state, options) => {
|
|
1893
2055
|
const builder = new RangeSetBuilder3();
|
|
1894
2056
|
const cursor = state.selection.main.head;
|
|
1895
2057
|
const tables = [];
|
|
@@ -1898,7 +2060,7 @@ var update3 = (state, options) => {
|
|
|
1898
2060
|
const table2 = getTable();
|
|
1899
2061
|
return table2.rows?.[table2.rows.length - 1];
|
|
1900
2062
|
};
|
|
1901
|
-
|
|
2063
|
+
syntaxTree4(state).iterate({
|
|
1902
2064
|
enter: (node) => {
|
|
1903
2065
|
switch (node.name) {
|
|
1904
2066
|
case "Table": {
|
|
@@ -1930,11 +2092,10 @@ var update3 = (state, options) => {
|
|
|
1930
2092
|
});
|
|
1931
2093
|
tables.forEach((table2) => {
|
|
1932
2094
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1933
|
-
hide && builder.add(table2.from, table2.to,
|
|
1934
|
-
block: true,
|
|
2095
|
+
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
1935
2096
|
widget: new TableWidget(table2)
|
|
1936
2097
|
}));
|
|
1937
|
-
builder.add(table2.from, table2.to,
|
|
2098
|
+
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
1938
2099
|
class: "cm-table"
|
|
1939
2100
|
}));
|
|
1940
2101
|
});
|
|
@@ -1946,7 +2107,7 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1946
2107
|
this._table = _table;
|
|
1947
2108
|
}
|
|
1948
2109
|
eq(other) {
|
|
1949
|
-
return this._table.
|
|
2110
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1950
2111
|
}
|
|
1951
2112
|
toDOM(view) {
|
|
1952
2113
|
const table2 = document.createElement("table");
|
|
@@ -1972,90 +2133,105 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1972
2133
|
}
|
|
1973
2134
|
return table2;
|
|
1974
2135
|
}
|
|
2136
|
+
ignoreEvent(e) {
|
|
2137
|
+
return !/^mouse/.test(e.type);
|
|
2138
|
+
}
|
|
1975
2139
|
};
|
|
1976
2140
|
|
|
1977
2141
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
1978
|
-
import {
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
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"
|
|
1983
2152
|
}
|
|
1984
2153
|
});
|
|
1985
2154
|
var CheckboxWidget = class extends WidgetType6 {
|
|
1986
|
-
constructor(
|
|
2155
|
+
constructor(_checked) {
|
|
1987
2156
|
super();
|
|
1988
|
-
this._pos = _pos;
|
|
1989
2157
|
this._checked = _checked;
|
|
1990
|
-
this._indent = _indent;
|
|
1991
|
-
this._onCheck = _onCheck;
|
|
1992
2158
|
}
|
|
1993
2159
|
eq(other) {
|
|
1994
|
-
return this.
|
|
2160
|
+
return this._checked === other._checked;
|
|
1995
2161
|
}
|
|
1996
2162
|
toDOM(view) {
|
|
1997
|
-
const
|
|
1998
|
-
|
|
1999
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2000
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2001
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2163
|
+
const input = document.createElement("input");
|
|
2164
|
+
input.className = "cm-task-checkbox";
|
|
2002
2165
|
input.type = "checkbox";
|
|
2003
2166
|
input.checked = this._checked;
|
|
2004
|
-
if (
|
|
2167
|
+
if (view.state.readOnly) {
|
|
2005
2168
|
input.setAttribute("disabled", "true");
|
|
2006
|
-
}
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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
|
+
}
|
|
2011
2183
|
};
|
|
2012
2184
|
}
|
|
2013
|
-
return
|
|
2185
|
+
return input;
|
|
2014
2186
|
}
|
|
2015
2187
|
ignoreEvent() {
|
|
2016
2188
|
return false;
|
|
2017
2189
|
}
|
|
2018
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
|
+
};
|
|
2019
2220
|
var tasklist = (options = {}) => {
|
|
2020
|
-
const taskMatcher = new MatchDecorator3({
|
|
2021
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2022
|
-
decoration: (match, view, pos) => {
|
|
2023
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2024
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2025
|
-
return Decoration7.replace({
|
|
2026
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2027
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2028
|
-
view.dispatch({
|
|
2029
|
-
changes: {
|
|
2030
|
-
from: idx,
|
|
2031
|
-
to: idx + 1,
|
|
2032
|
-
insert: checked2 ? "x" : " "
|
|
2033
|
-
},
|
|
2034
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2035
|
-
selection: {
|
|
2036
|
-
anchor: idx + 3
|
|
2037
|
-
}
|
|
2038
|
-
});
|
|
2039
|
-
})
|
|
2040
|
-
});
|
|
2041
|
-
}
|
|
2042
|
-
});
|
|
2043
|
-
const tasks = ViewPlugin5.fromClass(class {
|
|
2044
|
-
constructor(view) {
|
|
2045
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2046
|
-
}
|
|
2047
|
-
update(update4) {
|
|
2048
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
2049
|
-
}
|
|
2050
|
-
}, {
|
|
2051
|
-
decorations: (value) => value.tasks,
|
|
2052
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2053
|
-
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
2054
|
-
})
|
|
2055
|
-
});
|
|
2056
2221
|
return [
|
|
2057
|
-
|
|
2058
|
-
|
|
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
|
|
2059
2235
|
];
|
|
2060
2236
|
};
|
|
2061
2237
|
|
|
@@ -2117,7 +2293,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2117
2293
|
};
|
|
2118
2294
|
|
|
2119
2295
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2120
|
-
import
|
|
2296
|
+
import get3 from "lodash.get";
|
|
2121
2297
|
var defaultTheme = {
|
|
2122
2298
|
//
|
|
2123
2299
|
// Main layout:
|
|
@@ -2146,21 +2322,21 @@ var defaultTheme = {
|
|
|
2146
2322
|
"&.cm-focused": {
|
|
2147
2323
|
outline: "none"
|
|
2148
2324
|
},
|
|
2149
|
-
"
|
|
2325
|
+
".cm-scroller": {
|
|
2150
2326
|
overflow: "visible",
|
|
2151
|
-
fontFamily:
|
|
2327
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2152
2328
|
},
|
|
2153
|
-
"
|
|
2329
|
+
".cm-content": {
|
|
2154
2330
|
padding: 0,
|
|
2155
2331
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2156
2332
|
fontSize: "16px"
|
|
2157
2333
|
},
|
|
2158
2334
|
"&light .cm-content": {
|
|
2159
|
-
color:
|
|
2335
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2160
2336
|
caretColor: "black"
|
|
2161
2337
|
},
|
|
2162
2338
|
"&dark .cm-content": {
|
|
2163
|
-
color:
|
|
2339
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2164
2340
|
caretColor: "white"
|
|
2165
2341
|
},
|
|
2166
2342
|
//
|
|
@@ -2172,158 +2348,120 @@ var defaultTheme = {
|
|
|
2172
2348
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2173
2349
|
borderLeft: "2px solid white"
|
|
2174
2350
|
},
|
|
2175
|
-
"
|
|
2351
|
+
".cm-placeholder": {
|
|
2176
2352
|
fontWeight: 100
|
|
2177
2353
|
},
|
|
2178
2354
|
//
|
|
2179
2355
|
// line
|
|
2180
2356
|
//
|
|
2181
|
-
"
|
|
2357
|
+
".cm-line": {
|
|
2182
2358
|
paddingInline: 0
|
|
2183
2359
|
},
|
|
2184
|
-
"
|
|
2360
|
+
".cm-activeLine": {
|
|
2185
2361
|
background: "inherit"
|
|
2186
2362
|
},
|
|
2187
2363
|
//
|
|
2188
2364
|
// Selection
|
|
2189
2365
|
//
|
|
2190
2366
|
"&light .cm-selectionBackground": {
|
|
2191
|
-
background:
|
|
2367
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2192
2368
|
},
|
|
2193
2369
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2194
|
-
background:
|
|
2370
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2195
2371
|
},
|
|
2196
2372
|
"&dark .cm-selectionBackground": {
|
|
2197
|
-
background:
|
|
2373
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2198
2374
|
},
|
|
2199
2375
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2200
|
-
background:
|
|
2376
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2201
2377
|
},
|
|
2202
2378
|
//
|
|
2203
2379
|
// Search
|
|
2204
2380
|
//
|
|
2205
2381
|
"&light .cm-searchMatch": {
|
|
2206
|
-
backgroundColor:
|
|
2382
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2207
2383
|
},
|
|
2208
2384
|
"&dark .cm-searchMatch": {
|
|
2209
|
-
backgroundColor:
|
|
2210
|
-
},
|
|
2211
|
-
//
|
|
2212
|
-
// collaboration
|
|
2213
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2214
|
-
//
|
|
2215
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2216
|
-
mixBlendMode: "multiply"
|
|
2217
|
-
},
|
|
2218
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2219
|
-
mixBlendMode: "screen"
|
|
2220
|
-
},
|
|
2221
|
-
"& .cm-ySelectionInfo": {
|
|
2222
|
-
padding: "2px 4px",
|
|
2223
|
-
marginBlockStart: "-4px"
|
|
2224
|
-
},
|
|
2225
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2226
|
-
paddingBlockStart: ".15em",
|
|
2227
|
-
paddingBlockEnd: ".15em"
|
|
2228
|
-
},
|
|
2229
|
-
"& .cm-ySelectionCaret": {
|
|
2230
|
-
display: "inline-block",
|
|
2231
|
-
insetBlockStart: ".1em",
|
|
2232
|
-
blockSize: "1.4em",
|
|
2233
|
-
verticalAlign: "top"
|
|
2234
|
-
},
|
|
2235
|
-
"& .cm-yLineSelection": {
|
|
2236
|
-
margin: 0
|
|
2385
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2237
2386
|
},
|
|
2238
2387
|
//
|
|
2239
2388
|
// link
|
|
2240
2389
|
//
|
|
2241
|
-
"
|
|
2242
|
-
color:
|
|
2390
|
+
".cm-link": {
|
|
2391
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2243
2392
|
textDecorationLine: "underline",
|
|
2244
2393
|
textDecorationThickness: "1px",
|
|
2245
2394
|
textUnderlineOffset: "2px",
|
|
2246
2395
|
borderRadius: ".125rem",
|
|
2247
|
-
fontFamily:
|
|
2396
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2248
2397
|
},
|
|
2249
2398
|
//
|
|
2250
2399
|
// tooltip
|
|
2251
2400
|
//
|
|
2252
|
-
"
|
|
2401
|
+
".cm-tooltip": {
|
|
2253
2402
|
border: "none"
|
|
2254
2403
|
},
|
|
2255
|
-
"
|
|
2404
|
+
".cm-tooltip-below": {},
|
|
2256
2405
|
//
|
|
2257
2406
|
// autocomplete
|
|
2258
2407
|
//
|
|
2259
|
-
"
|
|
2408
|
+
".cm-tooltip-autocomplete": {
|
|
2260
2409
|
marginTop: "4px",
|
|
2261
2410
|
marginLeft: "-3px"
|
|
2262
2411
|
},
|
|
2263
|
-
"
|
|
2264
|
-
"
|
|
2265
|
-
"
|
|
2412
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2413
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2414
|
+
".cm-completionIcon": {
|
|
2266
2415
|
display: "none"
|
|
2267
2416
|
},
|
|
2268
|
-
"
|
|
2269
|
-
fontFamily:
|
|
2417
|
+
".cm-completionLabel": {
|
|
2418
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2270
2419
|
},
|
|
2271
|
-
"
|
|
2420
|
+
".cm-completionMatchedText": {
|
|
2272
2421
|
textDecoration: "none"
|
|
2273
2422
|
},
|
|
2274
2423
|
//
|
|
2275
|
-
// widgets
|
|
2276
|
-
//
|
|
2277
|
-
"& .cm-widgetBuffer": {
|
|
2278
|
-
display: "none",
|
|
2279
|
-
height: 0
|
|
2280
|
-
},
|
|
2281
|
-
//
|
|
2282
2424
|
// table
|
|
2283
2425
|
//
|
|
2284
|
-
"
|
|
2285
|
-
fontFamily: `${
|
|
2426
|
+
".cm-table *": {
|
|
2427
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2286
2428
|
textDecoration: "none !important"
|
|
2287
2429
|
},
|
|
2288
|
-
"
|
|
2430
|
+
".cm-table-head": {
|
|
2289
2431
|
padding: "2px 16px 2px 0px",
|
|
2290
|
-
borderBottom: `1px solid ${
|
|
2432
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2291
2433
|
fontWeight: 100,
|
|
2292
2434
|
textAlign: "left",
|
|
2293
|
-
color:
|
|
2435
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2294
2436
|
},
|
|
2295
|
-
"
|
|
2437
|
+
".cm-table-cell": {
|
|
2296
2438
|
padding: "2px 16px 2px 0px"
|
|
2297
2439
|
},
|
|
2298
2440
|
//
|
|
2299
2441
|
// image
|
|
2300
2442
|
//
|
|
2301
|
-
"
|
|
2302
|
-
|
|
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"
|
|
2303
2451
|
},
|
|
2304
2452
|
//
|
|
2305
2453
|
// font size
|
|
2306
|
-
// 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.
|
|
2307
2456
|
//
|
|
2308
|
-
...Object.keys(
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2317
|
-
height
|
|
2318
|
-
};
|
|
2319
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2320
|
-
height
|
|
2321
|
-
};
|
|
2322
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2323
|
-
height
|
|
2324
|
-
};
|
|
2325
|
-
return acc;
|
|
2326
|
-
}, {}),
|
|
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
|
+
// }, {}),
|
|
2327
2465
|
/**
|
|
2328
2466
|
* Panels
|
|
2329
2467
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2340,144 +2478,140 @@ var defaultTheme = {
|
|
|
2340
2478
|
* </div>
|
|
2341
2479
|
* </div
|
|
2342
2480
|
*/
|
|
2343
|
-
"
|
|
2344
|
-
border: `1px solid ${
|
|
2481
|
+
".cm-panels": {
|
|
2482
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2345
2483
|
},
|
|
2346
|
-
"
|
|
2347
|
-
background:
|
|
2348
|
-
fontFamily:
|
|
2484
|
+
".cm-panel": {
|
|
2485
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2486
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2349
2487
|
},
|
|
2350
|
-
"
|
|
2488
|
+
".cm-button": {
|
|
2351
2489
|
margin: "4px",
|
|
2352
|
-
fontFamily:
|
|
2353
|
-
background:
|
|
2490
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2491
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2354
2492
|
backgroundImage: "none",
|
|
2355
2493
|
border: "none",
|
|
2356
2494
|
"&:hover": {
|
|
2357
|
-
background:
|
|
2495
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2358
2496
|
},
|
|
2359
2497
|
"&:active": {
|
|
2360
|
-
background:
|
|
2498
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2361
2499
|
backgroundImage: "none"
|
|
2362
2500
|
}
|
|
2363
2501
|
},
|
|
2364
|
-
"
|
|
2502
|
+
".cm-panel input[type=checkbox]": {
|
|
2365
2503
|
marginRight: "0.4rem !important"
|
|
2366
2504
|
}
|
|
2367
2505
|
};
|
|
2368
2506
|
var textTheme = {
|
|
2369
|
-
"
|
|
2370
|
-
fontFamily:
|
|
2507
|
+
".cm-scroller": {
|
|
2508
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2371
2509
|
},
|
|
2372
|
-
"
|
|
2373
|
-
fontFamily:
|
|
2510
|
+
".cm-placeholder": {
|
|
2511
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2374
2512
|
}
|
|
2375
2513
|
};
|
|
2376
2514
|
var markdownTheme = {
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2515
|
+
".cm-scroller": {
|
|
2516
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2517
|
+
},
|
|
2518
|
+
".cm-placeholder": {
|
|
2519
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2380
2520
|
}
|
|
2381
2521
|
};
|
|
2382
2522
|
var codeTheme = {
|
|
2383
|
-
"
|
|
2384
|
-
fontFamily:
|
|
2523
|
+
".cm-scroller": {
|
|
2524
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2385
2525
|
},
|
|
2386
|
-
"
|
|
2387
|
-
fontFamily:
|
|
2526
|
+
".cm-placeholder": {
|
|
2527
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2388
2528
|
}
|
|
2389
2529
|
};
|
|
2390
2530
|
|
|
2391
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";
|
|
2392
2533
|
var EditorModes = [
|
|
2393
2534
|
"default",
|
|
2394
2535
|
"vim"
|
|
2395
2536
|
];
|
|
2396
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2397
|
-
const { themeMode } = useThemeContext();
|
|
2537
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2398
2538
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2399
2539
|
tabBehavior: "limited"
|
|
2400
2540
|
});
|
|
2401
|
-
const
|
|
2402
|
-
const
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
state,
|
|
2541
|
+
const { themeMode } = useThemeContext();
|
|
2542
|
+
const rootRef = useRef(null);
|
|
2543
|
+
const [view, setView] = useState(null);
|
|
2544
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2406
2545
|
view
|
|
2407
|
-
}), [
|
|
2408
|
-
view,
|
|
2409
|
-
state,
|
|
2410
|
-
root
|
|
2411
|
-
]);
|
|
2412
|
-
const { awareness, peer } = model;
|
|
2413
|
-
useEffect2(() => {
|
|
2414
|
-
if (awareness && peer) {
|
|
2415
|
-
awareness.setLocalStateField("user", {
|
|
2416
|
-
name: peer.name ?? generateName(peer.id),
|
|
2417
|
-
color: getColorForValue({
|
|
2418
|
-
value: peer.id,
|
|
2419
|
-
type: "color"
|
|
2420
|
-
}),
|
|
2421
|
-
colorLight: getColorForValue({
|
|
2422
|
-
value: peer.id,
|
|
2423
|
-
themeMode,
|
|
2424
|
-
type: "highlight"
|
|
2425
|
-
})
|
|
2426
|
-
});
|
|
2427
|
-
}
|
|
2428
|
-
}, [
|
|
2429
|
-
awareness,
|
|
2430
|
-
peer,
|
|
2431
|
-
themeMode
|
|
2432
2546
|
]);
|
|
2433
2547
|
useEffect2(() => {
|
|
2434
|
-
if (
|
|
2435
|
-
view
|
|
2436
|
-
effects: setCommentRange.of({
|
|
2437
|
-
model,
|
|
2438
|
-
comments: comments2
|
|
2439
|
-
})
|
|
2440
|
-
});
|
|
2548
|
+
if (autoFocus) {
|
|
2549
|
+
view?.focus();
|
|
2441
2550
|
}
|
|
2442
2551
|
}, [
|
|
2443
2552
|
view,
|
|
2444
|
-
|
|
2553
|
+
autoFocus
|
|
2445
2554
|
]);
|
|
2446
2555
|
useEffect2(() => {
|
|
2447
|
-
if (!
|
|
2556
|
+
if (!model || !rootRef.current) {
|
|
2448
2557
|
return;
|
|
2449
2558
|
}
|
|
2450
|
-
const
|
|
2559
|
+
const state = EditorState2.create({
|
|
2451
2560
|
doc: model.text(),
|
|
2561
|
+
selection,
|
|
2452
2562
|
extensions: [
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
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
|
+
}),
|
|
2456
2572
|
// Theme.
|
|
2457
|
-
// TODO(burdon): Make
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
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),
|
|
2461
2585
|
// Storage and replication.
|
|
2586
|
+
// NOTE: This must come before user extensions.
|
|
2462
2587
|
model.extension,
|
|
2588
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2589
|
+
editorMode === "vim" && vim(),
|
|
2463
2590
|
// Custom.
|
|
2464
2591
|
...extensions
|
|
2465
2592
|
].filter(Boolean)
|
|
2466
2593
|
});
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
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
|
+
}
|
|
2474
2606
|
});
|
|
2607
|
+
view?.destroy();
|
|
2608
|
+
setView(newView);
|
|
2475
2609
|
return () => {
|
|
2476
|
-
|
|
2477
|
-
|
|
2610
|
+
newView?.destroy();
|
|
2611
|
+
setView(null);
|
|
2478
2612
|
};
|
|
2479
2613
|
}, [
|
|
2480
|
-
|
|
2614
|
+
rootRef,
|
|
2481
2615
|
model,
|
|
2482
2616
|
readonly,
|
|
2483
2617
|
editorMode,
|
|
@@ -2487,11 +2621,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2487
2621
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2488
2622
|
switch (key) {
|
|
2489
2623
|
case "Enter": {
|
|
2490
|
-
view?.
|
|
2624
|
+
view?.focus();
|
|
2491
2625
|
break;
|
|
2492
2626
|
}
|
|
2493
2627
|
case "Escape": {
|
|
2494
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2628
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2629
|
+
rootRef.current?.focus();
|
|
2630
|
+
}
|
|
2495
2631
|
break;
|
|
2496
2632
|
}
|
|
2497
2633
|
}
|
|
@@ -2501,106 +2637,305 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2501
2637
|
]);
|
|
2502
2638
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2503
2639
|
key: model.id,
|
|
2504
|
-
|
|
2640
|
+
role: "none",
|
|
2505
2641
|
tabIndex: 0,
|
|
2506
|
-
|
|
2642
|
+
onKeyUp: handleKeyUp,
|
|
2643
|
+
...slots.root,
|
|
2507
2644
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2508
|
-
|
|
2645
|
+
ref: rootRef
|
|
2509
2646
|
});
|
|
2510
2647
|
});
|
|
2511
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2648
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2512
2649
|
const { themeMode } = useThemeContext();
|
|
2513
|
-
const
|
|
2650
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2514
2651
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2515
2652
|
ref: forwardedRef,
|
|
2516
2653
|
readonly,
|
|
2517
2654
|
extensions: [
|
|
2518
2655
|
basicBundle({
|
|
2519
|
-
readonly,
|
|
2520
2656
|
themeMode,
|
|
2521
|
-
placeholder:
|
|
2657
|
+
placeholder: placeholder3,
|
|
2658
|
+
lineWrapping
|
|
2522
2659
|
}),
|
|
2523
2660
|
...extensions
|
|
2524
2661
|
],
|
|
2525
|
-
|
|
2662
|
+
theme,
|
|
2663
|
+
slots: updatedSlots,
|
|
2526
2664
|
...props
|
|
2527
2665
|
});
|
|
2528
2666
|
});
|
|
2529
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2667
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2530
2668
|
const { themeMode } = useThemeContext();
|
|
2531
|
-
const
|
|
2669
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2532
2670
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2533
2671
|
ref: forwardedRef,
|
|
2534
2672
|
readonly,
|
|
2535
2673
|
extensions: [
|
|
2536
2674
|
markdownBundle({
|
|
2537
|
-
readonly,
|
|
2538
2675
|
themeMode,
|
|
2539
|
-
|
|
2676
|
+
readonly,
|
|
2677
|
+
placeholder: placeholder3
|
|
2540
2678
|
}),
|
|
2541
2679
|
...extensions
|
|
2542
2680
|
],
|
|
2543
|
-
|
|
2681
|
+
theme,
|
|
2682
|
+
slots: updatedSlots,
|
|
2544
2683
|
...props
|
|
2545
2684
|
});
|
|
2546
2685
|
});
|
|
2547
2686
|
var defaultSlots = {
|
|
2548
2687
|
root: {
|
|
2549
|
-
|
|
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"
|
|
2550
2693
|
}
|
|
2551
2694
|
};
|
|
2552
2695
|
var defaultTextSlots = {
|
|
2553
|
-
...defaultSlots
|
|
2554
|
-
editor: {
|
|
2555
|
-
theme: textTheme
|
|
2556
|
-
}
|
|
2696
|
+
...defaultSlots
|
|
2557
2697
|
};
|
|
2558
2698
|
var defaultMarkdownSlots = {
|
|
2559
|
-
...defaultSlots
|
|
2560
|
-
|
|
2561
|
-
|
|
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();
|
|
2562
2803
|
}
|
|
2563
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
|
+
};
|
|
2564
2888
|
export {
|
|
2889
|
+
AwarenessProvider,
|
|
2565
2890
|
BaseTextEditor,
|
|
2891
|
+
Cursor,
|
|
2566
2892
|
Doc,
|
|
2567
2893
|
EditorModes,
|
|
2568
2894
|
MarkdownEditor,
|
|
2895
|
+
RemoteSelectionsDecorator,
|
|
2569
2896
|
SpaceAwarenessProvider,
|
|
2570
2897
|
TextEditor,
|
|
2571
2898
|
TextKind,
|
|
2572
2899
|
YText,
|
|
2573
2900
|
YXmlFragment,
|
|
2574
2901
|
autocomplete,
|
|
2902
|
+
automerge3 as automerge,
|
|
2903
|
+
awareness,
|
|
2575
2904
|
basicBundle,
|
|
2576
2905
|
blast,
|
|
2906
|
+
callbackWrapper,
|
|
2577
2907
|
code2 as code,
|
|
2578
2908
|
codeTheme,
|
|
2579
2909
|
comments,
|
|
2580
|
-
cursorColor,
|
|
2581
2910
|
defaultMarkdownSlots,
|
|
2582
2911
|
defaultOptions,
|
|
2583
2912
|
defaultSlots,
|
|
2584
2913
|
defaultTextSlots,
|
|
2585
2914
|
defaultTheme,
|
|
2915
|
+
getToken,
|
|
2586
2916
|
hr,
|
|
2587
2917
|
image,
|
|
2588
2918
|
link,
|
|
2589
2919
|
listener,
|
|
2920
|
+
logChanges,
|
|
2590
2921
|
markdownBundle,
|
|
2591
2922
|
markdownHighlightStyle,
|
|
2592
2923
|
markdownTags,
|
|
2593
2924
|
markdownTagsExtensions,
|
|
2594
2925
|
markdownTheme,
|
|
2595
2926
|
mention,
|
|
2596
|
-
mermaid,
|
|
2597
2927
|
modelState,
|
|
2598
|
-
|
|
2928
|
+
outliner,
|
|
2929
|
+
setComments,
|
|
2930
|
+
setFocus,
|
|
2931
|
+
setSelection,
|
|
2599
2932
|
table,
|
|
2600
2933
|
tags2 as tags,
|
|
2601
2934
|
tasklist,
|
|
2602
2935
|
textTheme,
|
|
2603
2936
|
typewriter,
|
|
2937
|
+
useComments,
|
|
2938
|
+
useTextEditor,
|
|
2604
2939
|
useTextModel
|
|
2605
2940
|
};
|
|
2606
2941
|
//# sourceMappingURL=index.mjs.map
|