@dxos/react-ui-editor 0.3.10-main.16895f7 → 0.3.10-main.375af01
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 +728 -732
- 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 +35 -0
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +4 -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 +9 -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/{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 +5 -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 +5 -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 +17 -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/package.json +20 -32
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +242 -0
- package/src/components/TextEditor/TextEditor.stories.tsx +46 -43
- package/src/components/TextEditor/TextEditor.tsx +59 -45
- package/src/components/TextEditor/extensions/autocomplete.ts +72 -0
- package/src/components/TextEditor/extensions/{basic/bundle.ts → basic.ts} +4 -2
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkWidget.tsx → experimental.tsx} +17 -2
- package/src/components/TextEditor/extensions/index.ts +5 -2
- package/src/components/TextEditor/extensions/{hyperlink/hyperlinkDecoration.ts → link.ts} +68 -31
- package/src/components/TextEditor/extensions/{change.ts → listener.ts} +3 -3
- package/src/components/TextEditor/extensions/markdown/bundle.ts +15 -11
- package/src/components/TextEditor/extensions/markdown/highlight.ts +166 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +1 -1
- package/src/components/TextEditor/extensions/tasklist.ts +113 -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 +170 -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 +50 -40
- package/src/styles/markdown.ts +26 -24
- package/src/testing/replicator.ts +2 -2
- 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,149 +1,128 @@
|
|
|
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 = ({ getOptions }) => {
|
|
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: getOptions(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 get from "lodash.get";
|
|
24
|
-
|
|
25
|
-
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
26
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
27
|
-
var heading = {
|
|
28
|
-
1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
|
|
29
|
-
2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
|
|
30
|
-
3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
|
|
31
|
-
4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
|
|
32
|
-
5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
|
|
33
|
-
6: "mbs-4 mbe-2 font-black text-inherit no-underline"
|
|
34
|
-
};
|
|
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
|
-
|
|
46
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
|
|
47
|
-
var basicTheme = {
|
|
48
|
-
"&.cm-focused": {
|
|
49
|
-
outline: "none"
|
|
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"
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/change.ts
|
|
81
|
-
import { StateField } from "@codemirror/state";
|
|
82
|
-
var onChangeExtension = (onChange) => StateField.define({
|
|
83
|
-
create: () => null,
|
|
84
|
-
update: (_value, transaction) => {
|
|
85
|
-
if (transaction.docChanged && onChange) {
|
|
86
|
-
onChange(transaction.newDoc.toString());
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts
|
|
57
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
93
58
|
import { syntaxTree } from "@codemirror/language";
|
|
94
|
-
import { RangeSetBuilder, StateField
|
|
59
|
+
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
95
60
|
import { Decoration, EditorView as EditorView2, WidgetType } from "@codemirror/view";
|
|
96
|
-
var
|
|
97
|
-
constructor(
|
|
61
|
+
var LinkButton = class extends WidgetType {
|
|
62
|
+
constructor(_pos, _url, _onAttach) {
|
|
63
|
+
super();
|
|
64
|
+
this._pos = _pos;
|
|
65
|
+
this._url = _url;
|
|
66
|
+
this._onAttach = _onAttach;
|
|
67
|
+
}
|
|
68
|
+
eq(other) {
|
|
69
|
+
return this._pos === other._pos && this._url === other._url;
|
|
70
|
+
}
|
|
71
|
+
toDOM(view) {
|
|
72
|
+
const el = document.createElement("span");
|
|
73
|
+
this._onAttach(el, this._url);
|
|
74
|
+
return el;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var LinkText = class extends WidgetType {
|
|
78
|
+
constructor(_pos, _text, _url) {
|
|
98
79
|
super();
|
|
99
|
-
this.
|
|
80
|
+
this._pos = _pos;
|
|
100
81
|
this._text = _text;
|
|
101
82
|
this._url = _url;
|
|
102
83
|
}
|
|
103
84
|
eq(other) {
|
|
104
|
-
return this.
|
|
85
|
+
return this._pos === other._pos && this._url === other._url;
|
|
105
86
|
}
|
|
106
87
|
toDOM(view) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
88
|
+
const link2 = document.createElement("a");
|
|
89
|
+
link2.setAttribute("class", "cm-link");
|
|
90
|
+
link2.textContent = this._text;
|
|
110
91
|
if (this._url) {
|
|
111
|
-
|
|
112
|
-
|
|
92
|
+
link2.setAttribute("rel", "noreferrer");
|
|
93
|
+
link2.setAttribute("target", "_blank");
|
|
94
|
+
link2.href = this._url;
|
|
113
95
|
} else {
|
|
114
|
-
|
|
96
|
+
link2.onclick = () => {
|
|
115
97
|
view.dispatch({
|
|
116
98
|
selection: {
|
|
117
|
-
anchor: this.
|
|
99
|
+
anchor: this._pos
|
|
118
100
|
}
|
|
119
101
|
});
|
|
120
102
|
};
|
|
121
103
|
}
|
|
122
|
-
return
|
|
104
|
+
return link2;
|
|
123
105
|
}
|
|
124
106
|
};
|
|
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) => {
|
|
107
|
+
var update = (state, options) => {
|
|
133
108
|
const builder = new RangeSetBuilder();
|
|
134
109
|
const cursor = state.selection.main.head;
|
|
135
110
|
syntaxTree(state).iterate({
|
|
136
111
|
enter: (node) => {
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
112
|
+
if (node.name === "Link") {
|
|
113
|
+
const marks = node.node.getChildren("LinkMark");
|
|
114
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
115
|
+
const urlNode = node.node.getChild("URL");
|
|
116
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
117
|
+
if (cursor < node.from || cursor > node.to) {
|
|
143
118
|
builder.add(node.from, node.to, Decoration.replace({
|
|
144
|
-
widget: new
|
|
119
|
+
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
if (options.onRender) {
|
|
123
|
+
builder.add(node.to, node.to, Decoration.replace({
|
|
124
|
+
widget: new LinkButton(node.from, url, options.onRender)
|
|
145
125
|
}));
|
|
146
|
-
return false;
|
|
147
126
|
}
|
|
148
127
|
}
|
|
149
128
|
return true;
|
|
@@ -151,142 +130,25 @@ var update = (state, link) => {
|
|
|
151
130
|
});
|
|
152
131
|
return builder.finish();
|
|
153
132
|
};
|
|
133
|
+
var link = (options = {}) => {
|
|
134
|
+
return StateField.define({
|
|
135
|
+
create: (state) => update(state, options),
|
|
136
|
+
update: (_, tr) => update(tr.state, options),
|
|
137
|
+
provide: (field) => EditorView2.decorations.from(field)
|
|
138
|
+
});
|
|
139
|
+
};
|
|
154
140
|
|
|
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;
|
|
141
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
142
|
+
import { StateField as StateField2 } from "@codemirror/state";
|
|
143
|
+
var listener = (onChange) => StateField2.define({
|
|
144
|
+
create: () => null,
|
|
145
|
+
update: (_value, transaction) => {
|
|
146
|
+
if (transaction.docChanged && onChange) {
|
|
147
|
+
onChange(transaction.newDoc.toString());
|
|
173
148
|
}
|
|
174
|
-
idx += match[0].length;
|
|
175
|
-
} while (true);
|
|
176
|
-
if (!match) {
|
|
177
149
|
return null;
|
|
178
150
|
}
|
|
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
|
-
});
|
|
197
|
-
|
|
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
151
|
});
|
|
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
152
|
|
|
291
153
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
292
154
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
@@ -298,222 +160,59 @@ import { lintKeymap } from "@codemirror/lint";
|
|
|
298
160
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
299
161
|
import { EditorState } from "@codemirror/state";
|
|
300
162
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
301
|
-
import { crosshairCursor, drawSelection, dropCursor, EditorView as
|
|
163
|
+
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView3, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap2, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
164
|
+
|
|
165
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
166
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
167
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
168
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
169
|
+
import get from "lodash.get";
|
|
170
|
+
|
|
171
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
172
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
173
|
+
var heading = {
|
|
174
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
175
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
176
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
177
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
178
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
179
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
180
|
+
};
|
|
181
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
182
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
183
|
+
var bold = "font-bold";
|
|
184
|
+
var italic = "italic";
|
|
185
|
+
var strikethrough = "line-through";
|
|
186
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
187
|
+
var codeMark = "font-mono text-primary-500";
|
|
188
|
+
var inlineUrl = mx(code, "px-1");
|
|
189
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
190
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
|
|
191
|
+
|
|
192
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
193
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
194
|
+
var tokens = tailwindConfig({}).theme;
|
|
302
195
|
|
|
303
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/
|
|
304
|
-
import { styleTags, Tag } from "@lezer/highlight";
|
|
196
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
305
197
|
var markdownTags = {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
198
|
+
Blockquote: Tag.define(),
|
|
199
|
+
CodeMark: Tag.define(),
|
|
200
|
+
CodeText: Tag.define(),
|
|
201
|
+
EmphasisMark: Tag.define(),
|
|
202
|
+
HeaderMark: Tag.define(),
|
|
203
|
+
HorizontalRule: Tag.define(),
|
|
204
|
+
InlineCode: Tag.define(),
|
|
205
|
+
LinkLabel: Tag.define(),
|
|
206
|
+
LinkReference: Tag.define(),
|
|
207
|
+
ListMark: Tag.define(),
|
|
208
|
+
QuoteMark: Tag.define(),
|
|
209
|
+
URL: Tag.define()
|
|
317
210
|
};
|
|
318
211
|
var markdownTagsExtension = {
|
|
319
212
|
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
|
-
})
|
|
213
|
+
styleTags(markdownTags)
|
|
333
214
|
]
|
|
334
215
|
};
|
|
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
216
|
var markdownHighlightStyle = HighlightStyle.define([
|
|
518
217
|
{
|
|
519
218
|
tag: [
|
|
@@ -553,48 +252,22 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
553
252
|
],
|
|
554
253
|
color: "inherit !important"
|
|
555
254
|
},
|
|
255
|
+
// Markdown marks.
|
|
556
256
|
{
|
|
557
257
|
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
258
|
tags.meta,
|
|
583
|
-
tags.processingInstruction
|
|
259
|
+
tags.processingInstruction,
|
|
260
|
+
markdownTags.CodeMark,
|
|
261
|
+
markdownTags.EmphasisMark,
|
|
262
|
+
markdownTags.HeaderMark,
|
|
263
|
+
markdownTags.LinkLabel,
|
|
264
|
+
markdownTags.LinkReference,
|
|
265
|
+
markdownTags.ListMark,
|
|
266
|
+
markdownTags.QuoteMark
|
|
584
267
|
],
|
|
585
268
|
class: mark
|
|
586
269
|
},
|
|
587
|
-
|
|
588
|
-
tag: [
|
|
589
|
-
markdownTags.codeText,
|
|
590
|
-
markdownTags.inlineCode
|
|
591
|
-
],
|
|
592
|
-
class: "font-mono"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
tag: tags.emphasis,
|
|
596
|
-
class: italic
|
|
597
|
-
},
|
|
270
|
+
// Headings.
|
|
598
271
|
{
|
|
599
272
|
tag: tags.heading1,
|
|
600
273
|
class: heading[1]
|
|
@@ -619,18 +292,61 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
619
292
|
tag: tags.heading6,
|
|
620
293
|
class: heading[6]
|
|
621
294
|
},
|
|
295
|
+
// Emphasis.
|
|
622
296
|
{
|
|
623
|
-
tag: tags.
|
|
624
|
-
class:
|
|
297
|
+
tag: tags.emphasis,
|
|
298
|
+
class: italic
|
|
625
299
|
},
|
|
626
300
|
{
|
|
627
301
|
tag: tags.strong,
|
|
628
302
|
class: bold
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
tag: tags.strikethrough,
|
|
306
|
+
class: strikethrough
|
|
307
|
+
},
|
|
308
|
+
// Naked URLs.
|
|
309
|
+
{
|
|
310
|
+
tag: [
|
|
311
|
+
markdownTags.URL
|
|
312
|
+
],
|
|
313
|
+
class: inlineUrl
|
|
314
|
+
},
|
|
315
|
+
// E.g., code block language (after ```).
|
|
316
|
+
{
|
|
317
|
+
tag: [
|
|
318
|
+
tags.function(tags.variableName),
|
|
319
|
+
tags.labelName
|
|
320
|
+
],
|
|
321
|
+
class: codeMark
|
|
322
|
+
},
|
|
323
|
+
// The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
324
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
325
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
326
|
+
// the code, but all other CSS properties will be inherited.
|
|
327
|
+
{
|
|
328
|
+
tag: [
|
|
329
|
+
markdownTags.CodeText,
|
|
330
|
+
markdownTags.InlineCode
|
|
331
|
+
],
|
|
332
|
+
class: code
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
tag: [
|
|
336
|
+
markdownTags.QuoteMark
|
|
337
|
+
],
|
|
338
|
+
class: blockquote
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
tag: [
|
|
342
|
+
markdownTags.HorizontalRule
|
|
343
|
+
],
|
|
344
|
+
class: horizontalRule
|
|
629
345
|
}
|
|
630
346
|
], {
|
|
631
347
|
scope: markdownLanguage,
|
|
632
348
|
all: {
|
|
633
|
-
fontFamily:
|
|
349
|
+
fontFamily: get(tokens, "fontFamily.body", []).join(",")
|
|
634
350
|
}
|
|
635
351
|
});
|
|
636
352
|
|
|
@@ -641,7 +357,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
641
357
|
closeBrackets2(),
|
|
642
358
|
_placeholder && placeholder2(_placeholder),
|
|
643
359
|
EditorState.allowMultipleSelections.of(true),
|
|
644
|
-
|
|
360
|
+
EditorView3.lineWrapping,
|
|
645
361
|
// autocompletion(),
|
|
646
362
|
crosshairCursor(),
|
|
647
363
|
dropCursor(),
|
|
@@ -653,7 +369,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
653
369
|
history(),
|
|
654
370
|
indentOnInput(),
|
|
655
371
|
rectangularSelection(),
|
|
656
|
-
|
|
372
|
+
keymap2.of([
|
|
657
373
|
...closeBracketsKeymap,
|
|
658
374
|
// ...completionKeymap,
|
|
659
375
|
...defaultKeymap,
|
|
@@ -665,53 +381,484 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
665
381
|
]),
|
|
666
382
|
// Main extension.
|
|
667
383
|
// https://github.com/codemirror/lang-markdown
|
|
384
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
668
385
|
markdown({
|
|
386
|
+
// GRM by default (vs strict CommonMark):
|
|
387
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
388
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
389
|
+
// https://github.github.com/gfm
|
|
390
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
669
391
|
base: markdownLanguage2,
|
|
392
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
670
393
|
codeLanguages: languages,
|
|
394
|
+
// Parser extensions.
|
|
671
395
|
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.
|
|
396
|
+
// GFM, // TODO(burdon): Provided by default?
|
|
678
397
|
markdownTagsExtension
|
|
679
398
|
]
|
|
680
399
|
}),
|
|
681
|
-
//
|
|
400
|
+
// Custom styles.
|
|
682
401
|
syntaxHighlighting2(markdownHighlightStyle),
|
|
402
|
+
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
683
403
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
684
404
|
].filter(Boolean);
|
|
685
405
|
};
|
|
686
406
|
|
|
407
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
408
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
409
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
|
|
410
|
+
import { EditorView as EditorView4, Decoration as Decoration2, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
411
|
+
var CheckboxWidget = class extends WidgetType2 {
|
|
412
|
+
constructor(_pos, _getCursor, _checked) {
|
|
413
|
+
super();
|
|
414
|
+
this._pos = _pos;
|
|
415
|
+
this._getCursor = _getCursor;
|
|
416
|
+
this._checked = _checked;
|
|
417
|
+
}
|
|
418
|
+
eq(other) {
|
|
419
|
+
return this._pos === other._pos && this._checked === other._checked;
|
|
420
|
+
}
|
|
421
|
+
toDOM(view) {
|
|
422
|
+
const wrap = document.createElement("span");
|
|
423
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
424
|
+
wrap.className = "cm-task-item";
|
|
425
|
+
const box = wrap.appendChild(document.createElement("input"));
|
|
426
|
+
box.type = "checkbox";
|
|
427
|
+
box.checked = this._checked;
|
|
428
|
+
box.onclick = (event) => {
|
|
429
|
+
this._checked = !isChecked(view.state, this._pos);
|
|
430
|
+
view.dispatch({
|
|
431
|
+
changes: {
|
|
432
|
+
from: this._pos + 1,
|
|
433
|
+
to: this._pos + 2,
|
|
434
|
+
insert: this._checked ? "x" : " "
|
|
435
|
+
},
|
|
436
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
437
|
+
selection: {
|
|
438
|
+
anchor: this._pos + 4
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
return true;
|
|
442
|
+
};
|
|
443
|
+
return wrap;
|
|
444
|
+
}
|
|
445
|
+
// TODO(burdon): Remove listener?
|
|
446
|
+
// override destroy() {
|
|
447
|
+
// console.log('destroy', this._pos);
|
|
448
|
+
// }
|
|
449
|
+
ignoreEvent() {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
var isChecked = (state, pos) => {
|
|
454
|
+
return state.sliceDoc(pos, pos + 3).toLowerCase() === "[x]";
|
|
455
|
+
};
|
|
456
|
+
var statefield = () => {
|
|
457
|
+
let lastPosition = 0;
|
|
458
|
+
const listener2 = EditorView4.updateListener.of((update2) => {
|
|
459
|
+
lastPosition = update2.startState.selection.main.head;
|
|
460
|
+
});
|
|
461
|
+
const checkbox = (state) => {
|
|
462
|
+
const builder = new RangeSetBuilder2();
|
|
463
|
+
syntaxTree2(state).iterate({
|
|
464
|
+
enter: (node) => {
|
|
465
|
+
if (node.name === "TaskMarker") {
|
|
466
|
+
builder.add(node.from, node.to, Decoration2.replace({
|
|
467
|
+
widget: new CheckboxWidget(node.from, () => lastPosition, isChecked(state, node.from))
|
|
468
|
+
}));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
return builder.finish();
|
|
473
|
+
};
|
|
474
|
+
return [
|
|
475
|
+
listener2,
|
|
476
|
+
StateField3.define({
|
|
477
|
+
create: (state) => checkbox(state),
|
|
478
|
+
update: (_, tr) => checkbox(tr.state),
|
|
479
|
+
provide: (field) => EditorView4.decorations.from(field)
|
|
480
|
+
})
|
|
481
|
+
];
|
|
482
|
+
};
|
|
483
|
+
var styles = EditorView4.baseTheme({
|
|
484
|
+
"& .cm-task-item": {
|
|
485
|
+
padding: "0 4px"
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
var tasklist = () => [
|
|
489
|
+
statefield(),
|
|
490
|
+
styles
|
|
491
|
+
];
|
|
492
|
+
|
|
493
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
494
|
+
import { hoverTooltip } from "@codemirror/view";
|
|
495
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
496
|
+
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
497
|
+
var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view, pos) => {
|
|
498
|
+
const { from, text } = view.state.doc.lineAt(pos);
|
|
499
|
+
const p = pos - from;
|
|
500
|
+
let idx = 0;
|
|
501
|
+
let match;
|
|
502
|
+
do {
|
|
503
|
+
match = text.substring(idx).match(regexp);
|
|
504
|
+
if (!match) {
|
|
505
|
+
match = void 0;
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
idx = text.indexOf(match[0]);
|
|
509
|
+
if (p >= idx && p < idx + match[0].length) {
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
idx += match[0].length;
|
|
513
|
+
} while (true);
|
|
514
|
+
if (!match) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
const [, , url] = match ?? [];
|
|
518
|
+
return {
|
|
519
|
+
pos: idx + from,
|
|
520
|
+
end: idx + from + match[0].length,
|
|
521
|
+
above: true,
|
|
522
|
+
create: () => {
|
|
523
|
+
const el = document.createElement("div");
|
|
524
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
525
|
+
onHover(el, url);
|
|
526
|
+
return {
|
|
527
|
+
dom: el,
|
|
528
|
+
offset: {
|
|
529
|
+
x: 0,
|
|
530
|
+
y: 12
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
538
|
+
import get2 from "lodash.get";
|
|
539
|
+
var defaultTheme = {
|
|
540
|
+
//
|
|
541
|
+
// Main layout:
|
|
542
|
+
// <div class=".cm-editor .cm-focused">
|
|
543
|
+
// <div class=".cm-scroller">
|
|
544
|
+
// <div class=".cm-content" role="textbox" contenteditable="true">
|
|
545
|
+
// <div class=".cm-line" />
|
|
546
|
+
// </div>
|
|
547
|
+
// </div>
|
|
548
|
+
// </div>
|
|
549
|
+
//
|
|
550
|
+
"&": {},
|
|
551
|
+
"&.cm-focused": {
|
|
552
|
+
outline: "none"
|
|
553
|
+
},
|
|
554
|
+
"& .cm-scroller": {
|
|
555
|
+
overflow: "visible"
|
|
556
|
+
},
|
|
557
|
+
"& .cm-content": {
|
|
558
|
+
padding: 0,
|
|
559
|
+
// Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
560
|
+
fontSize: "16px"
|
|
561
|
+
},
|
|
562
|
+
"&light .cm-content": {
|
|
563
|
+
color: get2(tokens, "extend.colors.neutral.900", "black"),
|
|
564
|
+
caretColor: "black"
|
|
565
|
+
},
|
|
566
|
+
"&dark .cm-content": {
|
|
567
|
+
color: get2(tokens, "extend.colors.neutral.100", "white"),
|
|
568
|
+
caretColor: "white"
|
|
569
|
+
},
|
|
570
|
+
//
|
|
571
|
+
// Cursor
|
|
572
|
+
//
|
|
573
|
+
"&light .cm-cursor": {
|
|
574
|
+
borderLeft: "2px solid black"
|
|
575
|
+
},
|
|
576
|
+
"&dark .cm-cursor": {
|
|
577
|
+
borderLeft: "2px solid white"
|
|
578
|
+
},
|
|
579
|
+
"& .cm-placeholder": {
|
|
580
|
+
fontWeight: 100
|
|
581
|
+
},
|
|
582
|
+
//
|
|
583
|
+
// line
|
|
584
|
+
//
|
|
585
|
+
"& .cm-line": {
|
|
586
|
+
paddingInline: 0
|
|
587
|
+
},
|
|
588
|
+
"& .cm-line *": {},
|
|
589
|
+
"& .cm-activeLine": {
|
|
590
|
+
backgroundColor: "transparent"
|
|
591
|
+
},
|
|
592
|
+
//
|
|
593
|
+
// selection
|
|
594
|
+
//
|
|
595
|
+
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
596
|
+
background: get2(tokens, "extend.colors.primary.150", "#00ffff")
|
|
597
|
+
},
|
|
598
|
+
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
599
|
+
background: get2(tokens, "extend.colors.primary.850", "#00ffff")
|
|
600
|
+
},
|
|
601
|
+
"&light .cm-selectionMatch": {
|
|
602
|
+
background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
603
|
+
},
|
|
604
|
+
"&dark .cm-selectionMatch": {
|
|
605
|
+
background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
606
|
+
},
|
|
607
|
+
//
|
|
608
|
+
// collaboration
|
|
609
|
+
// TODO(burdon): Review classnames (YJS dependent?)
|
|
610
|
+
//
|
|
611
|
+
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
612
|
+
mixBlendMode: "multiply"
|
|
613
|
+
},
|
|
614
|
+
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
615
|
+
mixBlendMode: "screen"
|
|
616
|
+
},
|
|
617
|
+
"& .cm-ySelectionInfo": {
|
|
618
|
+
padding: "2px 4px",
|
|
619
|
+
marginBlockStart: "-4px"
|
|
620
|
+
},
|
|
621
|
+
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
622
|
+
paddingBlockStart: ".15em",
|
|
623
|
+
paddingBlockEnd: ".15em"
|
|
624
|
+
},
|
|
625
|
+
"& .cm-ySelectionCaret": {
|
|
626
|
+
display: "inline-block",
|
|
627
|
+
insetBlockStart: ".1em",
|
|
628
|
+
blockSize: "1.4em",
|
|
629
|
+
verticalAlign: "top"
|
|
630
|
+
},
|
|
631
|
+
"& .cm-yLineSelection": {
|
|
632
|
+
margin: 0
|
|
633
|
+
},
|
|
634
|
+
//
|
|
635
|
+
// link
|
|
636
|
+
//
|
|
637
|
+
"& .cm-link": {
|
|
638
|
+
color: get2(tokens, "extend.colors.primary.500"),
|
|
639
|
+
textDecorationLine: "underline",
|
|
640
|
+
textDecorationThickness: "1px",
|
|
641
|
+
textUnderlineOffset: "2px",
|
|
642
|
+
borderRadius: ".125rem",
|
|
643
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
644
|
+
},
|
|
645
|
+
//
|
|
646
|
+
// tooltip
|
|
647
|
+
//
|
|
648
|
+
"& .cm-tooltip": {
|
|
649
|
+
border: "none"
|
|
650
|
+
},
|
|
651
|
+
// '& .cm-tooltip-below': {},
|
|
652
|
+
// '& .cm-tooltip-autocomplete': {},
|
|
653
|
+
//
|
|
654
|
+
// font size
|
|
655
|
+
// 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.
|
|
656
|
+
//
|
|
657
|
+
...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
658
|
+
const height = get2(tokens, [
|
|
659
|
+
"extend",
|
|
660
|
+
"fontSize",
|
|
661
|
+
fontSize,
|
|
662
|
+
1,
|
|
663
|
+
"lineHeight"
|
|
664
|
+
]);
|
|
665
|
+
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
666
|
+
height
|
|
667
|
+
};
|
|
668
|
+
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
669
|
+
height
|
|
670
|
+
};
|
|
671
|
+
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
672
|
+
height
|
|
673
|
+
};
|
|
674
|
+
return acc;
|
|
675
|
+
}, {})
|
|
676
|
+
};
|
|
677
|
+
var textTheme = {
|
|
678
|
+
"& .cm-scroller": {
|
|
679
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
var codeTheme = {
|
|
683
|
+
"& .cm-scroller": {
|
|
684
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
|
|
687
688
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
688
689
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
689
690
|
import { EditorView as EditorView5 } from "@codemirror/view";
|
|
690
691
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
691
692
|
import { vim } from "@replit/codemirror-vim";
|
|
692
693
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
693
|
-
import
|
|
694
|
-
import
|
|
695
|
-
import { isDocAccessor as isDocAccessor2 } from "@dxos/echo-schema";
|
|
694
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
695
|
+
import { generateName } from "@dxos/display-name";
|
|
696
696
|
import { useThemeContext } from "@dxos/react-ui";
|
|
697
|
+
import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
|
|
698
|
+
var EditorModes = [
|
|
699
|
+
"default",
|
|
700
|
+
"vim"
|
|
701
|
+
];
|
|
702
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
|
|
703
|
+
const { themeMode } = useThemeContext();
|
|
704
|
+
const tabsterDOMAttribute = useFocusableGroup({
|
|
705
|
+
tabBehavior: "limited"
|
|
706
|
+
});
|
|
707
|
+
const { awareness, peer } = model;
|
|
708
|
+
useEffect(() => {
|
|
709
|
+
if (awareness && peer) {
|
|
710
|
+
awareness.setLocalStateField("user", {
|
|
711
|
+
name: peer.name ?? generateName(peer.id),
|
|
712
|
+
color: getColorForValue({
|
|
713
|
+
value: peer.id,
|
|
714
|
+
type: "color"
|
|
715
|
+
}),
|
|
716
|
+
colorLight: getColorForValue({
|
|
717
|
+
value: peer.id,
|
|
718
|
+
themeMode,
|
|
719
|
+
type: "highlight"
|
|
720
|
+
})
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}, [
|
|
724
|
+
awareness,
|
|
725
|
+
peer,
|
|
726
|
+
themeMode
|
|
727
|
+
]);
|
|
728
|
+
const [root, setRoot] = useState(null);
|
|
729
|
+
const [state, setState] = useState();
|
|
730
|
+
const [view, setView] = useState();
|
|
731
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
732
|
+
root,
|
|
733
|
+
state,
|
|
734
|
+
view
|
|
735
|
+
}), [
|
|
736
|
+
view,
|
|
737
|
+
state,
|
|
738
|
+
root
|
|
739
|
+
]);
|
|
740
|
+
useEffect(() => {
|
|
741
|
+
if (!root) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
const state2 = EditorState2.create({
|
|
745
|
+
doc: model.text(),
|
|
746
|
+
extensions: [
|
|
747
|
+
// TODO(burdon): Factor out VIM mode?
|
|
748
|
+
editorMode === "vim" && vim(),
|
|
749
|
+
// Theme.
|
|
750
|
+
EditorView5.baseTheme(defaultTheme),
|
|
751
|
+
EditorView5.theme(slots?.editor?.theme ?? {}),
|
|
752
|
+
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
753
|
+
EditorView5.darkTheme.of(themeMode === "dark"),
|
|
754
|
+
// Storage and replication.
|
|
755
|
+
model.extension,
|
|
756
|
+
// Custom.
|
|
757
|
+
...extensions
|
|
758
|
+
].filter(Boolean)
|
|
759
|
+
});
|
|
760
|
+
view?.destroy();
|
|
761
|
+
setView(new EditorView5({
|
|
762
|
+
state: state2,
|
|
763
|
+
parent: root
|
|
764
|
+
}));
|
|
765
|
+
setState(state2);
|
|
766
|
+
return () => {
|
|
767
|
+
view?.destroy();
|
|
768
|
+
setView(void 0);
|
|
769
|
+
setState(void 0);
|
|
770
|
+
};
|
|
771
|
+
}, [
|
|
772
|
+
root,
|
|
773
|
+
model,
|
|
774
|
+
themeMode,
|
|
775
|
+
editorMode
|
|
776
|
+
]);
|
|
777
|
+
const handleKeyUp = useCallback((event) => {
|
|
778
|
+
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
779
|
+
switch (key) {
|
|
780
|
+
case "Enter": {
|
|
781
|
+
view?.contentDOM.focus();
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
case "Escape": {
|
|
785
|
+
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
|
|
786
|
+
break;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}, [
|
|
790
|
+
view,
|
|
791
|
+
editorMode
|
|
792
|
+
]);
|
|
793
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
794
|
+
key: model.id,
|
|
795
|
+
ref: setRoot,
|
|
796
|
+
tabIndex: 0,
|
|
797
|
+
...slots?.root,
|
|
798
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
799
|
+
onKeyUp: handleKeyUp
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
803
|
+
const { themeMode } = useThemeContext();
|
|
804
|
+
const slots = defaultsDeep({}, _slots, defaultTextSlots);
|
|
805
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
806
|
+
ref: forwardedRef,
|
|
807
|
+
extensions: [
|
|
808
|
+
basicBundle({
|
|
809
|
+
themeMode,
|
|
810
|
+
placeholder: slots?.editor?.placeholder
|
|
811
|
+
}),
|
|
812
|
+
...extensions
|
|
813
|
+
],
|
|
814
|
+
slots,
|
|
815
|
+
...props
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
819
|
+
const { themeMode } = useThemeContext();
|
|
820
|
+
const slots = defaultsDeep({}, _slots, defaultSlots);
|
|
821
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
822
|
+
ref: forwardedRef,
|
|
823
|
+
extensions: [
|
|
824
|
+
markdownBundle({
|
|
825
|
+
themeMode,
|
|
826
|
+
placeholder: slots?.editor?.placeholder
|
|
827
|
+
}),
|
|
828
|
+
...extensions
|
|
829
|
+
],
|
|
830
|
+
slots,
|
|
831
|
+
...props
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
var defaultSlots = {
|
|
835
|
+
root: {
|
|
836
|
+
className: mx2("p-2", inputSurface)
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
var defaultTextSlots = {
|
|
840
|
+
...defaultSlots,
|
|
841
|
+
editor: {
|
|
842
|
+
theme: textTheme
|
|
843
|
+
}
|
|
844
|
+
};
|
|
697
845
|
|
|
698
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
699
|
-
import
|
|
846
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
847
|
+
import get3 from "lodash.get";
|
|
848
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
700
849
|
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";
|
|
850
|
+
import { invariant } from "@dxos/invariant";
|
|
851
|
+
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
705
852
|
|
|
706
|
-
// packages/ui/react-ui-editor/src/
|
|
707
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
708
|
-
import { ViewPlugin
|
|
853
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
854
|
+
import { Annotation, Facet, StateEffect, StateField as StateField4 } from "@codemirror/state";
|
|
855
|
+
import { ViewPlugin } from "@codemirror/view";
|
|
709
856
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
710
857
|
|
|
711
|
-
// packages/ui/react-ui-editor/src/
|
|
858
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
712
859
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
713
860
|
|
|
714
|
-
// packages/ui/react-ui-editor/src/
|
|
861
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
|
|
715
862
|
import { ChangeSet } from "@codemirror/state";
|
|
716
863
|
var amToCodemirror_default = (view, selection, target, patches) => {
|
|
717
864
|
for (const patch of patches) {
|
|
@@ -818,7 +965,7 @@ var charPath = (textPath, candidatePath) => {
|
|
|
818
965
|
return null;
|
|
819
966
|
};
|
|
820
967
|
|
|
821
|
-
// packages/ui/react-ui-editor/src/
|
|
968
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
|
|
822
969
|
import { next as am } from "@dxos/automerge/automerge";
|
|
823
970
|
var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
824
971
|
const { lastHeads, path } = state.field(field);
|
|
@@ -841,7 +988,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
|
841
988
|
return newHeads ?? void 0;
|
|
842
989
|
};
|
|
843
990
|
|
|
844
|
-
// packages/ui/react-ui-editor/src/
|
|
991
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
845
992
|
var PatchSemaphore = class {
|
|
846
993
|
constructor(field) {
|
|
847
994
|
this._inReconcile = false;
|
|
@@ -882,7 +1029,7 @@ var PatchSemaphore = class {
|
|
|
882
1029
|
}
|
|
883
1030
|
};
|
|
884
1031
|
|
|
885
|
-
// packages/ui/react-ui-editor/src/
|
|
1032
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
886
1033
|
var effectType = StateEffect.define({});
|
|
887
1034
|
var updateHeads = (newHeads) => effectType.of({
|
|
888
1035
|
newHeads
|
|
@@ -893,7 +1040,7 @@ var semaphoreFacet = Facet.define({
|
|
|
893
1040
|
combine: (values) => values.at(-1)
|
|
894
1041
|
});
|
|
895
1042
|
var automergePlugin = (handle, path) => {
|
|
896
|
-
const stateField =
|
|
1043
|
+
const stateField = StateField4.define({
|
|
897
1044
|
create: () => ({
|
|
898
1045
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
899
1046
|
unreconciledTransactions: [],
|
|
@@ -923,7 +1070,7 @@ var automergePlugin = (handle, path) => {
|
|
|
923
1070
|
}
|
|
924
1071
|
});
|
|
925
1072
|
const semaphore = new PatchSemaphore(stateField);
|
|
926
|
-
const viewPlugin =
|
|
1073
|
+
const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
927
1074
|
constructor(view) {
|
|
928
1075
|
this._handleChange = () => {
|
|
929
1076
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -953,45 +1100,6 @@ var automergePlugin = (handle, path) => {
|
|
|
953
1100
|
var reconcileAnnotationType = Annotation.define();
|
|
954
1101
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
955
1102
|
|
|
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
1103
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
996
1104
|
import * as random from "lib0/random";
|
|
997
1105
|
var cursorColors = [
|
|
@@ -1131,185 +1239,80 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1131
1239
|
};
|
|
1132
1240
|
|
|
1133
1241
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1242
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1134
1243
|
var useTextModel = ({ identity, space, text }) => {
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1244
|
+
const [model, setModel] = useState2(() => createModel({
|
|
1245
|
+
identity,
|
|
1246
|
+
space,
|
|
1247
|
+
text
|
|
1248
|
+
}));
|
|
1249
|
+
useEffect2(() => {
|
|
1250
|
+
setModel(createModel({
|
|
1251
|
+
identity,
|
|
1143
1252
|
space,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
});
|
|
1253
|
+
text
|
|
1254
|
+
}));
|
|
1147
1255
|
}, [
|
|
1148
1256
|
identity,
|
|
1149
1257
|
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
1258
|
text
|
|
1164
1259
|
]);
|
|
1260
|
+
return model;
|
|
1261
|
+
};
|
|
1262
|
+
var createModel = (options) => {
|
|
1263
|
+
const { space, text } = options;
|
|
1165
1264
|
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;
|
|
1265
|
+
return createAutomergeModel(options);
|
|
1266
|
+
} else {
|
|
1267
|
+
if (!space || !text?.doc || !text?.content) {
|
|
1268
|
+
return void 0;
|
|
1269
|
+
}
|
|
1270
|
+
return createYjsModel(options);
|
|
1179
1271
|
}
|
|
1272
|
+
};
|
|
1273
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
1274
|
+
invariant(space && text?.doc && text?.content, void 0, {
|
|
1275
|
+
F: __dxlog_file2,
|
|
1276
|
+
L: 73,
|
|
1277
|
+
S: void 0,
|
|
1278
|
+
A: [
|
|
1279
|
+
"space && text?.doc && text?.content",
|
|
1280
|
+
""
|
|
1281
|
+
]
|
|
1282
|
+
});
|
|
1283
|
+
const provider = new SpaceAwarenessProvider({
|
|
1284
|
+
space,
|
|
1285
|
+
doc: text.doc,
|
|
1286
|
+
channel: `yjs.awareness.${text.id}`
|
|
1287
|
+
});
|
|
1180
1288
|
return {
|
|
1181
1289
|
id: text.doc.guid,
|
|
1182
1290
|
content: text.content,
|
|
1183
|
-
|
|
1291
|
+
text: () => text.content.toString(),
|
|
1292
|
+
extension: yCollab(text.content, provider.awareness),
|
|
1293
|
+
awareness: provider.awareness,
|
|
1184
1294
|
peer: identity ? {
|
|
1185
1295
|
id: identity.identityKey.toHex(),
|
|
1186
1296
|
name: identity.profile?.displayName
|
|
1187
1297
|
} : void 0
|
|
1188
1298
|
};
|
|
1189
1299
|
};
|
|
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
|
|
1300
|
+
var createAutomergeModel = ({ identity, space, text }) => {
|
|
1301
|
+
const obj = text;
|
|
1302
|
+
const doc = getRawDoc(obj, [
|
|
1303
|
+
obj.field
|
|
1264
1304
|
]);
|
|
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
|
-
});
|
|
1305
|
+
return {
|
|
1306
|
+
id: obj.id,
|
|
1307
|
+
content: doc,
|
|
1308
|
+
text: () => get3(doc.handle.docSync(), doc.path),
|
|
1309
|
+
extension: automergePlugin(doc.handle, doc.path),
|
|
1310
|
+
peer: identity ? {
|
|
1311
|
+
id: identity.identityKey.toHex(),
|
|
1312
|
+
name: identity.profile?.displayName
|
|
1313
|
+
} : void 0
|
|
1314
|
+
};
|
|
1315
|
+
};
|
|
1313
1316
|
export {
|
|
1314
1317
|
BaseTextEditor,
|
|
1315
1318
|
Doc,
|
|
@@ -1318,34 +1321,27 @@ export {
|
|
|
1318
1321
|
SpaceAwarenessProvider,
|
|
1319
1322
|
TextEditor,
|
|
1320
1323
|
TextKind,
|
|
1321
|
-
|
|
1324
|
+
YText,
|
|
1322
1325
|
YXmlFragment,
|
|
1326
|
+
autocomplete,
|
|
1323
1327
|
basicBundle,
|
|
1324
|
-
|
|
1325
|
-
chalky,
|
|
1326
|
-
coral,
|
|
1327
|
-
createHyperlinkTooltip,
|
|
1328
|
+
codeTheme,
|
|
1328
1329
|
cursorColor,
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
hyperlinkWidget,
|
|
1335
|
-
invalid,
|
|
1336
|
-
ivory,
|
|
1337
|
-
malibu,
|
|
1330
|
+
defaultSlots,
|
|
1331
|
+
defaultTextSlots,
|
|
1332
|
+
defaultTheme,
|
|
1333
|
+
link,
|
|
1334
|
+
listener,
|
|
1338
1335
|
markdownBundle,
|
|
1339
1336
|
markdownHighlightStyle,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1337
|
+
markdownTags,
|
|
1338
|
+
markdownTagsExtension,
|
|
1339
|
+
statefield,
|
|
1340
|
+
styles,
|
|
1344
1341
|
tags2 as tags,
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
whiskey
|
|
1342
|
+
tasklist,
|
|
1343
|
+
textTheme,
|
|
1344
|
+
tooltip,
|
|
1345
|
+
useTextModel
|
|
1350
1346
|
};
|
|
1351
1347
|
//# sourceMappingURL=index.mjs.map
|