@dxos/react-ui-editor 0.3.10-main.16895f7 → 0.3.10-main.279fbbe
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 +868 -738
- 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 +14 -0
- package/dist/types/src/components/TextEditor/extensions/comments.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 +6 -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 +7 -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 +20 -32
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +273 -0
- package/src/components/TextEditor/TextEditor.stories.tsx +46 -43
- package/src/components/TextEditor/TextEditor.tsx +65 -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 +173 -0
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkWidget.tsx → experimental.tsx} +18 -2
- package/src/components/TextEditor/extensions/index.ts +6 -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,339 @@
|
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
"& .cm-line": {
|
|
52
|
-
paddingInline: 0,
|
|
53
|
-
lineHeight: 1.6,
|
|
54
|
-
minBlockSize: "1.6em"
|
|
55
|
-
},
|
|
56
|
-
"& .cm-line *": {
|
|
57
|
-
lineHeight: 1.6
|
|
58
|
-
},
|
|
59
|
-
"& .cm-scroller": {
|
|
60
|
-
fontFamily: get(tokens, "fontFamily.body", []).join(","),
|
|
61
|
-
overflow: "visible"
|
|
62
|
-
},
|
|
63
|
-
"& .cm-content": {
|
|
64
|
-
padding: 0,
|
|
65
|
-
caretColor: "black"
|
|
66
|
-
},
|
|
67
|
-
".dark & .cm-content": {
|
|
68
|
-
caretColor: "white"
|
|
69
|
-
},
|
|
70
|
-
"& .cm-tooltip": {
|
|
71
|
-
backgroundColor: "transparent",
|
|
72
|
-
border: "none"
|
|
73
|
-
},
|
|
74
|
-
"& .cm-link": {
|
|
75
|
-
color: get(tokens, "extend.colors.primary.500"),
|
|
76
|
-
textDecoration: "underline"
|
|
57
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
58
|
+
import { Decoration, EditorView as EditorView2, keymap as keymap2, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
|
|
59
|
+
import { invariant } from "@dxos/invariant";
|
|
60
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
|
|
61
|
+
var BookmarkWidget = class extends WidgetType {
|
|
62
|
+
constructor(_pos, _id) {
|
|
63
|
+
super();
|
|
64
|
+
this._pos = _pos;
|
|
65
|
+
this._id = _id;
|
|
66
|
+
invariant(this._id, void 0, {
|
|
67
|
+
F: __dxlog_file,
|
|
68
|
+
L: 40,
|
|
69
|
+
S: this,
|
|
70
|
+
A: [
|
|
71
|
+
"this._id",
|
|
72
|
+
""
|
|
73
|
+
]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
eq(other) {
|
|
77
|
+
return this._id === other._id;
|
|
78
|
+
}
|
|
79
|
+
// TODO(burdon): Click to select.
|
|
80
|
+
toDOM() {
|
|
81
|
+
const span = document.createElement("span");
|
|
82
|
+
span.className = "cm-bookmark";
|
|
83
|
+
span.textContent = "\u{1F4AC}";
|
|
84
|
+
return span;
|
|
77
85
|
}
|
|
78
86
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (transaction.docChanged && onChange) {
|
|
86
|
-
onChange(transaction.newDoc.toString());
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
87
|
+
var styles = EditorView2.baseTheme({
|
|
88
|
+
"& .cm-bookmark": {
|
|
89
|
+
cursor: "pointer",
|
|
90
|
+
margin: "4px",
|
|
91
|
+
padding: "4px",
|
|
92
|
+
backgroundColor: "yellow"
|
|
89
93
|
}
|
|
90
94
|
});
|
|
95
|
+
var comments = (options = {}) => {
|
|
96
|
+
const bookmarkMatcher = new MatchDecorator({
|
|
97
|
+
regexp: /\[\^(\w+)\]/g,
|
|
98
|
+
decoration: (match, view, pos) => {
|
|
99
|
+
const id = match[1];
|
|
100
|
+
return Decoration.replace({
|
|
101
|
+
id,
|
|
102
|
+
widget: new BookmarkWidget(pos, id)
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const bookmarks = ViewPlugin.fromClass(class {
|
|
107
|
+
constructor(view) {
|
|
108
|
+
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
109
|
+
}
|
|
110
|
+
update(update2) {
|
|
111
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update2, this.bookmarks);
|
|
112
|
+
}
|
|
113
|
+
}, {
|
|
114
|
+
decorations: (instance) => instance.bookmarks,
|
|
115
|
+
provide: (plugin) => EditorView2.atomicRanges.of((view) => {
|
|
116
|
+
return view.plugin(plugin)?.bookmarks || Decoration.none;
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
return [
|
|
120
|
+
keymap2.of([
|
|
121
|
+
{
|
|
122
|
+
key: options?.key ?? "alt-meta-c",
|
|
123
|
+
run: (view) => {
|
|
124
|
+
const id = options.onCreate?.();
|
|
125
|
+
if (id) {
|
|
126
|
+
const pos = view.state.selection.main.head;
|
|
127
|
+
const tag = `[^${id}]`;
|
|
128
|
+
view.dispatch({
|
|
129
|
+
changes: {
|
|
130
|
+
from: pos,
|
|
131
|
+
insert: tag
|
|
132
|
+
},
|
|
133
|
+
selection: {
|
|
134
|
+
anchor: pos + tag.length
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
]),
|
|
143
|
+
bookmarks,
|
|
144
|
+
// Monitor cursor movement.
|
|
145
|
+
EditorView2.updateListener.of((update2) => {
|
|
146
|
+
const view = update2.view;
|
|
147
|
+
const pos = view.state.selection.main.head;
|
|
148
|
+
const decorations = [];
|
|
149
|
+
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
150
|
+
rangeSet?.between(pos, pos + 1, (from, to, value) => {
|
|
151
|
+
if (value.spec.widget) {
|
|
152
|
+
decorations.push({
|
|
153
|
+
from,
|
|
154
|
+
to,
|
|
155
|
+
value
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
if (decorations.length) {
|
|
160
|
+
const { from, value: { spec: { id } } } = decorations[0];
|
|
161
|
+
const location = view.coordsAtPos(from);
|
|
162
|
+
if (location) {
|
|
163
|
+
options.onUpdate?.({
|
|
164
|
+
items: decorations.map(({ value: { spec: { id: id2 } } }) => id2),
|
|
165
|
+
active: id,
|
|
166
|
+
pos,
|
|
167
|
+
location
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}),
|
|
172
|
+
styles
|
|
173
|
+
];
|
|
174
|
+
};
|
|
91
175
|
|
|
92
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
176
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
93
177
|
import { syntaxTree } from "@codemirror/language";
|
|
94
|
-
import { RangeSetBuilder, StateField
|
|
95
|
-
import { Decoration, EditorView as
|
|
96
|
-
var
|
|
97
|
-
constructor(
|
|
178
|
+
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
179
|
+
import { Decoration as Decoration2, EditorView as EditorView3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
180
|
+
var LinkButton = class extends WidgetType2 {
|
|
181
|
+
constructor(_pos, _url, _onAttach) {
|
|
98
182
|
super();
|
|
99
|
-
this.
|
|
183
|
+
this._pos = _pos;
|
|
184
|
+
this._url = _url;
|
|
185
|
+
this._onAttach = _onAttach;
|
|
186
|
+
}
|
|
187
|
+
eq(other) {
|
|
188
|
+
return this._pos === other._pos && this._url === other._url;
|
|
189
|
+
}
|
|
190
|
+
toDOM(view) {
|
|
191
|
+
const el = document.createElement("span");
|
|
192
|
+
this._onAttach(el, this._url);
|
|
193
|
+
return el;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var LinkText = class extends WidgetType2 {
|
|
197
|
+
constructor(_pos, _text, _url) {
|
|
198
|
+
super();
|
|
199
|
+
this._pos = _pos;
|
|
100
200
|
this._text = _text;
|
|
101
201
|
this._url = _url;
|
|
102
202
|
}
|
|
103
203
|
eq(other) {
|
|
104
|
-
return this.
|
|
204
|
+
return this._pos === other._pos && this._url === other._url;
|
|
105
205
|
}
|
|
106
206
|
toDOM(view) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
207
|
+
const link2 = document.createElement("a");
|
|
208
|
+
link2.setAttribute("class", "cm-link");
|
|
209
|
+
link2.textContent = this._text;
|
|
110
210
|
if (this._url) {
|
|
111
|
-
|
|
112
|
-
|
|
211
|
+
link2.setAttribute("rel", "noreferrer");
|
|
212
|
+
link2.setAttribute("target", "_blank");
|
|
213
|
+
link2.href = this._url;
|
|
113
214
|
} else {
|
|
114
|
-
|
|
215
|
+
link2.onclick = () => {
|
|
115
216
|
view.dispatch({
|
|
116
217
|
selection: {
|
|
117
|
-
anchor: this.
|
|
218
|
+
anchor: this._pos
|
|
118
219
|
}
|
|
119
220
|
});
|
|
120
221
|
};
|
|
121
222
|
}
|
|
122
|
-
return
|
|
223
|
+
return link2;
|
|
123
224
|
}
|
|
124
225
|
};
|
|
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) => {
|
|
226
|
+
var update = (state, options) => {
|
|
133
227
|
const builder = new RangeSetBuilder();
|
|
134
228
|
const cursor = state.selection.main.head;
|
|
135
229
|
syntaxTree(state).iterate({
|
|
136
230
|
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
|
-
}));
|
|
231
|
+
if (node.name === "Link") {
|
|
232
|
+
const marks = node.node.getChildren("LinkMark");
|
|
233
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
234
|
+
const urlNode = node.node.getChild("URL");
|
|
235
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
236
|
+
if (!url) {
|
|
146
237
|
return false;
|
|
147
238
|
}
|
|
239
|
+
if (cursor < node.from || cursor > node.to) {
|
|
240
|
+
builder.add(node.from, node.to, Decoration2.replace({
|
|
241
|
+
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
if (options.onRender) {
|
|
245
|
+
builder.add(node.to, node.to, Decoration2.replace({
|
|
246
|
+
widget: new LinkButton(node.from, url, options.onRender)
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
148
250
|
}
|
|
149
|
-
return true;
|
|
150
251
|
}
|
|
151
252
|
});
|
|
152
253
|
return builder.finish();
|
|
153
254
|
};
|
|
255
|
+
var link = (options = {}) => {
|
|
256
|
+
return StateField.define({
|
|
257
|
+
create: (state) => update(state, options),
|
|
258
|
+
update: (_, tr) => update(tr.state, options),
|
|
259
|
+
provide: (field) => EditorView3.decorations.from(field)
|
|
260
|
+
});
|
|
261
|
+
};
|
|
154
262
|
|
|
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;
|
|
263
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
264
|
+
import { StateField as StateField2 } from "@codemirror/state";
|
|
265
|
+
var listener = (onChange) => StateField2.define({
|
|
266
|
+
create: () => null,
|
|
267
|
+
update: (_value, transaction) => {
|
|
268
|
+
if (transaction.docChanged && onChange) {
|
|
269
|
+
onChange(transaction.newDoc.toString());
|
|
173
270
|
}
|
|
174
|
-
idx += match[0].length;
|
|
175
|
-
} while (true);
|
|
176
|
-
if (!match) {
|
|
177
271
|
return null;
|
|
178
272
|
}
|
|
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
273
|
});
|
|
197
274
|
|
|
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
275
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
292
276
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
293
|
-
import { defaultKeymap, history,
|
|
277
|
+
import { defaultKeymap, history, indentWithTab } from "@codemirror/commands";
|
|
294
278
|
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
295
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2,
|
|
279
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
296
280
|
import { languages } from "@codemirror/language-data";
|
|
297
|
-
import { lintKeymap } from "@codemirror/lint";
|
|
298
281
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
299
282
|
import { EditorState } from "@codemirror/state";
|
|
300
283
|
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";
|
|
284
|
+
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap3, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
285
|
+
|
|
286
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
287
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
288
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
289
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
290
|
+
import get from "lodash.get";
|
|
291
|
+
|
|
292
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
293
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
294
|
+
var heading = {
|
|
295
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
296
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
297
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
298
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
299
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
300
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
301
|
+
};
|
|
302
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
303
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
304
|
+
var bold = "font-bold";
|
|
305
|
+
var italic = "italic";
|
|
306
|
+
var strikethrough = "line-through";
|
|
307
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
308
|
+
var codeMark = "font-mono text-primary-500";
|
|
309
|
+
var inlineUrl = mx(code, "px-1");
|
|
310
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
311
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
|
|
312
|
+
|
|
313
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
314
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
315
|
+
var tokens = tailwindConfig({}).theme;
|
|
302
316
|
|
|
303
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/
|
|
304
|
-
import { styleTags, Tag } from "@lezer/highlight";
|
|
317
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
305
318
|
var markdownTags = {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
319
|
+
Blockquote: Tag.define(),
|
|
320
|
+
CodeMark: Tag.define(),
|
|
321
|
+
CodeText: Tag.define(),
|
|
322
|
+
EmphasisMark: Tag.define(),
|
|
323
|
+
HeaderMark: Tag.define(),
|
|
324
|
+
HorizontalRule: Tag.define(),
|
|
325
|
+
InlineCode: Tag.define(),
|
|
326
|
+
LinkLabel: Tag.define(),
|
|
327
|
+
LinkReference: Tag.define(),
|
|
328
|
+
ListMark: Tag.define(),
|
|
329
|
+
QuoteMark: Tag.define(),
|
|
330
|
+
URL: Tag.define()
|
|
317
331
|
};
|
|
318
332
|
var markdownTagsExtension = {
|
|
319
333
|
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
|
-
})
|
|
334
|
+
styleTags(markdownTags)
|
|
333
335
|
]
|
|
334
336
|
};
|
|
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
337
|
var markdownHighlightStyle = HighlightStyle.define([
|
|
518
338
|
{
|
|
519
339
|
tag: [
|
|
@@ -553,48 +373,22 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
553
373
|
],
|
|
554
374
|
color: "inherit !important"
|
|
555
375
|
},
|
|
376
|
+
// Markdown marks.
|
|
556
377
|
{
|
|
557
378
|
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
379
|
tags.meta,
|
|
583
|
-
tags.processingInstruction
|
|
380
|
+
tags.processingInstruction,
|
|
381
|
+
markdownTags.CodeMark,
|
|
382
|
+
markdownTags.EmphasisMark,
|
|
383
|
+
markdownTags.HeaderMark,
|
|
384
|
+
markdownTags.LinkLabel,
|
|
385
|
+
markdownTags.LinkReference,
|
|
386
|
+
markdownTags.ListMark,
|
|
387
|
+
markdownTags.QuoteMark
|
|
584
388
|
],
|
|
585
389
|
class: mark
|
|
586
390
|
},
|
|
587
|
-
|
|
588
|
-
tag: [
|
|
589
|
-
markdownTags.codeText,
|
|
590
|
-
markdownTags.inlineCode
|
|
591
|
-
],
|
|
592
|
-
class: "font-mono"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
tag: tags.emphasis,
|
|
596
|
-
class: italic
|
|
597
|
-
},
|
|
391
|
+
// Headings.
|
|
598
392
|
{
|
|
599
393
|
tag: tags.heading1,
|
|
600
394
|
class: heading[1]
|
|
@@ -619,18 +413,62 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
619
413
|
tag: tags.heading6,
|
|
620
414
|
class: heading[6]
|
|
621
415
|
},
|
|
416
|
+
// Emphasis.
|
|
622
417
|
{
|
|
623
|
-
tag: tags.
|
|
624
|
-
class:
|
|
418
|
+
tag: tags.emphasis,
|
|
419
|
+
class: italic
|
|
625
420
|
},
|
|
626
421
|
{
|
|
627
422
|
tag: tags.strong,
|
|
628
423
|
class: bold
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
tag: tags.strikethrough,
|
|
427
|
+
class: strikethrough
|
|
428
|
+
},
|
|
429
|
+
// Naked URLs.
|
|
430
|
+
{
|
|
431
|
+
tag: [
|
|
432
|
+
markdownTags.URL
|
|
433
|
+
],
|
|
434
|
+
class: inlineUrl
|
|
435
|
+
},
|
|
436
|
+
// E.g., code block language (after ```).
|
|
437
|
+
{
|
|
438
|
+
tag: [
|
|
439
|
+
tags.function(tags.variableName),
|
|
440
|
+
tags.labelName
|
|
441
|
+
],
|
|
442
|
+
class: codeMark
|
|
443
|
+
},
|
|
444
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
445
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
446
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
447
|
+
// the code, but all other CSS properties will be inherited.
|
|
448
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
449
|
+
{
|
|
450
|
+
tag: [
|
|
451
|
+
markdownTags.CodeText,
|
|
452
|
+
markdownTags.InlineCode
|
|
453
|
+
],
|
|
454
|
+
class: code
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
tag: [
|
|
458
|
+
markdownTags.QuoteMark
|
|
459
|
+
],
|
|
460
|
+
class: blockquote
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
tag: [
|
|
464
|
+
markdownTags.HorizontalRule
|
|
465
|
+
],
|
|
466
|
+
class: horizontalRule
|
|
629
467
|
}
|
|
630
468
|
], {
|
|
631
469
|
scope: markdownLanguage,
|
|
632
470
|
all: {
|
|
633
|
-
fontFamily:
|
|
471
|
+
fontFamily: get(tokens, "fontFamily.body", []).join(",")
|
|
634
472
|
}
|
|
635
473
|
});
|
|
636
474
|
|
|
@@ -642,7 +480,6 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
642
480
|
_placeholder && placeholder2(_placeholder),
|
|
643
481
|
EditorState.allowMultipleSelections.of(true),
|
|
644
482
|
EditorView4.lineWrapping,
|
|
645
|
-
// autocompletion(),
|
|
646
483
|
crosshairCursor(),
|
|
647
484
|
dropCursor(),
|
|
648
485
|
drawSelection(),
|
|
@@ -653,65 +490,508 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
653
490
|
history(),
|
|
654
491
|
indentOnInput(),
|
|
655
492
|
rectangularSelection(),
|
|
656
|
-
|
|
493
|
+
// TODO(burdon): Review.
|
|
494
|
+
keymap3.of([
|
|
657
495
|
...closeBracketsKeymap,
|
|
658
|
-
// ...completionKeymap,
|
|
659
496
|
...defaultKeymap,
|
|
660
|
-
...foldKeymap,
|
|
661
|
-
...historyKeymap,
|
|
662
|
-
...lintKeymap,
|
|
497
|
+
// ...foldKeymap,
|
|
498
|
+
// ...historyKeymap,
|
|
499
|
+
// ...lintKeymap,
|
|
663
500
|
...searchKeymap,
|
|
664
501
|
indentWithTab
|
|
665
502
|
]),
|
|
666
503
|
// Main extension.
|
|
667
504
|
// https://github.com/codemirror/lang-markdown
|
|
505
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
668
506
|
markdown({
|
|
507
|
+
// GRM by default (vs strict CommonMark):
|
|
508
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
509
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
510
|
+
// https://github.github.com/gfm
|
|
511
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
669
512
|
base: markdownLanguage2,
|
|
513
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
670
514
|
codeLanguages: languages,
|
|
515
|
+
// Parser extensions.
|
|
671
516
|
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.
|
|
517
|
+
// GFM, // TODO(burdon): Provided by default?
|
|
678
518
|
markdownTagsExtension
|
|
679
519
|
]
|
|
680
520
|
}),
|
|
681
|
-
//
|
|
521
|
+
// Custom styles.
|
|
682
522
|
syntaxHighlighting2(markdownHighlightStyle),
|
|
523
|
+
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
683
524
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
684
525
|
].filter(Boolean);
|
|
685
526
|
};
|
|
686
527
|
|
|
528
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
529
|
+
import { EditorView as EditorView5, Decoration as Decoration3, WidgetType as WidgetType3, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
530
|
+
var CheckboxWidget = class extends WidgetType3 {
|
|
531
|
+
constructor(_pos, _checked, _indent, _onCheck) {
|
|
532
|
+
super();
|
|
533
|
+
this._pos = _pos;
|
|
534
|
+
this._checked = _checked;
|
|
535
|
+
this._indent = _indent;
|
|
536
|
+
this._onCheck = _onCheck;
|
|
537
|
+
}
|
|
538
|
+
eq(other) {
|
|
539
|
+
return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
|
|
540
|
+
}
|
|
541
|
+
toDOM(view) {
|
|
542
|
+
const wrap = document.createElement("span");
|
|
543
|
+
wrap.className = "cm-task-item";
|
|
544
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
545
|
+
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
546
|
+
const input = wrap.appendChild(document.createElement("input"));
|
|
547
|
+
input.type = "checkbox";
|
|
548
|
+
input.checked = this._checked;
|
|
549
|
+
input.onchange = (event) => {
|
|
550
|
+
this._onCheck(event.target.checked);
|
|
551
|
+
return true;
|
|
552
|
+
};
|
|
553
|
+
return wrap;
|
|
554
|
+
}
|
|
555
|
+
ignoreEvent() {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
var styles2 = EditorView5.baseTheme({
|
|
560
|
+
"& .cm-task-item": {
|
|
561
|
+
paddingLeft: "4px",
|
|
562
|
+
paddingRight: "8px"
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
var tasklist = () => {
|
|
566
|
+
const taskMatcher = new MatchDecorator2({
|
|
567
|
+
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
568
|
+
decoration: (match, view, pos) => {
|
|
569
|
+
const indent = Math.floor(match[1].length / 2);
|
|
570
|
+
const checked = match[2] === "x" || match[2] === "X";
|
|
571
|
+
return Decoration3.replace({
|
|
572
|
+
widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
|
|
573
|
+
const idx = pos + match[0].indexOf("[") + 1;
|
|
574
|
+
view.dispatch({
|
|
575
|
+
changes: {
|
|
576
|
+
from: idx,
|
|
577
|
+
to: idx + 1,
|
|
578
|
+
insert: checked2 ? "x" : " "
|
|
579
|
+
},
|
|
580
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
581
|
+
selection: {
|
|
582
|
+
anchor: idx + 3
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
})
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
const tasks = ViewPlugin2.fromClass(class {
|
|
590
|
+
constructor(view) {
|
|
591
|
+
this.tasks = taskMatcher.createDeco(view);
|
|
592
|
+
}
|
|
593
|
+
update(update2) {
|
|
594
|
+
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
595
|
+
}
|
|
596
|
+
}, {
|
|
597
|
+
decorations: (instance) => instance.tasks,
|
|
598
|
+
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
599
|
+
return view.plugin(plugin)?.tasks || Decoration3.none;
|
|
600
|
+
})
|
|
601
|
+
});
|
|
602
|
+
return [
|
|
603
|
+
tasks,
|
|
604
|
+
styles2
|
|
605
|
+
];
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
609
|
+
import { hoverTooltip } from "@codemirror/view";
|
|
610
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
611
|
+
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
612
|
+
var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view, pos) => {
|
|
613
|
+
const { from, text } = view.state.doc.lineAt(pos);
|
|
614
|
+
const p = pos - from;
|
|
615
|
+
let idx = 0;
|
|
616
|
+
let match;
|
|
617
|
+
do {
|
|
618
|
+
match = text.substring(idx).match(regexp);
|
|
619
|
+
if (!match) {
|
|
620
|
+
match = void 0;
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
idx = text.indexOf(match[0]);
|
|
624
|
+
if (p >= idx && p < idx + match[0].length) {
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
idx += match[0].length;
|
|
628
|
+
} while (true);
|
|
629
|
+
if (!match) {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
const [, , url] = match ?? [];
|
|
633
|
+
return {
|
|
634
|
+
pos: idx + from,
|
|
635
|
+
end: idx + from + match[0].length,
|
|
636
|
+
above: true,
|
|
637
|
+
create: () => {
|
|
638
|
+
const el = document.createElement("div");
|
|
639
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
640
|
+
onHover(el, url);
|
|
641
|
+
return {
|
|
642
|
+
dom: el,
|
|
643
|
+
offset: {
|
|
644
|
+
x: 0,
|
|
645
|
+
y: 12
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
653
|
+
import get2 from "lodash.get";
|
|
654
|
+
var defaultTheme = {
|
|
655
|
+
//
|
|
656
|
+
// Main layout:
|
|
657
|
+
// <div class=".cm-editor .cm-focused">
|
|
658
|
+
// <div class=".cm-scroller">
|
|
659
|
+
// <div class=".cm-content" role="textbox" contenteditable="true">
|
|
660
|
+
// <div class=".cm-line" />
|
|
661
|
+
// </div>
|
|
662
|
+
// </div>
|
|
663
|
+
// </div>
|
|
664
|
+
//
|
|
665
|
+
"&": {},
|
|
666
|
+
"&.cm-focused": {
|
|
667
|
+
outline: "none"
|
|
668
|
+
},
|
|
669
|
+
"& .cm-scroller": {
|
|
670
|
+
overflow: "visible"
|
|
671
|
+
},
|
|
672
|
+
"& .cm-content": {
|
|
673
|
+
padding: 0,
|
|
674
|
+
// Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
675
|
+
fontSize: "16px"
|
|
676
|
+
},
|
|
677
|
+
"&light .cm-content": {
|
|
678
|
+
color: get2(tokens, "extend.colors.neutral.900", "black"),
|
|
679
|
+
caretColor: "black"
|
|
680
|
+
},
|
|
681
|
+
"&dark .cm-content": {
|
|
682
|
+
color: get2(tokens, "extend.colors.neutral.100", "white"),
|
|
683
|
+
caretColor: "white"
|
|
684
|
+
},
|
|
685
|
+
//
|
|
686
|
+
// Cursor
|
|
687
|
+
//
|
|
688
|
+
"&light .cm-cursor": {
|
|
689
|
+
borderLeft: "2px solid black"
|
|
690
|
+
},
|
|
691
|
+
"&dark .cm-cursor": {
|
|
692
|
+
borderLeft: "2px solid white"
|
|
693
|
+
},
|
|
694
|
+
"& .cm-placeholder": {
|
|
695
|
+
fontWeight: 100
|
|
696
|
+
},
|
|
697
|
+
//
|
|
698
|
+
// line
|
|
699
|
+
//
|
|
700
|
+
"& .cm-line": {
|
|
701
|
+
paddingInline: 0
|
|
702
|
+
},
|
|
703
|
+
"& .cm-line *": {},
|
|
704
|
+
"& .cm-activeLine": {
|
|
705
|
+
backgroundColor: "transparent"
|
|
706
|
+
},
|
|
707
|
+
//
|
|
708
|
+
// selection
|
|
709
|
+
//
|
|
710
|
+
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
711
|
+
background: get2(tokens, "extend.colors.primary.150", "#00ffff")
|
|
712
|
+
},
|
|
713
|
+
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
714
|
+
background: get2(tokens, "extend.colors.primary.850", "#00ffff")
|
|
715
|
+
},
|
|
716
|
+
"&light .cm-selectionMatch": {
|
|
717
|
+
background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
718
|
+
},
|
|
719
|
+
"&dark .cm-selectionMatch": {
|
|
720
|
+
background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
721
|
+
},
|
|
722
|
+
//
|
|
723
|
+
// collaboration
|
|
724
|
+
// TODO(burdon): Review classnames (YJS dependent?)
|
|
725
|
+
//
|
|
726
|
+
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
727
|
+
mixBlendMode: "multiply"
|
|
728
|
+
},
|
|
729
|
+
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
730
|
+
mixBlendMode: "screen"
|
|
731
|
+
},
|
|
732
|
+
"& .cm-ySelectionInfo": {
|
|
733
|
+
padding: "2px 4px",
|
|
734
|
+
marginBlockStart: "-4px"
|
|
735
|
+
},
|
|
736
|
+
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
737
|
+
paddingBlockStart: ".15em",
|
|
738
|
+
paddingBlockEnd: ".15em"
|
|
739
|
+
},
|
|
740
|
+
"& .cm-ySelectionCaret": {
|
|
741
|
+
display: "inline-block",
|
|
742
|
+
insetBlockStart: ".1em",
|
|
743
|
+
blockSize: "1.4em",
|
|
744
|
+
verticalAlign: "top"
|
|
745
|
+
},
|
|
746
|
+
"& .cm-yLineSelection": {
|
|
747
|
+
margin: 0
|
|
748
|
+
},
|
|
749
|
+
//
|
|
750
|
+
// link
|
|
751
|
+
//
|
|
752
|
+
"& .cm-link": {
|
|
753
|
+
color: get2(tokens, "extend.colors.primary.500"),
|
|
754
|
+
textDecorationLine: "underline",
|
|
755
|
+
textDecorationThickness: "1px",
|
|
756
|
+
textUnderlineOffset: "2px",
|
|
757
|
+
borderRadius: ".125rem",
|
|
758
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
759
|
+
},
|
|
760
|
+
//
|
|
761
|
+
// tooltip
|
|
762
|
+
//
|
|
763
|
+
"& .cm-tooltip": {
|
|
764
|
+
border: "none"
|
|
765
|
+
},
|
|
766
|
+
// '& .cm-tooltip-below': {},
|
|
767
|
+
// '& .cm-tooltip-autocomplete': {},
|
|
768
|
+
//
|
|
769
|
+
// font size
|
|
770
|
+
// 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.
|
|
771
|
+
//
|
|
772
|
+
...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
773
|
+
const height = get2(tokens, [
|
|
774
|
+
"extend",
|
|
775
|
+
"fontSize",
|
|
776
|
+
fontSize,
|
|
777
|
+
1,
|
|
778
|
+
"lineHeight"
|
|
779
|
+
]);
|
|
780
|
+
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
781
|
+
height
|
|
782
|
+
};
|
|
783
|
+
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
784
|
+
height
|
|
785
|
+
};
|
|
786
|
+
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
787
|
+
height
|
|
788
|
+
};
|
|
789
|
+
return acc;
|
|
790
|
+
}, {})
|
|
791
|
+
};
|
|
792
|
+
var textTheme = {
|
|
793
|
+
"& .cm-scroller": {
|
|
794
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
795
|
+
},
|
|
796
|
+
"& .cm-placeholder": {
|
|
797
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
var markdownTheme = {
|
|
801
|
+
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
802
|
+
"& .cm-placeholder": {
|
|
803
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
var codeTheme = {
|
|
807
|
+
"& .cm-scroller": {
|
|
808
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
809
|
+
},
|
|
810
|
+
"& .cm-placeholder": {
|
|
811
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
687
815
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
688
816
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
689
|
-
import { EditorView as
|
|
817
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
690
818
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
691
819
|
import { vim } from "@replit/codemirror-vim";
|
|
692
820
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
693
|
-
import
|
|
694
|
-
import
|
|
695
|
-
import { isDocAccessor as isDocAccessor2 } from "@dxos/echo-schema";
|
|
821
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
822
|
+
import { generateName } from "@dxos/display-name";
|
|
696
823
|
import { useThemeContext } from "@dxos/react-ui";
|
|
824
|
+
import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
|
|
825
|
+
var EditorModes = [
|
|
826
|
+
"default",
|
|
827
|
+
"vim"
|
|
828
|
+
];
|
|
829
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
|
|
830
|
+
const { themeMode } = useThemeContext();
|
|
831
|
+
const tabsterDOMAttribute = useFocusableGroup({
|
|
832
|
+
tabBehavior: "limited"
|
|
833
|
+
});
|
|
834
|
+
const [root, setRoot] = useState(null);
|
|
835
|
+
const [state, setState] = useState();
|
|
836
|
+
const [view, setView] = useState();
|
|
837
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
838
|
+
root,
|
|
839
|
+
state,
|
|
840
|
+
view
|
|
841
|
+
}), [
|
|
842
|
+
view,
|
|
843
|
+
state,
|
|
844
|
+
root
|
|
845
|
+
]);
|
|
846
|
+
const { awareness, peer } = model;
|
|
847
|
+
useEffect(() => {
|
|
848
|
+
if (awareness && peer) {
|
|
849
|
+
awareness.setLocalStateField("user", {
|
|
850
|
+
name: peer.name ?? generateName(peer.id),
|
|
851
|
+
color: getColorForValue({
|
|
852
|
+
value: peer.id,
|
|
853
|
+
type: "color"
|
|
854
|
+
}),
|
|
855
|
+
colorLight: getColorForValue({
|
|
856
|
+
value: peer.id,
|
|
857
|
+
themeMode,
|
|
858
|
+
type: "highlight"
|
|
859
|
+
})
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}, [
|
|
863
|
+
awareness,
|
|
864
|
+
peer,
|
|
865
|
+
themeMode
|
|
866
|
+
]);
|
|
867
|
+
useEffect(() => {
|
|
868
|
+
if (!root) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const state2 = EditorState2.create({
|
|
872
|
+
doc: model.text(),
|
|
873
|
+
extensions: [
|
|
874
|
+
// TODO(burdon): Factor out VIM mode?
|
|
875
|
+
editorMode === "vim" && vim(),
|
|
876
|
+
// Theme.
|
|
877
|
+
EditorView6.baseTheme(defaultTheme),
|
|
878
|
+
EditorView6.theme(slots?.editor?.theme ?? {}),
|
|
879
|
+
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
880
|
+
EditorView6.darkTheme.of(themeMode === "dark"),
|
|
881
|
+
// Storage and replication.
|
|
882
|
+
model.extension,
|
|
883
|
+
// Custom.
|
|
884
|
+
...extensions
|
|
885
|
+
].filter(Boolean)
|
|
886
|
+
});
|
|
887
|
+
view?.destroy();
|
|
888
|
+
setView(new EditorView6({
|
|
889
|
+
state: state2,
|
|
890
|
+
parent: root
|
|
891
|
+
}));
|
|
892
|
+
setState(state2);
|
|
893
|
+
return () => {
|
|
894
|
+
view?.destroy();
|
|
895
|
+
setView(void 0);
|
|
896
|
+
setState(void 0);
|
|
897
|
+
};
|
|
898
|
+
}, [
|
|
899
|
+
root,
|
|
900
|
+
model,
|
|
901
|
+
themeMode,
|
|
902
|
+
editorMode
|
|
903
|
+
]);
|
|
904
|
+
const handleKeyUp = useCallback((event) => {
|
|
905
|
+
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
906
|
+
switch (key) {
|
|
907
|
+
case "Enter": {
|
|
908
|
+
view?.contentDOM.focus();
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
case "Escape": {
|
|
912
|
+
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}, [
|
|
917
|
+
view,
|
|
918
|
+
editorMode
|
|
919
|
+
]);
|
|
920
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
921
|
+
key: model.id,
|
|
922
|
+
ref: setRoot,
|
|
923
|
+
tabIndex: 0,
|
|
924
|
+
...slots?.root,
|
|
925
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
926
|
+
onKeyUp: handleKeyUp
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
930
|
+
const { themeMode } = useThemeContext();
|
|
931
|
+
const slots = defaultsDeep({}, _slots, defaultTextSlots);
|
|
932
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
933
|
+
ref: forwardedRef,
|
|
934
|
+
extensions: [
|
|
935
|
+
basicBundle({
|
|
936
|
+
themeMode,
|
|
937
|
+
placeholder: slots?.editor?.placeholder
|
|
938
|
+
}),
|
|
939
|
+
...extensions
|
|
940
|
+
],
|
|
941
|
+
slots,
|
|
942
|
+
...props
|
|
943
|
+
});
|
|
944
|
+
});
|
|
945
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
946
|
+
const { themeMode } = useThemeContext();
|
|
947
|
+
const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
|
|
948
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
949
|
+
ref: forwardedRef,
|
|
950
|
+
extensions: [
|
|
951
|
+
markdownBundle({
|
|
952
|
+
themeMode,
|
|
953
|
+
placeholder: slots?.editor?.placeholder
|
|
954
|
+
}),
|
|
955
|
+
...extensions
|
|
956
|
+
],
|
|
957
|
+
slots,
|
|
958
|
+
...props
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
var defaultSlots = {
|
|
962
|
+
root: {
|
|
963
|
+
className: mx2("p-2", inputSurface)
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
var defaultTextSlots = {
|
|
967
|
+
...defaultSlots,
|
|
968
|
+
editor: {
|
|
969
|
+
theme: textTheme
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
var defaultMarkdownSlots = {
|
|
973
|
+
...defaultSlots,
|
|
974
|
+
editor: {
|
|
975
|
+
theme: markdownTheme
|
|
976
|
+
}
|
|
977
|
+
};
|
|
697
978
|
|
|
698
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
699
|
-
import
|
|
979
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
980
|
+
import get3 from "lodash.get";
|
|
981
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
700
982
|
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";
|
|
983
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
984
|
+
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
705
985
|
|
|
706
|
-
// packages/ui/react-ui-editor/src/
|
|
986
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
707
987
|
import { Annotation, Facet, StateEffect, StateField as StateField3 } from "@codemirror/state";
|
|
708
|
-
import { ViewPlugin as
|
|
988
|
+
import { ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
709
989
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
710
990
|
|
|
711
|
-
// packages/ui/react-ui-editor/src/
|
|
991
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
712
992
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
713
993
|
|
|
714
|
-
// packages/ui/react-ui-editor/src/
|
|
994
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
|
|
715
995
|
import { ChangeSet } from "@codemirror/state";
|
|
716
996
|
var amToCodemirror_default = (view, selection, target, patches) => {
|
|
717
997
|
for (const patch of patches) {
|
|
@@ -818,7 +1098,7 @@ var charPath = (textPath, candidatePath) => {
|
|
|
818
1098
|
return null;
|
|
819
1099
|
};
|
|
820
1100
|
|
|
821
|
-
// packages/ui/react-ui-editor/src/
|
|
1101
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
|
|
822
1102
|
import { next as am } from "@dxos/automerge/automerge";
|
|
823
1103
|
var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
824
1104
|
const { lastHeads, path } = state.field(field);
|
|
@@ -841,7 +1121,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
|
841
1121
|
return newHeads ?? void 0;
|
|
842
1122
|
};
|
|
843
1123
|
|
|
844
|
-
// packages/ui/react-ui-editor/src/
|
|
1124
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
845
1125
|
var PatchSemaphore = class {
|
|
846
1126
|
constructor(field) {
|
|
847
1127
|
this._inReconcile = false;
|
|
@@ -882,7 +1162,7 @@ var PatchSemaphore = class {
|
|
|
882
1162
|
}
|
|
883
1163
|
};
|
|
884
1164
|
|
|
885
|
-
// packages/ui/react-ui-editor/src/
|
|
1165
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
886
1166
|
var effectType = StateEffect.define({});
|
|
887
1167
|
var updateHeads = (newHeads) => effectType.of({
|
|
888
1168
|
newHeads
|
|
@@ -923,7 +1203,7 @@ var automergePlugin = (handle, path) => {
|
|
|
923
1203
|
}
|
|
924
1204
|
});
|
|
925
1205
|
const semaphore = new PatchSemaphore(stateField);
|
|
926
|
-
const viewPlugin =
|
|
1206
|
+
const viewPlugin = ViewPlugin3.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
927
1207
|
constructor(view) {
|
|
928
1208
|
this._handleChange = () => {
|
|
929
1209
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -953,45 +1233,6 @@ var automergePlugin = (handle, path) => {
|
|
|
953
1233
|
var reconcileAnnotationType = Annotation.define();
|
|
954
1234
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
955
1235
|
|
|
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
1236
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
996
1237
|
import * as random from "lib0/random";
|
|
997
1238
|
var cursorColors = [
|
|
@@ -1036,7 +1277,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1036
1277
|
import { Observable } from "lib0/observable";
|
|
1037
1278
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1038
1279
|
import { log } from "@dxos/log";
|
|
1039
|
-
var
|
|
1280
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1040
1281
|
var messageAwareness = 1;
|
|
1041
1282
|
var messageQueryAwareness = 3;
|
|
1042
1283
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1073,7 +1314,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1073
1314
|
removed,
|
|
1074
1315
|
origin
|
|
1075
1316
|
}, {
|
|
1076
|
-
F:
|
|
1317
|
+
F: __dxlog_file2,
|
|
1077
1318
|
L: 67,
|
|
1078
1319
|
S: this,
|
|
1079
1320
|
C: (f, a) => f(...a)
|
|
@@ -1086,7 +1327,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1086
1327
|
}
|
|
1087
1328
|
_handleSpaceMessage({ payload }) {
|
|
1088
1329
|
log("space message", payload, {
|
|
1089
|
-
F:
|
|
1330
|
+
F: __dxlog_file2,
|
|
1090
1331
|
L: 79,
|
|
1091
1332
|
S: this,
|
|
1092
1333
|
C: (f, a) => f(...a)
|
|
@@ -1131,185 +1372,80 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1131
1372
|
};
|
|
1132
1373
|
|
|
1133
1374
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1375
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1134
1376
|
var useTextModel = ({ identity, space, text }) => {
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1377
|
+
const [model, setModel] = useState2(() => createModel({
|
|
1378
|
+
identity,
|
|
1379
|
+
space,
|
|
1380
|
+
text
|
|
1381
|
+
}));
|
|
1382
|
+
useEffect2(() => {
|
|
1383
|
+
setModel(createModel({
|
|
1384
|
+
identity,
|
|
1143
1385
|
space,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
});
|
|
1386
|
+
text
|
|
1387
|
+
}));
|
|
1147
1388
|
}, [
|
|
1148
1389
|
identity,
|
|
1149
1390
|
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
1391
|
text
|
|
1164
1392
|
]);
|
|
1393
|
+
return model;
|
|
1394
|
+
};
|
|
1395
|
+
var createModel = (options) => {
|
|
1396
|
+
const { text } = options;
|
|
1165
1397
|
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;
|
|
1398
|
+
return createAutomergeModel(options);
|
|
1399
|
+
} else {
|
|
1400
|
+
if (!text?.doc) {
|
|
1401
|
+
return void 0;
|
|
1402
|
+
}
|
|
1403
|
+
return createYjsModel(options);
|
|
1179
1404
|
}
|
|
1405
|
+
};
|
|
1406
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
1407
|
+
invariant2(text?.doc && text?.content, void 0, {
|
|
1408
|
+
F: __dxlog_file3,
|
|
1409
|
+
L: 74,
|
|
1410
|
+
S: void 0,
|
|
1411
|
+
A: [
|
|
1412
|
+
"text?.doc && text?.content",
|
|
1413
|
+
""
|
|
1414
|
+
]
|
|
1415
|
+
});
|
|
1416
|
+
const provider = space ? new SpaceAwarenessProvider({
|
|
1417
|
+
space,
|
|
1418
|
+
doc: text.doc,
|
|
1419
|
+
channel: `yjs.awareness.${text.id}`
|
|
1420
|
+
}) : void 0;
|
|
1180
1421
|
return {
|
|
1181
1422
|
id: text.doc.guid,
|
|
1182
1423
|
content: text.content,
|
|
1183
|
-
|
|
1424
|
+
text: () => text.content.toString(),
|
|
1425
|
+
extension: yCollab(text.content, provider?.awareness),
|
|
1426
|
+
awareness: provider?.awareness,
|
|
1184
1427
|
peer: identity ? {
|
|
1185
1428
|
id: identity.identityKey.toHex(),
|
|
1186
1429
|
name: identity.profile?.displayName
|
|
1187
1430
|
} : void 0
|
|
1188
1431
|
};
|
|
1189
1432
|
};
|
|
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
|
|
1433
|
+
var createAutomergeModel = ({ identity, text }) => {
|
|
1434
|
+
const obj = text;
|
|
1435
|
+
const doc = getRawDoc(obj, [
|
|
1436
|
+
obj.field
|
|
1264
1437
|
]);
|
|
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
|
-
});
|
|
1438
|
+
return {
|
|
1439
|
+
id: obj.id,
|
|
1440
|
+
content: doc,
|
|
1441
|
+
text: () => get3(doc.handle.docSync(), doc.path),
|
|
1442
|
+
extension: automergePlugin(doc.handle, doc.path),
|
|
1443
|
+
peer: identity ? {
|
|
1444
|
+
id: identity.identityKey.toHex(),
|
|
1445
|
+
name: identity.profile?.displayName
|
|
1446
|
+
} : void 0
|
|
1447
|
+
};
|
|
1448
|
+
};
|
|
1313
1449
|
export {
|
|
1314
1450
|
BaseTextEditor,
|
|
1315
1451
|
Doc,
|
|
@@ -1318,34 +1454,28 @@ export {
|
|
|
1318
1454
|
SpaceAwarenessProvider,
|
|
1319
1455
|
TextEditor,
|
|
1320
1456
|
TextKind,
|
|
1321
|
-
|
|
1457
|
+
YText,
|
|
1322
1458
|
YXmlFragment,
|
|
1459
|
+
autocomplete,
|
|
1323
1460
|
basicBundle,
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
coral,
|
|
1327
|
-
createHyperlinkTooltip,
|
|
1461
|
+
codeTheme,
|
|
1462
|
+
comments,
|
|
1328
1463
|
cursorColor,
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
invalid,
|
|
1336
|
-
ivory,
|
|
1337
|
-
malibu,
|
|
1464
|
+
defaultMarkdownSlots,
|
|
1465
|
+
defaultSlots,
|
|
1466
|
+
defaultTextSlots,
|
|
1467
|
+
defaultTheme,
|
|
1468
|
+
link,
|
|
1469
|
+
listener,
|
|
1338
1470
|
markdownBundle,
|
|
1339
1471
|
markdownHighlightStyle,
|
|
1472
|
+
markdownTags,
|
|
1473
|
+
markdownTagsExtension,
|
|
1340
1474
|
markdownTheme,
|
|
1341
|
-
onChangeExtension,
|
|
1342
|
-
sage,
|
|
1343
|
-
stone,
|
|
1344
1475
|
tags2 as tags,
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
whiskey
|
|
1476
|
+
tasklist,
|
|
1477
|
+
textTheme,
|
|
1478
|
+
tooltip,
|
|
1479
|
+
useTextModel
|
|
1350
1480
|
};
|
|
1351
1481
|
//# sourceMappingURL=index.mjs.map
|