@dxos/react-ui-editor 0.3.9-main.9ca5eac → 0.3.9-main.9da1d41
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 +654 -734
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts +9 -0
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-plugin/index.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts +6 -5
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge.stories.d.ts +1 -0
- package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +24 -20
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -25
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/{stories/html/code-mirror.stories.d.ts → src/components/TextEditor/codemirror.stories.d.ts} +2 -2
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/{hyperlink.d.ts → hyperlink/hyperlinkWidget.d.ts} +3 -3
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -1
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +1 -3
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +4 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
- package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
- package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +1 -13
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +4 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts +1 -1
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/package.json +30 -27
- package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
- package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
- package/src/automerge/automerge-plugin/handle.ts +14 -0
- package/src/automerge/automerge-plugin/index.ts +2 -2
- package/src/automerge/automerge-plugin/plugin.ts +39 -10
- package/src/automerge/automerge.stories.tsx +31 -46
- package/src/components/TextEditor/TextEditor.stories.tsx +43 -65
- package/src/components/TextEditor/TextEditor.tsx +108 -56
- package/src/components/TextEditor/codemirror.stories.ts +114 -0
- package/src/components/TextEditor/extensions/basic/bundle.ts +26 -0
- package/src/components/TextEditor/extensions/basic/index.ts +6 -0
- package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
- package/src/components/TextEditor/extensions/change.ts +22 -0
- package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
- package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +1 -0
- package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx} +21 -10
- package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
- package/src/components/TextEditor/extensions/index.ts +3 -1
- package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
- package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +23 -12
- package/src/components/TextEditor/index.ts +1 -4
- package/src/components/TextEditor/yjs.stories.tsx +55 -0
- package/src/components/index.ts +0 -3
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useCollaboration.ts +35 -0
- package/src/{model.ts → hooks/useTextModel.ts} +4 -14
- package/src/index.ts +3 -3
- package/src/styles/tokens.ts +6 -0
- package/src/testing/replicator.ts +1 -2
- package/dist/types/src/automerge/demo.d.ts +0 -25
- package/dist/types/src/automerge/demo.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.d.ts +0 -15
- package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -29
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
- package/dist/types/src/components/Editor/index.d.ts +0 -2
- package/dist/types/src/components/Editor/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.d.ts +0 -20
- package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -20
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/index.d.ts +0 -2
- package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -93
- package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.d.ts +0 -20
- package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -27
- package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
- package/dist/types/src/components/RichText/index.d.ts +0 -2
- package/dist/types/src/components/RichText/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
- package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
- package/dist/types/src/model.d.ts.map +0 -1
- package/dist/types/src/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/yjs/index.d.ts.map +0 -1
- package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
- package/src/automerge/demo.ts +0 -106
- package/src/components/Editor/Editor.stories.tsx +0 -82
- package/src/components/Editor/Editor.tsx +0 -33
- package/src/components/Editor/index.ts +0 -5
- package/src/components/Markdown/Markdown.stories.tsx +0 -59
- package/src/components/Markdown/Markdown.tsx +0 -214
- package/src/components/Markdown/index.ts +0 -5
- package/src/components/RichText/RichText.stories.tsx +0 -70
- package/src/components/RichText/RichText.tsx +0 -181
- package/src/components/RichText/index.ts +0 -5
- package/src/components/TextEditor/theme.ts +0 -33
- /package/dist/types/src/components/TextEditor/extensions/{hyperlinkTooltip.d.ts → hyperlink/hyperlinkTooltip.d.ts} +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/cursors.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/index.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/space-provider.d.ts +0 -0
- /package/src/components/{Markdown/markdownTags.ts → TextEditor/extensions/markdown/tags.ts} +0 -0
- /package/src/{yjs → hooks/yjs}/cursors.ts +0 -0
- /package/src/{yjs → hooks/yjs}/index.ts +0 -0
- /package/src/{yjs → hooks/yjs}/space-provider.ts +0 -0
|
@@ -1,199 +1,305 @@
|
|
|
1
|
-
// packages/ui/react-ui-editor/src/
|
|
2
|
-
import
|
|
3
|
-
import { YXmlFragment } from "@dxos/text-model";
|
|
1
|
+
// packages/ui/react-ui-editor/src/index.ts
|
|
2
|
+
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
|
+
import { Doc, YText as YText2, YXmlFragment } from "@dxos/text-model";
|
|
4
4
|
|
|
5
|
-
// packages/ui/react-ui-editor/src/
|
|
6
|
-
import {
|
|
5
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
|
+
import { tags as tags2 } from "@lezer/highlight";
|
|
7
7
|
|
|
8
|
-
// packages/ui/react-ui-editor/src/
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/bundle.ts
|
|
9
|
+
import { closeBrackets } from "@codemirror/autocomplete";
|
|
10
|
+
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
11
|
+
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
12
|
+
import { placeholder } from "@codemirror/view";
|
|
13
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
14
|
+
bracketMatching(),
|
|
15
|
+
closeBrackets(),
|
|
16
|
+
_placeholder && placeholder(_placeholder),
|
|
17
|
+
// TODO(burdon): Is this required?
|
|
18
|
+
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
19
|
+
].filter(Boolean);
|
|
20
|
+
|
|
21
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
|
|
22
|
+
import get from "lodash.get";
|
|
23
|
+
|
|
24
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
25
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
26
|
+
var heading = {
|
|
27
|
+
1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
|
|
28
|
+
2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
|
|
29
|
+
3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
|
|
30
|
+
4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
|
|
31
|
+
5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
|
|
32
|
+
6: "mbs-4 mbe-2 font-black text-inherit no-underline"
|
|
33
|
+
};
|
|
34
|
+
var bold = "font-bold";
|
|
35
|
+
var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
|
|
36
|
+
var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
|
|
37
|
+
var italic = "italic";
|
|
38
|
+
var strikethrough = "line-through";
|
|
39
|
+
var mark = "!font-normal !no-underline !text-inherit opacity-40";
|
|
40
|
+
|
|
41
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
42
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
43
|
+
var tokens = tailwindConfig({}).theme;
|
|
44
|
+
|
|
45
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
|
|
46
|
+
var basicTheme = {
|
|
47
|
+
"&.cm-focused": {
|
|
48
|
+
outline: "none"
|
|
14
49
|
},
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
50
|
+
"& .cm-line": {
|
|
51
|
+
paddingInline: 0,
|
|
52
|
+
lineHeight: 1.6,
|
|
53
|
+
minBlockSize: "1.6em"
|
|
18
54
|
},
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
light: "#ffbc4233"
|
|
55
|
+
"& .cm-line *": {
|
|
56
|
+
lineHeight: 1.6
|
|
22
57
|
},
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
58
|
+
"& .cm-scroller": {
|
|
59
|
+
fontFamily: get(tokens, "fontFamily.body", []).join(","),
|
|
60
|
+
overflow: "visible"
|
|
26
61
|
},
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
62
|
+
"& .cm-content": {
|
|
63
|
+
padding: 0,
|
|
64
|
+
caretColor: "black"
|
|
30
65
|
},
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
light: "#9ac2c933"
|
|
66
|
+
".dark & .cm-content": {
|
|
67
|
+
caretColor: "white"
|
|
34
68
|
},
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
69
|
+
"& .cm-tooltip": {
|
|
70
|
+
backgroundColor: "transparent",
|
|
71
|
+
border: "none"
|
|
38
72
|
},
|
|
39
|
-
{
|
|
40
|
-
color: "
|
|
41
|
-
|
|
73
|
+
"& .cm-link": {
|
|
74
|
+
color: get(tokens, "extend.colors.primary.500"),
|
|
75
|
+
textDecoration: "underline"
|
|
42
76
|
}
|
|
43
|
-
|
|
44
|
-
var cursorColor = cursorColors[random.uint32() % cursorColors.length];
|
|
77
|
+
};
|
|
45
78
|
|
|
46
|
-
// packages/ui/react-ui-editor/src/
|
|
47
|
-
import
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
var messageAwareness = 1;
|
|
54
|
-
var messageQueryAwareness = 3;
|
|
55
|
-
var SpaceAwarenessProvider = class extends Observable {
|
|
56
|
-
constructor({ space, doc, channel, awareness }) {
|
|
57
|
-
super();
|
|
58
|
-
this._space = space;
|
|
59
|
-
this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
|
|
60
|
-
this._channel = channel;
|
|
61
|
-
this._clientId = doc.clientID;
|
|
62
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
63
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
64
|
-
if (typeof window !== "undefined") {
|
|
65
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
66
|
-
} else if (typeof process !== "undefined") {
|
|
67
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
79
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/change.ts
|
|
80
|
+
import { StateField } from "@codemirror/state";
|
|
81
|
+
var onChangeExtension = (onChange) => StateField.define({
|
|
82
|
+
create: () => null,
|
|
83
|
+
update: (_value, transaction) => {
|
|
84
|
+
if (transaction.docChanged && onChange) {
|
|
85
|
+
onChange(transaction.newDoc.toString());
|
|
68
86
|
}
|
|
69
|
-
|
|
70
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
71
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
72
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
73
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
74
|
-
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
75
|
-
this._clientId
|
|
76
|
-
]));
|
|
77
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
87
|
+
return null;
|
|
78
88
|
}
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts
|
|
92
|
+
import { syntaxTree } from "@codemirror/language";
|
|
93
|
+
import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
|
|
94
|
+
import { Decoration, EditorView, WidgetType } from "@codemirror/view";
|
|
95
|
+
var Link = class extends WidgetType {
|
|
96
|
+
constructor(_anchor, _text, _url) {
|
|
97
|
+
super();
|
|
98
|
+
this._anchor = _anchor;
|
|
99
|
+
this._text = _text;
|
|
100
|
+
this._url = _url;
|
|
81
101
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
added,
|
|
85
|
-
updated,
|
|
86
|
-
removed,
|
|
87
|
-
origin
|
|
88
|
-
}, {
|
|
89
|
-
F: __dxlog_file,
|
|
90
|
-
L: 67,
|
|
91
|
-
S: this,
|
|
92
|
-
C: (f, a) => f(...a)
|
|
93
|
-
});
|
|
94
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
95
|
-
const encoderAwareness = encoding.createEncoder();
|
|
96
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
97
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
98
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
102
|
+
eq(other) {
|
|
103
|
+
return this._text === other.text && this._url === other.url;
|
|
99
104
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
toDOM(view) {
|
|
106
|
+
const link = document.createElement("a");
|
|
107
|
+
link.setAttribute("class", "cm-link");
|
|
108
|
+
link.textContent = this._text;
|
|
109
|
+
if (this._url) {
|
|
110
|
+
link.setAttribute("target", "_blank");
|
|
111
|
+
link.href = this._url;
|
|
112
|
+
} else {
|
|
113
|
+
link.onclick = () => {
|
|
114
|
+
view.dispatch({
|
|
115
|
+
selection: {
|
|
116
|
+
anchor: this._anchor
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
111
120
|
}
|
|
121
|
+
return link;
|
|
112
122
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
};
|
|
124
|
+
var hyperlinkDecoration = ({ link } = {}) => {
|
|
125
|
+
return StateField2.define({
|
|
126
|
+
create: (state) => update(state, link),
|
|
127
|
+
update: (_, tr) => update(tr.state, link),
|
|
128
|
+
provide: (field) => EditorView.decorations.from(field)
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
var update = (state, link) => {
|
|
132
|
+
const builder = new RangeSetBuilder();
|
|
133
|
+
const cursor = state.selection.main.head;
|
|
134
|
+
syntaxTree(state).iterate({
|
|
135
|
+
enter: (node) => {
|
|
136
|
+
if (cursor < node.from || cursor > node.to) {
|
|
137
|
+
if (node.name === "Link") {
|
|
138
|
+
const marks = node.node.getChildren("LinkMark");
|
|
139
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
140
|
+
const urlNode = node.node.getChild("URL");
|
|
141
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
142
|
+
builder.add(node.from, node.to, Decoration.replace({
|
|
143
|
+
widget: new Link(node.from, text, link ? url : void 0)
|
|
144
|
+
}));
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
132
147
|
}
|
|
148
|
+
return true;
|
|
133
149
|
}
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
});
|
|
151
|
+
return builder.finish();
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.tsx
|
|
155
|
+
import { hoverTooltip } from "@codemirror/view";
|
|
156
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
157
|
+
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
158
|
+
var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp) => hoverTooltip((view, pos) => {
|
|
159
|
+
const { from, text } = view.state.doc.lineAt(pos);
|
|
160
|
+
const p = pos - from;
|
|
161
|
+
let idx = 0;
|
|
162
|
+
let match;
|
|
163
|
+
do {
|
|
164
|
+
match = text.substring(idx).match(regexp);
|
|
165
|
+
if (!match) {
|
|
166
|
+
match = void 0;
|
|
167
|
+
break;
|
|
136
168
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
169
|
+
idx = text.indexOf(match[0]);
|
|
170
|
+
if (p >= idx && p < idx + match[0].length) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
idx += match[0].length;
|
|
174
|
+
} while (true);
|
|
175
|
+
if (!match) {
|
|
176
|
+
return null;
|
|
143
177
|
}
|
|
144
|
-
|
|
178
|
+
const [, , url] = match ?? [];
|
|
179
|
+
return {
|
|
180
|
+
pos: idx + from,
|
|
181
|
+
end: idx + from + match[0].length,
|
|
182
|
+
above: true,
|
|
183
|
+
create: () => {
|
|
184
|
+
const el = document.createElement("a");
|
|
185
|
+
el.innerText = "_";
|
|
186
|
+
el.className = tooltipContent({}, "mb-2 p-1");
|
|
187
|
+
el.setAttribute("target", "_blank");
|
|
188
|
+
el.setAttribute("href", url);
|
|
189
|
+
onHover(el, url);
|
|
190
|
+
return {
|
|
191
|
+
dom: el
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
});
|
|
145
196
|
|
|
146
|
-
// packages/ui/react-ui-editor/src/
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
197
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.tsx
|
|
198
|
+
import { Decoration as Decoration2, EditorView as EditorView2, MatchDecorator, ViewPlugin } from "@codemirror/view";
|
|
199
|
+
var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
|
|
200
|
+
var linkDecorator = () => new MatchDecorator({
|
|
201
|
+
regexp: markdownLinkRegexp2,
|
|
202
|
+
decorate: (add, from, to, match, view) => {
|
|
203
|
+
const [_, label, url] = match;
|
|
204
|
+
const p0 = {
|
|
205
|
+
start: from,
|
|
206
|
+
end: from + 1
|
|
207
|
+
};
|
|
208
|
+
const p1 = {
|
|
209
|
+
start: from + 1,
|
|
210
|
+
end: from + 1 + label.length
|
|
211
|
+
};
|
|
212
|
+
const p2 = {
|
|
213
|
+
start: p1.end,
|
|
214
|
+
end: p1.end + 1
|
|
215
|
+
};
|
|
216
|
+
const p3 = {
|
|
217
|
+
start: p1.end + 1,
|
|
218
|
+
end: p1.end + 1 + url.length + 2
|
|
219
|
+
};
|
|
220
|
+
add(p0.start, p0.end, Decoration2.mark({
|
|
221
|
+
class: "cm-hyperlink-bracket",
|
|
222
|
+
_attributes: {
|
|
223
|
+
style: "display: none"
|
|
224
|
+
}
|
|
225
|
+
}));
|
|
226
|
+
add(p1.start, p1.end, Decoration2.mark({
|
|
227
|
+
class: "cm-hyperlink-label"
|
|
228
|
+
}));
|
|
229
|
+
add(p2.start, p2.end, Decoration2.mark({
|
|
230
|
+
class: "cm-hyperlink-bracket",
|
|
231
|
+
_attributes: {
|
|
232
|
+
style: "display: none"
|
|
233
|
+
}
|
|
234
|
+
}));
|
|
235
|
+
add(p3.start, p3.end, Decoration2.mark({
|
|
236
|
+
class: "cm-hyperlink-url",
|
|
237
|
+
_attributes: {
|
|
238
|
+
style: "display: none"
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
function hyperLinkExtension() {
|
|
244
|
+
return ViewPlugin.fromClass(class HyperLinkView {
|
|
245
|
+
constructor(view) {
|
|
246
|
+
this.decorator = linkDecorator();
|
|
247
|
+
this.decorations = this.decorator.createDeco(view);
|
|
151
248
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
249
|
+
update(update2) {
|
|
250
|
+
if (update2.docChanged || update2.viewportChanged) {
|
|
251
|
+
this.decorations = this.decorator.updateDeco(update2, this.decorations);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}, {
|
|
255
|
+
decorations: (view) => view.decorations,
|
|
256
|
+
eventHandlers: {
|
|
257
|
+
// TODO(burdon): CLick to expand link.
|
|
258
|
+
// https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
|
|
259
|
+
mousedown: function(event, view) {
|
|
260
|
+
const pos = view.posAtDOM(event.target);
|
|
261
|
+
if (pos !== 0) {
|
|
262
|
+
console.log(this);
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
// TODO(burdon): Hide when cursor moves away.
|
|
266
|
+
keydown: (event, view) => {
|
|
267
|
+
view.update([]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
var hyperlinkStyle = EditorView2.baseTheme({
|
|
273
|
+
".cm-hyperlink-label": {
|
|
274
|
+
cursor: "pointer",
|
|
275
|
+
textDecoration: "underline"
|
|
276
|
+
},
|
|
277
|
+
".cm-hyperlink-bracket": {
|
|
278
|
+
opacity: 0.2
|
|
279
|
+
},
|
|
280
|
+
".cm-hyperlink-url": {
|
|
281
|
+
opacity: 0.5,
|
|
282
|
+
fontFamily: "monospace"
|
|
164
283
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
id: identity.identityKey.toHex(),
|
|
171
|
-
name: identity.profile?.displayName
|
|
172
|
-
} : void 0
|
|
173
|
-
};
|
|
174
|
-
};
|
|
284
|
+
});
|
|
285
|
+
var hyperlinkWidget = [
|
|
286
|
+
hyperLinkExtension(),
|
|
287
|
+
hyperlinkStyle
|
|
288
|
+
];
|
|
175
289
|
|
|
176
|
-
// packages/ui/react-ui-editor/src/components/
|
|
177
|
-
import {
|
|
290
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
291
|
+
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
178
292
|
import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
|
|
179
|
-
import {
|
|
180
|
-
import { bracketMatching, defaultHighlightStyle, foldKeymap, indentOnInput, syntaxHighlighting } from "@codemirror/language";
|
|
293
|
+
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
294
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, foldKeymap, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
181
295
|
import { languages } from "@codemirror/language-data";
|
|
182
296
|
import { lintKeymap } from "@codemirror/lint";
|
|
183
|
-
import {
|
|
184
|
-
import { EditorState
|
|
185
|
-
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
186
|
-
import {
|
|
187
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
188
|
-
import { vim } from "@replit/codemirror-vim";
|
|
189
|
-
import React, { forwardRef, useEffect, useImperativeHandle, useState, useMemo as useMemo2, useCallback } from "react";
|
|
190
|
-
import { yCollab } from "y-codemirror.next";
|
|
191
|
-
import { generateName } from "@dxos/display-name";
|
|
192
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
193
|
-
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
194
|
-
import { YText } from "@dxos/text-model";
|
|
297
|
+
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
298
|
+
import { EditorState } from "@codemirror/state";
|
|
299
|
+
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
300
|
+
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView3, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
195
301
|
|
|
196
|
-
// packages/ui/react-ui-editor/src/components/
|
|
302
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/tags.ts
|
|
197
303
|
import { styleTags, Tag } from "@lezer/highlight";
|
|
198
304
|
var markdownTags = {
|
|
199
305
|
headingMark: Tag.define(),
|
|
@@ -226,48 +332,28 @@ var markdownTagsExtension = {
|
|
|
226
332
|
]
|
|
227
333
|
};
|
|
228
334
|
|
|
229
|
-
// packages/ui/react-ui-editor/src/components/
|
|
335
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/theme.ts
|
|
230
336
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
231
337
|
import { HighlightStyle } from "@codemirror/language";
|
|
232
338
|
import { tags } from "@lezer/highlight";
|
|
233
|
-
import
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
var
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
|
|
241
|
-
4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
|
|
242
|
-
5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
|
|
243
|
-
6: "mbs-4 mbe-2 font-black text-inherit no-underline"
|
|
244
|
-
};
|
|
245
|
-
var blockquote = "mlb-2 border-is-4 border-neutral-500/50 pis-5";
|
|
246
|
-
var unorderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[attr(marker)] [&>li:before]:mlb-1 [&>li:before]:mie-2";
|
|
247
|
-
var orderedList = 'mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[counters(section,_".")_"._"] [counter-reset:section] [&>li:before]:mlb-1';
|
|
248
|
-
var listItem = "contents before:[counter-increment:section]";
|
|
249
|
-
var codeBlock = "mlb-2 font-mono bg-neutral-500/10 p-3 rounded";
|
|
250
|
-
var horizontalRule = "mlb-4 border-neutral-500/50";
|
|
251
|
-
var paragraph = "mlb-1";
|
|
252
|
-
var bold = "font-bold";
|
|
253
|
-
var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
|
|
254
|
-
var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
|
|
255
|
-
var italic = "italic";
|
|
256
|
-
var strikethrough = "line-through";
|
|
257
|
-
var mark = "!font-normal !no-underline !text-inherit opacity-40";
|
|
258
|
-
|
|
259
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
260
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
261
|
-
var tokens = tailwindConfig({}).theme;
|
|
262
|
-
|
|
263
|
-
// packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
|
|
339
|
+
import get2 from "lodash.get";
|
|
340
|
+
var chalky = "#e5c07b";
|
|
341
|
+
var coral = "#e06c75";
|
|
342
|
+
var cyan = "#56b6c2";
|
|
343
|
+
var invalid = "#ffffff";
|
|
344
|
+
var ivory = "#abb2bf";
|
|
345
|
+
var stone = "#7d8799";
|
|
264
346
|
var malibu = "#61afef";
|
|
265
|
-
var
|
|
266
|
-
var
|
|
347
|
+
var sage = "#98c379";
|
|
348
|
+
var whiskey = "#d19a66";
|
|
349
|
+
var violet = "#c678dd";
|
|
350
|
+
var highlightBackground = "#2c313a";
|
|
351
|
+
var tooltipBackground = "#353a42";
|
|
352
|
+
var monospace = get2(tokens, "fontFamily.mono", [
|
|
267
353
|
"monospace"
|
|
268
354
|
]).join(",");
|
|
269
355
|
var markdownTheme = {
|
|
270
|
-
// TODO(thure):
|
|
356
|
+
// TODO(thure): Consider whether these commented-out rules from one-dark-theme should be integrated.
|
|
271
357
|
// '&': {
|
|
272
358
|
// color: ivory,
|
|
273
359
|
// backgroundColor: background
|
|
@@ -304,7 +390,7 @@ var markdownTheme = {
|
|
|
304
390
|
// border: 'none',
|
|
305
391
|
// color: '#ddd'
|
|
306
392
|
// },
|
|
307
|
-
".cm-tooltip": {
|
|
393
|
+
"& .cm-tooltip": {
|
|
308
394
|
backgroundColor: "transparent",
|
|
309
395
|
border: "none"
|
|
310
396
|
},
|
|
@@ -331,40 +417,42 @@ var markdownTheme = {
|
|
|
331
417
|
},
|
|
332
418
|
"& .cm-line": {
|
|
333
419
|
paddingInline: 0,
|
|
420
|
+
lineHeight: 1.6,
|
|
334
421
|
minBlockSize: "1.6em"
|
|
335
422
|
},
|
|
336
423
|
"& .cm-line *": {
|
|
337
424
|
lineHeight: 1.6
|
|
338
425
|
},
|
|
339
426
|
"&.cm-focused .cm-selectionBackground, & .cm-selectionBackground": {
|
|
340
|
-
background:
|
|
427
|
+
background: get2(tokens, "extend.colors.primary.150", "#00ffff")
|
|
341
428
|
},
|
|
342
429
|
".dark & .cm-selectionBackground, .dark &.cm-focused .cm-selectionBackground": {
|
|
343
|
-
background:
|
|
430
|
+
background: get2(tokens, "extend.colors.primary.850", "#00ffff")
|
|
344
431
|
},
|
|
345
432
|
"& .cm-selectionMatch": {
|
|
346
|
-
background:
|
|
433
|
+
background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
347
434
|
},
|
|
348
435
|
".dark & .cm-selectionMatch": {
|
|
349
|
-
background:
|
|
436
|
+
background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
350
437
|
},
|
|
351
438
|
"& .cm-content": {
|
|
439
|
+
padding: 0,
|
|
352
440
|
caretColor: "black"
|
|
353
441
|
},
|
|
354
442
|
".dark & .cm-content": {
|
|
355
|
-
caretColor:
|
|
443
|
+
caretColor: "white"
|
|
356
444
|
},
|
|
357
445
|
"& .cm-cursor": {
|
|
358
446
|
borderLeftColor: "black"
|
|
359
447
|
},
|
|
360
448
|
".dark & .cm-cursor": {
|
|
361
|
-
borderLeftColor:
|
|
449
|
+
borderLeftColor: "white"
|
|
362
450
|
},
|
|
363
451
|
".cm-placeholder": {
|
|
364
|
-
fontFamily:
|
|
452
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
365
453
|
},
|
|
366
454
|
"& .cm-scroller": {
|
|
367
|
-
fontFamily:
|
|
455
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(","),
|
|
368
456
|
overflow: "visible"
|
|
369
457
|
},
|
|
370
458
|
"& .cm-activeLine": {
|
|
@@ -374,7 +462,7 @@ var markdownTheme = {
|
|
|
374
462
|
backgroundColor: "transparent"
|
|
375
463
|
},
|
|
376
464
|
"& .cm-ySelectionInfo": {
|
|
377
|
-
fontFamily:
|
|
465
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(","),
|
|
378
466
|
padding: "2px 4px",
|
|
379
467
|
marginBlockStart: "-4px"
|
|
380
468
|
},
|
|
@@ -397,8 +485,16 @@ var markdownTheme = {
|
|
|
397
485
|
"& .cm-yLineSelection": {
|
|
398
486
|
margin: "0"
|
|
399
487
|
},
|
|
400
|
-
|
|
401
|
-
|
|
488
|
+
".cm-link": {
|
|
489
|
+
color: "rgb(20 89 208)",
|
|
490
|
+
textDecorationLine: "underline",
|
|
491
|
+
textDecorationThickness: "1px",
|
|
492
|
+
textUnderlineOffset: "2px",
|
|
493
|
+
borderRadius: ".125rem"
|
|
494
|
+
},
|
|
495
|
+
// TODO(burdon): Document.
|
|
496
|
+
...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
497
|
+
const height = get2(tokens, [
|
|
402
498
|
"extend",
|
|
403
499
|
"fontSize",
|
|
404
500
|
fontSize,
|
|
@@ -417,7 +513,7 @@ var markdownTheme = {
|
|
|
417
513
|
return acc;
|
|
418
514
|
}, {})
|
|
419
515
|
};
|
|
420
|
-
var
|
|
516
|
+
var markdownHighlightStyle = HighlightStyle.define([
|
|
421
517
|
{
|
|
422
518
|
tag: [
|
|
423
519
|
tags.keyword,
|
|
@@ -533,17 +629,278 @@ var markdownDarkHighlighting = HighlightStyle.define([
|
|
|
533
629
|
], {
|
|
534
630
|
scope: markdownLanguage,
|
|
535
631
|
all: {
|
|
536
|
-
fontFamily:
|
|
632
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
537
633
|
}
|
|
538
634
|
});
|
|
539
635
|
|
|
540
|
-
// packages/ui/react-ui-editor/src/components/
|
|
636
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
637
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
638
|
+
return [
|
|
639
|
+
bracketMatching2(),
|
|
640
|
+
closeBrackets2(),
|
|
641
|
+
_placeholder && placeholder2(_placeholder),
|
|
642
|
+
EditorState.allowMultipleSelections.of(true),
|
|
643
|
+
EditorView3.lineWrapping,
|
|
644
|
+
// autocompletion(),
|
|
645
|
+
crosshairCursor(),
|
|
646
|
+
dropCursor(),
|
|
647
|
+
drawSelection(),
|
|
648
|
+
highlightActiveLine(),
|
|
649
|
+
highlightActiveLineGutter(),
|
|
650
|
+
highlightSelectionMatches(),
|
|
651
|
+
highlightSpecialChars(),
|
|
652
|
+
history(),
|
|
653
|
+
indentOnInput(),
|
|
654
|
+
rectangularSelection(),
|
|
655
|
+
keymap.of([
|
|
656
|
+
...closeBracketsKeymap,
|
|
657
|
+
// ...completionKeymap,
|
|
658
|
+
...defaultKeymap,
|
|
659
|
+
...foldKeymap,
|
|
660
|
+
...historyKeymap,
|
|
661
|
+
...lintKeymap,
|
|
662
|
+
...searchKeymap,
|
|
663
|
+
indentWithTab
|
|
664
|
+
]),
|
|
665
|
+
// Main extension.
|
|
666
|
+
// https://github.com/codemirror/lang-markdown
|
|
667
|
+
markdown({
|
|
668
|
+
base: markdownLanguage2,
|
|
669
|
+
codeLanguages: languages,
|
|
670
|
+
extensions: [
|
|
671
|
+
// TODO(burdon): This seems to upgrade the parser.
|
|
672
|
+
// GitHub flavored markdown bundle: Table, TaskList, Strikethrough, and Autolink.
|
|
673
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
674
|
+
// https://github.github.com/gfm
|
|
675
|
+
// GFM,
|
|
676
|
+
// Custom styling.
|
|
677
|
+
markdownTagsExtension
|
|
678
|
+
]
|
|
679
|
+
}),
|
|
680
|
+
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
681
|
+
syntaxHighlighting2(markdownHighlightStyle),
|
|
682
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
683
|
+
].filter(Boolean);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
687
|
+
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
688
|
+
import { EditorView as EditorView4 } from "@codemirror/view";
|
|
689
|
+
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
690
|
+
import { vim } from "@replit/codemirror-vim";
|
|
691
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
692
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
|
|
693
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
694
|
+
|
|
695
|
+
// packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
|
|
696
|
+
import { useEffect, useMemo } from "react";
|
|
697
|
+
import { yCollab } from "y-codemirror.next";
|
|
698
|
+
import { generateName } from "@dxos/display-name";
|
|
699
|
+
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
700
|
+
import { YText } from "@dxos/text-model";
|
|
701
|
+
var useCollaboration = (model, themeMode) => {
|
|
702
|
+
const { provider, peer, content } = model;
|
|
703
|
+
const extension = useMemo(() => content instanceof YText ? yCollab(content, provider?.awareness) : void 0, []);
|
|
704
|
+
useEffect(() => {
|
|
705
|
+
if (provider && peer) {
|
|
706
|
+
provider.awareness.setLocalStateField("user", {
|
|
707
|
+
name: peer.name ?? generateName(peer.id),
|
|
708
|
+
color: getColorForValue({
|
|
709
|
+
value: peer.id,
|
|
710
|
+
type: "color"
|
|
711
|
+
}),
|
|
712
|
+
colorLight: getColorForValue({
|
|
713
|
+
value: peer.id,
|
|
714
|
+
themeMode,
|
|
715
|
+
type: "highlight"
|
|
716
|
+
})
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
}, [
|
|
720
|
+
provider,
|
|
721
|
+
peer,
|
|
722
|
+
themeMode
|
|
723
|
+
]);
|
|
724
|
+
return extension;
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
728
|
+
import { useMemo as useMemo2 } from "react";
|
|
729
|
+
|
|
730
|
+
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
731
|
+
import * as random from "lib0/random";
|
|
732
|
+
var cursorColors = [
|
|
733
|
+
{
|
|
734
|
+
color: "#30bced",
|
|
735
|
+
light: "#30bced33"
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
color: "#6eeb83",
|
|
739
|
+
light: "#6eeb8333"
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
color: "#ffbc42",
|
|
743
|
+
light: "#ffbc4233"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
color: "#ecd444",
|
|
747
|
+
light: "#ecd44433"
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
color: "#ee6352",
|
|
751
|
+
light: "#ee635233"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
color: "#9ac2c9",
|
|
755
|
+
light: "#9ac2c933"
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
color: "#8acb88",
|
|
759
|
+
light: "#8acb8833"
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
color: "#1be7ff",
|
|
763
|
+
light: "#1be7ff33"
|
|
764
|
+
}
|
|
765
|
+
];
|
|
766
|
+
var cursorColor = cursorColors[random.uint32() % cursorColors.length];
|
|
767
|
+
|
|
768
|
+
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
769
|
+
import * as decoding from "lib0/decoding";
|
|
770
|
+
import * as encoding from "lib0/encoding";
|
|
771
|
+
import { Observable } from "lib0/observable";
|
|
772
|
+
import * as awarenessProtocol from "y-protocols/awareness";
|
|
773
|
+
import { log } from "@dxos/log";
|
|
774
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
775
|
+
var messageAwareness = 1;
|
|
776
|
+
var messageQueryAwareness = 3;
|
|
777
|
+
var SpaceAwarenessProvider = class extends Observable {
|
|
778
|
+
constructor({ space, doc, channel, awareness }) {
|
|
779
|
+
super();
|
|
780
|
+
this._space = space;
|
|
781
|
+
this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
|
|
782
|
+
this._channel = channel;
|
|
783
|
+
this._clientId = doc.clientID;
|
|
784
|
+
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
785
|
+
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
786
|
+
if (typeof window !== "undefined") {
|
|
787
|
+
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
788
|
+
} else if (typeof process !== "undefined") {
|
|
789
|
+
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
790
|
+
}
|
|
791
|
+
const encoderAwarenessQuery = encoding.createEncoder();
|
|
792
|
+
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
793
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
794
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
795
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
796
|
+
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
797
|
+
this._clientId
|
|
798
|
+
]));
|
|
799
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
800
|
+
}
|
|
801
|
+
get awareness() {
|
|
802
|
+
return this._awareness;
|
|
803
|
+
}
|
|
804
|
+
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
805
|
+
log("awareness update", {
|
|
806
|
+
added,
|
|
807
|
+
updated,
|
|
808
|
+
removed,
|
|
809
|
+
origin
|
|
810
|
+
}, {
|
|
811
|
+
F: __dxlog_file,
|
|
812
|
+
L: 67,
|
|
813
|
+
S: this,
|
|
814
|
+
C: (f, a) => f(...a)
|
|
815
|
+
});
|
|
816
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
817
|
+
const encoderAwareness = encoding.createEncoder();
|
|
818
|
+
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
819
|
+
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
820
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
821
|
+
}
|
|
822
|
+
_handleSpaceMessage({ payload }) {
|
|
823
|
+
log("space message", payload, {
|
|
824
|
+
F: __dxlog_file,
|
|
825
|
+
L: 79,
|
|
826
|
+
S: this,
|
|
827
|
+
C: (f, a) => f(...a)
|
|
828
|
+
});
|
|
829
|
+
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
830
|
+
const encoder = this._readMessage(data);
|
|
831
|
+
if (encoder) {
|
|
832
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
_readMessage(message) {
|
|
836
|
+
const decoder = decoding.createDecoder(message);
|
|
837
|
+
const encoder = encoding.createEncoder();
|
|
838
|
+
const messageType = decoding.readVarUint(decoder);
|
|
839
|
+
let sendReply = false;
|
|
840
|
+
switch (messageType) {
|
|
841
|
+
case messageAwareness: {
|
|
842
|
+
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
case messageQueryAwareness: {
|
|
846
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
847
|
+
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
848
|
+
sendReply = true;
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
default: {
|
|
852
|
+
console.error("Invalid message:", messageType);
|
|
853
|
+
return encoder;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (!sendReply) {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
return encoder;
|
|
860
|
+
}
|
|
861
|
+
_handleBeforeUnload() {
|
|
862
|
+
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
863
|
+
this._clientId
|
|
864
|
+
], "window unload");
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
869
|
+
var useTextModel = ({ identity, space, text }) => {
|
|
870
|
+
const provider = useMemo2(() => {
|
|
871
|
+
if (!space || !text?.doc) {
|
|
872
|
+
return void 0;
|
|
873
|
+
}
|
|
874
|
+
return new SpaceAwarenessProvider({
|
|
875
|
+
space,
|
|
876
|
+
doc: text.doc,
|
|
877
|
+
channel: `yjs.awareness.${text.id}`
|
|
878
|
+
});
|
|
879
|
+
}, [
|
|
880
|
+
identity,
|
|
881
|
+
space,
|
|
882
|
+
text?.doc
|
|
883
|
+
]);
|
|
884
|
+
if (!text?.doc || !text?.content) {
|
|
885
|
+
return void 0;
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
id: text.doc.guid,
|
|
889
|
+
content: text.content,
|
|
890
|
+
provider,
|
|
891
|
+
peer: identity ? {
|
|
892
|
+
id: identity.identityKey.toHex(),
|
|
893
|
+
name: identity.profile?.displayName
|
|
894
|
+
} : void 0
|
|
895
|
+
};
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
541
899
|
var EditorModes = [
|
|
542
900
|
"default",
|
|
543
901
|
"vim"
|
|
544
902
|
];
|
|
545
|
-
var
|
|
546
|
-
const { id, content, provider, peer } = model ?? {};
|
|
903
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots, editorMode }, forwardedRef) => {
|
|
547
904
|
const { themeMode } = useThemeContext();
|
|
548
905
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
549
906
|
tabBehavior: "limited"
|
|
@@ -555,110 +912,32 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
|
|
|
555
912
|
editor: parent,
|
|
556
913
|
state,
|
|
557
914
|
view
|
|
558
|
-
}));
|
|
559
|
-
const listenChangesExtension = useMemo2(() => StateField.define({
|
|
560
|
-
create: () => null,
|
|
561
|
-
update: (_value, transaction) => {
|
|
562
|
-
if (transaction.docChanged && onChange) {
|
|
563
|
-
onChange(transaction.newDoc);
|
|
564
|
-
}
|
|
565
|
-
return null;
|
|
566
|
-
}
|
|
567
915
|
}), [
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (provider && peer) {
|
|
572
|
-
provider.awareness.setLocalStateField("user", {
|
|
573
|
-
name: peer.name ?? generateName(peer.id),
|
|
574
|
-
color: getColorForValue({
|
|
575
|
-
value: peer.id,
|
|
576
|
-
type: "color"
|
|
577
|
-
}),
|
|
578
|
-
colorLight: getColorForValue({
|
|
579
|
-
value: peer.id,
|
|
580
|
-
themeMode,
|
|
581
|
-
type: "highlight"
|
|
582
|
-
})
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
}, [
|
|
586
|
-
provider,
|
|
587
|
-
peer,
|
|
588
|
-
themeMode
|
|
916
|
+
view,
|
|
917
|
+
state,
|
|
918
|
+
parent
|
|
589
919
|
]);
|
|
590
|
-
|
|
920
|
+
const collaboration = useCollaboration(model, themeMode);
|
|
921
|
+
useEffect2(() => {
|
|
591
922
|
if (!parent) {
|
|
592
923
|
return;
|
|
593
924
|
}
|
|
594
|
-
const state2 =
|
|
595
|
-
doc: content?.toString(),
|
|
925
|
+
const state2 = EditorState2.create({
|
|
926
|
+
doc: model.content?.toString(),
|
|
596
927
|
extensions: [
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
highlightActiveLineGutter(),
|
|
604
|
-
highlightSpecialChars(),
|
|
605
|
-
history(),
|
|
606
|
-
drawSelection(),
|
|
607
|
-
dropCursor(),
|
|
608
|
-
EditorState.allowMultipleSelections.of(true),
|
|
609
|
-
indentOnInput(),
|
|
610
|
-
syntaxHighlighting(defaultHighlightStyle, {
|
|
611
|
-
fallback: true
|
|
612
|
-
}),
|
|
613
|
-
bracketMatching(),
|
|
614
|
-
closeBrackets(),
|
|
615
|
-
autocompletion(),
|
|
616
|
-
rectangularSelection(),
|
|
617
|
-
crosshairCursor(),
|
|
618
|
-
highlightActiveLine(),
|
|
619
|
-
highlightSelectionMatches(),
|
|
620
|
-
placeholder(slots.editor?.placeholder ?? ""),
|
|
621
|
-
keymap.of([
|
|
622
|
-
...closeBracketsKeymap,
|
|
623
|
-
...defaultKeymap,
|
|
624
|
-
...searchKeymap,
|
|
625
|
-
...historyKeymap,
|
|
626
|
-
...foldKeymap,
|
|
627
|
-
...completionKeymap,
|
|
628
|
-
...lintKeymap,
|
|
629
|
-
indentWithTab
|
|
630
|
-
]),
|
|
631
|
-
EditorView.lineWrapping,
|
|
632
|
-
// Themes.
|
|
633
|
-
markdown({
|
|
634
|
-
base: markdownLanguage2,
|
|
635
|
-
codeLanguages: languages,
|
|
636
|
-
extensions: [
|
|
637
|
-
markdownTagsExtension
|
|
638
|
-
]
|
|
639
|
-
}),
|
|
640
|
-
EditorView.theme({
|
|
641
|
-
...markdownTheme,
|
|
642
|
-
...slots.editor?.markdownTheme
|
|
643
|
-
}),
|
|
644
|
-
...themeMode === "dark" ? [
|
|
645
|
-
syntaxHighlighting(oneDarkHighlightStyle)
|
|
646
|
-
] : [
|
|
647
|
-
syntaxHighlighting(defaultHighlightStyle)
|
|
648
|
-
],
|
|
649
|
-
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
650
|
-
syntaxHighlighting(markdownDarkHighlighting),
|
|
651
|
-
// Replication and awareness (incl. remote selection).
|
|
652
|
-
...content instanceof YText ? [
|
|
653
|
-
yCollab(content, provider?.awareness)
|
|
654
|
-
] : [],
|
|
928
|
+
// TODO(burdon): Factor out VIM mode?
|
|
929
|
+
editorMode === "vim" && vim(),
|
|
930
|
+
// Replication.
|
|
931
|
+
collaboration,
|
|
932
|
+
// Theme.
|
|
933
|
+
slots?.editor?.theme && EditorView4.theme(slots?.editor?.theme),
|
|
655
934
|
// Custom.
|
|
656
935
|
...extensions
|
|
657
|
-
]
|
|
936
|
+
].filter(Boolean)
|
|
658
937
|
});
|
|
659
938
|
setState(state2);
|
|
660
939
|
view?.destroy();
|
|
661
|
-
setView(new
|
|
940
|
+
setView(new EditorView4({
|
|
662
941
|
state: state2,
|
|
663
942
|
parent
|
|
664
943
|
}));
|
|
@@ -669,8 +948,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
|
|
|
669
948
|
};
|
|
670
949
|
}, [
|
|
671
950
|
parent,
|
|
672
|
-
content,
|
|
673
|
-
provider?.awareness,
|
|
951
|
+
model.content,
|
|
674
952
|
themeMode,
|
|
675
953
|
editorMode
|
|
676
954
|
]);
|
|
@@ -691,447 +969,89 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
|
|
|
691
969
|
editorMode
|
|
692
970
|
]);
|
|
693
971
|
return /* @__PURE__ */ React.createElement("div", {
|
|
694
|
-
|
|
972
|
+
key: model.id,
|
|
695
973
|
ref: setParent,
|
|
696
|
-
|
|
697
|
-
...slots
|
|
698
|
-
...editorMode !== "vim"
|
|
974
|
+
tabIndex: 0,
|
|
975
|
+
...slots?.root,
|
|
976
|
+
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
699
977
|
onKeyUp: handleKeyUp
|
|
700
978
|
});
|
|
701
979
|
});
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
import Placeholder from "@tiptap/extension-placeholder";
|
|
710
|
-
import { EditorContent, useEditor as useNaturalEditor } from "@tiptap/react";
|
|
711
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
712
|
-
import React2, { forwardRef as forwardRef2, useImperativeHandle as useImperativeHandle2, useMemo as useMemo3 } from "react";
|
|
713
|
-
import { generateName as generateName2 } from "@dxos/display-name";
|
|
714
|
-
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
715
|
-
var useEditor = ({ model, placeholder: placeholder3 = "Enter text\u2026", slots = {} }) => {
|
|
716
|
-
const extensions = useMemo3(() => [
|
|
717
|
-
StarterKit.configure({
|
|
718
|
-
// Extensions
|
|
719
|
-
history: false,
|
|
720
|
-
// Nodes
|
|
721
|
-
blockquote: {
|
|
722
|
-
HTMLAttributes: {
|
|
723
|
-
class: blockquote
|
|
724
|
-
}
|
|
725
|
-
},
|
|
726
|
-
bulletList: {
|
|
727
|
-
HTMLAttributes: {
|
|
728
|
-
class: unorderedList
|
|
729
|
-
}
|
|
730
|
-
},
|
|
731
|
-
codeBlock: {
|
|
732
|
-
HTMLAttributes: {
|
|
733
|
-
class: codeBlock
|
|
734
|
-
}
|
|
735
|
-
},
|
|
736
|
-
heading: false,
|
|
737
|
-
horizontalRule: {
|
|
738
|
-
HTMLAttributes: {
|
|
739
|
-
class: horizontalRule
|
|
740
|
-
}
|
|
741
|
-
},
|
|
742
|
-
listItem: false,
|
|
743
|
-
orderedList: {
|
|
744
|
-
HTMLAttributes: {
|
|
745
|
-
class: orderedList
|
|
746
|
-
}
|
|
747
|
-
},
|
|
748
|
-
paragraph: {
|
|
749
|
-
HTMLAttributes: {
|
|
750
|
-
class: paragraph
|
|
751
|
-
}
|
|
752
|
-
},
|
|
753
|
-
// Marks
|
|
754
|
-
bold: {
|
|
755
|
-
HTMLAttributes: {
|
|
756
|
-
class: bold
|
|
757
|
-
}
|
|
758
|
-
},
|
|
759
|
-
code: {
|
|
760
|
-
HTMLAttributes: {
|
|
761
|
-
class: codeWithoutMarks
|
|
762
|
-
}
|
|
763
|
-
},
|
|
764
|
-
italic: {
|
|
765
|
-
HTMLAttributes: {
|
|
766
|
-
class: italic
|
|
767
|
-
}
|
|
768
|
-
},
|
|
769
|
-
strike: {
|
|
770
|
-
HTMLAttributes: {
|
|
771
|
-
class: strikethrough
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
}),
|
|
775
|
-
Heading.extend({
|
|
776
|
-
renderHTML({ node, HTMLAttributes }) {
|
|
777
|
-
const hasLevel = this.options.levels.includes(node.attrs.level);
|
|
778
|
-
const level = hasLevel ? node.attrs.level : this.options.levels[0];
|
|
779
|
-
return [
|
|
780
|
-
`h${level}`,
|
|
781
|
-
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
782
|
-
class: heading[level]
|
|
783
|
-
}),
|
|
784
|
-
0
|
|
785
|
-
];
|
|
786
|
-
}
|
|
787
|
-
}),
|
|
788
|
-
ListItem.extend({
|
|
789
|
-
renderHTML: ({ HTMLAttributes }) => [
|
|
790
|
-
"li",
|
|
791
|
-
mergeAttributes(HTMLAttributes, {
|
|
792
|
-
marker: "\u2022 ",
|
|
793
|
-
class: listItem
|
|
794
|
-
}),
|
|
795
|
-
[
|
|
796
|
-
"div",
|
|
797
|
-
{
|
|
798
|
-
role: "none"
|
|
799
|
-
},
|
|
800
|
-
0
|
|
801
|
-
]
|
|
802
|
-
]
|
|
803
|
-
}),
|
|
804
|
-
// https://github.com/ueberdosis/tiptap/tree/main/packages/extension-collaboration
|
|
805
|
-
...model && typeof model.content !== "string" ? [
|
|
806
|
-
Collaboration.configure({
|
|
807
|
-
fragment: model.content
|
|
808
|
-
})
|
|
809
|
-
] : [],
|
|
810
|
-
...model?.provider ? [
|
|
811
|
-
CollaborationCursor.configure({
|
|
812
|
-
provider: model.provider,
|
|
813
|
-
user: model.peer && {
|
|
814
|
-
name: model.peer.name ?? generateName2(model.peer.id),
|
|
815
|
-
color: cursorColor.color
|
|
816
|
-
}
|
|
817
|
-
})
|
|
818
|
-
] : [],
|
|
819
|
-
Placeholder.configure({
|
|
820
|
-
placeholder: placeholder3,
|
|
821
|
-
emptyEditorClass: "before:content-[attr(data-placeholder)] before:absolute opacity-50 cursor-text"
|
|
980
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
|
|
981
|
+
const { themeMode } = useThemeContext();
|
|
982
|
+
const extensions = [
|
|
983
|
+
..._extensions ?? [],
|
|
984
|
+
basicBundle({
|
|
985
|
+
themeMode,
|
|
986
|
+
placeholder: slots?.editor?.placeholder
|
|
822
987
|
})
|
|
823
|
-
]
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
return useNaturalEditor({
|
|
988
|
+
];
|
|
989
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
990
|
+
ref: forwardedRef,
|
|
827
991
|
extensions,
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
spellcheck: slots.editor?.spellCheck === false ? "false" : "true",
|
|
832
|
-
tabindex: slots.editor?.tabIndex ? String(slots.editor?.tabIndex) : "0"
|
|
992
|
+
slots: defaultsDeep({}, slots, {
|
|
993
|
+
editor: {
|
|
994
|
+
theme: basicTheme
|
|
833
995
|
}
|
|
834
|
-
}
|
|
835
|
-
}, [
|
|
836
|
-
extensions
|
|
837
|
-
]);
|
|
838
|
-
};
|
|
839
|
-
var RichTextEditor = /* @__PURE__ */ forwardRef2((props, ref) => {
|
|
840
|
-
const editor = useEditor(props);
|
|
841
|
-
useImperativeHandle2(ref, () => editor, [
|
|
842
|
-
editor
|
|
843
|
-
]);
|
|
844
|
-
return /* @__PURE__ */ React2.createElement(EditorContent, {
|
|
845
|
-
...props.slots?.root,
|
|
846
|
-
editor
|
|
847
|
-
});
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
// packages/ui/react-ui-editor/src/components/Editor/Editor.tsx
|
|
851
|
-
var Editor = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef3(({ slots, ...params }, forwardedRef) => {
|
|
852
|
-
const model = useTextModel(params);
|
|
853
|
-
if (model?.content instanceof YXmlFragment) {
|
|
854
|
-
return /* @__PURE__ */ React3.createElement(RichTextEditor, {
|
|
855
|
-
ref: forwardedRef,
|
|
856
|
-
model,
|
|
857
|
-
slots
|
|
858
|
-
});
|
|
859
|
-
} else {
|
|
860
|
-
return /* @__PURE__ */ React3.createElement(MarkdownEditor, {
|
|
861
|
-
ref: forwardedRef,
|
|
862
|
-
model,
|
|
863
|
-
slots
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
}));
|
|
867
|
-
|
|
868
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
869
|
-
import { tags as tags2 } from "@lezer/highlight";
|
|
870
|
-
|
|
871
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
872
|
-
import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
|
|
873
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
874
|
-
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
875
|
-
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
876
|
-
import { EditorView as EditorView2, placeholder as placeholder2 } from "@codemirror/view";
|
|
877
|
-
import React4, { forwardRef as forwardRef4, useEffect as useEffect2, useImperativeHandle as useImperativeHandle3, useState as useState2, useCallback as useCallback2 } from "react";
|
|
878
|
-
import { yCollab as yCollab2 } from "y-codemirror.next";
|
|
879
|
-
import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
|
|
880
|
-
import { YText as YText2 } from "@dxos/text-model";
|
|
881
|
-
|
|
882
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/theme.ts
|
|
883
|
-
import get2 from "lodash.get";
|
|
884
|
-
import { tailwindConfig as tailwindConfig2 } from "@dxos/react-ui-theme";
|
|
885
|
-
var tokens2 = tailwindConfig2({}).theme;
|
|
886
|
-
var defaultStyles = {
|
|
887
|
-
"&.cm-focused": {
|
|
888
|
-
outline: "none"
|
|
889
|
-
},
|
|
890
|
-
".cm-placeholder": {
|
|
891
|
-
fontFamily: get2(tokens2, "fontFamily.body", []).join(",")
|
|
892
|
-
},
|
|
893
|
-
"& .cm-scroller": {
|
|
894
|
-
fontFamily: get2(tokens2, "fontFamily.body", []).join(","),
|
|
895
|
-
overflow: "visible"
|
|
896
|
-
},
|
|
897
|
-
".cm-tooltip": {
|
|
898
|
-
backgroundColor: "transparent",
|
|
899
|
-
border: "none"
|
|
900
|
-
}
|
|
901
|
-
};
|
|
902
|
-
|
|
903
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
904
|
-
var TextEditor = /* @__PURE__ */ forwardRef4(({ model, extensions = [], theme = defaultStyles, slots = {}, onKeyDown, ...props }, forwardedRef) => {
|
|
905
|
-
const { id, content } = model ?? {};
|
|
906
|
-
const { themeMode } = useThemeContext2();
|
|
907
|
-
const [parent, setParent] = useState2(null);
|
|
908
|
-
const [state, setState] = useState2();
|
|
909
|
-
const [view, setView] = useState2();
|
|
910
|
-
useImperativeHandle3(forwardedRef, () => {
|
|
911
|
-
return {
|
|
912
|
-
editor: parent,
|
|
913
|
-
state,
|
|
914
|
-
view
|
|
915
|
-
};
|
|
916
|
-
}, [
|
|
917
|
-
view
|
|
918
|
-
]);
|
|
919
|
-
useEffect2(() => {
|
|
920
|
-
if (!parent) {
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
view?.destroy();
|
|
924
|
-
const state2 = EditorState2.create({
|
|
925
|
-
doc: content?.toString(),
|
|
926
|
-
extensions: [
|
|
927
|
-
bracketMatching2(),
|
|
928
|
-
closeBrackets2(),
|
|
929
|
-
placeholder2(slots.editor?.placeholder ?? ""),
|
|
930
|
-
EditorView2.lineWrapping,
|
|
931
|
-
// Themes.
|
|
932
|
-
EditorView2.theme(theme),
|
|
933
|
-
...themeMode === "dark" ? [
|
|
934
|
-
syntaxHighlighting2(oneDarkHighlightStyle2)
|
|
935
|
-
] : [
|
|
936
|
-
syntaxHighlighting2(defaultHighlightStyle2)
|
|
937
|
-
],
|
|
938
|
-
// Replication.
|
|
939
|
-
...content instanceof YText2 ? [
|
|
940
|
-
yCollab2(content, void 0)
|
|
941
|
-
] : [],
|
|
942
|
-
// Custom.
|
|
943
|
-
...extensions
|
|
944
|
-
]
|
|
945
|
-
});
|
|
946
|
-
setState(state2);
|
|
947
|
-
setView(new EditorView2({
|
|
948
|
-
state: state2,
|
|
949
|
-
parent
|
|
950
|
-
}));
|
|
951
|
-
return () => {
|
|
952
|
-
view?.destroy();
|
|
953
|
-
setView(void 0);
|
|
954
|
-
setState(void 0);
|
|
955
|
-
};
|
|
956
|
-
}, [
|
|
957
|
-
parent,
|
|
958
|
-
content,
|
|
959
|
-
themeMode
|
|
960
|
-
]);
|
|
961
|
-
const handleKeyDown = useCallback2((event) => {
|
|
962
|
-
if (view) {
|
|
963
|
-
const { head, from, to } = view.state.selection.ranges[0];
|
|
964
|
-
const { number } = view.state.doc.lineAt(head);
|
|
965
|
-
const after = view.state.sliceDoc(from);
|
|
966
|
-
onKeyDown?.(event, {
|
|
967
|
-
from,
|
|
968
|
-
to,
|
|
969
|
-
line: number,
|
|
970
|
-
lines: view.state.doc.lines,
|
|
971
|
-
after
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
}, [
|
|
975
|
-
view
|
|
976
|
-
]);
|
|
977
|
-
return /* @__PURE__ */ React4.createElement("div", {
|
|
978
|
-
key: id,
|
|
979
|
-
ref: setParent,
|
|
980
|
-
...slots.root,
|
|
981
|
-
onKeyDown: handleKeyDown,
|
|
996
|
+
}),
|
|
982
997
|
...props
|
|
983
998
|
});
|
|
984
999
|
});
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
end: from + 1 + label.length
|
|
1000
|
-
};
|
|
1001
|
-
const p2 = {
|
|
1002
|
-
start: p1.end,
|
|
1003
|
-
end: p1.end + 1
|
|
1004
|
-
};
|
|
1005
|
-
const p3 = {
|
|
1006
|
-
start: p1.end + 1,
|
|
1007
|
-
end: p1.end + 1 + url.length + 2
|
|
1008
|
-
};
|
|
1009
|
-
add(p0.start, p0.end, Decoration.mark({
|
|
1010
|
-
class: "cm-hyperlink-bracket"
|
|
1011
|
-
}));
|
|
1012
|
-
add(p1.start, p1.end, Decoration.mark({
|
|
1013
|
-
class: "cm-hyperlink-label"
|
|
1014
|
-
}));
|
|
1015
|
-
add(p2.start, p2.end, Decoration.mark({
|
|
1016
|
-
class: "cm-hyperlink-bracket"
|
|
1017
|
-
}));
|
|
1018
|
-
add(p3.start, p3.end, Decoration.mark({
|
|
1019
|
-
class: "cm-hyperlink-url",
|
|
1020
|
-
__attributes: {
|
|
1021
|
-
style: "display: none"
|
|
1022
|
-
}
|
|
1023
|
-
}));
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
function hyperLinkExtension() {
|
|
1027
|
-
return ViewPlugin.fromClass(class HyperLinkView {
|
|
1028
|
-
constructor(view) {
|
|
1029
|
-
this.decorator = linkDecorator();
|
|
1030
|
-
this.decorations = this.decorator.createDeco(view);
|
|
1031
|
-
}
|
|
1032
|
-
update(update) {
|
|
1033
|
-
if (update.docChanged || update.viewportChanged) {
|
|
1034
|
-
this.decorations = this.decorator.updateDeco(update, this.decorations);
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
}, {
|
|
1038
|
-
decorations: (view) => view.decorations,
|
|
1039
|
-
eventHandlers: {
|
|
1040
|
-
// TODO(burdon): CLick to expand link.
|
|
1041
|
-
// https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
|
|
1042
|
-
mousedown: function(event, view) {
|
|
1043
|
-
const pos = view.posAtDOM(event.target);
|
|
1044
|
-
if (pos !== 0) {
|
|
1045
|
-
console.log(this);
|
|
1046
|
-
}
|
|
1047
|
-
},
|
|
1048
|
-
// TODO(burdon): Hide when cursor moves away.
|
|
1049
|
-
keydown: (event, view) => {
|
|
1050
|
-
view.update([]);
|
|
1000
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
|
|
1001
|
+
const { themeMode } = useThemeContext();
|
|
1002
|
+
const extensions = [
|
|
1003
|
+
..._extensions ?? [],
|
|
1004
|
+
markdownBundle({
|
|
1005
|
+
themeMode
|
|
1006
|
+
})
|
|
1007
|
+
];
|
|
1008
|
+
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1009
|
+
ref: forwardedRef,
|
|
1010
|
+
extensions,
|
|
1011
|
+
slots: defaultsDeep({}, slots, {
|
|
1012
|
+
editor: {
|
|
1013
|
+
theme: markdownTheme
|
|
1051
1014
|
}
|
|
1052
|
-
}
|
|
1015
|
+
}),
|
|
1016
|
+
...props
|
|
1053
1017
|
});
|
|
1054
|
-
}
|
|
1055
|
-
var hyperLinkStyle = EditorView3.baseTheme({
|
|
1056
|
-
".cm-hyperlink-label": {
|
|
1057
|
-
cursor: "pointer",
|
|
1058
|
-
textDecoration: "underline"
|
|
1059
|
-
},
|
|
1060
|
-
".cm-hyperlink-bracket": {
|
|
1061
|
-
opacity: 0.2
|
|
1062
|
-
},
|
|
1063
|
-
".cm-hyperlink-url": {
|
|
1064
|
-
opacity: 0.5,
|
|
1065
|
-
fontFamily: "monospace"
|
|
1066
|
-
}
|
|
1067
|
-
});
|
|
1068
|
-
var hyperlink = [
|
|
1069
|
-
hyperLinkExtension(),
|
|
1070
|
-
hyperLinkStyle
|
|
1071
|
-
];
|
|
1072
|
-
|
|
1073
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlinkTooltip.tsx
|
|
1074
|
-
import { hoverTooltip } from "@codemirror/view";
|
|
1075
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1076
|
-
var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1077
|
-
var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp2) => hoverTooltip((view, pos) => {
|
|
1078
|
-
const { from, text } = view.state.doc.lineAt(pos);
|
|
1079
|
-
const p = pos - from;
|
|
1080
|
-
let idx = 0;
|
|
1081
|
-
let match;
|
|
1082
|
-
do {
|
|
1083
|
-
match = text.substring(idx).match(regexp);
|
|
1084
|
-
if (!match) {
|
|
1085
|
-
match = void 0;
|
|
1086
|
-
break;
|
|
1087
|
-
}
|
|
1088
|
-
idx = text.indexOf(match[0]);
|
|
1089
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1090
|
-
break;
|
|
1091
|
-
}
|
|
1092
|
-
idx += match[0].length;
|
|
1093
|
-
} while (true);
|
|
1094
|
-
if (!match) {
|
|
1095
|
-
return null;
|
|
1096
|
-
}
|
|
1097
|
-
const [, , url] = match ?? [];
|
|
1098
|
-
return {
|
|
1099
|
-
pos: idx + from,
|
|
1100
|
-
end: idx + from + match[0].length,
|
|
1101
|
-
above: true,
|
|
1102
|
-
create: () => {
|
|
1103
|
-
const el = document.createElement("a");
|
|
1104
|
-
el.innerText = "_";
|
|
1105
|
-
el.className = tooltipContent({}, "mb-2 p-1");
|
|
1106
|
-
el.setAttribute("target", "_blank");
|
|
1107
|
-
el.setAttribute("href", url);
|
|
1108
|
-
onHover(el, url);
|
|
1109
|
-
return {
|
|
1110
|
-
dom: el
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
1114
1018
|
});
|
|
1115
|
-
|
|
1116
|
-
// packages/ui/react-ui-editor/src/index.ts
|
|
1117
|
-
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
1118
|
-
import { Doc, YText as YText3, YXmlFragment as YXmlFragment2 } from "@dxos/text-model";
|
|
1119
1019
|
export {
|
|
1020
|
+
BaseTextEditor,
|
|
1120
1021
|
Doc,
|
|
1121
|
-
Editor,
|
|
1122
1022
|
EditorModes,
|
|
1123
1023
|
MarkdownEditor,
|
|
1124
|
-
|
|
1024
|
+
SpaceAwarenessProvider,
|
|
1125
1025
|
TextEditor,
|
|
1126
1026
|
TextKind,
|
|
1127
|
-
|
|
1128
|
-
|
|
1027
|
+
YText2 as YText,
|
|
1028
|
+
YXmlFragment,
|
|
1029
|
+
basicBundle,
|
|
1030
|
+
basicTheme,
|
|
1031
|
+
chalky,
|
|
1032
|
+
coral,
|
|
1129
1033
|
createHyperlinkTooltip,
|
|
1130
|
-
|
|
1034
|
+
cursorColor,
|
|
1035
|
+
cyan,
|
|
1036
|
+
highlightBackground,
|
|
1131
1037
|
hyperLinkExtension,
|
|
1132
|
-
|
|
1133
|
-
|
|
1038
|
+
hyperlinkDecoration,
|
|
1039
|
+
hyperlinkStyle,
|
|
1040
|
+
hyperlinkWidget,
|
|
1041
|
+
invalid,
|
|
1042
|
+
ivory,
|
|
1043
|
+
malibu,
|
|
1044
|
+
markdownBundle,
|
|
1045
|
+
markdownHighlightStyle,
|
|
1046
|
+
markdownTheme,
|
|
1047
|
+
onChangeExtension,
|
|
1048
|
+
sage,
|
|
1049
|
+
stone,
|
|
1134
1050
|
tags2 as tags,
|
|
1135
|
-
|
|
1051
|
+
tooltipBackground,
|
|
1052
|
+
useCollaboration,
|
|
1053
|
+
useTextModel,
|
|
1054
|
+
violet,
|
|
1055
|
+
whiskey
|
|
1136
1056
|
};
|
|
1137
1057
|
//# sourceMappingURL=index.mjs.map
|