@dxos/react-ui-editor 0.3.9 → 0.3.10-main.04816d3
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 +952 -736
- 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 +38 -0
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +5 -2
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +9 -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} +1 -1
- package/dist/types/src/components/TextEditor/extensions/basic.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 +10 -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/index.d.ts +7 -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.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +31 -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/tasklist.d.ts +2 -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 +20 -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/components/TextEditor/yjs.stories.d.ts +1 -0
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/handle.d.ts.map +1 -0
- 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/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +4 -4
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +12 -10
- 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 +22 -32
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +275 -0
- package/src/components/TextEditor/TextEditor.stories.tsx +46 -43
- package/src/components/TextEditor/TextEditor.tsx +79 -44
- package/src/components/TextEditor/extensions/autocomplete.ts +74 -0
- package/src/components/TextEditor/extensions/{basic/bundle.ts → basic.ts} +4 -2
- package/src/components/TextEditor/extensions/comments.ts +190 -0
- package/src/components/TextEditor/extensions/demo.ts +66 -0
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkWidget.tsx → experimental.tsx} +18 -2
- package/src/components/TextEditor/extensions/index.ts +7 -2
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkDecoration.ts → link.ts} +76 -31
- package/src/components/TextEditor/extensions/{change.ts → listener.ts} +4 -3
- package/src/components/TextEditor/extensions/markdown/bundle.ts +21 -25
- package/src/components/TextEditor/extensions/markdown/highlight.ts +167 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +1 -1
- package/src/components/TextEditor/extensions/tasklist.ts +107 -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 +185 -0
- package/src/components/TextEditor/themes/index.ts +5 -0
- package/src/components/TextEditor/yjs.stories.tsx +1 -0
- package/src/{automerge → hooks/automerge}/automerge.stories.tsx +2 -1
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useTextModel.ts +52 -39
- package/src/styles/markdown.ts +26 -24
- package/src/testing/replicator.ts +6 -6
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts.map +0 -1
- 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.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/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}/PatchSemaphore.d.ts +0 -0
- /package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/amToCodemirror.d.ts +0 -0
- /package/dist/types/src/{automerge → hooks/automerge}/automerge.stories.d.ts +0 -0
- /package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/codeMirrorToAm.d.ts +0 -0
- /package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/handle.d.ts +0 -0
- /package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/index.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}/PatchSemaphore.ts +0 -0
- /package/src/{automerge/automerge-plugin → hooks/automerge}/amToCodemirror.ts +0 -0
- /package/src/{automerge/automerge-plugin → hooks/automerge}/codeMirrorToAm.ts +0 -0
- /package/src/{automerge/automerge-plugin → hooks/automerge}/handle.ts +0 -0
- /package/src/{automerge/automerge-plugin → hooks/automerge}/index.ts +0 -0
- /package/src/{automerge/automerge-plugin → hooks/automerge}/plugin.ts +0 -0
|
@@ -1,519 +1,413 @@
|
|
|
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 word = context.matchBefore(/\w*/);
|
|
28
|
+
if (!word || word.from === word.to && !context.explicit) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
from: word.from,
|
|
33
|
+
options: onSearch(word.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
45
|
import { EditorView, placeholder } from "@codemirror/view";
|
|
13
46
|
var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
47
|
+
// TODO(burdon): Compare with minimalSetup.
|
|
48
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
14
49
|
bracketMatching(),
|
|
15
50
|
closeBrackets(),
|
|
16
|
-
_placeholder && placeholder(_placeholder),
|
|
17
51
|
EditorView.lineWrapping,
|
|
52
|
+
_placeholder && placeholder(_placeholder),
|
|
18
53
|
// TODO(burdon): Is this required?
|
|
19
54
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
20
55
|
].filter(Boolean);
|
|
21
56
|
|
|
22
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
57
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
|
|
58
|
+
import { keymap as keymap2 } from "@codemirror/view";
|
|
59
|
+
var defaultItems = [
|
|
60
|
+
"hello world!",
|
|
61
|
+
"this is a test.",
|
|
62
|
+
"this is [DXOS](https://dxos.org)"
|
|
63
|
+
];
|
|
64
|
+
var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
65
|
+
let t;
|
|
66
|
+
let idx = 0;
|
|
67
|
+
return [
|
|
68
|
+
keymap2.of([
|
|
69
|
+
{
|
|
70
|
+
// Reset.
|
|
71
|
+
key: "alt-meta-'",
|
|
72
|
+
run: (view) => {
|
|
73
|
+
clearTimeout(t);
|
|
74
|
+
idx = 0;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
// Next prompt.
|
|
80
|
+
// TODO(burdon): Press 1-9 to select prompt?
|
|
81
|
+
key: "shift-meta-'",
|
|
82
|
+
run: (view) => {
|
|
83
|
+
clearTimeout(t);
|
|
84
|
+
const text = items[idx++];
|
|
85
|
+
if (idx === items?.length) {
|
|
86
|
+
idx = 0;
|
|
87
|
+
}
|
|
88
|
+
let i = 0;
|
|
89
|
+
const insert = (d = 0) => {
|
|
90
|
+
t = setTimeout(() => {
|
|
91
|
+
const pos = view.state.selection.main.head;
|
|
92
|
+
view.dispatch({
|
|
93
|
+
changes: {
|
|
94
|
+
from: pos,
|
|
95
|
+
insert: text[i++]
|
|
96
|
+
},
|
|
97
|
+
selection: {
|
|
98
|
+
anchor: pos + 1
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
if (i < text.length) {
|
|
102
|
+
insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
|
|
103
|
+
}
|
|
104
|
+
}, d);
|
|
105
|
+
};
|
|
106
|
+
insert();
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
])
|
|
111
|
+
];
|
|
34
112
|
};
|
|
35
|
-
var bold = "font-bold";
|
|
36
|
-
var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
|
|
37
|
-
var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
|
|
38
|
-
var italic = "italic";
|
|
39
|
-
var strikethrough = "line-through";
|
|
40
|
-
var mark = "!font-normal !no-underline !text-inherit opacity-40";
|
|
41
|
-
|
|
42
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
43
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
44
|
-
var tokens = tailwindConfig({}).theme;
|
|
45
113
|
|
|
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
|
-
"& .cm-link": {
|
|
75
|
-
color: get(tokens, "extend.colors.primary.500"),
|
|
76
|
-
textDecoration: "underline"
|
|
114
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
115
|
+
import { keymap as keymap3, Decoration, EditorView as EditorView2, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
|
|
116
|
+
import { debounce } from "@dxos/async";
|
|
117
|
+
import { invariant } from "@dxos/invariant";
|
|
118
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
|
|
119
|
+
var BookmarkWidget = class extends WidgetType {
|
|
120
|
+
constructor(_pos, _id) {
|
|
121
|
+
super();
|
|
122
|
+
this._pos = _pos;
|
|
123
|
+
this._id = _id;
|
|
124
|
+
invariant(this._id, void 0, {
|
|
125
|
+
F: __dxlog_file,
|
|
126
|
+
L: 41,
|
|
127
|
+
S: this,
|
|
128
|
+
A: [
|
|
129
|
+
"this._id",
|
|
130
|
+
""
|
|
131
|
+
]
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
eq(other) {
|
|
135
|
+
return this._id === other._id;
|
|
136
|
+
}
|
|
137
|
+
toDOM() {
|
|
138
|
+
const span = document.createElement("span");
|
|
139
|
+
span.className = "cm-bookmark";
|
|
140
|
+
span.textContent = "\u{1F4AC}";
|
|
141
|
+
return span;
|
|
77
142
|
}
|
|
78
143
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return null;
|
|
144
|
+
var styles = EditorView2.baseTheme({
|
|
145
|
+
"& .cm-bookmark": {
|
|
146
|
+
cursor: "pointer",
|
|
147
|
+
margin: "4px",
|
|
148
|
+
padding: "4px",
|
|
149
|
+
backgroundColor: "yellow"
|
|
150
|
+
},
|
|
151
|
+
"& .cm-bookmark-selected": {
|
|
152
|
+
backgroundColor: "orange"
|
|
89
153
|
}
|
|
90
154
|
});
|
|
155
|
+
var comments = (options = {}) => {
|
|
156
|
+
let active;
|
|
157
|
+
const bookmarkMatcher = new MatchDecorator({
|
|
158
|
+
regexp: /\[\^(\w+)\]/g,
|
|
159
|
+
decoration: (match, view, pos) => {
|
|
160
|
+
const id = match[1];
|
|
161
|
+
return Decoration.replace({
|
|
162
|
+
id,
|
|
163
|
+
widget: new BookmarkWidget(pos, id)
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
const bookmarks = ViewPlugin.fromClass(class {
|
|
168
|
+
constructor(view) {
|
|
169
|
+
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
170
|
+
}
|
|
171
|
+
update(update2) {
|
|
172
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update2, this.bookmarks);
|
|
173
|
+
}
|
|
174
|
+
}, {
|
|
175
|
+
decorations: (instance) => instance.bookmarks,
|
|
176
|
+
provide: (plugin) => EditorView2.atomicRanges.of((view) => {
|
|
177
|
+
return view.plugin(plugin)?.bookmarks || Decoration.none;
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
const doUpdate = debounce((data) => {
|
|
181
|
+
options.onUpdate?.(data);
|
|
182
|
+
}, 200);
|
|
183
|
+
return [
|
|
184
|
+
keymap3.of([
|
|
185
|
+
{
|
|
186
|
+
key: options?.key ?? "shift-meta-c",
|
|
187
|
+
run: (view) => {
|
|
188
|
+
const id = options.onCreate?.();
|
|
189
|
+
if (id) {
|
|
190
|
+
const pos = view.state.selection.main.head;
|
|
191
|
+
const tag = `[^${id}]`;
|
|
192
|
+
view.dispatch({
|
|
193
|
+
changes: {
|
|
194
|
+
from: pos,
|
|
195
|
+
insert: tag
|
|
196
|
+
},
|
|
197
|
+
selection: {
|
|
198
|
+
anchor: pos + tag.length
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
]),
|
|
207
|
+
bookmarks,
|
|
208
|
+
// Monitor cursor movement.
|
|
209
|
+
EditorView2.updateListener.of((update2) => {
|
|
210
|
+
active = void 0;
|
|
211
|
+
if (!options.onUpdate) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const view = update2.view;
|
|
215
|
+
const pos = view.state.selection.main.head;
|
|
216
|
+
const decorations = [];
|
|
217
|
+
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
218
|
+
let closest = Infinity;
|
|
219
|
+
const { from, to } = view.visibleRanges?.[0] ?? {
|
|
220
|
+
from: 0,
|
|
221
|
+
to: view.state.doc.length
|
|
222
|
+
};
|
|
223
|
+
rangeSet?.between(from, to, (from2, to2, value) => {
|
|
224
|
+
decorations.push({
|
|
225
|
+
from: from2,
|
|
226
|
+
to: to2,
|
|
227
|
+
value
|
|
228
|
+
});
|
|
229
|
+
const d = Math.min(Math.abs(pos - from2), Math.abs(pos - to2));
|
|
230
|
+
if (d < closest) {
|
|
231
|
+
active = value.spec.id;
|
|
232
|
+
closest = d;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
if (decorations.length) {
|
|
236
|
+
doUpdate({
|
|
237
|
+
active,
|
|
238
|
+
items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
|
|
239
|
+
id,
|
|
240
|
+
pos: from2,
|
|
241
|
+
location: view.coordsAtPos(from2)
|
|
242
|
+
}))
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}),
|
|
246
|
+
styles
|
|
247
|
+
];
|
|
248
|
+
};
|
|
91
249
|
|
|
92
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
250
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
93
251
|
import { syntaxTree } from "@codemirror/language";
|
|
94
|
-
import { RangeSetBuilder, StateField
|
|
95
|
-
import { Decoration, EditorView as
|
|
96
|
-
var
|
|
97
|
-
constructor(
|
|
252
|
+
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
253
|
+
import { Decoration as Decoration2, EditorView as EditorView3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
254
|
+
var LinkButton = class extends WidgetType2 {
|
|
255
|
+
constructor(_pos, _url, _onAttach) {
|
|
98
256
|
super();
|
|
99
|
-
this.
|
|
257
|
+
this._pos = _pos;
|
|
258
|
+
this._url = _url;
|
|
259
|
+
this._onAttach = _onAttach;
|
|
260
|
+
}
|
|
261
|
+
eq(other) {
|
|
262
|
+
return this._pos === other._pos && this._url === other._url;
|
|
263
|
+
}
|
|
264
|
+
toDOM(view) {
|
|
265
|
+
const el = document.createElement("span");
|
|
266
|
+
this._onAttach(el, this._url);
|
|
267
|
+
return el;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var LinkText = class extends WidgetType2 {
|
|
271
|
+
constructor(_pos, _text, _url) {
|
|
272
|
+
super();
|
|
273
|
+
this._pos = _pos;
|
|
100
274
|
this._text = _text;
|
|
101
275
|
this._url = _url;
|
|
102
276
|
}
|
|
103
277
|
eq(other) {
|
|
104
|
-
return this.
|
|
278
|
+
return this._pos === other._pos && this._url === other._url;
|
|
105
279
|
}
|
|
106
280
|
toDOM(view) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
281
|
+
const link2 = document.createElement("a");
|
|
282
|
+
link2.setAttribute("class", "cm-link");
|
|
283
|
+
link2.textContent = this._text;
|
|
110
284
|
if (this._url) {
|
|
111
|
-
|
|
112
|
-
|
|
285
|
+
link2.setAttribute("rel", "noreferrer");
|
|
286
|
+
link2.setAttribute("target", "_blank");
|
|
287
|
+
link2.href = this._url;
|
|
113
288
|
} else {
|
|
114
|
-
|
|
289
|
+
link2.onclick = () => {
|
|
115
290
|
view.dispatch({
|
|
116
291
|
selection: {
|
|
117
|
-
anchor: this.
|
|
292
|
+
anchor: this._pos
|
|
118
293
|
}
|
|
119
294
|
});
|
|
120
295
|
};
|
|
121
296
|
}
|
|
122
|
-
return
|
|
297
|
+
return link2;
|
|
123
298
|
}
|
|
124
299
|
};
|
|
125
|
-
var
|
|
126
|
-
return StateField2.define({
|
|
127
|
-
create: (state) => update(state, link),
|
|
128
|
-
update: (_, tr) => update(tr.state, link),
|
|
129
|
-
provide: (field) => EditorView2.decorations.from(field)
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
|
-
var update = (state, link) => {
|
|
300
|
+
var update = (state, options) => {
|
|
133
301
|
const builder = new RangeSetBuilder();
|
|
134
302
|
const cursor = state.selection.main.head;
|
|
135
303
|
syntaxTree(state).iterate({
|
|
136
304
|
enter: (node) => {
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
builder.add(node.from, node.to, Decoration.replace({
|
|
144
|
-
widget: new Link(node.from, text, link ? url : void 0)
|
|
145
|
-
}));
|
|
305
|
+
if (node.name === "Link") {
|
|
306
|
+
const marks = node.node.getChildren("LinkMark");
|
|
307
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
308
|
+
const urlNode = node.node.getChild("URL");
|
|
309
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
310
|
+
if (!url) {
|
|
146
311
|
return false;
|
|
147
312
|
}
|
|
313
|
+
if (cursor < node.from || cursor > node.to) {
|
|
314
|
+
builder.add(node.from, node.to, Decoration2.replace({
|
|
315
|
+
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
if (options.onRender) {
|
|
319
|
+
builder.add(node.to, node.to, Decoration2.replace({
|
|
320
|
+
widget: new LinkButton(node.from, url, options.onRender)
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
return false;
|
|
148
324
|
}
|
|
149
|
-
return true;
|
|
150
325
|
}
|
|
151
326
|
});
|
|
152
327
|
return builder.finish();
|
|
153
328
|
};
|
|
329
|
+
var link = (options = {}) => {
|
|
330
|
+
return StateField.define({
|
|
331
|
+
create: (state) => update(state, options),
|
|
332
|
+
update: (_, tr) => update(tr.state, options),
|
|
333
|
+
provide: (field) => EditorView3.decorations.from(field)
|
|
334
|
+
});
|
|
335
|
+
};
|
|
154
336
|
|
|
155
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
156
|
-
import {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
let idx = 0;
|
|
163
|
-
let match;
|
|
164
|
-
do {
|
|
165
|
-
match = text.substring(idx).match(regexp);
|
|
166
|
-
if (!match) {
|
|
167
|
-
match = void 0;
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
idx = text.indexOf(match[0]);
|
|
171
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
172
|
-
break;
|
|
337
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
338
|
+
import { StateField as StateField2 } from "@codemirror/state";
|
|
339
|
+
var listener = ({ onChange }) => StateField2.define({
|
|
340
|
+
create: () => null,
|
|
341
|
+
update: (_value, transaction) => {
|
|
342
|
+
if (transaction.docChanged && onChange) {
|
|
343
|
+
onChange(transaction.newDoc.toString());
|
|
173
344
|
}
|
|
174
|
-
idx += match[0].length;
|
|
175
|
-
} while (true);
|
|
176
|
-
if (!match) {
|
|
177
345
|
return null;
|
|
178
346
|
}
|
|
179
|
-
const [, , url] = match ?? [];
|
|
180
|
-
return {
|
|
181
|
-
pos: idx + from,
|
|
182
|
-
end: idx + from + match[0].length,
|
|
183
|
-
above: true,
|
|
184
|
-
create: () => {
|
|
185
|
-
const el = document.createElement("a");
|
|
186
|
-
el.innerText = "_";
|
|
187
|
-
el.className = tooltipContent({}, "mb-2 p-1");
|
|
188
|
-
el.setAttribute("target", "_blank");
|
|
189
|
-
el.setAttribute("href", url);
|
|
190
|
-
onHover(el, url);
|
|
191
|
-
return {
|
|
192
|
-
dom: el
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
347
|
});
|
|
197
348
|
|
|
198
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.tsx
|
|
199
|
-
import { Decoration as Decoration2, EditorView as EditorView3, MatchDecorator, ViewPlugin } from "@codemirror/view";
|
|
200
|
-
var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
|
|
201
|
-
var linkDecorator = () => new MatchDecorator({
|
|
202
|
-
regexp: markdownLinkRegexp2,
|
|
203
|
-
decorate: (add, from, to, match, view) => {
|
|
204
|
-
const [_, label, url] = match;
|
|
205
|
-
const p0 = {
|
|
206
|
-
start: from,
|
|
207
|
-
end: from + 1
|
|
208
|
-
};
|
|
209
|
-
const p1 = {
|
|
210
|
-
start: from + 1,
|
|
211
|
-
end: from + 1 + label.length
|
|
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
349
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
292
350
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
293
|
-
import { defaultKeymap, history,
|
|
351
|
+
import { defaultKeymap, history, indentWithTab } from "@codemirror/commands";
|
|
294
352
|
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
295
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2,
|
|
353
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
296
354
|
import { languages } from "@codemirror/language-data";
|
|
297
|
-
import { lintKeymap } from "@codemirror/lint";
|
|
298
355
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
299
356
|
import { EditorState } from "@codemirror/state";
|
|
300
357
|
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";
|
|
358
|
+
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap4, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
359
|
+
|
|
360
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
361
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
362
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
363
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
364
|
+
import get from "lodash.get";
|
|
365
|
+
|
|
366
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
367
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
368
|
+
var heading = {
|
|
369
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
370
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
371
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
372
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
373
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
374
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
375
|
+
};
|
|
376
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
377
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
378
|
+
var bold = "font-bold";
|
|
379
|
+
var italic = "italic";
|
|
380
|
+
var strikethrough = "line-through";
|
|
381
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
382
|
+
var codeMark = "font-mono text-primary-500";
|
|
383
|
+
var inlineUrl = mx(code, "px-1");
|
|
384
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
385
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
|
|
386
|
+
|
|
387
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
388
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
389
|
+
var tokens = tailwindConfig({}).theme;
|
|
302
390
|
|
|
303
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/
|
|
304
|
-
import { styleTags, Tag } from "@lezer/highlight";
|
|
391
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
305
392
|
var markdownTags = {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
393
|
+
Blockquote: Tag.define(),
|
|
394
|
+
CodeMark: Tag.define(),
|
|
395
|
+
CodeText: Tag.define(),
|
|
396
|
+
EmphasisMark: Tag.define(),
|
|
397
|
+
HeaderMark: Tag.define(),
|
|
398
|
+
HorizontalRule: Tag.define(),
|
|
399
|
+
InlineCode: Tag.define(),
|
|
400
|
+
LinkLabel: Tag.define(),
|
|
401
|
+
LinkReference: Tag.define(),
|
|
402
|
+
ListMark: Tag.define(),
|
|
403
|
+
QuoteMark: Tag.define(),
|
|
404
|
+
URL: Tag.define()
|
|
317
405
|
};
|
|
318
406
|
var markdownTagsExtension = {
|
|
319
407
|
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
|
-
})
|
|
408
|
+
styleTags(markdownTags)
|
|
333
409
|
]
|
|
334
410
|
};
|
|
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
|
-
// },
|
|
416
|
-
"&.cm-focused": {
|
|
417
|
-
outline: "none"
|
|
418
|
-
},
|
|
419
|
-
"& .cm-line": {
|
|
420
|
-
paddingInline: 0,
|
|
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"
|
|
438
|
-
},
|
|
439
|
-
"& .cm-content": {
|
|
440
|
-
padding: 0,
|
|
441
|
-
caretColor: "black"
|
|
442
|
-
},
|
|
443
|
-
".dark & .cm-content": {
|
|
444
|
-
caretColor: "white"
|
|
445
|
-
},
|
|
446
|
-
"& .cm-cursor": {
|
|
447
|
-
borderLeftColor: "black"
|
|
448
|
-
},
|
|
449
|
-
".dark & .cm-cursor": {
|
|
450
|
-
borderLeftColor: "white"
|
|
451
|
-
},
|
|
452
|
-
".cm-placeholder": {
|
|
453
|
-
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
454
|
-
},
|
|
455
|
-
"& .cm-scroller": {
|
|
456
|
-
fontFamily: get2(tokens, "fontFamily.mono", []).join(","),
|
|
457
|
-
overflow: "visible"
|
|
458
|
-
},
|
|
459
|
-
"& .cm-activeLine": {
|
|
460
|
-
backgroundColor: "transparent"
|
|
461
|
-
},
|
|
462
|
-
".dark & .cm-activeLine": {
|
|
463
|
-
backgroundColor: "transparent"
|
|
464
|
-
},
|
|
465
|
-
"& .cm-ySelectionInfo": {
|
|
466
|
-
fontFamily: get2(tokens, "fontFamily.body", []).join(","),
|
|
467
|
-
padding: "2px 4px",
|
|
468
|
-
marginBlockStart: "-4px"
|
|
469
|
-
},
|
|
470
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
471
|
-
paddingBlockStart: ".15em",
|
|
472
|
-
paddingBlockEnd: ".15em"
|
|
473
|
-
},
|
|
474
|
-
"& .cm-ySelection, & .cm-yLineSelection": {
|
|
475
|
-
mixBlendMode: "multiply"
|
|
476
|
-
},
|
|
477
|
-
".dark & .cm-ySelection, .dark & .cm-yLineSelection": {
|
|
478
|
-
mixBlendMode: "screen"
|
|
479
|
-
},
|
|
480
|
-
"& .cm-ySelectionCaret": {
|
|
481
|
-
display: "inline-block",
|
|
482
|
-
insetBlockStart: ".1em",
|
|
483
|
-
blockSize: "1.4em",
|
|
484
|
-
verticalAlign: "top"
|
|
485
|
-
},
|
|
486
|
-
"& .cm-yLineSelection": {
|
|
487
|
-
margin: "0"
|
|
488
|
-
},
|
|
489
|
-
".cm-link": {
|
|
490
|
-
color: "rgb(20 89 208)",
|
|
491
|
-
textDecorationLine: "underline",
|
|
492
|
-
textDecorationThickness: "1px",
|
|
493
|
-
textUnderlineOffset: "2px",
|
|
494
|
-
borderRadius: ".125rem"
|
|
495
|
-
},
|
|
496
|
-
// TODO(burdon): Document.
|
|
497
|
-
...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
498
|
-
const height = get2(tokens, [
|
|
499
|
-
"extend",
|
|
500
|
-
"fontSize",
|
|
501
|
-
fontSize,
|
|
502
|
-
1,
|
|
503
|
-
"lineHeight"
|
|
504
|
-
]);
|
|
505
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
506
|
-
height
|
|
507
|
-
};
|
|
508
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
509
|
-
height
|
|
510
|
-
};
|
|
511
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
512
|
-
height
|
|
513
|
-
};
|
|
514
|
-
return acc;
|
|
515
|
-
}, {})
|
|
516
|
-
};
|
|
517
411
|
var markdownHighlightStyle = HighlightStyle.define([
|
|
518
412
|
{
|
|
519
413
|
tag: [
|
|
@@ -553,48 +447,22 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
553
447
|
],
|
|
554
448
|
color: "inherit !important"
|
|
555
449
|
},
|
|
450
|
+
// Markdown marks.
|
|
556
451
|
{
|
|
557
452
|
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
453
|
tags.meta,
|
|
583
|
-
tags.processingInstruction
|
|
454
|
+
tags.processingInstruction,
|
|
455
|
+
markdownTags.CodeMark,
|
|
456
|
+
markdownTags.EmphasisMark,
|
|
457
|
+
markdownTags.HeaderMark,
|
|
458
|
+
markdownTags.LinkLabel,
|
|
459
|
+
markdownTags.LinkReference,
|
|
460
|
+
markdownTags.ListMark,
|
|
461
|
+
markdownTags.QuoteMark
|
|
584
462
|
],
|
|
585
463
|
class: mark
|
|
586
464
|
},
|
|
587
|
-
|
|
588
|
-
tag: [
|
|
589
|
-
markdownTags.codeText,
|
|
590
|
-
markdownTags.inlineCode
|
|
591
|
-
],
|
|
592
|
-
class: "font-mono"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
tag: tags.emphasis,
|
|
596
|
-
class: italic
|
|
597
|
-
},
|
|
465
|
+
// Headings.
|
|
598
466
|
{
|
|
599
467
|
tag: tags.heading1,
|
|
600
468
|
class: heading[1]
|
|
@@ -619,18 +487,62 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
619
487
|
tag: tags.heading6,
|
|
620
488
|
class: heading[6]
|
|
621
489
|
},
|
|
490
|
+
// Emphasis.
|
|
622
491
|
{
|
|
623
|
-
tag: tags.
|
|
624
|
-
class:
|
|
492
|
+
tag: tags.emphasis,
|
|
493
|
+
class: italic
|
|
625
494
|
},
|
|
626
495
|
{
|
|
627
496
|
tag: tags.strong,
|
|
628
497
|
class: bold
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
tag: tags.strikethrough,
|
|
501
|
+
class: strikethrough
|
|
502
|
+
},
|
|
503
|
+
// Naked URLs.
|
|
504
|
+
{
|
|
505
|
+
tag: [
|
|
506
|
+
markdownTags.URL
|
|
507
|
+
],
|
|
508
|
+
class: inlineUrl
|
|
509
|
+
},
|
|
510
|
+
// E.g., code block language (after ```).
|
|
511
|
+
{
|
|
512
|
+
tag: [
|
|
513
|
+
tags.function(tags.variableName),
|
|
514
|
+
tags.labelName
|
|
515
|
+
],
|
|
516
|
+
class: codeMark
|
|
517
|
+
},
|
|
518
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
519
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
520
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
521
|
+
// the code, but all other CSS properties will be inherited.
|
|
522
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
523
|
+
{
|
|
524
|
+
tag: [
|
|
525
|
+
markdownTags.CodeText,
|
|
526
|
+
markdownTags.InlineCode
|
|
527
|
+
],
|
|
528
|
+
class: code
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
tag: [
|
|
532
|
+
markdownTags.QuoteMark
|
|
533
|
+
],
|
|
534
|
+
class: blockquote
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
tag: [
|
|
538
|
+
markdownTags.HorizontalRule
|
|
539
|
+
],
|
|
540
|
+
class: horizontalRule
|
|
629
541
|
}
|
|
630
542
|
], {
|
|
631
543
|
scope: markdownLanguage,
|
|
632
544
|
all: {
|
|
633
|
-
fontFamily:
|
|
545
|
+
fontFamily: get(tokens, "fontFamily.body", []).join(",")
|
|
634
546
|
}
|
|
635
547
|
});
|
|
636
548
|
|
|
@@ -642,7 +554,6 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
642
554
|
_placeholder && placeholder2(_placeholder),
|
|
643
555
|
EditorState.allowMultipleSelections.of(true),
|
|
644
556
|
EditorView4.lineWrapping,
|
|
645
|
-
// autocompletion(),
|
|
646
557
|
crosshairCursor(),
|
|
647
558
|
dropCursor(),
|
|
648
559
|
drawSelection(),
|
|
@@ -653,65 +564,519 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
653
564
|
history(),
|
|
654
565
|
indentOnInput(),
|
|
655
566
|
rectangularSelection(),
|
|
656
|
-
|
|
567
|
+
// TODO(burdon): Review.
|
|
568
|
+
keymap4.of([
|
|
657
569
|
...closeBracketsKeymap,
|
|
658
|
-
// ...completionKeymap,
|
|
659
570
|
...defaultKeymap,
|
|
660
|
-
...foldKeymap,
|
|
661
|
-
...historyKeymap,
|
|
662
|
-
...lintKeymap,
|
|
571
|
+
// ...foldKeymap,
|
|
572
|
+
// ...historyKeymap,
|
|
573
|
+
// ...lintKeymap,
|
|
663
574
|
...searchKeymap,
|
|
664
575
|
indentWithTab
|
|
665
576
|
]),
|
|
666
577
|
// Main extension.
|
|
667
578
|
// https://github.com/codemirror/lang-markdown
|
|
579
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
668
580
|
markdown({
|
|
581
|
+
// GRM by default (vs strict CommonMark):
|
|
582
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
583
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
584
|
+
// https://github.github.com/gfm
|
|
585
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
669
586
|
base: markdownLanguage2,
|
|
587
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
670
588
|
codeLanguages: languages,
|
|
589
|
+
// Parser extensions.
|
|
671
590
|
extensions: [
|
|
672
|
-
// TODO(burdon):
|
|
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.
|
|
591
|
+
// GFM, // TODO(burdon): Provided by default?
|
|
678
592
|
markdownTagsExtension
|
|
679
593
|
]
|
|
680
594
|
}),
|
|
681
|
-
//
|
|
595
|
+
// Custom styles.
|
|
682
596
|
syntaxHighlighting2(markdownHighlightStyle),
|
|
597
|
+
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
683
598
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
684
599
|
].filter(Boolean);
|
|
685
600
|
};
|
|
686
601
|
|
|
602
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
603
|
+
import { EditorView as EditorView5, Decoration as Decoration3, WidgetType as WidgetType3, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
604
|
+
var CheckboxWidget = class extends WidgetType3 {
|
|
605
|
+
constructor(_pos, _checked, _indent, _onCheck) {
|
|
606
|
+
super();
|
|
607
|
+
this._pos = _pos;
|
|
608
|
+
this._checked = _checked;
|
|
609
|
+
this._indent = _indent;
|
|
610
|
+
this._onCheck = _onCheck;
|
|
611
|
+
}
|
|
612
|
+
eq(other) {
|
|
613
|
+
return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
|
|
614
|
+
}
|
|
615
|
+
toDOM(view) {
|
|
616
|
+
const wrap = document.createElement("span");
|
|
617
|
+
wrap.className = "cm-task-item";
|
|
618
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
619
|
+
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
620
|
+
const input = wrap.appendChild(document.createElement("input"));
|
|
621
|
+
input.type = "checkbox";
|
|
622
|
+
input.checked = this._checked;
|
|
623
|
+
input.onchange = (event) => {
|
|
624
|
+
this._onCheck(event.target.checked);
|
|
625
|
+
return true;
|
|
626
|
+
};
|
|
627
|
+
return wrap;
|
|
628
|
+
}
|
|
629
|
+
ignoreEvent() {
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
var styles2 = EditorView5.baseTheme({
|
|
634
|
+
"& .cm-task-item": {
|
|
635
|
+
paddingLeft: "4px",
|
|
636
|
+
paddingRight: "8px"
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
var tasklist = () => {
|
|
640
|
+
const taskMatcher = new MatchDecorator2({
|
|
641
|
+
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
642
|
+
decoration: (match, view, pos) => {
|
|
643
|
+
const indent = Math.floor(match[1].length / 2);
|
|
644
|
+
const checked = match[2] === "x" || match[2] === "X";
|
|
645
|
+
return Decoration3.replace({
|
|
646
|
+
widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
|
|
647
|
+
const idx = pos + match[0].indexOf("[") + 1;
|
|
648
|
+
view.dispatch({
|
|
649
|
+
changes: {
|
|
650
|
+
from: idx,
|
|
651
|
+
to: idx + 1,
|
|
652
|
+
insert: checked2 ? "x" : " "
|
|
653
|
+
},
|
|
654
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
655
|
+
selection: {
|
|
656
|
+
anchor: idx + 3
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
})
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
const tasks = ViewPlugin2.fromClass(class {
|
|
664
|
+
constructor(view) {
|
|
665
|
+
this.tasks = taskMatcher.createDeco(view);
|
|
666
|
+
}
|
|
667
|
+
update(update2) {
|
|
668
|
+
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
669
|
+
}
|
|
670
|
+
}, {
|
|
671
|
+
decorations: (instance) => instance.tasks,
|
|
672
|
+
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
673
|
+
return view.plugin(plugin)?.tasks || Decoration3.none;
|
|
674
|
+
})
|
|
675
|
+
});
|
|
676
|
+
return [
|
|
677
|
+
tasks,
|
|
678
|
+
styles2
|
|
679
|
+
];
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
683
|
+
import { hoverTooltip } from "@codemirror/view";
|
|
684
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
685
|
+
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
686
|
+
var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view, pos) => {
|
|
687
|
+
const { from, text } = view.state.doc.lineAt(pos);
|
|
688
|
+
const p = pos - from;
|
|
689
|
+
let idx = 0;
|
|
690
|
+
let match;
|
|
691
|
+
do {
|
|
692
|
+
match = text.substring(idx).match(regexp);
|
|
693
|
+
if (!match) {
|
|
694
|
+
match = void 0;
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
idx = text.indexOf(match[0]);
|
|
698
|
+
if (p >= idx && p < idx + match[0].length) {
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
idx += match[0].length;
|
|
702
|
+
} while (true);
|
|
703
|
+
if (!match) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
const [, , url] = match ?? [];
|
|
707
|
+
return {
|
|
708
|
+
pos: idx + from,
|
|
709
|
+
end: idx + from + match[0].length,
|
|
710
|
+
above: true,
|
|
711
|
+
create: () => {
|
|
712
|
+
const el = document.createElement("div");
|
|
713
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
714
|
+
onHover(el, url);
|
|
715
|
+
return {
|
|
716
|
+
dom: el,
|
|
717
|
+
offset: {
|
|
718
|
+
x: 0,
|
|
719
|
+
y: 12
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
727
|
+
import get2 from "lodash.get";
|
|
728
|
+
var defaultTheme = {
|
|
729
|
+
//
|
|
730
|
+
// Main layout:
|
|
731
|
+
// <div class=".cm-editor .cm-focused">
|
|
732
|
+
// <div class=".cm-scroller">
|
|
733
|
+
// <div class=".cm-content" role="textbox" contenteditable="true">
|
|
734
|
+
// <div class=".cm-line" />
|
|
735
|
+
// </div>
|
|
736
|
+
// </div>
|
|
737
|
+
// </div>
|
|
738
|
+
//
|
|
739
|
+
"&": {},
|
|
740
|
+
"&.cm-focused": {
|
|
741
|
+
outline: "none"
|
|
742
|
+
},
|
|
743
|
+
"& .cm-scroller": {
|
|
744
|
+
overflow: "visible"
|
|
745
|
+
},
|
|
746
|
+
"& .cm-content": {
|
|
747
|
+
padding: 0,
|
|
748
|
+
// Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
749
|
+
fontSize: "16px"
|
|
750
|
+
},
|
|
751
|
+
"&light .cm-content": {
|
|
752
|
+
color: get2(tokens, "extend.colors.neutral.900", "black"),
|
|
753
|
+
caretColor: "black"
|
|
754
|
+
},
|
|
755
|
+
"&dark .cm-content": {
|
|
756
|
+
color: get2(tokens, "extend.colors.neutral.100", "white"),
|
|
757
|
+
caretColor: "white"
|
|
758
|
+
},
|
|
759
|
+
//
|
|
760
|
+
// Cursor
|
|
761
|
+
//
|
|
762
|
+
"&light .cm-cursor": {
|
|
763
|
+
borderLeft: "2px solid black"
|
|
764
|
+
},
|
|
765
|
+
"&dark .cm-cursor": {
|
|
766
|
+
borderLeft: "2px solid white"
|
|
767
|
+
},
|
|
768
|
+
"& .cm-placeholder": {
|
|
769
|
+
fontWeight: 100
|
|
770
|
+
},
|
|
771
|
+
//
|
|
772
|
+
// line
|
|
773
|
+
//
|
|
774
|
+
"& .cm-line": {
|
|
775
|
+
paddingInline: 0
|
|
776
|
+
},
|
|
777
|
+
"& .cm-line *": {},
|
|
778
|
+
"& .cm-activeLine": {
|
|
779
|
+
backgroundColor: "transparent"
|
|
780
|
+
},
|
|
781
|
+
//
|
|
782
|
+
// selection
|
|
783
|
+
//
|
|
784
|
+
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
785
|
+
background: get2(tokens, "extend.colors.primary.150", "#00ffff")
|
|
786
|
+
},
|
|
787
|
+
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
788
|
+
background: get2(tokens, "extend.colors.primary.850", "#00ffff")
|
|
789
|
+
},
|
|
790
|
+
"&light .cm-selectionMatch": {
|
|
791
|
+
background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
792
|
+
},
|
|
793
|
+
"&dark .cm-selectionMatch": {
|
|
794
|
+
background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
795
|
+
},
|
|
796
|
+
//
|
|
797
|
+
// collaboration
|
|
798
|
+
// TODO(burdon): Review classnames (YJS dependent?)
|
|
799
|
+
//
|
|
800
|
+
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
801
|
+
mixBlendMode: "multiply"
|
|
802
|
+
},
|
|
803
|
+
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
804
|
+
mixBlendMode: "screen"
|
|
805
|
+
},
|
|
806
|
+
"& .cm-ySelectionInfo": {
|
|
807
|
+
padding: "2px 4px",
|
|
808
|
+
marginBlockStart: "-4px"
|
|
809
|
+
},
|
|
810
|
+
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
811
|
+
paddingBlockStart: ".15em",
|
|
812
|
+
paddingBlockEnd: ".15em"
|
|
813
|
+
},
|
|
814
|
+
"& .cm-ySelectionCaret": {
|
|
815
|
+
display: "inline-block",
|
|
816
|
+
insetBlockStart: ".1em",
|
|
817
|
+
blockSize: "1.4em",
|
|
818
|
+
verticalAlign: "top"
|
|
819
|
+
},
|
|
820
|
+
"& .cm-yLineSelection": {
|
|
821
|
+
margin: 0
|
|
822
|
+
},
|
|
823
|
+
//
|
|
824
|
+
// link
|
|
825
|
+
//
|
|
826
|
+
"& .cm-link": {
|
|
827
|
+
color: get2(tokens, "extend.colors.primary.500"),
|
|
828
|
+
textDecorationLine: "underline",
|
|
829
|
+
textDecorationThickness: "1px",
|
|
830
|
+
textUnderlineOffset: "2px",
|
|
831
|
+
borderRadius: ".125rem",
|
|
832
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
833
|
+
},
|
|
834
|
+
//
|
|
835
|
+
// tooltip
|
|
836
|
+
//
|
|
837
|
+
"& .cm-tooltip": {
|
|
838
|
+
border: "none"
|
|
839
|
+
},
|
|
840
|
+
// '& .cm-tooltip-below': {},
|
|
841
|
+
// '& .cm-tooltip-autocomplete': {},
|
|
842
|
+
//
|
|
843
|
+
// font size
|
|
844
|
+
// 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.
|
|
845
|
+
//
|
|
846
|
+
...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
847
|
+
const height = get2(tokens, [
|
|
848
|
+
"extend",
|
|
849
|
+
"fontSize",
|
|
850
|
+
fontSize,
|
|
851
|
+
1,
|
|
852
|
+
"lineHeight"
|
|
853
|
+
]);
|
|
854
|
+
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
855
|
+
height
|
|
856
|
+
};
|
|
857
|
+
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
858
|
+
height
|
|
859
|
+
};
|
|
860
|
+
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
861
|
+
height
|
|
862
|
+
};
|
|
863
|
+
return acc;
|
|
864
|
+
}, {})
|
|
865
|
+
};
|
|
866
|
+
var textTheme = {
|
|
867
|
+
"& .cm-scroller": {
|
|
868
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
869
|
+
},
|
|
870
|
+
"& .cm-placeholder": {
|
|
871
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
var markdownTheme = {
|
|
875
|
+
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
876
|
+
"& .cm-placeholder": {
|
|
877
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
var codeTheme = {
|
|
881
|
+
"& .cm-scroller": {
|
|
882
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
883
|
+
},
|
|
884
|
+
"& .cm-placeholder": {
|
|
885
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
|
|
687
889
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
688
890
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
689
|
-
import { EditorView as
|
|
891
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
690
892
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
691
893
|
import { vim } from "@replit/codemirror-vim";
|
|
692
894
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
693
|
-
import
|
|
694
|
-
import
|
|
695
|
-
import { isDocAccessor as isDocAccessor2 } from "@dxos/echo-schema";
|
|
895
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
896
|
+
import { generateName } from "@dxos/display-name";
|
|
696
897
|
import { useThemeContext } from "@dxos/react-ui";
|
|
898
|
+
import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
|
|
899
|
+
var EditorModes = [
|
|
900
|
+
"default",
|
|
901
|
+
"vim"
|
|
902
|
+
];
|
|
903
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
|
|
904
|
+
const { themeMode } = useThemeContext();
|
|
905
|
+
const tabsterDOMAttribute = useFocusableGroup({
|
|
906
|
+
tabBehavior: "limited"
|
|
907
|
+
});
|
|
908
|
+
const [root, setRoot] = useState(null);
|
|
909
|
+
const [state, setState] = useState();
|
|
910
|
+
const [view, setView] = useState();
|
|
911
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
912
|
+
root,
|
|
913
|
+
state,
|
|
914
|
+
view
|
|
915
|
+
}), [
|
|
916
|
+
view,
|
|
917
|
+
state,
|
|
918
|
+
root
|
|
919
|
+
]);
|
|
920
|
+
const { awareness, peer } = model;
|
|
921
|
+
useEffect(() => {
|
|
922
|
+
if (awareness && peer) {
|
|
923
|
+
awareness.setLocalStateField("user", {
|
|
924
|
+
name: peer.name ?? generateName(peer.id),
|
|
925
|
+
color: getColorForValue({
|
|
926
|
+
value: peer.id,
|
|
927
|
+
type: "color"
|
|
928
|
+
}),
|
|
929
|
+
colorLight: getColorForValue({
|
|
930
|
+
value: peer.id,
|
|
931
|
+
themeMode,
|
|
932
|
+
type: "highlight"
|
|
933
|
+
})
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
}, [
|
|
937
|
+
awareness,
|
|
938
|
+
peer,
|
|
939
|
+
themeMode
|
|
940
|
+
]);
|
|
941
|
+
useEffect(() => {
|
|
942
|
+
if (!root) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
const state2 = EditorState2.create({
|
|
946
|
+
doc: model.text(),
|
|
947
|
+
extensions: [
|
|
948
|
+
// TODO(burdon): Factor out VIM mode?
|
|
949
|
+
editorMode === "vim" && vim(),
|
|
950
|
+
// Theme.
|
|
951
|
+
EditorView6.baseTheme(defaultTheme),
|
|
952
|
+
EditorView6.theme(slots?.editor?.theme ?? {}),
|
|
953
|
+
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
954
|
+
EditorView6.darkTheme.of(themeMode === "dark"),
|
|
955
|
+
// Storage and replication.
|
|
956
|
+
model.extension,
|
|
957
|
+
// Custom.
|
|
958
|
+
...extensions
|
|
959
|
+
].filter(Boolean)
|
|
960
|
+
});
|
|
961
|
+
view?.destroy();
|
|
962
|
+
setView(new EditorView6({
|
|
963
|
+
state: state2,
|
|
964
|
+
parent: root
|
|
965
|
+
}));
|
|
966
|
+
setState(state2);
|
|
967
|
+
return () => {
|
|
968
|
+
view?.destroy();
|
|
969
|
+
setView(void 0);
|
|
970
|
+
setState(void 0);
|
|
971
|
+
};
|
|
972
|
+
}, [
|
|
973
|
+
root,
|
|
974
|
+
model,
|
|
975
|
+
themeMode,
|
|
976
|
+
editorMode
|
|
977
|
+
]);
|
|
978
|
+
const handleKeyUp = useCallback((event) => {
|
|
979
|
+
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
980
|
+
switch (key) {
|
|
981
|
+
case "Enter": {
|
|
982
|
+
view?.contentDOM.focus();
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
case "Escape": {
|
|
986
|
+
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}, [
|
|
991
|
+
view,
|
|
992
|
+
editorMode
|
|
993
|
+
]);
|
|
994
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
995
|
+
key: model.id,
|
|
996
|
+
ref: setRoot,
|
|
997
|
+
tabIndex: 0,
|
|
998
|
+
...slots?.root,
|
|
999
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
1000
|
+
onKeyUp: handleKeyUp
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
var maybeDebug = () => {
|
|
1004
|
+
const items = localStorage.getItem("dxos.composer.demo");
|
|
1005
|
+
if (items) {
|
|
1006
|
+
return demo({
|
|
1007
|
+
items: items.split(",")
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
return [];
|
|
1011
|
+
};
|
|
1012
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1013
|
+
const { themeMode } = useThemeContext();
|
|
1014
|
+
const slots = defaultsDeep({}, _slots, defaultTextSlots);
|
|
1015
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1016
|
+
ref: forwardedRef,
|
|
1017
|
+
extensions: [
|
|
1018
|
+
basicBundle({
|
|
1019
|
+
themeMode,
|
|
1020
|
+
placeholder: slots?.editor?.placeholder
|
|
1021
|
+
}),
|
|
1022
|
+
maybeDebug(),
|
|
1023
|
+
...extensions
|
|
1024
|
+
],
|
|
1025
|
+
slots,
|
|
1026
|
+
...props
|
|
1027
|
+
});
|
|
1028
|
+
});
|
|
1029
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1030
|
+
const { themeMode } = useThemeContext();
|
|
1031
|
+
const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
|
|
1032
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1033
|
+
ref: forwardedRef,
|
|
1034
|
+
extensions: [
|
|
1035
|
+
markdownBundle({
|
|
1036
|
+
themeMode,
|
|
1037
|
+
placeholder: slots?.editor?.placeholder
|
|
1038
|
+
}),
|
|
1039
|
+
maybeDebug(),
|
|
1040
|
+
...extensions
|
|
1041
|
+
],
|
|
1042
|
+
slots,
|
|
1043
|
+
...props
|
|
1044
|
+
});
|
|
1045
|
+
});
|
|
1046
|
+
var defaultSlots = {
|
|
1047
|
+
root: {
|
|
1048
|
+
className: mx2("p-2", inputSurface)
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
var defaultTextSlots = {
|
|
1052
|
+
...defaultSlots,
|
|
1053
|
+
editor: {
|
|
1054
|
+
theme: textTheme
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
var defaultMarkdownSlots = {
|
|
1058
|
+
...defaultSlots,
|
|
1059
|
+
editor: {
|
|
1060
|
+
theme: markdownTheme
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
697
1063
|
|
|
698
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
699
|
-
import
|
|
1064
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1065
|
+
import get3 from "lodash.get";
|
|
1066
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
700
1067
|
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";
|
|
1068
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1069
|
+
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
705
1070
|
|
|
706
|
-
// packages/ui/react-ui-editor/src/
|
|
1071
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
707
1072
|
import { Annotation, Facet, StateEffect, StateField as StateField3 } from "@codemirror/state";
|
|
708
|
-
import { ViewPlugin as
|
|
1073
|
+
import { ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
709
1074
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
710
1075
|
|
|
711
|
-
// packages/ui/react-ui-editor/src/
|
|
1076
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
712
1077
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
713
1078
|
|
|
714
|
-
// packages/ui/react-ui-editor/src/
|
|
1079
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
|
|
715
1080
|
import { ChangeSet } from "@codemirror/state";
|
|
716
1081
|
var amToCodemirror_default = (view, selection, target, patches) => {
|
|
717
1082
|
for (const patch of patches) {
|
|
@@ -818,7 +1183,7 @@ var charPath = (textPath, candidatePath) => {
|
|
|
818
1183
|
return null;
|
|
819
1184
|
};
|
|
820
1185
|
|
|
821
|
-
// packages/ui/react-ui-editor/src/
|
|
1186
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
|
|
822
1187
|
import { next as am } from "@dxos/automerge/automerge";
|
|
823
1188
|
var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
824
1189
|
const { lastHeads, path } = state.field(field);
|
|
@@ -841,7 +1206,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
|
841
1206
|
return newHeads ?? void 0;
|
|
842
1207
|
};
|
|
843
1208
|
|
|
844
|
-
// packages/ui/react-ui-editor/src/
|
|
1209
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
845
1210
|
var PatchSemaphore = class {
|
|
846
1211
|
constructor(field) {
|
|
847
1212
|
this._inReconcile = false;
|
|
@@ -882,7 +1247,7 @@ var PatchSemaphore = class {
|
|
|
882
1247
|
}
|
|
883
1248
|
};
|
|
884
1249
|
|
|
885
|
-
// packages/ui/react-ui-editor/src/
|
|
1250
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
886
1251
|
var effectType = StateEffect.define({});
|
|
887
1252
|
var updateHeads = (newHeads) => effectType.of({
|
|
888
1253
|
newHeads
|
|
@@ -923,7 +1288,7 @@ var automergePlugin = (handle, path) => {
|
|
|
923
1288
|
}
|
|
924
1289
|
});
|
|
925
1290
|
const semaphore = new PatchSemaphore(stateField);
|
|
926
|
-
const viewPlugin =
|
|
1291
|
+
const viewPlugin = ViewPlugin3.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
927
1292
|
constructor(view) {
|
|
928
1293
|
this._handleChange = () => {
|
|
929
1294
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -953,45 +1318,6 @@ var automergePlugin = (handle, path) => {
|
|
|
953
1318
|
var reconcileAnnotationType = Annotation.define();
|
|
954
1319
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
955
1320
|
|
|
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
1321
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
996
1322
|
import * as random from "lib0/random";
|
|
997
1323
|
var cursorColors = [
|
|
@@ -1036,7 +1362,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1036
1362
|
import { Observable } from "lib0/observable";
|
|
1037
1363
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1038
1364
|
import { log } from "@dxos/log";
|
|
1039
|
-
var
|
|
1365
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1040
1366
|
var messageAwareness = 1;
|
|
1041
1367
|
var messageQueryAwareness = 3;
|
|
1042
1368
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1073,7 +1399,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1073
1399
|
removed,
|
|
1074
1400
|
origin
|
|
1075
1401
|
}, {
|
|
1076
|
-
F:
|
|
1402
|
+
F: __dxlog_file2,
|
|
1077
1403
|
L: 67,
|
|
1078
1404
|
S: this,
|
|
1079
1405
|
C: (f, a) => f(...a)
|
|
@@ -1086,7 +1412,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1086
1412
|
}
|
|
1087
1413
|
_handleSpaceMessage({ payload }) {
|
|
1088
1414
|
log("space message", payload, {
|
|
1089
|
-
F:
|
|
1415
|
+
F: __dxlog_file2,
|
|
1090
1416
|
L: 79,
|
|
1091
1417
|
S: this,
|
|
1092
1418
|
C: (f, a) => f(...a)
|
|
@@ -1131,185 +1457,80 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1131
1457
|
};
|
|
1132
1458
|
|
|
1133
1459
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1460
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1134
1461
|
var useTextModel = ({ identity, space, text }) => {
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1462
|
+
const [model, setModel] = useState2(() => createModel({
|
|
1463
|
+
identity,
|
|
1464
|
+
space,
|
|
1465
|
+
text
|
|
1466
|
+
}));
|
|
1467
|
+
useEffect2(() => {
|
|
1468
|
+
setModel(createModel({
|
|
1469
|
+
identity,
|
|
1143
1470
|
space,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
});
|
|
1471
|
+
text
|
|
1472
|
+
}));
|
|
1147
1473
|
}, [
|
|
1148
1474
|
identity,
|
|
1149
1475
|
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
1476
|
text
|
|
1164
1477
|
]);
|
|
1478
|
+
return model;
|
|
1479
|
+
};
|
|
1480
|
+
var createModel = (options) => {
|
|
1481
|
+
const { text } = options;
|
|
1165
1482
|
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;
|
|
1483
|
+
return createAutomergeModel(options);
|
|
1484
|
+
} else {
|
|
1485
|
+
if (!text?.doc) {
|
|
1486
|
+
return void 0;
|
|
1487
|
+
}
|
|
1488
|
+
return createYjsModel(options);
|
|
1179
1489
|
}
|
|
1490
|
+
};
|
|
1491
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
1492
|
+
invariant2(text?.doc && text?.content, void 0, {
|
|
1493
|
+
F: __dxlog_file3,
|
|
1494
|
+
L: 74,
|
|
1495
|
+
S: void 0,
|
|
1496
|
+
A: [
|
|
1497
|
+
"text?.doc && text?.content",
|
|
1498
|
+
""
|
|
1499
|
+
]
|
|
1500
|
+
});
|
|
1501
|
+
const provider = space ? new SpaceAwarenessProvider({
|
|
1502
|
+
space,
|
|
1503
|
+
doc: text.doc,
|
|
1504
|
+
channel: `yjs.awareness.${text.id}`
|
|
1505
|
+
}) : void 0;
|
|
1180
1506
|
return {
|
|
1181
1507
|
id: text.doc.guid,
|
|
1182
1508
|
content: text.content,
|
|
1183
|
-
|
|
1509
|
+
text: () => text.content.toString(),
|
|
1510
|
+
extension: yCollab(text.content, provider?.awareness),
|
|
1511
|
+
awareness: provider?.awareness,
|
|
1184
1512
|
peer: identity ? {
|
|
1185
1513
|
id: identity.identityKey.toHex(),
|
|
1186
1514
|
name: identity.profile?.displayName
|
|
1187
1515
|
} : void 0
|
|
1188
1516
|
};
|
|
1189
1517
|
};
|
|
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
|
|
1518
|
+
var createAutomergeModel = ({ identity, text }) => {
|
|
1519
|
+
const obj = text;
|
|
1520
|
+
const doc = getRawDoc(obj, [
|
|
1521
|
+
obj.field
|
|
1264
1522
|
]);
|
|
1265
|
-
return
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
const extensions = [
|
|
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
|
-
});
|
|
1523
|
+
return {
|
|
1524
|
+
id: obj.id,
|
|
1525
|
+
content: doc,
|
|
1526
|
+
text: () => get3(doc.handle.docSync(), doc.path),
|
|
1527
|
+
extension: automergePlugin(doc.handle, doc.path),
|
|
1528
|
+
peer: identity ? {
|
|
1529
|
+
id: identity.identityKey.toHex(),
|
|
1530
|
+
name: identity.profile?.displayName
|
|
1531
|
+
} : void 0
|
|
1532
|
+
};
|
|
1533
|
+
};
|
|
1313
1534
|
export {
|
|
1314
1535
|
BaseTextEditor,
|
|
1315
1536
|
Doc,
|
|
@@ -1318,34 +1539,29 @@ export {
|
|
|
1318
1539
|
SpaceAwarenessProvider,
|
|
1319
1540
|
TextEditor,
|
|
1320
1541
|
TextKind,
|
|
1321
|
-
|
|
1542
|
+
YText,
|
|
1322
1543
|
YXmlFragment,
|
|
1544
|
+
autocomplete,
|
|
1323
1545
|
basicBundle,
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
coral,
|
|
1327
|
-
createHyperlinkTooltip,
|
|
1546
|
+
codeTheme,
|
|
1547
|
+
comments,
|
|
1328
1548
|
cursorColor,
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
ivory,
|
|
1337
|
-
malibu,
|
|
1549
|
+
defaultMarkdownSlots,
|
|
1550
|
+
defaultSlots,
|
|
1551
|
+
defaultTextSlots,
|
|
1552
|
+
defaultTheme,
|
|
1553
|
+
demo,
|
|
1554
|
+
link,
|
|
1555
|
+
listener,
|
|
1338
1556
|
markdownBundle,
|
|
1339
1557
|
markdownHighlightStyle,
|
|
1558
|
+
markdownTags,
|
|
1559
|
+
markdownTagsExtension,
|
|
1340
1560
|
markdownTheme,
|
|
1341
|
-
onChangeExtension,
|
|
1342
|
-
sage,
|
|
1343
|
-
stone,
|
|
1344
1561
|
tags2 as tags,
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
whiskey
|
|
1562
|
+
tasklist,
|
|
1563
|
+
textTheme,
|
|
1564
|
+
tooltip,
|
|
1565
|
+
useTextModel
|
|
1350
1566
|
};
|
|
1351
1567
|
//# sourceMappingURL=index.mjs.map
|