@dxos/react-ui-editor 0.3.10-main.43b334a → 0.3.10-main.4cae50a
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 +1826 -799
- 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 +59 -0
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +7 -3
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +12 -4
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts +10 -0
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/{basic/bundle.d.ts → basic.d.ts} +3 -2
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/code.d.ts +2 -0
- package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts +18 -0
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/{hyperlink/hyperlinkWidget.d.ts → experimental.d.ts} +2 -2
- package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/highlight.d.ts +24 -0
- package/dist/types/src/components/TextEditor/extensions/highlight.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
- package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +13 -2
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/link.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts +9 -0
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +10 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +37 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +12 -0
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +2 -0
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts +25 -0
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/themes/index.d.ts +2 -0
- package/dist/types/src/components/TextEditor/themes/index.d.ts.map +1 -0
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.d.ts +3 -0
- package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts +16 -0
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/handle.d.ts.map +1 -0
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/index.d.ts +1 -1
- package/dist/types/src/hooks/automerge/index.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
- package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
- package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
- package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +9 -3
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +2 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/styles/markdown.d.ts +14 -11
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/package.json +23 -32
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +367 -0
- package/src/components/TextEditor/TextEditor.stories.tsx +57 -43
- package/src/components/TextEditor/TextEditor.tsx +87 -45
- package/src/components/TextEditor/extensions/autocomplete.ts +59 -0
- package/src/components/TextEditor/extensions/{basic/bundle.ts → basic.ts} +8 -4
- package/src/components/TextEditor/extensions/blast.ts +373 -0
- package/src/components/TextEditor/extensions/code.ts +99 -0
- package/src/components/TextEditor/extensions/comments.ts +173 -0
- package/src/components/TextEditor/extensions/demo.ts +69 -0
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkWidget.tsx → experimental.tsx} +16 -21
- package/src/components/TextEditor/extensions/highlight.ts +128 -0
- package/src/components/TextEditor/extensions/image.ts +67 -0
- package/src/components/TextEditor/extensions/index.ts +13 -2
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkDecoration.ts → link.ts} +75 -38
- package/src/components/TextEditor/extensions/{change.ts → listener.ts} +5 -4
- package/src/components/TextEditor/extensions/markdown/bundle.ts +56 -49
- package/src/components/TextEditor/extensions/markdown/highlight.ts +207 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +1 -1
- package/src/components/TextEditor/extensions/mention.ts +31 -0
- package/src/components/TextEditor/extensions/table.ts +119 -0
- package/src/components/TextEditor/extensions/tasklist.ts +121 -0
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkTooltip.tsx → tooltip.tsx} +9 -9
- package/src/components/TextEditor/index.ts +3 -0
- package/src/components/TextEditor/themes/default.ts +278 -0
- package/src/components/TextEditor/themes/index.ts +5 -0
- package/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.ts +12 -9
- package/src/{automerge → hooks/automerge}/automerge.stories.tsx +6 -3
- package/src/{automerge/automerge-plugin → hooks/automerge}/plugin.ts +1 -0
- package/src/{automerge/automerge-plugin/amToCodemirror.ts → hooks/automerge/translation/automerge-to-codemirror.ts} +10 -2
- package/src/{automerge/automerge-plugin/codeMirrorToAm.ts → hooks/automerge/translation/codemirror-to-automerge.ts} +7 -4
- package/src/hooks/automerge/translation/index.ts +6 -0
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useTextModel.ts +61 -39
- package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +2 -1
- package/src/styles/markdown.ts +33 -24
- package/src/testing/replicator.ts +7 -6
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts +0 -6
- package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +0 -7
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge.stories.d.ts +0 -9
- package/dist/types/src/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +0 -3
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +0 -10
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/change.d.ts +0 -7
- package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +0 -11
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts +0 -8
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +0 -4
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts +0 -17
- package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +0 -21
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/useCollaboration.d.ts +0 -9
- package/dist/types/src/hooks/useCollaboration.d.ts.map +0 -1
- package/src/components/TextEditor/extensions/basic/index.ts +0 -6
- package/src/components/TextEditor/extensions/basic/theme.ts +0 -49
- package/src/components/TextEditor/extensions/hyperlink/index.ts +0 -7
- package/src/components/TextEditor/extensions/markdown/tags.ts +0 -38
- package/src/components/TextEditor/extensions/markdown/theme.ts +0 -265
- package/src/hooks/useCollaboration.ts +0 -45
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/handle.d.ts +0 -0
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/plugin.d.ts +0 -0
- package/src/{automerge/automerge-plugin → hooks/automerge}/handle.ts +0 -0
- package/src/{automerge/automerge-plugin → hooks/automerge}/index.ts +1 -1
|
@@ -1,162 +1,1410 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
|
-
import { Doc, YText
|
|
3
|
+
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
4
|
|
|
5
5
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
6
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
7
|
|
|
8
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
8
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/autocomplete.ts
|
|
9
|
+
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
10
|
+
import { keymap } from "@codemirror/view";
|
|
11
|
+
var autocomplete = ({ onSearch }) => {
|
|
12
|
+
return [
|
|
13
|
+
// https://codemirror.net/docs/ref/#view.keymap
|
|
14
|
+
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
15
|
+
keymap.of(completionKeymap),
|
|
16
|
+
// https://codemirror.net/examples/autocompletion
|
|
17
|
+
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
18
|
+
autocompletion({
|
|
19
|
+
// TODO(burdon): Set custom keymap.
|
|
20
|
+
// defaultKeymap: false,
|
|
21
|
+
// Don't start unless key press.
|
|
22
|
+
activateOnTyping: false,
|
|
23
|
+
// TODO(burdon): Option to create new page?
|
|
24
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
25
|
+
override: [
|
|
26
|
+
(context) => {
|
|
27
|
+
const match = context.matchBefore(/\w*/);
|
|
28
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
from: match.from,
|
|
33
|
+
options: onSearch(match.text.toLowerCase())
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic.ts
|
|
9
42
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
10
43
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
11
44
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
12
|
-
import { EditorView, placeholder } from "@codemirror/view";
|
|
13
|
-
var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
45
|
+
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
46
|
+
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
47
|
+
EditorView.lineWrapping,
|
|
48
|
+
// TODO(burdon): Compare with minimalSetup.
|
|
49
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
14
50
|
bracketMatching(),
|
|
15
51
|
closeBrackets(),
|
|
52
|
+
drawSelection(),
|
|
16
53
|
_placeholder && placeholder(_placeholder),
|
|
17
|
-
EditorView.lineWrapping,
|
|
18
54
|
// TODO(burdon): Is this required?
|
|
19
55
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
20
56
|
].filter(Boolean);
|
|
21
57
|
|
|
22
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
58
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts
|
|
59
|
+
import { EditorView as EditorView2, keymap as keymap2 } from "@codemirror/view";
|
|
60
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
61
|
+
import { invariant } from "@dxos/invariant";
|
|
62
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts";
|
|
63
|
+
var defaultOptions = {
|
|
64
|
+
effect: 2,
|
|
65
|
+
maxParticles: 200,
|
|
66
|
+
particleGravity: 0.08,
|
|
67
|
+
particleAlphaFadeout: 0.996,
|
|
68
|
+
particleSize: {
|
|
69
|
+
min: 2,
|
|
70
|
+
max: 8
|
|
71
|
+
},
|
|
72
|
+
particleNumRange: {
|
|
73
|
+
min: 5,
|
|
74
|
+
max: 10
|
|
75
|
+
},
|
|
76
|
+
particleVelocityRange: {
|
|
77
|
+
x: [
|
|
78
|
+
-1,
|
|
79
|
+
1
|
|
80
|
+
],
|
|
81
|
+
y: [
|
|
82
|
+
-3.5,
|
|
83
|
+
-1.5
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
particleShrinkRate: 0.95,
|
|
87
|
+
shakeIntensity: 5
|
|
88
|
+
};
|
|
89
|
+
var blast = (options = defaultOptions) => {
|
|
90
|
+
let blaster;
|
|
91
|
+
let last = 0;
|
|
92
|
+
const getPoint = (view, pos) => {
|
|
93
|
+
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
94
|
+
const element = document.elementFromPoint(x, y);
|
|
95
|
+
const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
|
|
96
|
+
const point = {
|
|
97
|
+
x: x - left,
|
|
98
|
+
y: y - top
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
element,
|
|
102
|
+
point
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
return [
|
|
106
|
+
// Cursor moved.
|
|
107
|
+
EditorView2.updateListener.of((update4) => {
|
|
108
|
+
if (blaster?.node !== update4.view.scrollDOM) {
|
|
109
|
+
if (blaster) {
|
|
110
|
+
blaster.destroy();
|
|
111
|
+
}
|
|
112
|
+
blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
|
|
113
|
+
particleGravity: 0.2,
|
|
114
|
+
particleShrinkRate: 0.995,
|
|
115
|
+
color: () => [
|
|
116
|
+
100 + Math.random() * 100,
|
|
117
|
+
0,
|
|
118
|
+
0
|
|
119
|
+
]
|
|
120
|
+
}, options, defaultOptions));
|
|
121
|
+
blaster.initialize();
|
|
122
|
+
blaster.start();
|
|
123
|
+
} else {
|
|
124
|
+
blaster.resize();
|
|
125
|
+
}
|
|
126
|
+
const current = update4.state.selection.main.head;
|
|
127
|
+
if (current !== last) {
|
|
128
|
+
last = current;
|
|
129
|
+
const { element, point } = getPoint(update4.view, current - 1);
|
|
130
|
+
if (element && point) {
|
|
131
|
+
blaster.spawn({
|
|
132
|
+
element,
|
|
133
|
+
point
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
keymap2.of([
|
|
139
|
+
{
|
|
140
|
+
any: (_, event) => {
|
|
141
|
+
if (blaster) {
|
|
142
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
143
|
+
blaster.shake({
|
|
144
|
+
time: 0.8
|
|
145
|
+
});
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
])
|
|
153
|
+
];
|
|
154
|
+
};
|
|
155
|
+
var Blaster = class {
|
|
156
|
+
constructor(_node, _options) {
|
|
157
|
+
this._node = _node;
|
|
158
|
+
this._options = _options;
|
|
159
|
+
this._running = false;
|
|
160
|
+
this._shakeTime = 0;
|
|
161
|
+
this._shakeTimeMax = 0;
|
|
162
|
+
this._particles = [];
|
|
163
|
+
this._particlePointer = 0;
|
|
164
|
+
this._lastPoint = {
|
|
165
|
+
x: 0,
|
|
166
|
+
y: 0
|
|
167
|
+
};
|
|
168
|
+
this.shake = throttle(({ time }) => {
|
|
169
|
+
this._shakeTime = this._shakeTimeMax || time;
|
|
170
|
+
this._shakeTimeMax = time;
|
|
171
|
+
}, 100);
|
|
172
|
+
this.spawn = throttle(({ element, point }) => {
|
|
173
|
+
const color = getRGBComponents(element, this._options.color);
|
|
174
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
175
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
176
|
+
this._lastPoint = point;
|
|
177
|
+
for (let i = numParticles; i--; i > 0) {
|
|
178
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
179
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
180
|
+
}
|
|
181
|
+
}, 100);
|
|
182
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
183
|
+
}
|
|
184
|
+
get node() {
|
|
185
|
+
return this._node;
|
|
186
|
+
}
|
|
187
|
+
initialize() {
|
|
188
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
189
|
+
F: __dxlog_file,
|
|
190
|
+
L: 138,
|
|
191
|
+
S: this,
|
|
192
|
+
A: [
|
|
193
|
+
"!this._canvas && !this._ctx",
|
|
194
|
+
""
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
this._canvas = document.createElement("canvas");
|
|
198
|
+
this._canvas.id = "code-blast-canvas";
|
|
199
|
+
this._canvas.style.position = "absolute";
|
|
200
|
+
this._canvas.style.zIndex = "0";
|
|
201
|
+
this._canvas.style.pointerEvents = "none";
|
|
202
|
+
this._ctx = this._canvas.getContext("2d");
|
|
203
|
+
const parent = this._node.parentElement?.parentElement;
|
|
204
|
+
parent?.appendChild(this._canvas);
|
|
205
|
+
this.resize();
|
|
206
|
+
}
|
|
207
|
+
destroy() {
|
|
208
|
+
this.stop();
|
|
209
|
+
if (this._canvas) {
|
|
210
|
+
this._canvas.remove();
|
|
211
|
+
this._canvas = void 0;
|
|
212
|
+
this._ctx = void 0;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
resize() {
|
|
216
|
+
if (this._node.parentElement && this._canvas) {
|
|
217
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
218
|
+
this._canvas.style.top = `${y}px`;
|
|
219
|
+
this._canvas.style.left = `${x}px`;
|
|
220
|
+
this._canvas.width = width;
|
|
221
|
+
this._canvas.height = height;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
start() {
|
|
225
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
226
|
+
F: __dxlog_file,
|
|
227
|
+
L: 177,
|
|
228
|
+
S: this,
|
|
229
|
+
A: [
|
|
230
|
+
"this._canvas && this._ctx",
|
|
231
|
+
""
|
|
232
|
+
]
|
|
233
|
+
});
|
|
234
|
+
this._running = true;
|
|
235
|
+
this.loop();
|
|
236
|
+
}
|
|
237
|
+
stop() {
|
|
238
|
+
this._running = false;
|
|
239
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
240
|
+
}
|
|
241
|
+
loop() {
|
|
242
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
246
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
247
|
+
this._lastTime ??= now;
|
|
248
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
249
|
+
this._lastTime = now;
|
|
250
|
+
if (this._shakeTime > 0) {
|
|
251
|
+
this._shakeTime -= dt;
|
|
252
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
253
|
+
const shakeX = random(-magnitude, magnitude);
|
|
254
|
+
const shakeY = random(-magnitude, magnitude);
|
|
255
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
256
|
+
}
|
|
257
|
+
this.drawParticles();
|
|
258
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
259
|
+
}
|
|
260
|
+
drawParticles() {
|
|
261
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
262
|
+
const particle = this._particles[i];
|
|
263
|
+
if (!particle) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
this._effect.update(this._ctx, particle);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
var Effect = class {
|
|
274
|
+
constructor(_options) {
|
|
275
|
+
this._options = _options;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
var Effect1 = class extends Effect {
|
|
279
|
+
create(x, y, color) {
|
|
280
|
+
return {
|
|
281
|
+
x,
|
|
282
|
+
y: y + 10,
|
|
283
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
284
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
285
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
286
|
+
color,
|
|
287
|
+
alpha: 1
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
update(ctx, particle) {
|
|
291
|
+
particle.vy += this._options.particleGravity;
|
|
292
|
+
particle.x += particle.vx;
|
|
293
|
+
particle.y += particle.vy;
|
|
294
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
295
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
296
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
var Effect2 = class extends Effect {
|
|
300
|
+
create(x, y, color) {
|
|
301
|
+
return {
|
|
302
|
+
x,
|
|
303
|
+
y: y + 10,
|
|
304
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
305
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
306
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
307
|
+
color,
|
|
308
|
+
alpha: 1,
|
|
309
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
310
|
+
drag: 0.92,
|
|
311
|
+
wander: 0.15
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
update(ctx, particle) {
|
|
315
|
+
particle.vy += this._options.particleGravity;
|
|
316
|
+
particle.x += particle.vx;
|
|
317
|
+
particle.y += particle.vy;
|
|
318
|
+
particle.vx *= particle.drag;
|
|
319
|
+
particle.vy *= particle.drag;
|
|
320
|
+
particle.theta += random(-0.5, 0.5);
|
|
321
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
322
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
323
|
+
particle.size *= this._options.particleShrinkRate;
|
|
324
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
325
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
326
|
+
ctx.beginPath();
|
|
327
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
328
|
+
ctx.fill();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
function throttle(callback, limit) {
|
|
332
|
+
let wait = false;
|
|
333
|
+
return function(...args) {
|
|
334
|
+
if (!wait) {
|
|
335
|
+
callback.apply(this, args);
|
|
336
|
+
wait = true;
|
|
337
|
+
setTimeout(() => {
|
|
338
|
+
wait = false;
|
|
339
|
+
}, limit);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
var getRGBComponents = (node, color) => {
|
|
344
|
+
if (typeof color === "function") {
|
|
345
|
+
return color();
|
|
346
|
+
}
|
|
347
|
+
const bgColor = getComputedStyle(node).color;
|
|
348
|
+
if (bgColor) {
|
|
349
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
350
|
+
if (x) {
|
|
351
|
+
return x;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return [
|
|
355
|
+
50,
|
|
356
|
+
50,
|
|
357
|
+
50
|
|
358
|
+
];
|
|
359
|
+
};
|
|
360
|
+
var random = (min, max) => {
|
|
361
|
+
if (!max) {
|
|
362
|
+
max = min;
|
|
363
|
+
min = 0;
|
|
364
|
+
}
|
|
365
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
369
|
+
import { ViewPlugin, EditorView as EditorView3, Decoration } from "@codemirror/view";
|
|
23
370
|
import get from "lodash.get";
|
|
371
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
24
372
|
|
|
25
373
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
26
374
|
import { mx } from "@dxos/react-ui-theme";
|
|
27
|
-
var
|
|
28
|
-
1:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
375
|
+
var headings = {
|
|
376
|
+
1: [
|
|
377
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
378
|
+
"-ml-[10px]"
|
|
379
|
+
],
|
|
380
|
+
2: [
|
|
381
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
382
|
+
"-ml-[8px]"
|
|
383
|
+
],
|
|
384
|
+
3: [
|
|
385
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
386
|
+
"-ml-[7px]"
|
|
387
|
+
],
|
|
388
|
+
4: [
|
|
389
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
390
|
+
"-ml-[6px]"
|
|
391
|
+
],
|
|
392
|
+
5: [
|
|
393
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
394
|
+
"-ml-[5px]"
|
|
395
|
+
],
|
|
396
|
+
6: [
|
|
397
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
398
|
+
"-ml-[4px]"
|
|
399
|
+
]
|
|
400
|
+
};
|
|
401
|
+
var heading = (level, readonly) => {
|
|
402
|
+
const [style, offset] = headings[level];
|
|
403
|
+
return mx(style, readonly && offset);
|
|
404
|
+
};
|
|
405
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
406
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
407
|
+
var bold = "font-bold";
|
|
408
|
+
var italic = "italic";
|
|
409
|
+
var strikethrough = "line-through";
|
|
410
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
411
|
+
var codeMark = "font-mono text-primary-500";
|
|
412
|
+
var inlineUrl = mx(code, "px-1");
|
|
413
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
414
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
|
|
415
|
+
|
|
416
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
417
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
418
|
+
var tokens = tailwindConfig({}).theme;
|
|
419
|
+
|
|
420
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
421
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
422
|
+
var styles = EditorView3.baseTheme({
|
|
423
|
+
"& .cm-code-block": {
|
|
424
|
+
display: "block",
|
|
425
|
+
paddingInline: "4px !important"
|
|
426
|
+
},
|
|
427
|
+
"&light .cm-code-block": {
|
|
428
|
+
background: get(tokens, "extend.colors.neutral.50")
|
|
429
|
+
},
|
|
430
|
+
"&dark .cm-code-block": {
|
|
431
|
+
background: get(tokens, "extend.colors.neutral.850")
|
|
432
|
+
},
|
|
433
|
+
"& .cm-code-block-first": {
|
|
434
|
+
paddingTop: "4px !important",
|
|
435
|
+
borderTopLeftRadius: "4px",
|
|
436
|
+
borderTopRightRadius: "4px"
|
|
437
|
+
},
|
|
438
|
+
"& .cm-code-block-last": {
|
|
439
|
+
paddingBottom: "4px !important",
|
|
440
|
+
borderBottomLeftRadius: "4px",
|
|
441
|
+
borderBottomRightRadius: "4px"
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
var getLineRange = (lines, from, to) => {
|
|
445
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
446
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
447
|
+
return [
|
|
448
|
+
start,
|
|
449
|
+
end
|
|
450
|
+
];
|
|
451
|
+
};
|
|
452
|
+
var code2 = () => {
|
|
453
|
+
const getDecorations = (view) => {
|
|
454
|
+
const decorations = [];
|
|
455
|
+
if (view.state.readOnly) {
|
|
456
|
+
const text = view.state.doc.sliceString(0);
|
|
457
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
458
|
+
const blocks = view.viewportLineBlocks;
|
|
459
|
+
for (const match of matches) {
|
|
460
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
461
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
462
|
+
const block = blocks[i];
|
|
463
|
+
decorations.push(Decoration.line({
|
|
464
|
+
class: mx2("cm-code-block", i === range[0] && "cm-code-block-first", i === range[1] && "cm-code-block-last")
|
|
465
|
+
}).range(block.from));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return Decoration.set(decorations);
|
|
470
|
+
};
|
|
471
|
+
return [
|
|
472
|
+
ViewPlugin.fromClass(class {
|
|
473
|
+
constructor(view) {
|
|
474
|
+
this.decorations = getDecorations(view);
|
|
475
|
+
}
|
|
476
|
+
update(update4) {
|
|
477
|
+
if (update4.docChanged || update4.viewportChanged) {
|
|
478
|
+
this.decorations = getDecorations(update4.view);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}, {
|
|
482
|
+
decorations: (value) => value.decorations
|
|
483
|
+
}),
|
|
484
|
+
styles
|
|
485
|
+
];
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
|
|
489
|
+
import { keymap as keymap3 } from "@codemirror/view";
|
|
490
|
+
var defaultItems = [
|
|
491
|
+
"hello world!",
|
|
492
|
+
"this is a test.",
|
|
493
|
+
"this is [DXOS](https://dxos.org)"
|
|
494
|
+
];
|
|
495
|
+
var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
496
|
+
let t;
|
|
497
|
+
let idx = 0;
|
|
498
|
+
return [
|
|
499
|
+
keymap3.of([
|
|
500
|
+
{
|
|
501
|
+
// Reset.
|
|
502
|
+
key: "alt-meta-'",
|
|
503
|
+
run: (view) => {
|
|
504
|
+
clearTimeout(t);
|
|
505
|
+
idx = 0;
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
// Next prompt.
|
|
511
|
+
// TODO(burdon): Press 1-9 to select prompt?
|
|
512
|
+
key: "shift-meta-'",
|
|
513
|
+
run: (view) => {
|
|
514
|
+
clearTimeout(t);
|
|
515
|
+
const text = items[idx++];
|
|
516
|
+
if (idx === items?.length) {
|
|
517
|
+
idx = 0;
|
|
518
|
+
}
|
|
519
|
+
let i = 0;
|
|
520
|
+
const insert = (d = 0) => {
|
|
521
|
+
t = setTimeout(() => {
|
|
522
|
+
const pos = view.state.selection.main.head;
|
|
523
|
+
view.dispatch({
|
|
524
|
+
changes: {
|
|
525
|
+
from: pos,
|
|
526
|
+
insert: text[i++]
|
|
527
|
+
},
|
|
528
|
+
selection: {
|
|
529
|
+
anchor: pos + 1
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
if (i < text.length) {
|
|
533
|
+
insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
|
|
534
|
+
}
|
|
535
|
+
}, d);
|
|
536
|
+
};
|
|
537
|
+
insert();
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
])
|
|
542
|
+
];
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
546
|
+
import { keymap as keymap4, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
547
|
+
import { debounce } from "@dxos/async";
|
|
548
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
549
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
|
|
550
|
+
var styles2 = EditorView4.baseTheme({
|
|
551
|
+
"& .cm-bookmark": {
|
|
552
|
+
cursor: "pointer",
|
|
553
|
+
margin: "4px",
|
|
554
|
+
padding: "4px",
|
|
555
|
+
backgroundColor: "yellow"
|
|
556
|
+
},
|
|
557
|
+
"& .cm-bookmark-selected": {
|
|
558
|
+
backgroundColor: "orange"
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
var BookmarkWidget = class extends WidgetType {
|
|
562
|
+
constructor(_pos, _id, _handleClick) {
|
|
563
|
+
super();
|
|
564
|
+
this._pos = _pos;
|
|
565
|
+
this._id = _id;
|
|
566
|
+
this._handleClick = _handleClick;
|
|
567
|
+
invariant2(this._id, void 0, {
|
|
568
|
+
F: __dxlog_file2,
|
|
569
|
+
L: 37,
|
|
570
|
+
S: this,
|
|
571
|
+
A: [
|
|
572
|
+
"this._id",
|
|
573
|
+
""
|
|
574
|
+
]
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
eq(other) {
|
|
578
|
+
return this._id === other._id;
|
|
579
|
+
}
|
|
580
|
+
toDOM() {
|
|
581
|
+
const span = document.createElement("span");
|
|
582
|
+
span.className = "cm-bookmark";
|
|
583
|
+
span.textContent = "\xA7";
|
|
584
|
+
span.onclick = () => this._handleClick();
|
|
585
|
+
return span;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
var comments = (options = {}) => {
|
|
589
|
+
let active;
|
|
590
|
+
const bookmarkMatcher = new MatchDecorator({
|
|
591
|
+
regexp: /\[\^(\w+)\]/g,
|
|
592
|
+
decoration: (match, view, pos) => {
|
|
593
|
+
const id = match[1];
|
|
594
|
+
return Decoration2.replace({
|
|
595
|
+
id,
|
|
596
|
+
widget: new BookmarkWidget(pos, id, () => handleUpdate({
|
|
597
|
+
active: id
|
|
598
|
+
}))
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
const bookmarks = ViewPlugin2.fromClass(class {
|
|
603
|
+
constructor(view) {
|
|
604
|
+
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
605
|
+
}
|
|
606
|
+
update(update4) {
|
|
607
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
608
|
+
}
|
|
609
|
+
}, {
|
|
610
|
+
decorations: (instance) => instance.bookmarks,
|
|
611
|
+
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
612
|
+
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
613
|
+
})
|
|
614
|
+
});
|
|
615
|
+
const handleUpdate = debounce((data) => {
|
|
616
|
+
options.onUpdate?.(data);
|
|
617
|
+
}, 200);
|
|
618
|
+
return [
|
|
619
|
+
keymap4.of([
|
|
620
|
+
{
|
|
621
|
+
key: options?.key ?? "shift-meta-c",
|
|
622
|
+
run: (view) => {
|
|
623
|
+
const { from, to, head } = view.state.selection.main;
|
|
624
|
+
const id = options.onCreate?.(from, to);
|
|
625
|
+
if (id) {
|
|
626
|
+
const tag = `[^${id}]`;
|
|
627
|
+
view.dispatch({
|
|
628
|
+
changes: {
|
|
629
|
+
from: head,
|
|
630
|
+
insert: tag
|
|
631
|
+
},
|
|
632
|
+
selection: {
|
|
633
|
+
anchor: head + tag.length
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
]),
|
|
642
|
+
bookmarks,
|
|
643
|
+
// Monitor cursor movement.
|
|
644
|
+
EditorView4.updateListener.of((update4) => {
|
|
645
|
+
active = void 0;
|
|
646
|
+
if (!options.onUpdate) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const { view, state } = update4;
|
|
650
|
+
const pos = state.selection.main.head;
|
|
651
|
+
const decorations = [];
|
|
652
|
+
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
653
|
+
let closest = Infinity;
|
|
654
|
+
const { from, to } = (
|
|
655
|
+
/* view.visibleRanges?.[0] ?? */
|
|
656
|
+
{
|
|
657
|
+
from: 0,
|
|
658
|
+
to: state.doc.length
|
|
659
|
+
}
|
|
660
|
+
);
|
|
661
|
+
rangeSet?.between(from, to, (from2, to2, value) => {
|
|
662
|
+
decorations.push({
|
|
663
|
+
from: from2,
|
|
664
|
+
to: to2,
|
|
665
|
+
value
|
|
666
|
+
});
|
|
667
|
+
const d = Math.min(Math.abs(pos - from2), Math.abs(pos - to2));
|
|
668
|
+
if (d < closest) {
|
|
669
|
+
active = value.spec.id;
|
|
670
|
+
closest = d;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
if (decorations.length) {
|
|
674
|
+
handleUpdate({
|
|
675
|
+
active,
|
|
676
|
+
items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
|
|
677
|
+
id,
|
|
678
|
+
pos: from2,
|
|
679
|
+
location: view.coordsAtPos(from2)
|
|
680
|
+
}))
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}),
|
|
684
|
+
styles2
|
|
685
|
+
];
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/highlight.ts
|
|
689
|
+
import { StateEffect, StateField } from "@codemirror/state";
|
|
690
|
+
import { Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
691
|
+
import sortBy from "lodash.sortby";
|
|
692
|
+
import { useEffect } from "react";
|
|
693
|
+
var styles3 = EditorView5.baseTheme({
|
|
694
|
+
"& .cm-highlight": {
|
|
695
|
+
backgroundColor: "yellow"
|
|
696
|
+
},
|
|
697
|
+
"& .cm-highlight::before": {
|
|
698
|
+
content: "]"
|
|
699
|
+
},
|
|
700
|
+
"& .cm-highlight-active": {
|
|
701
|
+
backgroundColor: "lime"
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
var marks = {
|
|
705
|
+
highlight: Decoration3.mark({
|
|
706
|
+
class: "cm-highlight"
|
|
707
|
+
}),
|
|
708
|
+
HighlightActive: Decoration3.mark({
|
|
709
|
+
class: "cm-highlight-active"
|
|
710
|
+
})
|
|
711
|
+
};
|
|
712
|
+
var setHighlights = StateEffect.define();
|
|
713
|
+
var useHighlights = (view, ranges = []) => {
|
|
714
|
+
useEffect(() => {
|
|
715
|
+
view?.dispatch({
|
|
716
|
+
effects: setHighlights.of(ranges)
|
|
717
|
+
});
|
|
718
|
+
}, [
|
|
719
|
+
view,
|
|
720
|
+
ranges
|
|
721
|
+
]);
|
|
722
|
+
};
|
|
723
|
+
var highlightStateField = StateField.define({
|
|
724
|
+
create: () => [],
|
|
725
|
+
update: (threads, tr) => {
|
|
726
|
+
for (const effect of tr.effects) {
|
|
727
|
+
if (effect.is(setHighlights)) {
|
|
728
|
+
return effect.value;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return threads;
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
var highlightDecorations = EditorView5.decorations.compute([
|
|
735
|
+
highlightStateField
|
|
736
|
+
], (state) => {
|
|
737
|
+
const selectionRanges = state.field(highlightStateField);
|
|
738
|
+
const decorations = sortBy(selectionRanges ?? [], (selection) => selection.from)?.flatMap((selection) => {
|
|
739
|
+
const range = {
|
|
740
|
+
from: selection.from,
|
|
741
|
+
to: selection.to + 1
|
|
742
|
+
};
|
|
743
|
+
if (selection.to > selection.from) {
|
|
744
|
+
if (selection.active) {
|
|
745
|
+
return marks.HighlightActive.range(range.from, range.to);
|
|
746
|
+
} else {
|
|
747
|
+
return marks.highlight.range(range.from, range.to);
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
return [];
|
|
751
|
+
}
|
|
752
|
+
}) ?? [];
|
|
753
|
+
return Decoration3.set(decorations);
|
|
754
|
+
});
|
|
755
|
+
var listener = (options) => {
|
|
756
|
+
return EditorView5.updateListener.of((update4) => {
|
|
757
|
+
const { view, state } = update4;
|
|
758
|
+
const { head } = state.selection.main;
|
|
759
|
+
const ranges = state.field(highlightStateField);
|
|
760
|
+
let mod = false;
|
|
761
|
+
const newRanges = ranges.map((range) => {
|
|
762
|
+
const active = head >= range.from && head <= range.to;
|
|
763
|
+
if (active !== range.active) {
|
|
764
|
+
mod = true;
|
|
765
|
+
return {
|
|
766
|
+
...range,
|
|
767
|
+
active
|
|
768
|
+
};
|
|
769
|
+
} else {
|
|
770
|
+
return range;
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
if (mod) {
|
|
774
|
+
view.dispatch({
|
|
775
|
+
effects: setHighlights.of(newRanges)
|
|
776
|
+
});
|
|
777
|
+
options?.onChange?.(newRanges.find((range) => range.active)?.id);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
};
|
|
781
|
+
var highlight = (options = {}) => {
|
|
782
|
+
return [
|
|
783
|
+
highlightStateField,
|
|
784
|
+
highlightDecorations,
|
|
785
|
+
listener(options),
|
|
786
|
+
styles3
|
|
787
|
+
];
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/image.ts
|
|
791
|
+
import { syntaxTree } from "@codemirror/language";
|
|
792
|
+
import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
|
|
793
|
+
import { Decoration as Decoration4, EditorView as EditorView6, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
794
|
+
var image = (options = {}) => {
|
|
795
|
+
return StateField2.define({
|
|
796
|
+
create: (state) => update(state, options),
|
|
797
|
+
update: (_, tr) => update(tr.state, options),
|
|
798
|
+
provide: (field) => EditorView6.decorations.from(field)
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
var update = (state, options) => {
|
|
802
|
+
const builder = new RangeSetBuilder();
|
|
803
|
+
const cursor = state.selection.main.head;
|
|
804
|
+
syntaxTree(state).iterate({
|
|
805
|
+
enter: (node) => {
|
|
806
|
+
if (node.name === "Image") {
|
|
807
|
+
const urlNode = node.node.getChild("URL");
|
|
808
|
+
if (urlNode) {
|
|
809
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
810
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
811
|
+
builder.add(hide ? node.from : node.to, node.to, Decoration4.replace({
|
|
812
|
+
widget: new ImageWidget(url)
|
|
813
|
+
}));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
return builder.finish();
|
|
819
|
+
};
|
|
820
|
+
var ImageWidget = class extends WidgetType2 {
|
|
821
|
+
constructor(_url) {
|
|
822
|
+
super();
|
|
823
|
+
this._url = _url;
|
|
824
|
+
}
|
|
825
|
+
eq(other) {
|
|
826
|
+
return this._url === other?._url;
|
|
827
|
+
}
|
|
828
|
+
toDOM(view) {
|
|
829
|
+
const img = document.createElement("img");
|
|
830
|
+
img.setAttribute("src", this._url);
|
|
831
|
+
img.setAttribute("class", "cm-image");
|
|
832
|
+
return img;
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
837
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
838
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
|
|
839
|
+
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
840
|
+
var link = (options = {}) => {
|
|
841
|
+
return StateField3.define({
|
|
842
|
+
create: (state) => update2(state, options),
|
|
843
|
+
update: (_, tr) => update2(tr.state, options),
|
|
844
|
+
provide: (field) => EditorView7.decorations.from(field)
|
|
845
|
+
});
|
|
846
|
+
};
|
|
847
|
+
var LinkButton = class extends WidgetType3 {
|
|
848
|
+
constructor(_pos, _url, _onAttach) {
|
|
849
|
+
super();
|
|
850
|
+
this._pos = _pos;
|
|
851
|
+
this._url = _url;
|
|
852
|
+
this._onAttach = _onAttach;
|
|
853
|
+
}
|
|
854
|
+
eq(other) {
|
|
855
|
+
return this._pos === other._pos && this._url === other._url;
|
|
856
|
+
}
|
|
857
|
+
toDOM(view) {
|
|
858
|
+
const el = document.createElement("span");
|
|
859
|
+
this._onAttach(el, this._url);
|
|
860
|
+
return el;
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
var LinkText = class extends WidgetType3 {
|
|
864
|
+
constructor(_pos, _text, _url) {
|
|
865
|
+
super();
|
|
866
|
+
this._pos = _pos;
|
|
867
|
+
this._text = _text;
|
|
868
|
+
this._url = _url;
|
|
869
|
+
}
|
|
870
|
+
eq(other) {
|
|
871
|
+
return this._pos === other._pos && this._url === other._url;
|
|
872
|
+
}
|
|
873
|
+
toDOM(view) {
|
|
874
|
+
const link2 = document.createElement("a");
|
|
875
|
+
link2.setAttribute("class", "cm-link");
|
|
876
|
+
link2.textContent = this._text;
|
|
877
|
+
if (this._url) {
|
|
878
|
+
link2.setAttribute("rel", "noreferrer");
|
|
879
|
+
link2.setAttribute("target", "_blank");
|
|
880
|
+
link2.href = this._url;
|
|
881
|
+
} else {
|
|
882
|
+
link2.onclick = () => {
|
|
883
|
+
view.dispatch({
|
|
884
|
+
selection: {
|
|
885
|
+
anchor: this._pos
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
return link2;
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
var update2 = (state, options) => {
|
|
894
|
+
const builder = new RangeSetBuilder2();
|
|
895
|
+
const cursor = state.selection.main.head;
|
|
896
|
+
syntaxTree2(state).iterate({
|
|
897
|
+
enter: (node) => {
|
|
898
|
+
if (node.name === "Link") {
|
|
899
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
900
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
901
|
+
const urlNode = node.node.getChild("URL");
|
|
902
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
903
|
+
if (!url) {
|
|
904
|
+
return false;
|
|
905
|
+
}
|
|
906
|
+
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
907
|
+
builder.add(node.from, node.to, Decoration5.replace({
|
|
908
|
+
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
if (options.onRender) {
|
|
912
|
+
builder.add(node.to, node.to, Decoration5.replace({
|
|
913
|
+
widget: new LinkButton(node.from, url, options.onRender)
|
|
914
|
+
}));
|
|
915
|
+
}
|
|
916
|
+
return false;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
return builder.finish();
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
924
|
+
import { StateField as StateField4 } from "@codemirror/state";
|
|
925
|
+
var listener2 = ({ onChange }) => {
|
|
926
|
+
return StateField4.define({
|
|
927
|
+
create: () => null,
|
|
928
|
+
update: (_value, transaction) => {
|
|
929
|
+
if (transaction.docChanged && onChange) {
|
|
930
|
+
onChange(transaction.newDoc.toString());
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
938
|
+
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
939
|
+
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
940
|
+
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
941
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
942
|
+
import { languages } from "@codemirror/language-data";
|
|
943
|
+
import { searchKeymap } from "@codemirror/search";
|
|
944
|
+
import { EditorState } from "@codemirror/state";
|
|
945
|
+
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
946
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView8, highlightActiveLine, keymap as keymap5, placeholder as placeholder2 } from "@codemirror/view";
|
|
947
|
+
|
|
948
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
949
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
950
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
951
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
952
|
+
import { Table } from "@lezer/markdown";
|
|
953
|
+
import get2 from "lodash.get";
|
|
954
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
955
|
+
var markdownTags = {
|
|
956
|
+
Blockquote: Tag.define(),
|
|
957
|
+
CodeMark: Tag.define(),
|
|
958
|
+
CodeText: Tag.define(),
|
|
959
|
+
EmphasisMark: Tag.define(),
|
|
960
|
+
HeaderMark: Tag.define(),
|
|
961
|
+
HorizontalRule: Tag.define(),
|
|
962
|
+
InlineCode: Tag.define(),
|
|
963
|
+
LinkLabel: Tag.define(),
|
|
964
|
+
LinkReference: Tag.define(),
|
|
965
|
+
ListMark: Tag.define(),
|
|
966
|
+
QuoteMark: Tag.define(),
|
|
967
|
+
URL: Tag.define(),
|
|
968
|
+
// Custom.
|
|
969
|
+
TableCell: Tag.define()
|
|
970
|
+
};
|
|
971
|
+
Table.defineNodes?.forEach((node) => {
|
|
972
|
+
switch (node?.name) {
|
|
973
|
+
case "TableCell": {
|
|
974
|
+
node.style = markdownTags.TableCell;
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
var markdownTagsExtensions = [
|
|
980
|
+
Table,
|
|
981
|
+
{
|
|
982
|
+
props: [
|
|
983
|
+
styleTags(markdownTags)
|
|
984
|
+
]
|
|
985
|
+
}
|
|
986
|
+
];
|
|
987
|
+
var markdownHighlightStyle = (readonly) => {
|
|
988
|
+
return HighlightStyle.define([
|
|
989
|
+
{
|
|
990
|
+
tag: [
|
|
991
|
+
tags.keyword,
|
|
992
|
+
tags.name,
|
|
993
|
+
tags.deleted,
|
|
994
|
+
tags.character,
|
|
995
|
+
tags.propertyName,
|
|
996
|
+
tags.macroName,
|
|
997
|
+
tags.color,
|
|
998
|
+
tags.constant(tags.name),
|
|
999
|
+
tags.standard(tags.name),
|
|
1000
|
+
tags.definition(tags.name),
|
|
1001
|
+
tags.separator,
|
|
1002
|
+
tags.typeName,
|
|
1003
|
+
tags.className,
|
|
1004
|
+
tags.number,
|
|
1005
|
+
tags.changed,
|
|
1006
|
+
tags.annotation,
|
|
1007
|
+
tags.modifier,
|
|
1008
|
+
tags.self,
|
|
1009
|
+
tags.namespace,
|
|
1010
|
+
tags.operator,
|
|
1011
|
+
tags.operatorKeyword,
|
|
1012
|
+
tags.escape,
|
|
1013
|
+
tags.regexp,
|
|
1014
|
+
tags.special(tags.string),
|
|
1015
|
+
tags.meta,
|
|
1016
|
+
tags.comment,
|
|
1017
|
+
tags.atom,
|
|
1018
|
+
tags.bool,
|
|
1019
|
+
tags.special(tags.variableName),
|
|
1020
|
+
tags.processingInstruction,
|
|
1021
|
+
tags.string,
|
|
1022
|
+
tags.inserted,
|
|
1023
|
+
tags.invalid
|
|
1024
|
+
],
|
|
1025
|
+
color: "inherit !important"
|
|
1026
|
+
},
|
|
1027
|
+
// Markdown marks.
|
|
1028
|
+
{
|
|
1029
|
+
tag: [
|
|
1030
|
+
tags.meta,
|
|
1031
|
+
tags.processingInstruction,
|
|
1032
|
+
markdownTags.LinkLabel,
|
|
1033
|
+
markdownTags.LinkReference,
|
|
1034
|
+
markdownTags.ListMark
|
|
1035
|
+
],
|
|
1036
|
+
class: mark
|
|
1037
|
+
},
|
|
1038
|
+
// Markdown marks.
|
|
1039
|
+
{
|
|
1040
|
+
tag: [
|
|
1041
|
+
markdownTags.CodeMark,
|
|
1042
|
+
markdownTags.HeaderMark,
|
|
1043
|
+
markdownTags.QuoteMark,
|
|
1044
|
+
markdownTags.EmphasisMark
|
|
1045
|
+
],
|
|
1046
|
+
class: readonly ? "hidden" : mark
|
|
1047
|
+
},
|
|
1048
|
+
// E.g., code block language (after ```).
|
|
1049
|
+
{
|
|
1050
|
+
tag: [
|
|
1051
|
+
tags.function(tags.variableName),
|
|
1052
|
+
tags.labelName
|
|
1053
|
+
],
|
|
1054
|
+
class: readonly ? "hidden" : codeMark
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
tag: [
|
|
1058
|
+
tags.monospace
|
|
1059
|
+
],
|
|
1060
|
+
class: "font-mono"
|
|
1061
|
+
},
|
|
1062
|
+
// Headings.
|
|
1063
|
+
{
|
|
1064
|
+
tag: tags.heading1,
|
|
1065
|
+
class: heading(1, readonly)
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
tag: tags.heading2,
|
|
1069
|
+
class: heading(2, readonly)
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
tag: tags.heading3,
|
|
1073
|
+
class: heading(3, readonly)
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
tag: tags.heading4,
|
|
1077
|
+
class: heading(4, readonly)
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
tag: tags.heading5,
|
|
1081
|
+
class: heading(5, readonly)
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
tag: tags.heading6,
|
|
1085
|
+
class: heading(6, readonly)
|
|
1086
|
+
},
|
|
1087
|
+
// Emphasis.
|
|
1088
|
+
{
|
|
1089
|
+
tag: tags.emphasis,
|
|
1090
|
+
class: italic
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
tag: tags.strong,
|
|
1094
|
+
class: bold
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
tag: tags.strikethrough,
|
|
1098
|
+
class: strikethrough
|
|
1099
|
+
},
|
|
1100
|
+
// Naked URLs.
|
|
1101
|
+
{
|
|
1102
|
+
tag: [
|
|
1103
|
+
markdownTags.URL
|
|
1104
|
+
],
|
|
1105
|
+
class: inlineUrl
|
|
1106
|
+
},
|
|
1107
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
1108
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1109
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1110
|
+
// the code, but all other CSS properties will be inherited.
|
|
1111
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1112
|
+
{
|
|
1113
|
+
tag: [
|
|
1114
|
+
markdownTags.CodeText,
|
|
1115
|
+
markdownTags.InlineCode
|
|
1116
|
+
],
|
|
1117
|
+
class: code
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
tag: [
|
|
1121
|
+
markdownTags.QuoteMark
|
|
1122
|
+
],
|
|
1123
|
+
class: blockquote
|
|
1124
|
+
},
|
|
1125
|
+
// TODO(burdon): Replace with extension.
|
|
1126
|
+
{
|
|
1127
|
+
tag: [
|
|
1128
|
+
markdownTags.HorizontalRule
|
|
1129
|
+
],
|
|
1130
|
+
class: mx3(horizontalRule, readonly && "-indent-[100rem]")
|
|
1131
|
+
},
|
|
1132
|
+
// TODO(burdon): Only if being edited.
|
|
1133
|
+
{
|
|
1134
|
+
tag: [
|
|
1135
|
+
markdownTags.TableCell
|
|
1136
|
+
],
|
|
1137
|
+
class: "font-mono"
|
|
1138
|
+
}
|
|
1139
|
+
], {
|
|
1140
|
+
scope: markdownLanguage,
|
|
1141
|
+
all: {
|
|
1142
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
1148
|
+
var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
1149
|
+
return [
|
|
1150
|
+
EditorState.allowMultipleSelections.of(true),
|
|
1151
|
+
EditorState.tabSize.of(2),
|
|
1152
|
+
EditorView8.lineWrapping,
|
|
1153
|
+
customKeymap(),
|
|
1154
|
+
bracketMatching2(),
|
|
1155
|
+
closeBrackets2(),
|
|
1156
|
+
crosshairCursor(),
|
|
1157
|
+
dropCursor(),
|
|
1158
|
+
drawSelection2(),
|
|
1159
|
+
highlightActiveLine(),
|
|
1160
|
+
history(),
|
|
1161
|
+
indentOnInput(),
|
|
1162
|
+
_placeholder && placeholder2(_placeholder),
|
|
1163
|
+
// Main extension.
|
|
1164
|
+
// https://github.com/codemirror/lang-markdown
|
|
1165
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
1166
|
+
markdown({
|
|
1167
|
+
// GRM by default (vs strict CommonMark):
|
|
1168
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
1169
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1170
|
+
// https://github.github.com/gfm
|
|
1171
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1172
|
+
base: markdownLanguage2,
|
|
1173
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
1174
|
+
codeLanguages: languages,
|
|
1175
|
+
// Parser extensions.
|
|
1176
|
+
extensions: [
|
|
1177
|
+
// GFM provided by default.
|
|
1178
|
+
markdownTagsExtensions
|
|
1179
|
+
]
|
|
1180
|
+
}),
|
|
1181
|
+
// https://github.com/codemirror/theme-one-dark
|
|
1182
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1183
|
+
// Custom styles.
|
|
1184
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1185
|
+
].filter(Boolean);
|
|
34
1186
|
};
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1187
|
+
var customKeymap = () => keymap5.of([
|
|
1188
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1189
|
+
indentWithTab,
|
|
1190
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1191
|
+
...standardKeymap,
|
|
1192
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1193
|
+
...historyKeymap,
|
|
1194
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1195
|
+
...closeBracketsKeymap,
|
|
1196
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1197
|
+
...searchKeymap
|
|
1198
|
+
]);
|
|
41
1199
|
|
|
42
|
-
// packages/ui/react-ui-editor/src/
|
|
43
|
-
import {
|
|
44
|
-
var
|
|
1200
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1201
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1202
|
+
var mention = ({ onSearch }) => {
|
|
1203
|
+
return autocompletion2({
|
|
1204
|
+
closeOnBlur: false,
|
|
1205
|
+
override: [
|
|
1206
|
+
(context) => {
|
|
1207
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
1208
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
console.log(match);
|
|
1212
|
+
return {
|
|
1213
|
+
from: match.from,
|
|
1214
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1215
|
+
label: `@${value}`
|
|
1216
|
+
}))
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
]
|
|
1220
|
+
});
|
|
1221
|
+
};
|
|
45
1222
|
|
|
46
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
1223
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
|
|
1224
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1225
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1226
|
+
import { Decoration as Decoration6, EditorView as EditorView9, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1227
|
+
var table = (options = {}) => {
|
|
1228
|
+
return StateField5.define({
|
|
1229
|
+
create: (state) => update3(state, options),
|
|
1230
|
+
update: (_, tr) => update3(tr.state, options),
|
|
1231
|
+
provide: (field) => EditorView9.decorations.from(field)
|
|
1232
|
+
});
|
|
1233
|
+
};
|
|
1234
|
+
var update3 = (state, options) => {
|
|
1235
|
+
const builder = new RangeSetBuilder3();
|
|
1236
|
+
const cursor = state.selection.main.head;
|
|
1237
|
+
const tables = [];
|
|
1238
|
+
const getTable = () => tables[tables.length - 1];
|
|
1239
|
+
const getRow = () => {
|
|
1240
|
+
const table2 = getTable();
|
|
1241
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
1242
|
+
};
|
|
1243
|
+
syntaxTree3(state).iterate({
|
|
1244
|
+
enter: (node) => {
|
|
1245
|
+
switch (node.name) {
|
|
1246
|
+
case "Table": {
|
|
1247
|
+
tables.push({
|
|
1248
|
+
from: node.from,
|
|
1249
|
+
to: node.to
|
|
1250
|
+
});
|
|
1251
|
+
break;
|
|
1252
|
+
}
|
|
1253
|
+
case "TableHeader": {
|
|
1254
|
+
getTable().header = [];
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case "TableRow": {
|
|
1258
|
+
(getTable().rows ??= []).push([]);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
case "TableCell": {
|
|
1262
|
+
const row = getRow();
|
|
1263
|
+
if (row) {
|
|
1264
|
+
row.push(state.sliceDoc(node.from, node.to));
|
|
1265
|
+
} else {
|
|
1266
|
+
getTable().header?.push(state.sliceDoc(node.from, node.to));
|
|
1267
|
+
}
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
tables.forEach((table2) => {
|
|
1274
|
+
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1275
|
+
hide && builder.add(table2.from, table2.to, Decoration6.replace({
|
|
1276
|
+
widget: new TableWidget(table2)
|
|
1277
|
+
}));
|
|
1278
|
+
builder.add(table2.from, table2.to, Decoration6.mark({
|
|
1279
|
+
class: "cm-table"
|
|
1280
|
+
}));
|
|
1281
|
+
});
|
|
1282
|
+
return builder.finish();
|
|
1283
|
+
};
|
|
1284
|
+
var TableWidget = class extends WidgetType4 {
|
|
1285
|
+
constructor(_table) {
|
|
1286
|
+
super();
|
|
1287
|
+
this._table = _table;
|
|
1288
|
+
}
|
|
1289
|
+
eq(other) {
|
|
1290
|
+
return this._table.from === other?._table?.from;
|
|
1291
|
+
}
|
|
1292
|
+
toDOM(view) {
|
|
1293
|
+
const table2 = document.createElement("table");
|
|
1294
|
+
{
|
|
1295
|
+
const header = table2.appendChild(document.createElement("thead"));
|
|
1296
|
+
const tr = header.appendChild(document.createElement("tr"));
|
|
1297
|
+
this._table.header?.forEach((cell) => {
|
|
1298
|
+
const th = document.createElement("th");
|
|
1299
|
+
th.setAttribute("class", "cm-table-head");
|
|
1300
|
+
tr.appendChild(th).textContent = cell;
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
{
|
|
1304
|
+
const body = table2.appendChild(document.createElement("tbody"));
|
|
1305
|
+
this._table.rows?.forEach((row) => {
|
|
1306
|
+
const tr = body.appendChild(document.createElement("tr"));
|
|
1307
|
+
row.forEach((cell) => {
|
|
1308
|
+
const td = document.createElement("td");
|
|
1309
|
+
td.setAttribute("class", "cm-table-cell");
|
|
1310
|
+
tr.appendChild(td).textContent = cell;
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
return table2;
|
|
77
1315
|
}
|
|
78
1316
|
};
|
|
79
1317
|
|
|
80
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
81
|
-
import {
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
onChange(transaction.newDoc.toString());
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
1318
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
1319
|
+
import { EditorView as EditorView10, Decoration as Decoration7, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
1320
|
+
var styles4 = EditorView10.baseTheme({
|
|
1321
|
+
"& .cm-task-item": {
|
|
1322
|
+
paddingLeft: "4px",
|
|
1323
|
+
paddingRight: "8px"
|
|
89
1324
|
}
|
|
90
1325
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
import { syntaxTree } from "@codemirror/language";
|
|
94
|
-
import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
|
|
95
|
-
import { Decoration, EditorView as EditorView2, WidgetType } from "@codemirror/view";
|
|
96
|
-
var Link = class extends WidgetType {
|
|
97
|
-
constructor(_anchor, _text, _url) {
|
|
1326
|
+
var CheckboxWidget = class extends WidgetType5 {
|
|
1327
|
+
constructor(_pos, _checked, _indent, _onCheck) {
|
|
98
1328
|
super();
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
1329
|
+
this._pos = _pos;
|
|
1330
|
+
this._checked = _checked;
|
|
1331
|
+
this._indent = _indent;
|
|
1332
|
+
this._onCheck = _onCheck;
|
|
102
1333
|
}
|
|
103
1334
|
eq(other) {
|
|
104
|
-
return this.
|
|
1335
|
+
return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
|
|
105
1336
|
}
|
|
106
1337
|
toDOM(view) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1338
|
+
const wrap = document.createElement("span");
|
|
1339
|
+
wrap.className = "cm-task-item";
|
|
1340
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
1341
|
+
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
1342
|
+
const input = wrap.appendChild(document.createElement("input"));
|
|
1343
|
+
input.type = "checkbox";
|
|
1344
|
+
input.checked = this._checked;
|
|
1345
|
+
if (!this._onCheck) {
|
|
1346
|
+
input.setAttribute("disabled", "true");
|
|
1347
|
+
}
|
|
1348
|
+
if (this._onCheck) {
|
|
1349
|
+
input.onchange = (event) => {
|
|
1350
|
+
this._onCheck?.(event.target.checked);
|
|
1351
|
+
return true;
|
|
120
1352
|
};
|
|
121
1353
|
}
|
|
122
|
-
return
|
|
1354
|
+
return wrap;
|
|
1355
|
+
}
|
|
1356
|
+
ignoreEvent() {
|
|
1357
|
+
return false;
|
|
123
1358
|
}
|
|
124
1359
|
};
|
|
125
|
-
var
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
1360
|
+
var tasklist = (options = {}) => {
|
|
1361
|
+
const taskMatcher = new MatchDecorator2({
|
|
1362
|
+
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
1363
|
+
decoration: (match, view, pos) => {
|
|
1364
|
+
const indent = Math.floor(match[1].length / 2);
|
|
1365
|
+
const checked = match[2] === "x" || match[2] === "X";
|
|
1366
|
+
return Decoration7.replace({
|
|
1367
|
+
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
1368
|
+
const idx = pos + match[0].indexOf("[") + 1;
|
|
1369
|
+
view.dispatch({
|
|
1370
|
+
changes: {
|
|
1371
|
+
from: idx,
|
|
1372
|
+
to: idx + 1,
|
|
1373
|
+
insert: checked2 ? "x" : " "
|
|
1374
|
+
},
|
|
1375
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
1376
|
+
selection: {
|
|
1377
|
+
anchor: idx + 3
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
})
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
130
1383
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const cursor = state.selection.main.head;
|
|
135
|
-
syntaxTree(state).iterate({
|
|
136
|
-
enter: (node) => {
|
|
137
|
-
if (cursor < node.from || cursor > node.to) {
|
|
138
|
-
if (node.name === "Link") {
|
|
139
|
-
const marks = node.node.getChildren("LinkMark");
|
|
140
|
-
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
141
|
-
const urlNode = node.node.getChild("URL");
|
|
142
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
143
|
-
builder.add(node.from, node.to, Decoration.replace({
|
|
144
|
-
widget: new Link(node.from, text, link ? url : void 0)
|
|
145
|
-
}));
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return true;
|
|
1384
|
+
const tasks = ViewPlugin3.fromClass(class {
|
|
1385
|
+
constructor(view) {
|
|
1386
|
+
this.tasks = taskMatcher.createDeco(view);
|
|
150
1387
|
}
|
|
1388
|
+
update(update4) {
|
|
1389
|
+
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
1390
|
+
}
|
|
1391
|
+
}, {
|
|
1392
|
+
decorations: (value) => value.tasks,
|
|
1393
|
+
provide: (plugin) => EditorView10.atomicRanges.of((view) => {
|
|
1394
|
+
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
1395
|
+
})
|
|
151
1396
|
});
|
|
152
|
-
return
|
|
1397
|
+
return [
|
|
1398
|
+
tasks,
|
|
1399
|
+
styles4
|
|
1400
|
+
];
|
|
153
1401
|
};
|
|
154
1402
|
|
|
155
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
1403
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
156
1404
|
import { hoverTooltip } from "@codemirror/view";
|
|
157
1405
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
158
1406
|
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
159
|
-
var
|
|
1407
|
+
var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view, pos) => {
|
|
160
1408
|
const { from, text } = view.state.doc.lineAt(pos);
|
|
161
1409
|
const p = pos - from;
|
|
162
1410
|
let idx = 0;
|
|
@@ -182,288 +1430,101 @@ var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp) => hoverTool
|
|
|
182
1430
|
end: idx + from + match[0].length,
|
|
183
1431
|
above: true,
|
|
184
1432
|
create: () => {
|
|
185
|
-
const el = document.createElement("
|
|
186
|
-
el.
|
|
187
|
-
el.className = tooltipContent({}, "mb-2 p-1");
|
|
188
|
-
el.setAttribute("target", "_blank");
|
|
189
|
-
el.setAttribute("href", url);
|
|
1433
|
+
const el = document.createElement("div");
|
|
1434
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
190
1435
|
onHover(el, url);
|
|
191
1436
|
return {
|
|
192
|
-
dom: el
|
|
1437
|
+
dom: el,
|
|
1438
|
+
offset: {
|
|
1439
|
+
x: 0,
|
|
1440
|
+
y: 12
|
|
1441
|
+
}
|
|
193
1442
|
};
|
|
194
1443
|
}
|
|
195
1444
|
};
|
|
196
1445
|
});
|
|
197
1446
|
|
|
198
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/
|
|
199
|
-
import
|
|
200
|
-
var
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
};
|
|
213
|
-
const p2 = {
|
|
214
|
-
start: p1.end,
|
|
215
|
-
end: p1.end + 1
|
|
216
|
-
};
|
|
217
|
-
const p3 = {
|
|
218
|
-
start: p1.end + 1,
|
|
219
|
-
end: p1.end + 1 + url.length + 2
|
|
220
|
-
};
|
|
221
|
-
add(p0.start, p0.end, Decoration2.mark({
|
|
222
|
-
class: "cm-hyperlink-bracket",
|
|
223
|
-
_attributes: {
|
|
224
|
-
style: "display: none"
|
|
225
|
-
}
|
|
226
|
-
}));
|
|
227
|
-
add(p1.start, p1.end, Decoration2.mark({
|
|
228
|
-
class: "cm-hyperlink-label"
|
|
229
|
-
}));
|
|
230
|
-
add(p2.start, p2.end, Decoration2.mark({
|
|
231
|
-
class: "cm-hyperlink-bracket",
|
|
232
|
-
_attributes: {
|
|
233
|
-
style: "display: none"
|
|
234
|
-
}
|
|
235
|
-
}));
|
|
236
|
-
add(p3.start, p3.end, Decoration2.mark({
|
|
237
|
-
class: "cm-hyperlink-url",
|
|
238
|
-
_attributes: {
|
|
239
|
-
style: "display: none"
|
|
240
|
-
}
|
|
241
|
-
}));
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
function hyperLinkExtension() {
|
|
245
|
-
return ViewPlugin.fromClass(class HyperLinkView {
|
|
246
|
-
constructor(view) {
|
|
247
|
-
this.decorator = linkDecorator();
|
|
248
|
-
this.decorations = this.decorator.createDeco(view);
|
|
249
|
-
}
|
|
250
|
-
update(update2) {
|
|
251
|
-
if (update2.docChanged || update2.viewportChanged) {
|
|
252
|
-
this.decorations = this.decorator.updateDeco(update2, this.decorations);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}, {
|
|
256
|
-
decorations: (view) => view.decorations,
|
|
257
|
-
eventHandlers: {
|
|
258
|
-
// TODO(burdon): CLick to expand link.
|
|
259
|
-
// https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
|
|
260
|
-
mousedown: function(event, view) {
|
|
261
|
-
const pos = view.posAtDOM(event.target);
|
|
262
|
-
if (pos !== 0) {
|
|
263
|
-
console.log(this);
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
// TODO(burdon): Hide when cursor moves away.
|
|
267
|
-
keydown: (event, view) => {
|
|
268
|
-
view.update([]);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
var hyperlinkStyle = EditorView3.baseTheme({
|
|
274
|
-
".cm-hyperlink-label": {
|
|
275
|
-
cursor: "pointer",
|
|
276
|
-
textDecoration: "underline"
|
|
277
|
-
},
|
|
278
|
-
".cm-hyperlink-bracket": {
|
|
279
|
-
opacity: 0.2
|
|
280
|
-
},
|
|
281
|
-
".cm-hyperlink-url": {
|
|
282
|
-
opacity: 0.5,
|
|
283
|
-
fontFamily: "monospace"
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
var hyperlinkWidget = [
|
|
287
|
-
hyperLinkExtension(),
|
|
288
|
-
hyperlinkStyle
|
|
289
|
-
];
|
|
290
|
-
|
|
291
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
292
|
-
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
293
|
-
import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
|
|
294
|
-
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
295
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, foldKeymap, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
296
|
-
import { languages } from "@codemirror/language-data";
|
|
297
|
-
import { lintKeymap } from "@codemirror/lint";
|
|
298
|
-
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
299
|
-
import { EditorState } from "@codemirror/state";
|
|
300
|
-
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
301
|
-
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
302
|
-
|
|
303
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/tags.ts
|
|
304
|
-
import { styleTags, Tag } from "@lezer/highlight";
|
|
305
|
-
var markdownTags = {
|
|
306
|
-
headingMark: Tag.define(),
|
|
307
|
-
quoteMark: Tag.define(),
|
|
308
|
-
listMark: Tag.define(),
|
|
309
|
-
linkMark: Tag.define(),
|
|
310
|
-
emphasisMark: Tag.define(),
|
|
311
|
-
codeMark: Tag.define(),
|
|
312
|
-
codeText: Tag.define(),
|
|
313
|
-
inlineCode: Tag.define(),
|
|
314
|
-
url: Tag.define(),
|
|
315
|
-
linkReference: Tag.define(),
|
|
316
|
-
linkLabel: Tag.define()
|
|
317
|
-
};
|
|
318
|
-
var markdownTagsExtension = {
|
|
319
|
-
props: [
|
|
320
|
-
styleTags({
|
|
321
|
-
HeaderMark: markdownTags.headingMark,
|
|
322
|
-
QuoteMark: markdownTags.quoteMark,
|
|
323
|
-
ListMark: markdownTags.listMark,
|
|
324
|
-
LinkMark: markdownTags.linkMark,
|
|
325
|
-
EmphasisMark: markdownTags.emphasisMark,
|
|
326
|
-
CodeMark: markdownTags.codeMark,
|
|
327
|
-
CodeText: markdownTags.codeText,
|
|
328
|
-
InlineCode: markdownTags.inlineCode,
|
|
329
|
-
URL: markdownTags.url,
|
|
330
|
-
LinkReference: markdownTags.linkReference,
|
|
331
|
-
LinkLabel: markdownTags.linkLabel
|
|
332
|
-
})
|
|
333
|
-
]
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/theme.ts
|
|
337
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
338
|
-
import { HighlightStyle } from "@codemirror/language";
|
|
339
|
-
import { tags } from "@lezer/highlight";
|
|
340
|
-
import get2 from "lodash.get";
|
|
341
|
-
var chalky = "#e5c07b";
|
|
342
|
-
var coral = "#e06c75";
|
|
343
|
-
var cyan = "#56b6c2";
|
|
344
|
-
var invalid = "#ffffff";
|
|
345
|
-
var ivory = "#abb2bf";
|
|
346
|
-
var stone = "#7d8799";
|
|
347
|
-
var malibu = "#61afef";
|
|
348
|
-
var sage = "#98c379";
|
|
349
|
-
var whiskey = "#d19a66";
|
|
350
|
-
var violet = "#c678dd";
|
|
351
|
-
var highlightBackground = "#2c313a";
|
|
352
|
-
var tooltipBackground = "#353a42";
|
|
353
|
-
var monospace = get2(tokens, "fontFamily.mono", [
|
|
354
|
-
"monospace"
|
|
355
|
-
]).join(",");
|
|
356
|
-
var markdownTheme = {
|
|
357
|
-
// TODO(thure): Consider whether these commented-out rules from one-dark-theme should be integrated.
|
|
358
|
-
// '&': {
|
|
359
|
-
// color: ivory,
|
|
360
|
-
// backgroundColor: background
|
|
361
|
-
// },
|
|
362
|
-
// '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor },
|
|
363
|
-
// '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
|
|
364
|
-
// backgroundColor: selection
|
|
365
|
-
// },
|
|
366
|
-
// '.cm-panels': { backgroundColor: darkBackground, color: ivory },
|
|
367
|
-
// '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' },
|
|
368
|
-
// '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' },
|
|
369
|
-
// '.cm-searchMatch': {
|
|
370
|
-
// backgroundColor: '#72a1ff59',
|
|
371
|
-
// outline: '1px solid #457dff'
|
|
372
|
-
// },
|
|
373
|
-
// '.cm-searchMatch.cm-searchMatch-selected': {
|
|
374
|
-
// backgroundColor: '#6199ff2f'
|
|
375
|
-
// },
|
|
376
|
-
// '.cm-activeLine': { backgroundColor: '#6699ff0b' },
|
|
377
|
-
// '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
|
|
378
|
-
// '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
|
|
379
|
-
// backgroundColor: '#bad0f847'
|
|
380
|
-
// },
|
|
381
|
-
// '.cm-gutters': {
|
|
382
|
-
// backgroundColor: background,
|
|
383
|
-
// color: stone,
|
|
384
|
-
// border: 'none'
|
|
385
|
-
// },
|
|
386
|
-
// '.cm-activeLineGutter': {
|
|
387
|
-
// backgroundColor: highlightBackground
|
|
388
|
-
// },
|
|
389
|
-
// '.cm-foldPlaceholder': {
|
|
390
|
-
// backgroundColor: 'transparent',
|
|
391
|
-
// border: 'none',
|
|
392
|
-
// color: '#ddd'
|
|
393
|
-
// },
|
|
394
|
-
"& .cm-tooltip": {
|
|
395
|
-
backgroundColor: "transparent",
|
|
396
|
-
border: "none"
|
|
397
|
-
},
|
|
398
|
-
// '.dark & .cm-tooltip': {
|
|
399
|
-
// border: 'none',
|
|
400
|
-
// backgroundColor: tooltipBackground,
|
|
401
|
-
// },
|
|
402
|
-
// '.dark & .cm-tooltip .cm-tooltip-arrow:before': {
|
|
403
|
-
// borderTopColor: 'transparent',
|
|
404
|
-
// borderBottomColor: 'transparent',
|
|
405
|
-
// },
|
|
406
|
-
// '.dark & .cm-tooltip .cm-tooltip-arrow:after': {
|
|
407
|
-
// borderTopColor: tooltipBackground,
|
|
408
|
-
// borderBottomColor: tooltipBackground,
|
|
409
|
-
// },
|
|
410
|
-
// '.dark & .cm-tooltip-autocomplete': {
|
|
411
|
-
// '& > ul > li[aria-selected]': {
|
|
412
|
-
// backgroundColor: highlightBackground,
|
|
413
|
-
// color: ivory,
|
|
414
|
-
// },
|
|
415
|
-
// },
|
|
1447
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
1448
|
+
import get3 from "lodash.get";
|
|
1449
|
+
var defaultTheme = {
|
|
1450
|
+
//
|
|
1451
|
+
// Main layout:
|
|
1452
|
+
// <div class=".cm-editor .cm-focused">
|
|
1453
|
+
// <div class=".cm-scroller">
|
|
1454
|
+
// <div class=".cm-content" role="textbox" contenteditable="true">
|
|
1455
|
+
// <div class=".cm-line" />
|
|
1456
|
+
// </div>
|
|
1457
|
+
// </div>
|
|
1458
|
+
// </div>
|
|
1459
|
+
//
|
|
1460
|
+
"&": {},
|
|
416
1461
|
"&.cm-focused": {
|
|
417
1462
|
outline: "none"
|
|
418
1463
|
},
|
|
419
|
-
"& .cm-
|
|
420
|
-
|
|
421
|
-
lineHeight: 1.6,
|
|
422
|
-
minBlockSize: "1.6em"
|
|
423
|
-
},
|
|
424
|
-
"& .cm-line *": {
|
|
425
|
-
lineHeight: 1.6
|
|
426
|
-
},
|
|
427
|
-
"&.cm-focused .cm-selectionBackground, & .cm-selectionBackground": {
|
|
428
|
-
background: get2(tokens, "extend.colors.primary.150", "#00ffff")
|
|
429
|
-
},
|
|
430
|
-
".dark & .cm-selectionBackground, .dark &.cm-focused .cm-selectionBackground": {
|
|
431
|
-
background: get2(tokens, "extend.colors.primary.850", "#00ffff")
|
|
432
|
-
},
|
|
433
|
-
"& .cm-selectionMatch": {
|
|
434
|
-
background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
435
|
-
},
|
|
436
|
-
".dark & .cm-selectionMatch": {
|
|
437
|
-
background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
1464
|
+
"& .cm-scroller": {
|
|
1465
|
+
overflow: "visible"
|
|
438
1466
|
},
|
|
439
1467
|
"& .cm-content": {
|
|
440
1468
|
padding: 0,
|
|
1469
|
+
// Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
1470
|
+
fontSize: "16px"
|
|
1471
|
+
},
|
|
1472
|
+
"&light .cm-content": {
|
|
1473
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
441
1474
|
caretColor: "black"
|
|
442
1475
|
},
|
|
443
|
-
"
|
|
1476
|
+
"&dark .cm-content": {
|
|
1477
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
444
1478
|
caretColor: "white"
|
|
445
1479
|
},
|
|
446
|
-
|
|
447
|
-
|
|
1480
|
+
//
|
|
1481
|
+
// Cursor
|
|
1482
|
+
//
|
|
1483
|
+
"&light .cm-cursor, &light .cm-dropCursor": {
|
|
1484
|
+
borderLeft: "2px solid black"
|
|
448
1485
|
},
|
|
449
|
-
"
|
|
450
|
-
|
|
1486
|
+
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
1487
|
+
borderLeft: "2px solid white"
|
|
451
1488
|
},
|
|
452
|
-
".cm-placeholder": {
|
|
453
|
-
|
|
1489
|
+
"& .cm-placeholder": {
|
|
1490
|
+
fontWeight: 100
|
|
454
1491
|
},
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1492
|
+
//
|
|
1493
|
+
// line
|
|
1494
|
+
//
|
|
1495
|
+
"& .cm-line": {
|
|
1496
|
+
paddingInline: 0
|
|
458
1497
|
},
|
|
1498
|
+
"& .cm-line *": {},
|
|
459
1499
|
"& .cm-activeLine": {
|
|
460
1500
|
backgroundColor: "transparent"
|
|
461
1501
|
},
|
|
462
|
-
|
|
463
|
-
|
|
1502
|
+
//
|
|
1503
|
+
// selection
|
|
1504
|
+
//
|
|
1505
|
+
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
1506
|
+
background: get3(tokens, "extend.colors.primary.150", "#00ffff")
|
|
1507
|
+
},
|
|
1508
|
+
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
1509
|
+
background: get3(tokens, "extend.colors.primary.850", "#00ffff")
|
|
1510
|
+
},
|
|
1511
|
+
"&light .cm-selectionMatch": {
|
|
1512
|
+
background: get3(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
1513
|
+
},
|
|
1514
|
+
"&dark .cm-selectionMatch": {
|
|
1515
|
+
background: get3(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
1516
|
+
},
|
|
1517
|
+
//
|
|
1518
|
+
// collaboration
|
|
1519
|
+
// TODO(burdon): Review classnames (YJS dependent?)
|
|
1520
|
+
//
|
|
1521
|
+
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
1522
|
+
mixBlendMode: "multiply"
|
|
1523
|
+
},
|
|
1524
|
+
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
1525
|
+
mixBlendMode: "screen"
|
|
464
1526
|
},
|
|
465
1527
|
"& .cm-ySelectionInfo": {
|
|
466
|
-
fontFamily: get2(tokens, "fontFamily.body", []).join(","),
|
|
467
1528
|
padding: "2px 4px",
|
|
468
1529
|
marginBlockStart: "-4px"
|
|
469
1530
|
},
|
|
@@ -471,12 +1532,6 @@ var markdownTheme = {
|
|
|
471
1532
|
paddingBlockStart: ".15em",
|
|
472
1533
|
paddingBlockEnd: ".15em"
|
|
473
1534
|
},
|
|
474
|
-
"& .cm-ySelection, & .cm-yLineSelection": {
|
|
475
|
-
mixBlendMode: "multiply"
|
|
476
|
-
},
|
|
477
|
-
".dark & .cm-ySelection, .dark & .cm-yLineSelection": {
|
|
478
|
-
mixBlendMode: "screen"
|
|
479
|
-
},
|
|
480
1535
|
"& .cm-ySelectionCaret": {
|
|
481
1536
|
display: "inline-block",
|
|
482
1537
|
insetBlockStart: ".1em",
|
|
@@ -484,18 +1539,80 @@ var markdownTheme = {
|
|
|
484
1539
|
verticalAlign: "top"
|
|
485
1540
|
},
|
|
486
1541
|
"& .cm-yLineSelection": {
|
|
487
|
-
margin:
|
|
1542
|
+
margin: 0
|
|
488
1543
|
},
|
|
489
|
-
|
|
490
|
-
|
|
1544
|
+
//
|
|
1545
|
+
// link
|
|
1546
|
+
//
|
|
1547
|
+
"& .cm-link": {
|
|
1548
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
491
1549
|
textDecorationLine: "underline",
|
|
492
1550
|
textDecorationThickness: "1px",
|
|
493
1551
|
textUnderlineOffset: "2px",
|
|
494
|
-
borderRadius: ".125rem"
|
|
1552
|
+
borderRadius: ".125rem",
|
|
1553
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1554
|
+
},
|
|
1555
|
+
//
|
|
1556
|
+
// tooltip
|
|
1557
|
+
//
|
|
1558
|
+
"& .cm-tooltip": {
|
|
1559
|
+
border: "none"
|
|
1560
|
+
},
|
|
1561
|
+
"& .cm-tooltip-below": {},
|
|
1562
|
+
//
|
|
1563
|
+
// autocomplete
|
|
1564
|
+
//
|
|
1565
|
+
"& .cm-tooltip-autocomplete": {
|
|
1566
|
+
marginTop: "4px",
|
|
1567
|
+
marginLeft: "-3px"
|
|
1568
|
+
},
|
|
1569
|
+
"& .cm-tooltip-autocomplete ul li": {},
|
|
1570
|
+
"& .cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
1571
|
+
"& .cm-completionIcon": {
|
|
1572
|
+
display: "none"
|
|
1573
|
+
},
|
|
1574
|
+
"& .cm-completionLabel": {
|
|
1575
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1576
|
+
},
|
|
1577
|
+
"& .cm-completionMatchedText": {
|
|
1578
|
+
textDecoration: "none"
|
|
1579
|
+
},
|
|
1580
|
+
//
|
|
1581
|
+
// widgets
|
|
1582
|
+
//
|
|
1583
|
+
"& .cm-widgetBuffer": {
|
|
1584
|
+
display: "none",
|
|
1585
|
+
height: 0
|
|
495
1586
|
},
|
|
496
|
-
//
|
|
497
|
-
|
|
498
|
-
|
|
1587
|
+
//
|
|
1588
|
+
// table
|
|
1589
|
+
//
|
|
1590
|
+
"& .cm-table *": {
|
|
1591
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
1592
|
+
textDecoration: "none !important"
|
|
1593
|
+
},
|
|
1594
|
+
"& .cm-table-head": {
|
|
1595
|
+
padding: "2px 16px 2px 0px",
|
|
1596
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
1597
|
+
fontWeight: 100,
|
|
1598
|
+
textAlign: "left",
|
|
1599
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
1600
|
+
},
|
|
1601
|
+
"& .cm-table-cell": {
|
|
1602
|
+
padding: "2px 16px 2px 0px"
|
|
1603
|
+
},
|
|
1604
|
+
//
|
|
1605
|
+
// image
|
|
1606
|
+
//
|
|
1607
|
+
"& .cm-image": {
|
|
1608
|
+
margin: "0.5rem 0"
|
|
1609
|
+
},
|
|
1610
|
+
//
|
|
1611
|
+
// font size
|
|
1612
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
|
|
1613
|
+
//
|
|
1614
|
+
...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
1615
|
+
const height = get3(tokens, [
|
|
499
1616
|
"extend",
|
|
500
1617
|
"fontSize",
|
|
501
1618
|
fontSize,
|
|
@@ -512,208 +1629,255 @@ var markdownTheme = {
|
|
|
512
1629
|
height
|
|
513
1630
|
};
|
|
514
1631
|
return acc;
|
|
515
|
-
}, {})
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
tags.changed,
|
|
535
|
-
tags.annotation,
|
|
536
|
-
tags.modifier,
|
|
537
|
-
tags.self,
|
|
538
|
-
tags.namespace,
|
|
539
|
-
tags.operator,
|
|
540
|
-
tags.operatorKeyword,
|
|
541
|
-
tags.escape,
|
|
542
|
-
tags.regexp,
|
|
543
|
-
tags.special(tags.string),
|
|
544
|
-
tags.meta,
|
|
545
|
-
tags.comment,
|
|
546
|
-
tags.atom,
|
|
547
|
-
tags.bool,
|
|
548
|
-
tags.special(tags.variableName),
|
|
549
|
-
tags.processingInstruction,
|
|
550
|
-
tags.string,
|
|
551
|
-
tags.inserted,
|
|
552
|
-
tags.invalid
|
|
553
|
-
],
|
|
554
|
-
color: "inherit !important"
|
|
555
|
-
},
|
|
556
|
-
{
|
|
557
|
-
tag: [
|
|
558
|
-
tags.link,
|
|
559
|
-
tags.url
|
|
560
|
-
],
|
|
561
|
-
color: "inherit !important",
|
|
562
|
-
textDecoration: "none !important"
|
|
563
|
-
},
|
|
564
|
-
{
|
|
565
|
-
tag: [
|
|
566
|
-
tags.function(tags.variableName),
|
|
567
|
-
tags.labelName
|
|
568
|
-
],
|
|
569
|
-
color: malibu,
|
|
570
|
-
fontFamily: monospace
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
tag: [
|
|
574
|
-
markdownTags.codeMark,
|
|
575
|
-
markdownTags.emphasisMark,
|
|
576
|
-
markdownTags.headingMark,
|
|
577
|
-
markdownTags.linkLabel,
|
|
578
|
-
markdownTags.linkReference,
|
|
579
|
-
markdownTags.listMark,
|
|
580
|
-
markdownTags.quoteMark,
|
|
581
|
-
markdownTags.url,
|
|
582
|
-
tags.meta,
|
|
583
|
-
tags.processingInstruction
|
|
584
|
-
],
|
|
585
|
-
class: mark
|
|
586
|
-
},
|
|
587
|
-
{
|
|
588
|
-
tag: [
|
|
589
|
-
markdownTags.codeText,
|
|
590
|
-
markdownTags.inlineCode
|
|
591
|
-
],
|
|
592
|
-
class: "font-mono"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
tag: tags.emphasis,
|
|
596
|
-
class: italic
|
|
597
|
-
},
|
|
598
|
-
{
|
|
599
|
-
tag: tags.heading1,
|
|
600
|
-
class: heading[1]
|
|
601
|
-
},
|
|
602
|
-
{
|
|
603
|
-
tag: tags.heading2,
|
|
604
|
-
class: heading[2]
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
tag: tags.heading3,
|
|
608
|
-
class: heading[3]
|
|
1632
|
+
}, {}),
|
|
1633
|
+
/**
|
|
1634
|
+
* Panels
|
|
1635
|
+
* https://github.com/codemirror/search/blob/main/src/search.ts#L745
|
|
1636
|
+
*
|
|
1637
|
+
* Find/replace panel.
|
|
1638
|
+
* <div class="cm-announced">...</div>
|
|
1639
|
+
* <div class="cm-scroller">...</div>
|
|
1640
|
+
* <div class="cm-panels cm-panels-bottom">
|
|
1641
|
+
* <div class="cm-search cm-panel">
|
|
1642
|
+
* <input class="cm-textfield" />
|
|
1643
|
+
* <button class="cm-button">...</button>
|
|
1644
|
+
* <label><input type="checkbox" />...</label>
|
|
1645
|
+
* </div>
|
|
1646
|
+
* </div
|
|
1647
|
+
*/
|
|
1648
|
+
"& .cm-panels": {
|
|
1649
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`,
|
|
1650
|
+
borderBottom: "none"
|
|
609
1651
|
},
|
|
610
|
-
{
|
|
611
|
-
|
|
612
|
-
|
|
1652
|
+
"& .cm-panel": {
|
|
1653
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
1654
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
613
1655
|
},
|
|
614
|
-
{
|
|
615
|
-
|
|
616
|
-
|
|
1656
|
+
"& .cm-button": {
|
|
1657
|
+
margin: "4px",
|
|
1658
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
1659
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
1660
|
+
border: "none"
|
|
617
1661
|
},
|
|
618
|
-
{
|
|
619
|
-
|
|
620
|
-
class: heading[6]
|
|
1662
|
+
"& .cm-searchMatch": {
|
|
1663
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
621
1664
|
},
|
|
622
|
-
{
|
|
623
|
-
|
|
624
|
-
|
|
1665
|
+
"& .cm-searchMatch.cm-searchMatch-selected": {
|
|
1666
|
+
backgroundColor: get3(tokens, "extend.colors.primary.100")
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
var textTheme = {
|
|
1670
|
+
"& .cm-scroller": {
|
|
1671
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
625
1672
|
},
|
|
626
|
-
{
|
|
627
|
-
|
|
628
|
-
class: bold
|
|
1673
|
+
"& .cm-placeholder": {
|
|
1674
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
629
1675
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
1676
|
+
};
|
|
1677
|
+
var markdownTheme = {
|
|
1678
|
+
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
1679
|
+
"& .cm-placeholder": {
|
|
1680
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
var codeTheme = {
|
|
1684
|
+
"& .cm-scroller": {
|
|
1685
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
1686
|
+
},
|
|
1687
|
+
"& .cm-placeholder": {
|
|
1688
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
634
1689
|
}
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
638
|
-
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
639
|
-
return [
|
|
640
|
-
bracketMatching2(),
|
|
641
|
-
closeBrackets2(),
|
|
642
|
-
_placeholder && placeholder2(_placeholder),
|
|
643
|
-
EditorState.allowMultipleSelections.of(true),
|
|
644
|
-
EditorView4.lineWrapping,
|
|
645
|
-
// autocompletion(),
|
|
646
|
-
crosshairCursor(),
|
|
647
|
-
dropCursor(),
|
|
648
|
-
drawSelection(),
|
|
649
|
-
highlightActiveLine(),
|
|
650
|
-
highlightActiveLineGutter(),
|
|
651
|
-
highlightSelectionMatches(),
|
|
652
|
-
highlightSpecialChars(),
|
|
653
|
-
history(),
|
|
654
|
-
indentOnInput(),
|
|
655
|
-
rectangularSelection(),
|
|
656
|
-
keymap.of([
|
|
657
|
-
...closeBracketsKeymap,
|
|
658
|
-
// ...completionKeymap,
|
|
659
|
-
...defaultKeymap,
|
|
660
|
-
...foldKeymap,
|
|
661
|
-
...historyKeymap,
|
|
662
|
-
...lintKeymap,
|
|
663
|
-
...searchKeymap,
|
|
664
|
-
indentWithTab
|
|
665
|
-
]),
|
|
666
|
-
// Main extension.
|
|
667
|
-
// https://github.com/codemirror/lang-markdown
|
|
668
|
-
markdown({
|
|
669
|
-
base: markdownLanguage2,
|
|
670
|
-
codeLanguages: languages,
|
|
671
|
-
extensions: [
|
|
672
|
-
// TODO(burdon): This seems to upgrade the parser.
|
|
673
|
-
// GitHub flavored markdown bundle: Table, TaskList, Strikethrough, and Autolink.
|
|
674
|
-
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
675
|
-
// https://github.github.com/gfm
|
|
676
|
-
// GFM,
|
|
677
|
-
// Custom styling.
|
|
678
|
-
markdownTagsExtension
|
|
679
|
-
]
|
|
680
|
-
}),
|
|
681
|
-
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
682
|
-
syntaxHighlighting2(markdownHighlightStyle),
|
|
683
|
-
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
684
|
-
].filter(Boolean);
|
|
685
1690
|
};
|
|
686
1691
|
|
|
687
1692
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
688
1693
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
689
|
-
import { EditorView as
|
|
1694
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
690
1695
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
691
1696
|
import { vim } from "@replit/codemirror-vim";
|
|
692
|
-
import
|
|
693
|
-
import get3 from "lodash.get";
|
|
1697
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
694
1698
|
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
|
|
695
|
-
import {
|
|
1699
|
+
import { generateName } from "@dxos/display-name";
|
|
696
1700
|
import { useThemeContext } from "@dxos/react-ui";
|
|
1701
|
+
import { getColorForValue, inputSurface, mx as mx4 } from "@dxos/react-ui-theme";
|
|
1702
|
+
var EditorModes = [
|
|
1703
|
+
"default",
|
|
1704
|
+
"vim"
|
|
1705
|
+
];
|
|
1706
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
|
|
1707
|
+
const { themeMode } = useThemeContext();
|
|
1708
|
+
const tabsterDOMAttribute = useFocusableGroup({
|
|
1709
|
+
tabBehavior: "limited"
|
|
1710
|
+
});
|
|
1711
|
+
const [root, setRoot] = useState(null);
|
|
1712
|
+
const [state, setState] = useState();
|
|
1713
|
+
const [view, setView] = useState();
|
|
1714
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
1715
|
+
root,
|
|
1716
|
+
state,
|
|
1717
|
+
view
|
|
1718
|
+
}), [
|
|
1719
|
+
view,
|
|
1720
|
+
state,
|
|
1721
|
+
root
|
|
1722
|
+
]);
|
|
1723
|
+
const { awareness, peer } = model;
|
|
1724
|
+
useEffect2(() => {
|
|
1725
|
+
if (awareness && peer) {
|
|
1726
|
+
awareness.setLocalStateField("user", {
|
|
1727
|
+
name: peer.name ?? generateName(peer.id),
|
|
1728
|
+
color: getColorForValue({
|
|
1729
|
+
value: peer.id,
|
|
1730
|
+
type: "color"
|
|
1731
|
+
}),
|
|
1732
|
+
colorLight: getColorForValue({
|
|
1733
|
+
value: peer.id,
|
|
1734
|
+
themeMode,
|
|
1735
|
+
type: "highlight"
|
|
1736
|
+
})
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
}, [
|
|
1740
|
+
awareness,
|
|
1741
|
+
peer,
|
|
1742
|
+
themeMode
|
|
1743
|
+
]);
|
|
1744
|
+
useEffect2(() => {
|
|
1745
|
+
if (!root) {
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
const state2 = EditorState2.create({
|
|
1749
|
+
doc: model.text(),
|
|
1750
|
+
extensions: [
|
|
1751
|
+
readonly && EditorState2.readOnly.of(readonly),
|
|
1752
|
+
// TODO(burdon): Factor out VIM mode?
|
|
1753
|
+
editorMode === "vim" && vim(),
|
|
1754
|
+
// Theme.
|
|
1755
|
+
// TODO(burdon): Make optional.
|
|
1756
|
+
EditorView11.baseTheme(defaultTheme),
|
|
1757
|
+
EditorView11.theme(slots?.editor?.theme ?? {}),
|
|
1758
|
+
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
1759
|
+
EditorView11.darkTheme.of(themeMode === "dark"),
|
|
1760
|
+
// Storage and replication.
|
|
1761
|
+
model.extension,
|
|
1762
|
+
// Custom.
|
|
1763
|
+
...extensions
|
|
1764
|
+
].filter(Boolean)
|
|
1765
|
+
});
|
|
1766
|
+
view?.destroy();
|
|
1767
|
+
setView(new EditorView11({
|
|
1768
|
+
state: state2,
|
|
1769
|
+
parent: root
|
|
1770
|
+
}));
|
|
1771
|
+
setState(state2);
|
|
1772
|
+
return () => {
|
|
1773
|
+
view?.destroy();
|
|
1774
|
+
setView(void 0);
|
|
1775
|
+
setState(void 0);
|
|
1776
|
+
};
|
|
1777
|
+
}, [
|
|
1778
|
+
root,
|
|
1779
|
+
model,
|
|
1780
|
+
themeMode,
|
|
1781
|
+
readonly,
|
|
1782
|
+
editorMode
|
|
1783
|
+
]);
|
|
1784
|
+
const handleKeyUp = useCallback((event) => {
|
|
1785
|
+
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
1786
|
+
switch (key) {
|
|
1787
|
+
case "Enter": {
|
|
1788
|
+
view?.contentDOM.focus();
|
|
1789
|
+
break;
|
|
1790
|
+
}
|
|
1791
|
+
case "Escape": {
|
|
1792
|
+
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
|
|
1793
|
+
break;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}, [
|
|
1797
|
+
view,
|
|
1798
|
+
editorMode
|
|
1799
|
+
]);
|
|
1800
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
1801
|
+
key: model.id,
|
|
1802
|
+
ref: setRoot,
|
|
1803
|
+
tabIndex: 0,
|
|
1804
|
+
...slots?.root,
|
|
1805
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
1806
|
+
onKeyUp: handleKeyUp
|
|
1807
|
+
});
|
|
1808
|
+
});
|
|
1809
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1810
|
+
const { themeMode } = useThemeContext();
|
|
1811
|
+
const slots = defaultsDeep2({}, _slots, defaultTextSlots);
|
|
1812
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1813
|
+
ref: forwardedRef,
|
|
1814
|
+
readonly,
|
|
1815
|
+
extensions: [
|
|
1816
|
+
basicBundle({
|
|
1817
|
+
readonly,
|
|
1818
|
+
themeMode,
|
|
1819
|
+
placeholder: slots?.editor?.placeholder
|
|
1820
|
+
}),
|
|
1821
|
+
...extensions
|
|
1822
|
+
],
|
|
1823
|
+
slots,
|
|
1824
|
+
...props
|
|
1825
|
+
});
|
|
1826
|
+
});
|
|
1827
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1828
|
+
const { themeMode } = useThemeContext();
|
|
1829
|
+
const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
|
|
1830
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1831
|
+
ref: forwardedRef,
|
|
1832
|
+
readonly,
|
|
1833
|
+
extensions: [
|
|
1834
|
+
markdownBundle({
|
|
1835
|
+
readonly,
|
|
1836
|
+
themeMode,
|
|
1837
|
+
placeholder: slots?.editor?.placeholder
|
|
1838
|
+
}),
|
|
1839
|
+
...extensions
|
|
1840
|
+
],
|
|
1841
|
+
slots,
|
|
1842
|
+
...props
|
|
1843
|
+
});
|
|
1844
|
+
});
|
|
1845
|
+
var defaultSlots = {
|
|
1846
|
+
root: {
|
|
1847
|
+
className: mx4("p-2", inputSurface)
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
var defaultTextSlots = {
|
|
1851
|
+
...defaultSlots,
|
|
1852
|
+
editor: {
|
|
1853
|
+
theme: textTheme
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
var defaultMarkdownSlots = {
|
|
1857
|
+
...defaultSlots,
|
|
1858
|
+
editor: {
|
|
1859
|
+
theme: markdownTheme
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
697
1862
|
|
|
698
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
699
|
-
import
|
|
1863
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1864
|
+
import get4 from "lodash.get";
|
|
1865
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
700
1866
|
import { yCollab } from "y-codemirror.next";
|
|
701
|
-
import {
|
|
702
|
-
import {
|
|
703
|
-
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
704
|
-
import { YText } from "@dxos/text-model";
|
|
1867
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1868
|
+
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
705
1869
|
|
|
706
|
-
// packages/ui/react-ui-editor/src/
|
|
707
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
708
|
-
import { ViewPlugin as
|
|
1870
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1871
|
+
import { Annotation, Facet, StateEffect as StateEffect2, StateField as StateField6 } from "@codemirror/state";
|
|
1872
|
+
import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
709
1873
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
710
1874
|
|
|
711
|
-
// packages/ui/react-ui-editor/src/
|
|
1875
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
712
1876
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
713
1877
|
|
|
714
|
-
// packages/ui/react-ui-editor/src/automerge/automerge-
|
|
1878
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/automerge-to-codemirror.ts
|
|
715
1879
|
import { ChangeSet } from "@codemirror/state";
|
|
716
|
-
var
|
|
1880
|
+
var automergeToCodemirror = (view, selection, target, patches) => {
|
|
717
1881
|
for (const patch of patches) {
|
|
718
1882
|
const changeSpec = handlePatch(patch, target, view.state);
|
|
719
1883
|
if (changeSpec != null) {
|
|
@@ -818,9 +1982,9 @@ var charPath = (textPath, candidatePath) => {
|
|
|
818
1982
|
return null;
|
|
819
1983
|
};
|
|
820
1984
|
|
|
821
|
-
// packages/ui/react-ui-editor/src/automerge/automerge
|
|
1985
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/codemirror-to-automerge.ts
|
|
822
1986
|
import { next as am } from "@dxos/automerge/automerge";
|
|
823
|
-
var
|
|
1987
|
+
var codemirrorToAutomerge = (field, handle, transactions, state) => {
|
|
824
1988
|
const { lastHeads, path } = state.field(field);
|
|
825
1989
|
let hasChanges = false;
|
|
826
1990
|
for (const tr of transactions) {
|
|
@@ -841,7 +2005,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
|
841
2005
|
return newHeads ?? void 0;
|
|
842
2006
|
};
|
|
843
2007
|
|
|
844
|
-
// packages/ui/react-ui-editor/src/
|
|
2008
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
845
2009
|
var PatchSemaphore = class {
|
|
846
2010
|
constructor(field) {
|
|
847
2011
|
this._inReconcile = false;
|
|
@@ -864,12 +2028,12 @@ var PatchSemaphore = class {
|
|
|
864
2028
|
annotations: reconcileAnnotationType.of(true)
|
|
865
2029
|
});
|
|
866
2030
|
}
|
|
867
|
-
let newHeads =
|
|
2031
|
+
let newHeads = codemirrorToAutomerge(this._field, handle, transactions, view.state);
|
|
868
2032
|
if (newHeads === null || newHeads === void 0) {
|
|
869
2033
|
newHeads = automerge.getHeads(handle.docSync());
|
|
870
2034
|
}
|
|
871
2035
|
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
872
|
-
|
|
2036
|
+
automergeToCodemirror(view, selection, path, diff);
|
|
873
2037
|
view.dispatch({
|
|
874
2038
|
effects: updateHeads(newHeads),
|
|
875
2039
|
annotations: reconcileAnnotationType.of({})
|
|
@@ -882,8 +2046,8 @@ var PatchSemaphore = class {
|
|
|
882
2046
|
}
|
|
883
2047
|
};
|
|
884
2048
|
|
|
885
|
-
// packages/ui/react-ui-editor/src/
|
|
886
|
-
var effectType =
|
|
2049
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
2050
|
+
var effectType = StateEffect2.define({});
|
|
887
2051
|
var updateHeads = (newHeads) => effectType.of({
|
|
888
2052
|
newHeads
|
|
889
2053
|
});
|
|
@@ -893,7 +2057,7 @@ var semaphoreFacet = Facet.define({
|
|
|
893
2057
|
combine: (values) => values.at(-1)
|
|
894
2058
|
});
|
|
895
2059
|
var automergePlugin = (handle, path) => {
|
|
896
|
-
const stateField =
|
|
2060
|
+
const stateField = StateField6.define({
|
|
897
2061
|
create: () => ({
|
|
898
2062
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
899
2063
|
unreconciledTransactions: [],
|
|
@@ -923,7 +2087,7 @@ var automergePlugin = (handle, path) => {
|
|
|
923
2087
|
}
|
|
924
2088
|
});
|
|
925
2089
|
const semaphore = new PatchSemaphore(stateField);
|
|
926
|
-
const viewPlugin =
|
|
2090
|
+
const viewPlugin = ViewPlugin4.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
927
2091
|
constructor(view) {
|
|
928
2092
|
this._handleChange = () => {
|
|
929
2093
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -931,8 +2095,8 @@ var automergePlugin = (handle, path) => {
|
|
|
931
2095
|
this._view = view;
|
|
932
2096
|
handle.addListener("change", this._handleChange);
|
|
933
2097
|
}
|
|
934
|
-
update(
|
|
935
|
-
if (
|
|
2098
|
+
update(update4) {
|
|
2099
|
+
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
936
2100
|
queueMicrotask(() => {
|
|
937
2101
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
938
2102
|
});
|
|
@@ -953,47 +2117,8 @@ var automergePlugin = (handle, path) => {
|
|
|
953
2117
|
var reconcileAnnotationType = Annotation.define();
|
|
954
2118
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
955
2119
|
|
|
956
|
-
// packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
|
|
957
|
-
var useCollaboration = (model, themeMode) => {
|
|
958
|
-
const { provider, peer, content } = model;
|
|
959
|
-
const extension = useMemo(() => {
|
|
960
|
-
if (content instanceof YText) {
|
|
961
|
-
return yCollab(content, provider?.awareness);
|
|
962
|
-
} else if (isDocAccessor(content)) {
|
|
963
|
-
return automergePlugin(content.handle, content.path);
|
|
964
|
-
} else {
|
|
965
|
-
return void 0;
|
|
966
|
-
}
|
|
967
|
-
}, []);
|
|
968
|
-
useEffect(() => {
|
|
969
|
-
if (provider && peer) {
|
|
970
|
-
provider.awareness.setLocalStateField("user", {
|
|
971
|
-
name: peer.name ?? generateName(peer.id),
|
|
972
|
-
color: getColorForValue({
|
|
973
|
-
value: peer.id,
|
|
974
|
-
type: "color"
|
|
975
|
-
}),
|
|
976
|
-
colorLight: getColorForValue({
|
|
977
|
-
value: peer.id,
|
|
978
|
-
themeMode,
|
|
979
|
-
type: "highlight"
|
|
980
|
-
})
|
|
981
|
-
});
|
|
982
|
-
}
|
|
983
|
-
}, [
|
|
984
|
-
provider,
|
|
985
|
-
peer,
|
|
986
|
-
themeMode
|
|
987
|
-
]);
|
|
988
|
-
return extension;
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
992
|
-
import { useMemo as useMemo2 } from "react";
|
|
993
|
-
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
994
|
-
|
|
995
2120
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
996
|
-
import * as
|
|
2121
|
+
import * as random2 from "lib0/random";
|
|
997
2122
|
var cursorColors = [
|
|
998
2123
|
{
|
|
999
2124
|
color: "#30bced",
|
|
@@ -1028,7 +2153,7 @@ var cursorColors = [
|
|
|
1028
2153
|
light: "#1be7ff33"
|
|
1029
2154
|
}
|
|
1030
2155
|
];
|
|
1031
|
-
var cursorColor = cursorColors[
|
|
2156
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
1032
2157
|
|
|
1033
2158
|
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
1034
2159
|
import * as decoding from "lib0/decoding";
|
|
@@ -1036,7 +2161,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1036
2161
|
import { Observable } from "lib0/observable";
|
|
1037
2162
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1038
2163
|
import { log } from "@dxos/log";
|
|
1039
|
-
var
|
|
2164
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1040
2165
|
var messageAwareness = 1;
|
|
1041
2166
|
var messageQueryAwareness = 3;
|
|
1042
2167
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1073,7 +2198,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1073
2198
|
removed,
|
|
1074
2199
|
origin
|
|
1075
2200
|
}, {
|
|
1076
|
-
F:
|
|
2201
|
+
F: __dxlog_file3,
|
|
1077
2202
|
L: 67,
|
|
1078
2203
|
S: this,
|
|
1079
2204
|
C: (f, a) => f(...a)
|
|
@@ -1086,7 +2211,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1086
2211
|
}
|
|
1087
2212
|
_handleSpaceMessage({ payload }) {
|
|
1088
2213
|
log("space message", payload, {
|
|
1089
|
-
F:
|
|
2214
|
+
F: __dxlog_file3,
|
|
1090
2215
|
L: 79,
|
|
1091
2216
|
S: this,
|
|
1092
2217
|
C: (f, a) => f(...a)
|
|
@@ -1131,185 +2256,82 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1131
2256
|
};
|
|
1132
2257
|
|
|
1133
2258
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2259
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1134
2260
|
var useTextModel = ({ identity, space, text }) => {
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
2261
|
+
const [model, setModel] = useState2(() => createModel({
|
|
2262
|
+
identity,
|
|
2263
|
+
space,
|
|
2264
|
+
text
|
|
2265
|
+
}));
|
|
2266
|
+
useEffect3(() => {
|
|
2267
|
+
setModel(createModel({
|
|
2268
|
+
identity,
|
|
1143
2269
|
space,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
});
|
|
2270
|
+
text
|
|
2271
|
+
}));
|
|
1147
2272
|
}, [
|
|
1148
2273
|
identity,
|
|
1149
2274
|
space,
|
|
1150
|
-
text,
|
|
1151
|
-
text?.doc
|
|
1152
|
-
]);
|
|
1153
|
-
const content = useMemo2(() => {
|
|
1154
|
-
if (isActualAutomergeObject(text)) {
|
|
1155
|
-
const obj = text;
|
|
1156
|
-
return getRawDoc(obj, [
|
|
1157
|
-
obj.field
|
|
1158
|
-
]);
|
|
1159
|
-
} else {
|
|
1160
|
-
return text?.content;
|
|
1161
|
-
}
|
|
1162
|
-
}, [
|
|
1163
2275
|
text
|
|
1164
2276
|
]);
|
|
2277
|
+
return model;
|
|
2278
|
+
};
|
|
2279
|
+
var createModel = (options) => {
|
|
2280
|
+
const { text } = options;
|
|
1165
2281
|
if (isActualAutomergeObject(text)) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
id: identity.identityKey.toHex(),
|
|
1173
|
-
name: identity.profile?.displayName
|
|
1174
|
-
} : void 0
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
|
-
if (!text?.doc || !text?.content) {
|
|
1178
|
-
return void 0;
|
|
2282
|
+
return createAutomergeModel(options);
|
|
2283
|
+
} else {
|
|
2284
|
+
if (!text?.doc) {
|
|
2285
|
+
return void 0;
|
|
2286
|
+
}
|
|
2287
|
+
return createYjsModel(options);
|
|
1179
2288
|
}
|
|
2289
|
+
};
|
|
2290
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
2291
|
+
invariant3(text?.doc && text?.content, void 0, {
|
|
2292
|
+
F: __dxlog_file4,
|
|
2293
|
+
L: 81,
|
|
2294
|
+
S: void 0,
|
|
2295
|
+
A: [
|
|
2296
|
+
"text?.doc && text?.content",
|
|
2297
|
+
""
|
|
2298
|
+
]
|
|
2299
|
+
});
|
|
2300
|
+
const provider = space ? new SpaceAwarenessProvider({
|
|
2301
|
+
space,
|
|
2302
|
+
doc: text.doc,
|
|
2303
|
+
channel: `yjs.awareness.${text.id}`
|
|
2304
|
+
}) : void 0;
|
|
1180
2305
|
return {
|
|
1181
2306
|
id: text.doc.guid,
|
|
1182
2307
|
content: text.content,
|
|
1183
|
-
|
|
2308
|
+
text: () => text.content.toString(),
|
|
2309
|
+
ranges: [],
|
|
2310
|
+
extension: yCollab(text.content, provider?.awareness),
|
|
2311
|
+
awareness: provider?.awareness,
|
|
1184
2312
|
peer: identity ? {
|
|
1185
2313
|
id: identity.identityKey.toHex(),
|
|
1186
2314
|
name: identity.profile?.displayName
|
|
1187
2315
|
} : void 0
|
|
1188
2316
|
};
|
|
1189
2317
|
};
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
"vim"
|
|
1195
|
-
];
|
|
1196
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots, editorMode }, forwardedRef) => {
|
|
1197
|
-
const { themeMode } = useThemeContext();
|
|
1198
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
1199
|
-
tabBehavior: "limited"
|
|
1200
|
-
});
|
|
1201
|
-
const [parent, setParent] = useState(null);
|
|
1202
|
-
const [state, setState] = useState();
|
|
1203
|
-
const [view, setView] = useState();
|
|
1204
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
1205
|
-
editor: parent,
|
|
1206
|
-
state,
|
|
1207
|
-
view
|
|
1208
|
-
}), [
|
|
1209
|
-
view,
|
|
1210
|
-
state,
|
|
1211
|
-
parent
|
|
1212
|
-
]);
|
|
1213
|
-
const collaboration = useCollaboration(model, themeMode);
|
|
1214
|
-
useEffect2(() => {
|
|
1215
|
-
if (!parent) {
|
|
1216
|
-
return;
|
|
1217
|
-
}
|
|
1218
|
-
const initialText = isDocAccessor2(model.content) ? get3(model.content.handle.docSync(), model.content.path) : model.content?.toString();
|
|
1219
|
-
const state2 = EditorState2.create({
|
|
1220
|
-
doc: initialText,
|
|
1221
|
-
extensions: [
|
|
1222
|
-
// TODO(burdon): Factor out VIM mode?
|
|
1223
|
-
editorMode === "vim" && vim(),
|
|
1224
|
-
// Replication.
|
|
1225
|
-
collaboration,
|
|
1226
|
-
// Theme.
|
|
1227
|
-
slots?.editor?.theme && EditorView5.theme(slots?.editor?.theme),
|
|
1228
|
-
// Custom.
|
|
1229
|
-
...extensions
|
|
1230
|
-
].filter(Boolean)
|
|
1231
|
-
});
|
|
1232
|
-
setState(state2);
|
|
1233
|
-
view?.destroy();
|
|
1234
|
-
setView(new EditorView5({
|
|
1235
|
-
state: state2,
|
|
1236
|
-
parent
|
|
1237
|
-
}));
|
|
1238
|
-
return () => {
|
|
1239
|
-
view?.destroy();
|
|
1240
|
-
setView(void 0);
|
|
1241
|
-
setState(void 0);
|
|
1242
|
-
};
|
|
1243
|
-
}, [
|
|
1244
|
-
parent,
|
|
1245
|
-
model.content,
|
|
1246
|
-
themeMode,
|
|
1247
|
-
editorMode
|
|
1248
|
-
]);
|
|
1249
|
-
const handleKeyUp = useCallback((event) => {
|
|
1250
|
-
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
1251
|
-
switch (key) {
|
|
1252
|
-
case "Enter": {
|
|
1253
|
-
view?.contentDOM.focus();
|
|
1254
|
-
break;
|
|
1255
|
-
}
|
|
1256
|
-
case "Escape": {
|
|
1257
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && parent?.focus();
|
|
1258
|
-
break;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
}, [
|
|
1262
|
-
view,
|
|
1263
|
-
editorMode
|
|
2318
|
+
var createAutomergeModel = ({ identity, text }) => {
|
|
2319
|
+
const obj = text;
|
|
2320
|
+
const doc = getRawDoc(obj, [
|
|
2321
|
+
obj.field
|
|
1264
2322
|
]);
|
|
1265
|
-
return
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
..._extensions ?? [],
|
|
1278
|
-
basicBundle({
|
|
1279
|
-
themeMode,
|
|
1280
|
-
placeholder: slots?.editor?.placeholder
|
|
1281
|
-
})
|
|
1282
|
-
];
|
|
1283
|
-
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1284
|
-
ref: forwardedRef,
|
|
1285
|
-
extensions,
|
|
1286
|
-
slots: defaultsDeep({}, slots, {
|
|
1287
|
-
editor: {
|
|
1288
|
-
theme: basicTheme
|
|
1289
|
-
}
|
|
1290
|
-
}),
|
|
1291
|
-
...props
|
|
1292
|
-
});
|
|
1293
|
-
});
|
|
1294
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
|
|
1295
|
-
const { themeMode } = useThemeContext();
|
|
1296
|
-
const extensions = [
|
|
1297
|
-
..._extensions ?? [],
|
|
1298
|
-
markdownBundle({
|
|
1299
|
-
themeMode
|
|
1300
|
-
})
|
|
1301
|
-
];
|
|
1302
|
-
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1303
|
-
ref: forwardedRef,
|
|
1304
|
-
extensions,
|
|
1305
|
-
slots: defaultsDeep({}, slots, {
|
|
1306
|
-
editor: {
|
|
1307
|
-
theme: markdownTheme
|
|
1308
|
-
}
|
|
1309
|
-
}),
|
|
1310
|
-
...props
|
|
1311
|
-
});
|
|
1312
|
-
});
|
|
2323
|
+
return {
|
|
2324
|
+
id: obj.id,
|
|
2325
|
+
content: doc,
|
|
2326
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2327
|
+
ranges: [],
|
|
2328
|
+
extension: automergePlugin(doc.handle, doc.path),
|
|
2329
|
+
peer: identity ? {
|
|
2330
|
+
id: identity.identityKey.toHex(),
|
|
2331
|
+
name: identity.profile?.displayName
|
|
2332
|
+
} : void 0
|
|
2333
|
+
};
|
|
2334
|
+
};
|
|
1313
2335
|
export {
|
|
1314
2336
|
BaseTextEditor,
|
|
1315
2337
|
Doc,
|
|
@@ -1318,34 +2340,39 @@ export {
|
|
|
1318
2340
|
SpaceAwarenessProvider,
|
|
1319
2341
|
TextEditor,
|
|
1320
2342
|
TextKind,
|
|
1321
|
-
|
|
2343
|
+
YText,
|
|
1322
2344
|
YXmlFragment,
|
|
2345
|
+
autocomplete,
|
|
1323
2346
|
basicBundle,
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
2347
|
+
blast,
|
|
2348
|
+
code2 as code,
|
|
2349
|
+
codeTheme,
|
|
2350
|
+
comments,
|
|
1328
2351
|
cursorColor,
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
2352
|
+
defaultMarkdownSlots,
|
|
2353
|
+
defaultOptions,
|
|
2354
|
+
defaultSlots,
|
|
2355
|
+
defaultTextSlots,
|
|
2356
|
+
defaultTheme,
|
|
2357
|
+
demo,
|
|
2358
|
+
highlight,
|
|
2359
|
+
highlightDecorations,
|
|
2360
|
+
highlightStateField,
|
|
2361
|
+
image,
|
|
2362
|
+
link,
|
|
2363
|
+
listener2 as listener,
|
|
1338
2364
|
markdownBundle,
|
|
1339
2365
|
markdownHighlightStyle,
|
|
2366
|
+
markdownTags,
|
|
2367
|
+
markdownTagsExtensions,
|
|
1340
2368
|
markdownTheme,
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
stone,
|
|
2369
|
+
mention,
|
|
2370
|
+
table,
|
|
1344
2371
|
tags2 as tags,
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2372
|
+
tasklist,
|
|
2373
|
+
textTheme,
|
|
2374
|
+
tooltip,
|
|
2375
|
+
useHighlights,
|
|
2376
|
+
useTextModel
|
|
1350
2377
|
};
|
|
1351
2378
|
//# sourceMappingURL=index.mjs.map
|