@dxos/react-ui-editor 0.3.11-main.a6c4a82 → 0.3.11-main.a757f8c
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 +1914 -1514
- 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 +14 -14
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -3
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +0 -2
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +9 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +5 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +24 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts +14 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/basic.d.ts +8 -0
- package/dist/types/src/extensions/basic.d.ts.map +1 -0
- package/dist/types/src/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/comments.d.ts +33 -18
- package/dist/types/src/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/extensions/cursor.d.ts +25 -0
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +13 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/extensions/listener.d.ts +10 -0
- package/dist/types/src/extensions/listener.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts +14 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +10 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/link.d.ts +1 -0
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/typewriter.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +31 -0
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +3 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -31
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/{components/TextEditor/themes → themes}/default.d.ts +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -0
- package/dist/types/src/themes/index.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +33 -34
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +91 -94
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -34
- package/src/components/TextEditor/TextEditor.tsx +124 -95
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/components/TextEditor/index.ts +0 -3
- package/src/{components/TextEditor/extensions → extensions}/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.ts +88 -0
- package/src/extensions/automerge/cursor.ts +52 -0
- package/src/extensions/automerge/defs.ts +41 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +34 -29
- package/src/{hooks → extensions}/automerge/update-automerge.ts +5 -6
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +13 -5
- package/src/extensions/awareness.ts +310 -0
- package/src/extensions/basic.ts +37 -0
- package/src/extensions/comments.ts +428 -0
- package/src/extensions/cursor.ts +50 -0
- package/src/{components/TextEditor/extensions → extensions}/index.ts +4 -8
- package/src/extensions/listener.ts +35 -0
- package/src/{components/TextEditor/extensions → extensions}/markdown/bundle.ts +20 -30
- package/src/extensions/markdown/code.ts +127 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/{components/TextEditor/extensions → extensions}/markdown/highlight.ts +12 -27
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/image.ts +87 -0
- package/src/extensions/markdown/index.ts +13 -0
- package/src/{components/TextEditor/extensions → extensions/markdown}/link.ts +115 -62
- package/src/{components/TextEditor/extensions → extensions/markdown}/table.ts +10 -4
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/{components/TextEditor/extensions → extensions}/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/{components/TextEditor/extensions → extensions}/typewriter.ts +1 -1
- package/src/hooks/awareness-provider.ts +124 -0
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +4 -1
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +30 -115
- package/src/index.ts +5 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/markdown.ts +9 -12
- package/src/styles/tokens.ts +3 -0
- package/src/{components/TextEditor/themes → themes}/default.ts +50 -79
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts +0 -9
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +0 -17
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts +0 -9
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +0 -17
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +0 -3
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +0 -12
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/typewriter.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/util.d.ts +0 -5
- package/dist/types/src/components/TextEditor/extensions/util.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/handle.d.ts +0 -9
- package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/index.d.ts +0 -3
- package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts +0 -26
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/semaphore.d.ts +0 -19
- package/dist/types/src/hooks/automerge/semaphore.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-automerge.d.ts +0 -6
- package/dist/types/src/hooks/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/index.d.ts +0 -3
- package/dist/types/src/hooks/yjs/index.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/space-provider.d.ts +0 -27
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts +0 -12
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/hooks/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -114
- package/src/components/TextEditor/extensions/basic.ts +0 -32
- package/src/components/TextEditor/extensions/code.ts +0 -99
- package/src/components/TextEditor/extensions/comments.ts +0 -388
- package/src/components/TextEditor/extensions/hr.ts +0 -74
- package/src/components/TextEditor/extensions/image.ts +0 -69
- package/src/components/TextEditor/extensions/listener.ts +0 -23
- package/src/components/TextEditor/extensions/markdown/index.ts +0 -6
- package/src/components/TextEditor/extensions/mermaid.ts +0 -11
- package/src/components/TextEditor/extensions/tasklist.ts +0 -121
- package/src/components/TextEditor/extensions/tooltip.ts +0 -61
- package/src/components/TextEditor/extensions/util.ts +0 -18
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -134
- package/src/hooks/yjs/index.ts +0 -6
- package/src/hooks/yjs/space-provider.ts +0 -126
- package/src/hooks/yjs/yjs.stories.tsx +0 -56
- package/src/hooks/yjs/yjs.test.ts +0 -59
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -189
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/autocomplete.d.ts +0 -0
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/blast.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/code.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/highlight.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/hr.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/image.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/table.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions/markdown}/tasklist.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/mention.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/typewriter.d.ts +0 -0
- /package/dist/types/src/{hooks/yjs → styles}/cursors.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/themes → themes}/index.d.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/blast.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{components/TextEditor/themes → themes}/index.ts +0 -0
|
@@ -5,61 +5,643 @@ import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
|
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/
|
|
8
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
|
+
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
|
+
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
|
+
import { vim } from "@replit/codemirror-vim";
|
|
13
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
+
import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
|
|
19
|
+
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
9
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
10
22
|
import { keymap } from "@codemirror/view";
|
|
11
23
|
var autocomplete = ({ onSearch }) => {
|
|
12
24
|
return [
|
|
13
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
14
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
15
28
|
keymap.of(completionKeymap),
|
|
16
29
|
// https://codemirror.net/examples/autocompletion
|
|
17
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
18
31
|
autocompletion({
|
|
19
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
20
34
|
// defaultKeymap: false,
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
from: match.from,
|
|
33
|
-
options: onSearch(match.text.toLowerCase())
|
|
34
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
35
45
|
}
|
|
36
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
37
51
|
})
|
|
38
52
|
];
|
|
39
53
|
};
|
|
40
54
|
|
|
41
|
-
// packages/ui/react-ui-editor/src/
|
|
55
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
58
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
59
|
+
import { invariant } from "@dxos/invariant";
|
|
60
|
+
|
|
61
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
62
|
+
import get from "lodash.get";
|
|
63
|
+
import { next as automerge } from "@dxos/automerge/automerge";
|
|
64
|
+
var cursorConverter = (handle, path) => ({
|
|
65
|
+
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
66
|
+
toCursor: (pos) => {
|
|
67
|
+
const doc = handle.docSync();
|
|
68
|
+
if (!doc) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
const value = get(doc, path);
|
|
72
|
+
if (typeof value === "string" && value.length <= pos) {
|
|
73
|
+
return "end";
|
|
74
|
+
}
|
|
75
|
+
return automerge.getCursor(doc, path.slice(), pos);
|
|
76
|
+
},
|
|
77
|
+
fromCursor: (cursor) => {
|
|
78
|
+
if (cursor === "") {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
const doc = handle.docSync();
|
|
82
|
+
if (!doc) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (cursor === "end") {
|
|
86
|
+
const value = get(doc, path);
|
|
87
|
+
if (typeof value === "string") {
|
|
88
|
+
return value.length;
|
|
89
|
+
} else {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return automerge.getCursorPosition(doc, path.slice(), cursor);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
98
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
99
|
+
var effectType = StateEffect.define({});
|
|
100
|
+
var reconcileAnnotationType = Annotation.define();
|
|
101
|
+
var getPath = (state, field) => state.field(field).path;
|
|
102
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
103
|
+
var updateHeads = (newHeads) => effectType.of({
|
|
104
|
+
newHeads
|
|
105
|
+
});
|
|
106
|
+
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
107
|
+
|
|
108
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
+
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
110
|
+
|
|
111
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
+
import { next as am } from "@dxos/automerge/automerge";
|
|
113
|
+
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
|
+
const { lastHeads, path } = state.field(field);
|
|
115
|
+
let hasChanges = false;
|
|
116
|
+
for (const tr of transactions) {
|
|
117
|
+
tr.changes.iterChanges(() => {
|
|
118
|
+
hasChanges = true;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (!hasChanges) {
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
125
|
+
for (const tr of transactions) {
|
|
126
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
127
|
+
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return newHeads ?? void 0;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-codemirror.ts
|
|
135
|
+
import { ChangeSet } from "@codemirror/state";
|
|
136
|
+
var updateCodeMirror = (view, selection, target, patches) => {
|
|
137
|
+
for (const patch of patches) {
|
|
138
|
+
const changeSpec = handlePatch(patch, target, view.state);
|
|
139
|
+
if (changeSpec != null) {
|
|
140
|
+
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
141
|
+
selection = selection.map(changeSet, 1);
|
|
142
|
+
view.dispatch({
|
|
143
|
+
changes: changeSet,
|
|
144
|
+
annotations: reconcileAnnotationType.of({})
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
view.dispatch({
|
|
149
|
+
selection,
|
|
150
|
+
annotations: reconcileAnnotationType.of({})
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
var handlePatch = (patch, target, state) => {
|
|
154
|
+
if (patch.action === "insert") {
|
|
155
|
+
return handleInsert(target, patch);
|
|
156
|
+
} else if (patch.action === "splice") {
|
|
157
|
+
return handleSplice(target, patch);
|
|
158
|
+
} else if (patch.action === "del") {
|
|
159
|
+
return handleDel(target, patch);
|
|
160
|
+
} else if (patch.action === "put") {
|
|
161
|
+
return handlePut(target, patch, state);
|
|
162
|
+
} else {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var handleInsert = (target, patch) => {
|
|
167
|
+
const index = charPath(target, patch.path);
|
|
168
|
+
if (index == null) {
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
from: index,
|
|
175
|
+
to: index,
|
|
176
|
+
insert: text
|
|
177
|
+
}
|
|
178
|
+
];
|
|
179
|
+
};
|
|
180
|
+
var handleSplice = (target, patch) => {
|
|
181
|
+
const index = charPath(target, patch.path);
|
|
182
|
+
if (index == null) {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
from: index,
|
|
188
|
+
insert: patch.value
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
};
|
|
192
|
+
var handleDel = (target, patch) => {
|
|
193
|
+
const index = charPath(target, patch.path);
|
|
194
|
+
if (index == null) {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
const length = patch.length || 1;
|
|
198
|
+
return [
|
|
199
|
+
{
|
|
200
|
+
from: index,
|
|
201
|
+
to: index + length
|
|
202
|
+
}
|
|
203
|
+
];
|
|
204
|
+
};
|
|
205
|
+
var handlePut = (target, patch, state) => {
|
|
206
|
+
const index = charPath(target, [
|
|
207
|
+
...patch.path,
|
|
208
|
+
0
|
|
209
|
+
]);
|
|
210
|
+
if (index == null) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
const length = state.doc.length;
|
|
214
|
+
if (typeof patch.value !== "string") {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
return [
|
|
218
|
+
{
|
|
219
|
+
from: 0,
|
|
220
|
+
to: length,
|
|
221
|
+
insert: patch.value
|
|
222
|
+
}
|
|
223
|
+
];
|
|
224
|
+
};
|
|
225
|
+
var charPath = (textPath, candidatePath) => {
|
|
226
|
+
if (candidatePath.length !== textPath.length + 1) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
230
|
+
if (textPath[i] !== candidatePath[i]) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
235
|
+
if (typeof index === "number") {
|
|
236
|
+
return index;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
|
+
var PatchSemaphore = class {
|
|
243
|
+
// prettier-ignore
|
|
244
|
+
constructor(_handle, _state) {
|
|
245
|
+
this._handle = _handle;
|
|
246
|
+
this._state = _state;
|
|
247
|
+
this._inReconcile = false;
|
|
248
|
+
}
|
|
249
|
+
// NOTE: Cannot destruct view.state.
|
|
250
|
+
reconcile(view) {
|
|
251
|
+
if (this._inReconcile) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this._inReconcile = true;
|
|
255
|
+
const path = getPath(view.state, this._state);
|
|
256
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
257
|
+
let selection = view.state.selection;
|
|
258
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
259
|
+
const toInvert = transactions.slice().reverse();
|
|
260
|
+
for (const tx of toInvert) {
|
|
261
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
262
|
+
selection = selection.map(inverted);
|
|
263
|
+
view.dispatch({
|
|
264
|
+
changes: inverted,
|
|
265
|
+
annotations: reconcileAnnotationType.of(true)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
269
|
+
if (newHeads === null || newHeads === void 0) {
|
|
270
|
+
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
271
|
+
}
|
|
272
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
273
|
+
updateCodeMirror(view, selection, path, diff);
|
|
274
|
+
view.dispatch({
|
|
275
|
+
effects: updateHeads(newHeads),
|
|
276
|
+
annotations: reconcileAnnotationType.of({})
|
|
277
|
+
});
|
|
278
|
+
this._inReconcile = false;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
283
|
+
import { Facet } from "@codemirror/state";
|
|
284
|
+
var defaultCursorConverter = {
|
|
285
|
+
toCursor: (position) => position.toString(),
|
|
286
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
287
|
+
};
|
|
288
|
+
var Cursor = class _Cursor {
|
|
289
|
+
static {
|
|
290
|
+
this.converter = Facet.define({
|
|
291
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
static {
|
|
295
|
+
this.getCursorFromRange = (state, range) => {
|
|
296
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
297
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
298
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
299
|
+
return [
|
|
300
|
+
from,
|
|
301
|
+
to
|
|
302
|
+
].join(":");
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
static {
|
|
306
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
|
+
const parts = cursor.split(":");
|
|
309
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
310
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
311
|
+
return from !== void 0 && to !== void 0 ? {
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
} : void 0;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
320
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
|
|
321
|
+
var automerge3 = ({ handle, path }) => {
|
|
322
|
+
const state = StateField.define({
|
|
323
|
+
create: () => ({
|
|
324
|
+
path: path.slice(),
|
|
325
|
+
lastHeads: A.getHeads(handle.docSync()),
|
|
326
|
+
unreconciledTransactions: []
|
|
327
|
+
}),
|
|
328
|
+
update: (value, tr) => {
|
|
329
|
+
const result = {
|
|
330
|
+
path: path.slice(),
|
|
331
|
+
lastHeads: value.lastHeads,
|
|
332
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
333
|
+
};
|
|
334
|
+
let clearUnreconciled = false;
|
|
335
|
+
for (const effect of tr.effects) {
|
|
336
|
+
if (effect.is(effectType)) {
|
|
337
|
+
result.lastHeads = effect.value.newHeads;
|
|
338
|
+
clearUnreconciled = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (clearUnreconciled) {
|
|
342
|
+
result.unreconciledTransactions = [];
|
|
343
|
+
} else {
|
|
344
|
+
if (!isReconcileTx(tr)) {
|
|
345
|
+
result.unreconciledTransactions.push(tr);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
const semaphore = new PatchSemaphore(handle, state);
|
|
352
|
+
return [
|
|
353
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
354
|
+
// Reconcile external updates.
|
|
355
|
+
ViewPlugin.fromClass(class {
|
|
356
|
+
constructor(_view) {
|
|
357
|
+
this._view = _view;
|
|
358
|
+
invariant(this._view, void 0, {
|
|
359
|
+
F: __dxlog_file,
|
|
360
|
+
L: 66,
|
|
361
|
+
S: this,
|
|
362
|
+
A: [
|
|
363
|
+
"this._view",
|
|
364
|
+
""
|
|
365
|
+
]
|
|
366
|
+
});
|
|
367
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
368
|
+
}
|
|
369
|
+
destroy() {
|
|
370
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
_handleChange() {
|
|
373
|
+
semaphore.reconcile(this._view);
|
|
374
|
+
}
|
|
375
|
+
}),
|
|
376
|
+
// Reconcile local updates.
|
|
377
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
378
|
+
if (!changes.empty) {
|
|
379
|
+
semaphore.reconcile(view);
|
|
380
|
+
}
|
|
381
|
+
}),
|
|
382
|
+
state
|
|
383
|
+
];
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
387
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
388
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
389
|
+
import { Event } from "@dxos/async";
|
|
390
|
+
import { Context } from "@dxos/context";
|
|
391
|
+
var dummyProvider = {
|
|
392
|
+
remoteStateChange: new Event(),
|
|
393
|
+
open: () => {
|
|
394
|
+
},
|
|
395
|
+
close: () => {
|
|
396
|
+
},
|
|
397
|
+
getRemoteStates: () => [],
|
|
398
|
+
update: () => {
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var AwarenessProvider = Facet2.define({
|
|
402
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
403
|
+
});
|
|
404
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
405
|
+
var awareness = (provider = dummyProvider) => {
|
|
406
|
+
return [
|
|
407
|
+
AwarenessProvider.of(provider),
|
|
408
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
409
|
+
decorations: (value) => value.decorations
|
|
410
|
+
}),
|
|
411
|
+
styles
|
|
412
|
+
];
|
|
413
|
+
};
|
|
414
|
+
var RemoteSelectionsDecorator = class {
|
|
415
|
+
constructor(view) {
|
|
416
|
+
this.decorations = RangeSet.of([]);
|
|
417
|
+
this._ctx = new Context();
|
|
418
|
+
this._lastAnchor = void 0;
|
|
419
|
+
this._lastHead = void 0;
|
|
420
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
421
|
+
this._provider = view.state.facet(AwarenessProvider);
|
|
422
|
+
this._provider.open();
|
|
423
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
424
|
+
view.dispatch({
|
|
425
|
+
annotations: [
|
|
426
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
427
|
+
]
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
destroy() {
|
|
432
|
+
void this._ctx.dispose();
|
|
433
|
+
this._provider.close();
|
|
434
|
+
}
|
|
435
|
+
update(update2) {
|
|
436
|
+
this._updateLocalSelection(update2);
|
|
437
|
+
this._updateRemoteSelections(update2);
|
|
438
|
+
}
|
|
439
|
+
_updateLocalSelection(update2) {
|
|
440
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
441
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
442
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this._lastAnchor = anchor;
|
|
446
|
+
this._lastHead = head;
|
|
447
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
448
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
449
|
+
head: this._cursorConverter.toCursor(head)
|
|
450
|
+
} : void 0);
|
|
451
|
+
}
|
|
452
|
+
_updateRemoteSelections(update2) {
|
|
453
|
+
const decorations = [];
|
|
454
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
455
|
+
for (const state of awarenessStates) {
|
|
456
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
457
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
458
|
+
if (anchor == null || head == null) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
462
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
463
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
464
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
465
|
+
const color = state.info.color ?? "#30bced";
|
|
466
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
467
|
+
if (startLine.number === endLine.number) {
|
|
468
|
+
decorations.push({
|
|
469
|
+
from: start,
|
|
470
|
+
to: end,
|
|
471
|
+
value: Decoration.mark({
|
|
472
|
+
attributes: {
|
|
473
|
+
style: `background-color: ${lightColor}`
|
|
474
|
+
},
|
|
475
|
+
class: "cm-collab-selection"
|
|
476
|
+
})
|
|
477
|
+
});
|
|
478
|
+
} else {
|
|
479
|
+
decorations.push({
|
|
480
|
+
from: start,
|
|
481
|
+
to: startLine.from + startLine.length,
|
|
482
|
+
value: Decoration.mark({
|
|
483
|
+
attributes: {
|
|
484
|
+
style: `background-color: ${color}`
|
|
485
|
+
},
|
|
486
|
+
class: "cm-collab-selection"
|
|
487
|
+
})
|
|
488
|
+
});
|
|
489
|
+
decorations.push({
|
|
490
|
+
from: endLine.from,
|
|
491
|
+
to: end,
|
|
492
|
+
value: Decoration.mark({
|
|
493
|
+
attributes: {
|
|
494
|
+
style: `background-color: ${color}`
|
|
495
|
+
},
|
|
496
|
+
class: "cm-collab-selection"
|
|
497
|
+
})
|
|
498
|
+
});
|
|
499
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
500
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
501
|
+
decorations.push({
|
|
502
|
+
from: linePos,
|
|
503
|
+
to: linePos,
|
|
504
|
+
value: Decoration.line({
|
|
505
|
+
attributes: {
|
|
506
|
+
style: `background-color: ${color}`,
|
|
507
|
+
class: "cm-collab-selectionLine"
|
|
508
|
+
}
|
|
509
|
+
})
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
decorations.push({
|
|
514
|
+
from: head,
|
|
515
|
+
to: head,
|
|
516
|
+
value: Decoration.widget({
|
|
517
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
518
|
+
block: false,
|
|
519
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
520
|
+
})
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
this.decorations = Decoration.set(decorations, true);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
527
|
+
constructor(_name, _color) {
|
|
528
|
+
super();
|
|
529
|
+
this._name = _name;
|
|
530
|
+
this._color = _color;
|
|
531
|
+
}
|
|
532
|
+
toDOM() {
|
|
533
|
+
const span = document.createElement("span");
|
|
534
|
+
span.className = "cm-collab-selectionCaret";
|
|
535
|
+
span.style.backgroundColor = this._color;
|
|
536
|
+
span.style.borderColor = this._color;
|
|
537
|
+
const dot = document.createElement("div");
|
|
538
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
539
|
+
const info = document.createElement("div");
|
|
540
|
+
info.className = "cm-collab-selectionInfo";
|
|
541
|
+
info.innerText = this._name;
|
|
542
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
543
|
+
span.appendChild(dot);
|
|
544
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
545
|
+
span.appendChild(info);
|
|
546
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
547
|
+
return span;
|
|
548
|
+
}
|
|
549
|
+
updateDOM() {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
eq(widget) {
|
|
553
|
+
return widget._color === this._color;
|
|
554
|
+
}
|
|
555
|
+
get estimatedHeight() {
|
|
556
|
+
return -1;
|
|
557
|
+
}
|
|
558
|
+
ignoreEvent() {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
var styles = EditorView2.baseTheme({
|
|
563
|
+
".cm-collab-selection": {},
|
|
564
|
+
".cm-collab-selectionLine": {
|
|
565
|
+
padding: 0,
|
|
566
|
+
margin: "0px 2px 0px 4px"
|
|
567
|
+
},
|
|
568
|
+
".cm-collab-selectionCaret": {
|
|
569
|
+
position: "relative",
|
|
570
|
+
borderLeft: "1px solid black",
|
|
571
|
+
borderRight: "1px solid black",
|
|
572
|
+
marginLeft: "-1px",
|
|
573
|
+
marginRight: "-1px",
|
|
574
|
+
boxSizing: "border-box",
|
|
575
|
+
display: "inline",
|
|
576
|
+
cursor: "pointer"
|
|
577
|
+
},
|
|
578
|
+
".cm-collab-selectionCaretDot": {
|
|
579
|
+
borderRadius: "50%",
|
|
580
|
+
position: "absolute",
|
|
581
|
+
width: ".5em",
|
|
582
|
+
height: ".5em",
|
|
583
|
+
top: "-.25em",
|
|
584
|
+
left: "-.25em",
|
|
585
|
+
backgroundColor: "inherit",
|
|
586
|
+
transition: "transform .3s ease-in-out",
|
|
587
|
+
boxSizing: "border-box"
|
|
588
|
+
},
|
|
589
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
590
|
+
transform: "scale(0)",
|
|
591
|
+
transformOrigin: "center"
|
|
592
|
+
},
|
|
593
|
+
".cm-collab-selectionInfo": {
|
|
594
|
+
position: "absolute",
|
|
595
|
+
transform: "translate(-50%, 0)",
|
|
596
|
+
top: "-20px",
|
|
597
|
+
left: 0,
|
|
598
|
+
fontSize: ".75em",
|
|
599
|
+
fontFamily: "sans-serif",
|
|
600
|
+
fontStyle: "normal",
|
|
601
|
+
fontWeight: "normal",
|
|
602
|
+
lineHeight: "normal",
|
|
603
|
+
userSelect: "none",
|
|
604
|
+
color: "white",
|
|
605
|
+
padding: "2px",
|
|
606
|
+
zIndex: 101,
|
|
607
|
+
transition: "opacity .3s ease-in-out",
|
|
608
|
+
backgroundColor: "inherit",
|
|
609
|
+
borderRadius: "2px",
|
|
610
|
+
// These should be separate.
|
|
611
|
+
opacity: 0,
|
|
612
|
+
transitionDelay: "0s",
|
|
613
|
+
whiteSpace: "nowrap"
|
|
614
|
+
},
|
|
615
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
616
|
+
opacity: 1,
|
|
617
|
+
transitionDelay: "0s"
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
42
622
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
623
|
+
import { history } from "@codemirror/commands";
|
|
43
624
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
44
625
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
45
|
-
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
46
|
-
var basicBundle = ({
|
|
47
|
-
|
|
48
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
626
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
628
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
49
629
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
50
630
|
bracketMatching(),
|
|
51
631
|
closeBrackets(),
|
|
52
632
|
drawSelection(),
|
|
53
|
-
|
|
54
|
-
|
|
633
|
+
highlightActiveLine(),
|
|
634
|
+
history(),
|
|
635
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
636
|
+
// https://github.com/codemirror/theme-one-dark
|
|
55
637
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
56
|
-
]
|
|
638
|
+
];
|
|
57
639
|
|
|
58
|
-
// packages/ui/react-ui-editor/src/
|
|
59
|
-
import { EditorView as
|
|
640
|
+
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
641
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
60
642
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
61
|
-
import { invariant } from "@dxos/invariant";
|
|
62
|
-
var
|
|
643
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
644
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
63
645
|
var defaultOptions = {
|
|
64
646
|
effect: 2,
|
|
65
647
|
maxParticles: 200,
|
|
@@ -92,10 +674,10 @@ var blast = (options = defaultOptions) => {
|
|
|
92
674
|
const getPoint = (view, pos) => {
|
|
93
675
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
94
676
|
const element = document.elementFromPoint(x, y);
|
|
95
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
677
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
96
678
|
const point = {
|
|
97
679
|
x: x - left,
|
|
98
|
-
y: y -
|
|
680
|
+
y: y - top2
|
|
99
681
|
};
|
|
100
682
|
return {
|
|
101
683
|
element,
|
|
@@ -104,12 +686,12 @@ var blast = (options = defaultOptions) => {
|
|
|
104
686
|
};
|
|
105
687
|
return [
|
|
106
688
|
// Cursor moved.
|
|
107
|
-
|
|
108
|
-
if (blaster?.node !==
|
|
689
|
+
EditorView4.updateListener.of((update2) => {
|
|
690
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
109
691
|
if (blaster) {
|
|
110
692
|
blaster.destroy();
|
|
111
693
|
}
|
|
112
|
-
blaster = new Blaster(
|
|
694
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
113
695
|
particleGravity: 0.2,
|
|
114
696
|
particleShrinkRate: 0.995,
|
|
115
697
|
color: () => [
|
|
@@ -123,10 +705,10 @@ var blast = (options = defaultOptions) => {
|
|
|
123
705
|
} else {
|
|
124
706
|
blaster.resize();
|
|
125
707
|
}
|
|
126
|
-
const current =
|
|
708
|
+
const current = update2.state.selection.main.head;
|
|
127
709
|
if (current !== last) {
|
|
128
710
|
last = current;
|
|
129
|
-
const { element, point } = getPoint(
|
|
711
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
130
712
|
if (element && point) {
|
|
131
713
|
blaster.spawn({
|
|
132
714
|
element,
|
|
@@ -185,8 +767,8 @@ var Blaster = class {
|
|
|
185
767
|
return this._node;
|
|
186
768
|
}
|
|
187
769
|
initialize() {
|
|
188
|
-
|
|
189
|
-
F:
|
|
770
|
+
invariant2(!this._canvas && !this._ctx, void 0, {
|
|
771
|
+
F: __dxlog_file2,
|
|
190
772
|
L: 138,
|
|
191
773
|
S: this,
|
|
192
774
|
A: [
|
|
@@ -222,8 +804,8 @@ var Blaster = class {
|
|
|
222
804
|
}
|
|
223
805
|
}
|
|
224
806
|
start() {
|
|
225
|
-
|
|
226
|
-
F:
|
|
807
|
+
invariant2(this._canvas && this._ctx, void 0, {
|
|
808
|
+
F: __dxlog_file2,
|
|
227
809
|
L: 177,
|
|
228
810
|
S: this,
|
|
229
811
|
A: [
|
|
@@ -254,525 +836,127 @@ var Blaster = class {
|
|
|
254
836
|
const shakeY = random(-magnitude, magnitude);
|
|
255
837
|
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
256
838
|
}
|
|
257
|
-
this.drawParticles();
|
|
258
|
-
requestAnimationFrame(this.loop.bind(this));
|
|
259
|
-
}
|
|
260
|
-
drawParticles() {
|
|
261
|
-
for (let i = this._particles.length; i--; i > 0) {
|
|
262
|
-
const particle = this._particles[i];
|
|
263
|
-
if (!particle) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
this._effect.update(this._ctx, particle);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
var Effect = class {
|
|
274
|
-
constructor(_options) {
|
|
275
|
-
this._options = _options;
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
var Effect1 = class extends Effect {
|
|
279
|
-
create(x, y, color) {
|
|
280
|
-
return {
|
|
281
|
-
x,
|
|
282
|
-
y: y + 10,
|
|
283
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
284
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
285
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
286
|
-
color,
|
|
287
|
-
alpha: 1
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
update(ctx, particle) {
|
|
291
|
-
particle.vy += this._options.particleGravity;
|
|
292
|
-
particle.x += particle.vx;
|
|
293
|
-
particle.y += particle.vy;
|
|
294
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
295
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
296
|
-
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
var Effect2 = class extends Effect {
|
|
300
|
-
create(x, y, color) {
|
|
301
|
-
return {
|
|
302
|
-
x,
|
|
303
|
-
y: y + 10,
|
|
304
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
305
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
306
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
307
|
-
color,
|
|
308
|
-
alpha: 1,
|
|
309
|
-
theta: random(0, 360) * Math.PI / 180,
|
|
310
|
-
drag: 0.92,
|
|
311
|
-
wander: 0.15
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
update(ctx, particle) {
|
|
315
|
-
particle.vy += this._options.particleGravity;
|
|
316
|
-
particle.x += particle.vx;
|
|
317
|
-
particle.y += particle.vy;
|
|
318
|
-
particle.vx *= particle.drag;
|
|
319
|
-
particle.vy *= particle.drag;
|
|
320
|
-
particle.theta += random(-0.5, 0.5);
|
|
321
|
-
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
322
|
-
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
323
|
-
particle.size *= this._options.particleShrinkRate;
|
|
324
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
325
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
326
|
-
ctx.beginPath();
|
|
327
|
-
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
328
|
-
ctx.fill();
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
function throttle(callback, limit) {
|
|
332
|
-
let wait = false;
|
|
333
|
-
return function(...args) {
|
|
334
|
-
if (!wait) {
|
|
335
|
-
callback.apply(this, args);
|
|
336
|
-
wait = true;
|
|
337
|
-
setTimeout(() => {
|
|
338
|
-
wait = false;
|
|
339
|
-
}, limit);
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
var getRGBComponents = (node, color) => {
|
|
344
|
-
if (typeof color === "function") {
|
|
345
|
-
return color();
|
|
346
|
-
}
|
|
347
|
-
const bgColor = getComputedStyle(node).color;
|
|
348
|
-
if (bgColor) {
|
|
349
|
-
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
350
|
-
if (x) {
|
|
351
|
-
return x;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return [
|
|
355
|
-
50,
|
|
356
|
-
50,
|
|
357
|
-
50
|
|
358
|
-
];
|
|
359
|
-
};
|
|
360
|
-
var random = (min, max) => {
|
|
361
|
-
if (!max) {
|
|
362
|
-
max = min;
|
|
363
|
-
min = 0;
|
|
364
|
-
}
|
|
365
|
-
return min + ~~(Math.random() * (max - min + 1));
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
369
|
-
import { ViewPlugin, EditorView as EditorView3, Decoration } from "@codemirror/view";
|
|
370
|
-
import get from "lodash.get";
|
|
371
|
-
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
372
|
-
|
|
373
|
-
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
374
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
375
|
-
var headings = {
|
|
376
|
-
1: [
|
|
377
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
378
|
-
"-ml-[10px]"
|
|
379
|
-
],
|
|
380
|
-
2: [
|
|
381
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
382
|
-
"-ml-[8px]"
|
|
383
|
-
],
|
|
384
|
-
3: [
|
|
385
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
386
|
-
"-ml-[7px]"
|
|
387
|
-
],
|
|
388
|
-
4: [
|
|
389
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
390
|
-
"-ml-[6px]"
|
|
391
|
-
],
|
|
392
|
-
5: [
|
|
393
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
394
|
-
"-ml-[5px]"
|
|
395
|
-
],
|
|
396
|
-
6: [
|
|
397
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
398
|
-
"-ml-[4px]"
|
|
399
|
-
]
|
|
400
|
-
};
|
|
401
|
-
var heading = (level, readonly) => {
|
|
402
|
-
const [style, offset] = headings[level];
|
|
403
|
-
return mx(style, readonly && offset);
|
|
404
|
-
};
|
|
405
|
-
var light = "text-neutral-200 dark:text-neutral-800";
|
|
406
|
-
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
407
|
-
var bold = "font-bold";
|
|
408
|
-
var italic = "italic";
|
|
409
|
-
var strikethrough = "line-through";
|
|
410
|
-
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
411
|
-
var codeMark = "font-mono text-primary-500";
|
|
412
|
-
var inlineUrl = mx(code, "px-1");
|
|
413
|
-
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
414
|
-
|
|
415
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
416
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
417
|
-
var tokens = tailwindConfig({}).theme;
|
|
418
|
-
|
|
419
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
420
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
421
|
-
var styles = EditorView3.baseTheme({
|
|
422
|
-
"& .cm-codeblock": {
|
|
423
|
-
fontFamily: get(tokens, "fontFamily.mono", []).join(",")
|
|
424
|
-
},
|
|
425
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
426
|
-
background: get(tokens, "extend.colors.neutral.50")
|
|
427
|
-
},
|
|
428
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
429
|
-
background: get(tokens, "extend.colors.neutral.850")
|
|
430
|
-
},
|
|
431
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
432
|
-
display: "block",
|
|
433
|
-
paddingInline: "4px !important"
|
|
434
|
-
},
|
|
435
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
436
|
-
paddingTop: "4px !important",
|
|
437
|
-
borderTopLeftRadius: "4px",
|
|
438
|
-
borderTopRightRadius: "4px"
|
|
439
|
-
},
|
|
440
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
441
|
-
paddingBottom: "4px !important",
|
|
442
|
-
borderBottomLeftRadius: "4px",
|
|
443
|
-
borderBottomRightRadius: "4px"
|
|
444
|
-
}
|
|
445
|
-
});
|
|
446
|
-
var getLineRange = (lines, from, to) => {
|
|
447
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
448
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
449
|
-
return [
|
|
450
|
-
start,
|
|
451
|
-
end
|
|
452
|
-
];
|
|
453
|
-
};
|
|
454
|
-
var code2 = () => {
|
|
455
|
-
const getDecorations = (view) => {
|
|
456
|
-
const decorations = [];
|
|
457
|
-
if (view.state.readOnly) {
|
|
458
|
-
const text = view.state.doc.sliceString(0);
|
|
459
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
460
|
-
const blocks = view.viewportLineBlocks;
|
|
461
|
-
for (const match of matches) {
|
|
462
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
463
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
464
|
-
const block = blocks[i];
|
|
465
|
-
decorations.push(Decoration.line({
|
|
466
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
467
|
-
}).range(block.from));
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
return Decoration.set(decorations);
|
|
472
|
-
};
|
|
473
|
-
return [
|
|
474
|
-
ViewPlugin.fromClass(class {
|
|
475
|
-
constructor(view) {
|
|
476
|
-
this.decorations = getDecorations(view);
|
|
477
|
-
}
|
|
478
|
-
update(update4) {
|
|
479
|
-
if (update4.docChanged || update4.viewportChanged) {
|
|
480
|
-
this.decorations = getDecorations(update4.view);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}, {
|
|
484
|
-
decorations: (value) => value.decorations
|
|
485
|
-
}),
|
|
486
|
-
styles
|
|
487
|
-
];
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
491
|
-
import { StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
|
|
492
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin3, WidgetType } from "@codemirror/view";
|
|
493
|
-
import sortBy from "lodash.sortby";
|
|
494
|
-
import { debounce } from "@dxos/async";
|
|
495
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
496
|
-
import { log as log3 } from "@dxos/log";
|
|
497
|
-
import { nonNullable } from "@dxos/util";
|
|
498
|
-
|
|
499
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/util.ts
|
|
500
|
-
import { log } from "@dxos/log";
|
|
501
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/util.ts";
|
|
502
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
503
|
-
try {
|
|
504
|
-
return fn(...args);
|
|
505
|
-
} catch (error) {
|
|
506
|
-
log.catch(error, void 0, {
|
|
507
|
-
F: __dxlog_file2,
|
|
508
|
-
L: 16,
|
|
509
|
-
S: void 0,
|
|
510
|
-
C: (f, a) => f(...a)
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
516
|
-
import { StateField as StateField2 } from "@codemirror/state";
|
|
517
|
-
import get2 from "lodash.get";
|
|
518
|
-
import { useEffect, useState } from "react";
|
|
519
|
-
import { yCollab } from "y-codemirror.next";
|
|
520
|
-
import * as Y from "yjs";
|
|
521
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
522
|
-
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
523
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
524
|
-
|
|
525
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
526
|
-
import { Annotation, Facet, StateEffect, StateField } from "@codemirror/state";
|
|
527
|
-
import { ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
528
|
-
import * as automerge2 from "@dxos/automerge/automerge";
|
|
529
|
-
|
|
530
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/semaphore.ts
|
|
531
|
-
import { next as automerge } from "@dxos/automerge/automerge";
|
|
532
|
-
|
|
533
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-automerge.ts
|
|
534
|
-
import { next as am } from "@dxos/automerge/automerge";
|
|
535
|
-
var updateAutomerge = (field, handle, transactions, state) => {
|
|
536
|
-
const { lastHeads, path } = state.field(field);
|
|
537
|
-
let hasChanges = false;
|
|
538
|
-
for (const tr of transactions) {
|
|
539
|
-
tr.changes.iterChanges(() => {
|
|
540
|
-
hasChanges = true;
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
if (!hasChanges) {
|
|
544
|
-
return void 0;
|
|
545
|
-
}
|
|
546
|
-
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
547
|
-
for (const tr of transactions) {
|
|
548
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
549
|
-
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
return newHeads ?? void 0;
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-codemirror.ts
|
|
557
|
-
import { ChangeSet } from "@codemirror/state";
|
|
558
|
-
var updateCodeMirror = (view, selection, target, patches) => {
|
|
559
|
-
for (const patch of patches) {
|
|
560
|
-
const changeSpec = handlePatch(patch, target, view.state);
|
|
561
|
-
if (changeSpec != null) {
|
|
562
|
-
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
563
|
-
selection = selection.map(changeSet, 1);
|
|
564
|
-
view.dispatch({
|
|
565
|
-
changes: changeSet,
|
|
566
|
-
annotations: reconcileAnnotationType.of({})
|
|
567
|
-
});
|
|
568
|
-
}
|
|
839
|
+
this.drawParticles();
|
|
840
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
569
841
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
return handleDel(target, patch);
|
|
582
|
-
} else if (patch.action === "put") {
|
|
583
|
-
return handlePut(target, patch, state);
|
|
584
|
-
} else {
|
|
585
|
-
return null;
|
|
842
|
+
drawParticles() {
|
|
843
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
844
|
+
const particle = this._particles[i];
|
|
845
|
+
if (!particle) {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
this._effect.update(this._ctx, particle);
|
|
852
|
+
}
|
|
586
853
|
}
|
|
587
854
|
};
|
|
588
|
-
var
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
return [];
|
|
855
|
+
var Effect = class {
|
|
856
|
+
constructor(_options) {
|
|
857
|
+
this._options = _options;
|
|
592
858
|
}
|
|
593
|
-
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
594
|
-
return [
|
|
595
|
-
{
|
|
596
|
-
from: index,
|
|
597
|
-
to: index,
|
|
598
|
-
insert: text
|
|
599
|
-
}
|
|
600
|
-
];
|
|
601
859
|
};
|
|
602
|
-
var
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
860
|
+
var Effect1 = class extends Effect {
|
|
861
|
+
create(x, y, color) {
|
|
862
|
+
return {
|
|
863
|
+
x,
|
|
864
|
+
y: y + 10,
|
|
865
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
866
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
867
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
868
|
+
color,
|
|
869
|
+
alpha: 1
|
|
870
|
+
};
|
|
606
871
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
var handleDel = (target, patch) => {
|
|
615
|
-
const index = charPath(target, patch.path);
|
|
616
|
-
if (index == null) {
|
|
617
|
-
return [];
|
|
872
|
+
update(ctx, particle) {
|
|
873
|
+
particle.vy += this._options.particleGravity;
|
|
874
|
+
particle.x += particle.vx;
|
|
875
|
+
particle.y += particle.vy;
|
|
876
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
877
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
878
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
618
879
|
}
|
|
619
|
-
const length = patch.length || 1;
|
|
620
|
-
return [
|
|
621
|
-
{
|
|
622
|
-
from: index,
|
|
623
|
-
to: index + length
|
|
624
|
-
}
|
|
625
|
-
];
|
|
626
880
|
};
|
|
627
|
-
var
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
881
|
+
var Effect2 = class extends Effect {
|
|
882
|
+
create(x, y, color) {
|
|
883
|
+
return {
|
|
884
|
+
x,
|
|
885
|
+
y: y + 10,
|
|
886
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
887
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
888
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
889
|
+
color,
|
|
890
|
+
alpha: 1,
|
|
891
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
892
|
+
drag: 0.92,
|
|
893
|
+
wander: 0.15
|
|
894
|
+
};
|
|
634
895
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
896
|
+
update(ctx, particle) {
|
|
897
|
+
particle.vy += this._options.particleGravity;
|
|
898
|
+
particle.x += particle.vx;
|
|
899
|
+
particle.y += particle.vy;
|
|
900
|
+
particle.vx *= particle.drag;
|
|
901
|
+
particle.vy *= particle.drag;
|
|
902
|
+
particle.theta += random(-0.5, 0.5);
|
|
903
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
904
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
905
|
+
particle.size *= this._options.particleShrinkRate;
|
|
906
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
907
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
908
|
+
ctx.beginPath();
|
|
909
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
910
|
+
ctx.fill();
|
|
638
911
|
}
|
|
639
|
-
return [
|
|
640
|
-
{
|
|
641
|
-
from: 0,
|
|
642
|
-
to: length,
|
|
643
|
-
insert: patch.value
|
|
644
|
-
}
|
|
645
|
-
];
|
|
646
912
|
};
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
913
|
+
function throttle(callback, limit) {
|
|
914
|
+
let wait = false;
|
|
915
|
+
return function(...args) {
|
|
916
|
+
if (!wait) {
|
|
917
|
+
callback.apply(this, args);
|
|
918
|
+
wait = true;
|
|
919
|
+
setTimeout(() => {
|
|
920
|
+
wait = false;
|
|
921
|
+
}, limit);
|
|
654
922
|
}
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
var getRGBComponents = (node, color) => {
|
|
926
|
+
if (typeof color === "function") {
|
|
927
|
+
return color();
|
|
655
928
|
}
|
|
656
|
-
const
|
|
657
|
-
if (
|
|
658
|
-
|
|
929
|
+
const bgColor = getComputedStyle(node).color;
|
|
930
|
+
if (bgColor) {
|
|
931
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
932
|
+
if (x) {
|
|
933
|
+
return x;
|
|
934
|
+
}
|
|
659
935
|
}
|
|
660
|
-
return
|
|
936
|
+
return [
|
|
937
|
+
50,
|
|
938
|
+
50,
|
|
939
|
+
50
|
|
940
|
+
];
|
|
661
941
|
};
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
this._inReconcile = false;
|
|
667
|
-
this._queue = [];
|
|
668
|
-
this.reconcile = (handle, view) => {
|
|
669
|
-
if (this._inReconcile) {
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
this._inReconcile = true;
|
|
673
|
-
const path = getPath(view.state, this._field);
|
|
674
|
-
const oldHeads = getLastHeads(view.state, this._field);
|
|
675
|
-
let selection = view.state.selection;
|
|
676
|
-
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
677
|
-
const toInvert = transactions.slice().reverse();
|
|
678
|
-
for (const tx of toInvert) {
|
|
679
|
-
const inverted = tx.changes.invert(tx.startState.doc);
|
|
680
|
-
selection = selection.map(inverted);
|
|
681
|
-
view.dispatch({
|
|
682
|
-
changes: inverted,
|
|
683
|
-
annotations: reconcileAnnotationType.of(true)
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
687
|
-
if (newHeads === null || newHeads === void 0) {
|
|
688
|
-
newHeads = automerge.getHeads(handle.docSync());
|
|
689
|
-
}
|
|
690
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
691
|
-
updateCodeMirror(view, selection, path, diff);
|
|
692
|
-
view.dispatch({
|
|
693
|
-
effects: updateHeads(newHeads),
|
|
694
|
-
annotations: reconcileAnnotationType.of({})
|
|
695
|
-
});
|
|
696
|
-
this._inReconcile = false;
|
|
697
|
-
};
|
|
698
|
-
if (field !== void 0) {
|
|
699
|
-
this._field = field;
|
|
700
|
-
}
|
|
942
|
+
var random = (min, max) => {
|
|
943
|
+
if (!max) {
|
|
944
|
+
max = min;
|
|
945
|
+
min = 0;
|
|
701
946
|
}
|
|
947
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
702
948
|
};
|
|
703
949
|
|
|
704
|
-
// packages/ui/react-ui-editor/src/
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
combine: (values) => values.at(-1)
|
|
713
|
-
});
|
|
714
|
-
var automergePlugin = (handle, path) => {
|
|
715
|
-
const stateField = StateField.define({
|
|
716
|
-
create: () => ({
|
|
717
|
-
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
718
|
-
unreconciledTransactions: [],
|
|
719
|
-
path: path.slice()
|
|
720
|
-
}),
|
|
721
|
-
update: (value, tr) => {
|
|
722
|
-
const result = {
|
|
723
|
-
lastHeads: value.lastHeads,
|
|
724
|
-
unreconciledTransactions: value.unreconciledTransactions.slice(),
|
|
725
|
-
path: path.slice()
|
|
726
|
-
};
|
|
727
|
-
let clearUnreconciled = false;
|
|
728
|
-
for (const effect of tr.effects) {
|
|
729
|
-
if (effect.is(effectType)) {
|
|
730
|
-
result.lastHeads = effect.value.newHeads;
|
|
731
|
-
clearUnreconciled = true;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
if (clearUnreconciled) {
|
|
735
|
-
result.unreconciledTransactions = [];
|
|
736
|
-
} else {
|
|
737
|
-
if (!isReconcileTx(tr)) {
|
|
738
|
-
result.unreconciledTransactions.push(tr);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
return result;
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
const semaphore = new PatchSemaphore(stateField);
|
|
745
|
-
const viewPlugin = ViewPlugin2.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
746
|
-
constructor(view) {
|
|
747
|
-
this._handleChange = () => {
|
|
748
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
749
|
-
};
|
|
750
|
-
this._view = view;
|
|
751
|
-
handle.addListener("change", this._handleChange);
|
|
752
|
-
}
|
|
753
|
-
update(update4) {
|
|
754
|
-
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
755
|
-
queueMicrotask(() => {
|
|
756
|
-
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
destroy() {
|
|
761
|
-
handle.addListener("change", this._handleChange);
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
return {
|
|
765
|
-
extension: [
|
|
766
|
-
stateField,
|
|
767
|
-
semaphoreFacet.of(semaphore),
|
|
768
|
-
viewPlugin
|
|
769
|
-
]
|
|
770
|
-
};
|
|
771
|
-
};
|
|
772
|
-
var reconcileAnnotationType = Annotation.define();
|
|
773
|
-
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
950
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
951
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
952
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
953
|
+
import sortBy from "lodash.sortby";
|
|
954
|
+
import { useEffect } from "react";
|
|
955
|
+
import { debounce } from "@dxos/async";
|
|
956
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
957
|
+
import { nonNullable } from "@dxos/util";
|
|
774
958
|
|
|
775
|
-
// packages/ui/react-ui-editor/src/
|
|
959
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
776
960
|
import * as random2 from "lib0/random";
|
|
777
961
|
var cursorColors = [
|
|
778
962
|
{
|
|
@@ -810,221 +994,78 @@ var cursorColors = [
|
|
|
810
994
|
];
|
|
811
995
|
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
812
996
|
|
|
813
|
-
// packages/ui/react-ui-editor/src/
|
|
814
|
-
import
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
return
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
log2("awareness update", {
|
|
851
|
-
added,
|
|
852
|
-
updated,
|
|
853
|
-
removed,
|
|
854
|
-
origin
|
|
855
|
-
}, {
|
|
856
|
-
F: __dxlog_file3,
|
|
857
|
-
L: 67,
|
|
858
|
-
S: this,
|
|
859
|
-
C: (f, a) => f(...a)
|
|
860
|
-
});
|
|
861
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
862
|
-
const encoderAwareness = encoding.createEncoder();
|
|
863
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
864
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
865
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
866
|
-
}
|
|
867
|
-
_handleSpaceMessage({ payload }) {
|
|
868
|
-
log2("space message", payload, {
|
|
997
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
998
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
999
|
+
var headings = {
|
|
1000
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1001
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1002
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1003
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1004
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1005
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1006
|
+
};
|
|
1007
|
+
var heading = (level) => {
|
|
1008
|
+
return headings[level];
|
|
1009
|
+
};
|
|
1010
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1011
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1012
|
+
var bold = "font-bold";
|
|
1013
|
+
var italic = "italic";
|
|
1014
|
+
var strikethrough = "line-through";
|
|
1015
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1016
|
+
var codeMark = "font-mono text-primary-500";
|
|
1017
|
+
var inlineUrl = mx(code, "px-1");
|
|
1018
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1019
|
+
|
|
1020
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1021
|
+
import get2 from "lodash.get";
|
|
1022
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1023
|
+
var tokens = tailwindConfig({}).theme;
|
|
1024
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1025
|
+
|
|
1026
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1027
|
+
import { log } from "@dxos/log";
|
|
1028
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1029
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1030
|
+
try {
|
|
1031
|
+
return fn(...args);
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
log.catch(err, void 0, {
|
|
869
1034
|
F: __dxlog_file3,
|
|
870
|
-
L:
|
|
871
|
-
S:
|
|
1035
|
+
L: 18,
|
|
1036
|
+
S: void 0,
|
|
872
1037
|
C: (f, a) => f(...a)
|
|
873
1038
|
});
|
|
874
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
875
|
-
const encoder = this._readMessage(data);
|
|
876
|
-
if (encoder) {
|
|
877
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
_readMessage(message) {
|
|
881
|
-
const decoder = decoding.createDecoder(message);
|
|
882
|
-
const encoder = encoding.createEncoder();
|
|
883
|
-
const messageType = decoding.readVarUint(decoder);
|
|
884
|
-
let sendReply = false;
|
|
885
|
-
switch (messageType) {
|
|
886
|
-
case messageAwareness: {
|
|
887
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
888
|
-
break;
|
|
889
|
-
}
|
|
890
|
-
case messageQueryAwareness: {
|
|
891
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
892
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
893
|
-
sendReply = true;
|
|
894
|
-
break;
|
|
895
|
-
}
|
|
896
|
-
default: {
|
|
897
|
-
console.error("Invalid message:", messageType);
|
|
898
|
-
return encoder;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
if (!sendReply) {
|
|
902
|
-
return null;
|
|
903
|
-
}
|
|
904
|
-
return encoder;
|
|
905
|
-
}
|
|
906
|
-
_handleBeforeUnload() {
|
|
907
|
-
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
908
|
-
this._clientId
|
|
909
|
-
], "window unload");
|
|
910
1039
|
}
|
|
911
1040
|
};
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
var modelState = StateField2.define({
|
|
916
|
-
create: () => void 0,
|
|
917
|
-
update: (model) => model
|
|
918
|
-
});
|
|
919
|
-
var useTextModel = (props) => {
|
|
920
|
-
const { identity, space, text } = props;
|
|
921
|
-
const [model, setModel] = useState(() => createModel(props));
|
|
922
|
-
useEffect(() => setModel(createModel(props)), [
|
|
923
|
-
identity,
|
|
924
|
-
space,
|
|
925
|
-
text
|
|
926
|
-
]);
|
|
927
|
-
return model;
|
|
928
|
-
};
|
|
929
|
-
var createModel = (props) => {
|
|
930
|
-
const { text } = props;
|
|
931
|
-
if (isActualAutomergeObject(text)) {
|
|
932
|
-
return createAutomergeModel(props);
|
|
933
|
-
} else {
|
|
934
|
-
if (!text?.doc) {
|
|
1041
|
+
var logChanges = (trs) => {
|
|
1042
|
+
const changes = trs.flatMap((tr) => {
|
|
1043
|
+
if (tr.changes.empty) {
|
|
935
1044
|
return void 0;
|
|
936
1045
|
}
|
|
937
|
-
|
|
1046
|
+
const changes2 = [];
|
|
1047
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1048
|
+
fromA,
|
|
1049
|
+
toA,
|
|
1050
|
+
fromB,
|
|
1051
|
+
toB,
|
|
1052
|
+
inserted: inserted.toString()
|
|
1053
|
+
})));
|
|
1054
|
+
return changes2;
|
|
1055
|
+
}).filter(Boolean);
|
|
1056
|
+
if (changes.length) {
|
|
1057
|
+
console.log("changes", changes);
|
|
938
1058
|
}
|
|
939
1059
|
};
|
|
940
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
941
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
942
|
-
F: __dxlog_file4,
|
|
943
|
-
L: 97,
|
|
944
|
-
S: void 0,
|
|
945
|
-
A: [
|
|
946
|
-
"text?.doc && text?.content",
|
|
947
|
-
""
|
|
948
|
-
]
|
|
949
|
-
});
|
|
950
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
951
|
-
space,
|
|
952
|
-
doc: text.doc,
|
|
953
|
-
channel: `yjs.awareness.${text.id}`
|
|
954
|
-
}) : void 0;
|
|
955
|
-
const model = {
|
|
956
|
-
id: text.doc.guid,
|
|
957
|
-
content: text.content,
|
|
958
|
-
text: () => text.content.toString(),
|
|
959
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
960
|
-
getCursorFromRange: (range) => {
|
|
961
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
962
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
963
|
-
return [
|
|
964
|
-
arrayToString(from),
|
|
965
|
-
arrayToString(to)
|
|
966
|
-
].join(":");
|
|
967
|
-
},
|
|
968
|
-
getRangeFromCursor: (cursor) => {
|
|
969
|
-
const parts = cursor.split(":");
|
|
970
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
971
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
972
|
-
return {
|
|
973
|
-
from: from.index,
|
|
974
|
-
to: to.index
|
|
975
|
-
};
|
|
976
|
-
},
|
|
977
|
-
extension: [
|
|
978
|
-
yCollab(text.content, provider?.awareness),
|
|
979
|
-
modelState.init(() => model)
|
|
980
|
-
],
|
|
981
|
-
awareness: provider?.awareness,
|
|
982
|
-
peer: identity ? {
|
|
983
|
-
id: identity.identityKey.toHex(),
|
|
984
|
-
name: identity.profile?.displayName
|
|
985
|
-
} : void 0
|
|
986
|
-
};
|
|
987
|
-
return model;
|
|
988
|
-
};
|
|
989
|
-
var createAutomergeModel = ({ identity, text }) => {
|
|
990
|
-
const obj = text;
|
|
991
|
-
const doc = getRawDoc(obj, [
|
|
992
|
-
obj.field
|
|
993
|
-
]);
|
|
994
|
-
const model = {
|
|
995
|
-
id: obj.id,
|
|
996
|
-
content: doc,
|
|
997
|
-
text: () => get2(doc.handle.docSync(), doc.path),
|
|
998
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
999
|
-
extension: [
|
|
1000
|
-
automergePlugin(doc.handle, doc.path),
|
|
1001
|
-
modelState.init(() => model)
|
|
1002
|
-
],
|
|
1003
|
-
peer: identity ? {
|
|
1004
|
-
id: identity.identityKey.toHex(),
|
|
1005
|
-
name: identity.profile?.displayName
|
|
1006
|
-
} : void 0
|
|
1007
|
-
};
|
|
1008
|
-
return model;
|
|
1009
|
-
};
|
|
1010
1060
|
|
|
1011
|
-
// packages/ui/react-ui-editor/src/
|
|
1012
|
-
var
|
|
1013
|
-
var styles2 =
|
|
1014
|
-
"& .cm-bookmark": {
|
|
1015
|
-
cursor: "pointer",
|
|
1016
|
-
margin: "4px",
|
|
1017
|
-
padding: "4px",
|
|
1018
|
-
backgroundColor: "yellow"
|
|
1019
|
-
},
|
|
1020
|
-
"& .cm-bookmark-selected": {
|
|
1021
|
-
backgroundColor: "orange"
|
|
1022
|
-
},
|
|
1061
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1062
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1063
|
+
var styles2 = EditorView5.baseTheme({
|
|
1023
1064
|
"& .cm-comment": {
|
|
1024
|
-
backgroundColor: "yellow"
|
|
1065
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1025
1066
|
},
|
|
1026
|
-
"& .cm-comment-
|
|
1027
|
-
backgroundColor: "
|
|
1067
|
+
"& .cm-comment-current": {
|
|
1068
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1028
1069
|
}
|
|
1029
1070
|
});
|
|
1030
1071
|
var marks = {
|
|
@@ -1032,36 +1073,62 @@ var marks = {
|
|
|
1032
1073
|
class: "cm-comment"
|
|
1033
1074
|
}),
|
|
1034
1075
|
highlightActive: Decoration2.mark({
|
|
1035
|
-
class: "cm-comment-
|
|
1076
|
+
class: "cm-comment-current"
|
|
1036
1077
|
})
|
|
1037
1078
|
};
|
|
1038
|
-
var
|
|
1079
|
+
var setFocus = (view, id, center = true) => {
|
|
1080
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1081
|
+
if (!comment?.comment.cursor) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1085
|
+
if (range) {
|
|
1086
|
+
view.dispatch({
|
|
1087
|
+
selection: {
|
|
1088
|
+
anchor: range.from
|
|
1089
|
+
},
|
|
1090
|
+
effects: [
|
|
1091
|
+
//
|
|
1092
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1093
|
+
y: "center"
|
|
1094
|
+
} : void 0),
|
|
1095
|
+
setSelection.of({
|
|
1096
|
+
current: id
|
|
1097
|
+
})
|
|
1098
|
+
]
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
var setComments = StateEffect2.define();
|
|
1039
1103
|
var setSelection = StateEffect2.define();
|
|
1040
1104
|
var setCommentState = StateEffect2.define();
|
|
1041
|
-
var
|
|
1105
|
+
var commentsState = StateField2.define({
|
|
1042
1106
|
create: () => ({
|
|
1043
|
-
|
|
1107
|
+
comments: [],
|
|
1108
|
+
selection: {}
|
|
1044
1109
|
}),
|
|
1045
1110
|
update: (value, tr) => {
|
|
1046
1111
|
for (const effect of tr.effects) {
|
|
1047
1112
|
if (effect.is(setSelection)) {
|
|
1048
1113
|
return {
|
|
1049
1114
|
...value,
|
|
1050
|
-
|
|
1115
|
+
selection: effect.value
|
|
1051
1116
|
};
|
|
1052
1117
|
}
|
|
1053
|
-
if (effect.is(
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1118
|
+
if (effect.is(setComments)) {
|
|
1119
|
+
const comments2 = effect.value.map((comment) => {
|
|
1120
|
+
if (!comment.cursor) {
|
|
1121
|
+
return void 0;
|
|
1122
|
+
}
|
|
1123
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1124
|
+
return range && {
|
|
1125
|
+
comment,
|
|
1126
|
+
range
|
|
1060
1127
|
};
|
|
1061
|
-
});
|
|
1128
|
+
}).filter(nonNullable);
|
|
1062
1129
|
return {
|
|
1063
1130
|
...value,
|
|
1064
|
-
|
|
1131
|
+
comments: comments2
|
|
1065
1132
|
};
|
|
1066
1133
|
}
|
|
1067
1134
|
if (effect.is(setCommentState)) {
|
|
@@ -1071,134 +1138,125 @@ var commentsStateField = StateField3.define({
|
|
|
1071
1138
|
return value;
|
|
1072
1139
|
}
|
|
1073
1140
|
});
|
|
1074
|
-
var highlightDecorations =
|
|
1075
|
-
|
|
1141
|
+
var highlightDecorations = EditorView5.decorations.compute([
|
|
1142
|
+
commentsState
|
|
1076
1143
|
], (state) => {
|
|
1077
|
-
const {
|
|
1078
|
-
const decorations = sortBy(
|
|
1079
|
-
|
|
1144
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1145
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1146
|
+
const range = comment.range;
|
|
1147
|
+
if (!range || range.from === range.to) {
|
|
1148
|
+
console.warn("Invalid range:", range);
|
|
1080
1149
|
return void 0;
|
|
1081
1150
|
}
|
|
1082
|
-
|
|
1083
|
-
from: selection.from,
|
|
1084
|
-
to: selection.to
|
|
1085
|
-
};
|
|
1086
|
-
if (selection.id === active) {
|
|
1151
|
+
if (comment.comment.id === current) {
|
|
1087
1152
|
return marks.highlightActive.range(range.from, range.to);
|
|
1088
1153
|
} else {
|
|
1089
1154
|
return marks.highlight.range(range.from, range.to);
|
|
1090
1155
|
}
|
|
1091
|
-
}).filter(nonNullable)
|
|
1156
|
+
}).filter(nonNullable);
|
|
1092
1157
|
return Decoration2.set(decorations);
|
|
1093
1158
|
});
|
|
1094
|
-
var
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1112
|
-
}
|
|
1113
|
-
toDOM() {
|
|
1114
|
-
const span = document.createElement("span");
|
|
1115
|
-
span.className = "cm-bookmark";
|
|
1116
|
-
span.textContent = "\u203B";
|
|
1117
|
-
if (this._handleClick) {
|
|
1118
|
-
span.onclick = () => this._handleClick();
|
|
1159
|
+
var trackPastedComments = (onUpdate) => {
|
|
1160
|
+
let tracked = null;
|
|
1161
|
+
const handleTrack = (event, view) => {
|
|
1162
|
+
const comments2 = view.state.field(commentsState);
|
|
1163
|
+
const { main } = view.state.selection;
|
|
1164
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1165
|
+
if (!selectedRanges.length) {
|
|
1166
|
+
tracked = null;
|
|
1167
|
+
} else {
|
|
1168
|
+
tracked = {
|
|
1169
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1170
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1171
|
+
id: comment.id,
|
|
1172
|
+
from: range.from - main.from,
|
|
1173
|
+
to: range.to - main.from
|
|
1174
|
+
}))
|
|
1175
|
+
};
|
|
1119
1176
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1177
|
+
};
|
|
1178
|
+
return [
|
|
1179
|
+
EditorView5.domEventHandlers({
|
|
1180
|
+
cut: handleTrack,
|
|
1181
|
+
copy: handleTrack
|
|
1182
|
+
}),
|
|
1183
|
+
// Handle paste.
|
|
1184
|
+
EditorView5.updateListener.of(({ view, state, transactions }) => {
|
|
1185
|
+
if (tracked) {
|
|
1186
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1187
|
+
if (paste) {
|
|
1188
|
+
let found = -1;
|
|
1189
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1190
|
+
if (text.eq(tracked.text)) {
|
|
1191
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1192
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1193
|
+
}
|
|
1194
|
+
found = fromB;
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
if (found > -1) {
|
|
1198
|
+
for (const moved of tracked.comments) {
|
|
1199
|
+
const range = {
|
|
1200
|
+
from: found + moved.from,
|
|
1201
|
+
to: found + moved.to
|
|
1202
|
+
};
|
|
1203
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1204
|
+
onUpdate(moved.id, cursor);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
tracked = null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
})
|
|
1211
|
+
];
|
|
1122
1212
|
};
|
|
1123
1213
|
var comments = (options = {}) => {
|
|
1214
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1124
1215
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1125
1216
|
const createCommentThread = (view) => {
|
|
1126
1217
|
invariant3(options.onCreate, void 0, {
|
|
1127
|
-
F:
|
|
1128
|
-
L:
|
|
1218
|
+
F: __dxlog_file4,
|
|
1219
|
+
L: 259,
|
|
1129
1220
|
S: void 0,
|
|
1130
1221
|
A: [
|
|
1131
1222
|
"options.onCreate",
|
|
1132
1223
|
""
|
|
1133
1224
|
]
|
|
1134
1225
|
});
|
|
1135
|
-
const {
|
|
1226
|
+
const { from, to } = view.state.selection.main;
|
|
1136
1227
|
if (from === to) {
|
|
1137
1228
|
return false;
|
|
1138
1229
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1230
|
+
if (to === view.state.doc.length) {
|
|
1231
|
+
view.dispatch({
|
|
1232
|
+
changes: {
|
|
1233
|
+
from: to,
|
|
1234
|
+
insert: "\n"
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1141
1239
|
from,
|
|
1142
1240
|
to
|
|
1143
1241
|
});
|
|
1144
|
-
if (
|
|
1145
|
-
const id =
|
|
1242
|
+
if (cursor) {
|
|
1243
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1146
1244
|
if (id) {
|
|
1147
1245
|
view.dispatch({
|
|
1148
1246
|
effects: setSelection.of({
|
|
1149
|
-
|
|
1247
|
+
current: id
|
|
1150
1248
|
}),
|
|
1151
1249
|
selection: {
|
|
1152
1250
|
anchor: from
|
|
1153
1251
|
}
|
|
1154
1252
|
});
|
|
1155
|
-
if (options.footnote) {
|
|
1156
|
-
const tag = `[^${id}]`;
|
|
1157
|
-
view.dispatch({
|
|
1158
|
-
changes: {
|
|
1159
|
-
from: head,
|
|
1160
|
-
insert: tag
|
|
1161
|
-
},
|
|
1162
|
-
selection: {
|
|
1163
|
-
anchor: head + tag.length
|
|
1164
|
-
}
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
1253
|
return true;
|
|
1168
1254
|
}
|
|
1169
1255
|
}
|
|
1170
1256
|
return false;
|
|
1171
1257
|
};
|
|
1172
|
-
const bookmarksViewPlugin = ViewPlugin3.fromClass(class BookmarkViewPlugin {
|
|
1173
|
-
static {
|
|
1174
|
-
// Match markdown footnotes (option).
|
|
1175
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1176
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1177
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1178
|
-
decoration: (match, view, pos) => {
|
|
1179
|
-
const id = match[1];
|
|
1180
|
-
return Decoration2.replace({
|
|
1181
|
-
id,
|
|
1182
|
-
widget: new BookmarkWidget(pos, id)
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
}
|
|
1187
|
-
constructor(view) {
|
|
1188
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1189
|
-
}
|
|
1190
|
-
update(update4) {
|
|
1191
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
1192
|
-
}
|
|
1193
|
-
}, {
|
|
1194
|
-
decorations: (instance) => instance.bookmarks,
|
|
1195
|
-
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
1196
|
-
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
1197
|
-
})
|
|
1198
|
-
});
|
|
1199
1258
|
return [
|
|
1200
|
-
|
|
1201
|
-
commentsStateField,
|
|
1259
|
+
commentsState,
|
|
1202
1260
|
highlightDecorations,
|
|
1203
1261
|
styles2,
|
|
1204
1262
|
//
|
|
@@ -1206,8 +1264,8 @@ var comments = (options = {}) => {
|
|
|
1206
1264
|
//
|
|
1207
1265
|
options.onCreate ? keymap3.of([
|
|
1208
1266
|
{
|
|
1209
|
-
key:
|
|
1210
|
-
run: createCommentThread
|
|
1267
|
+
key: shortcut,
|
|
1268
|
+
run: callbackWrapper(createCommentThread)
|
|
1211
1269
|
}
|
|
1212
1270
|
]) : [],
|
|
1213
1271
|
//
|
|
@@ -1223,7 +1281,7 @@ var comments = (options = {}) => {
|
|
|
1223
1281
|
above: true,
|
|
1224
1282
|
create: () => {
|
|
1225
1283
|
const el = document.createElement("div");
|
|
1226
|
-
options.onHover
|
|
1284
|
+
options.onHover(el, shortcut);
|
|
1227
1285
|
return {
|
|
1228
1286
|
dom: el,
|
|
1229
1287
|
offset: {
|
|
@@ -1236,314 +1294,127 @@ var comments = (options = {}) => {
|
|
|
1236
1294
|
}
|
|
1237
1295
|
return null;
|
|
1238
1296
|
}, {
|
|
1239
|
-
|
|
1297
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1298
|
+
// hideOnChange: true,
|
|
1240
1299
|
hoverTime: 1e3
|
|
1241
1300
|
}) : [],
|
|
1242
1301
|
//
|
|
1243
|
-
//
|
|
1244
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1302
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1245
1303
|
//
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
ranges.forEach((range) => {
|
|
1262
|
-
if (from2 === to2) {
|
|
1263
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1264
|
-
if (newRange.to - newRange.from === 0) {
|
|
1265
|
-
log3.info("deleted comment", {
|
|
1266
|
-
thread: range.id
|
|
1267
|
-
}, {
|
|
1268
|
-
F: __dxlog_file5,
|
|
1269
|
-
L: 339,
|
|
1270
|
-
S: void 0,
|
|
1271
|
-
C: (f, a) => f(...a)
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
if (from <= range.to) {
|
|
1276
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1277
|
-
Object.assign(range, newRange);
|
|
1278
|
-
mod = true;
|
|
1279
|
-
}
|
|
1280
|
-
});
|
|
1281
|
-
});
|
|
1282
|
-
if (mod) {
|
|
1283
|
-
view.dispatch({
|
|
1284
|
-
effects: setCommentState.of({
|
|
1285
|
-
active,
|
|
1286
|
-
ranges
|
|
1287
|
-
})
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
{
|
|
1292
|
-
const { head } = state.selection.main;
|
|
1293
|
-
let min = Infinity;
|
|
1294
|
-
const { active, closest, ranges } = state.field(commentsStateField);
|
|
1295
|
-
const selected = {
|
|
1296
|
-
active: void 0,
|
|
1297
|
-
closest: void 0
|
|
1298
|
-
};
|
|
1299
|
-
ranges.forEach((comment) => {
|
|
1300
|
-
const d = Math.min(Math.abs(head - comment.from), Math.abs(head - comment.to));
|
|
1301
|
-
if (head >= comment.from && head <= comment.to) {
|
|
1302
|
-
selected.active = comment.id;
|
|
1303
|
-
}
|
|
1304
|
-
if (d < min) {
|
|
1305
|
-
selected.closest = comment.id;
|
|
1306
|
-
min = d;
|
|
1307
|
-
}
|
|
1308
|
-
});
|
|
1309
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1310
|
-
view.dispatch({
|
|
1311
|
-
effects: setSelection.of(selected)
|
|
1312
|
-
});
|
|
1313
|
-
handleSelect({
|
|
1314
|
-
...selected,
|
|
1315
|
-
ranges: ranges.map((range) => ({
|
|
1316
|
-
...range,
|
|
1317
|
-
location: view.coordsAtPos(range.from)
|
|
1318
|
-
}))
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
})
|
|
1323
|
-
];
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/hr.ts
|
|
1327
|
-
import { Decoration as Decoration3, EditorView as EditorView5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1328
|
-
import get3 from "lodash.get";
|
|
1329
|
-
var styles3 = EditorView5.baseTheme({
|
|
1330
|
-
"& .cm-hr": {
|
|
1331
|
-
// TODO(burdon): ???
|
|
1332
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1333
|
-
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
1334
|
-
}
|
|
1335
|
-
});
|
|
1336
|
-
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1337
|
-
constructor(_pos) {
|
|
1338
|
-
super();
|
|
1339
|
-
this._pos = _pos;
|
|
1340
|
-
}
|
|
1341
|
-
eq(other) {
|
|
1342
|
-
return this._pos === other._pos;
|
|
1343
|
-
}
|
|
1344
|
-
toDOM(view) {
|
|
1345
|
-
const el = document.createElement("div");
|
|
1346
|
-
el.className = "cm-hr";
|
|
1347
|
-
return el;
|
|
1348
|
-
}
|
|
1349
|
-
};
|
|
1350
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1351
|
-
regexp: /^---$/g,
|
|
1352
|
-
decoration: (match, view, pos) => Decoration3.replace({
|
|
1353
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1354
|
-
})
|
|
1355
|
-
});
|
|
1356
|
-
var hr = () => [
|
|
1357
|
-
styles3,
|
|
1358
|
-
ViewPlugin4.fromClass(class {
|
|
1359
|
-
constructor(view) {
|
|
1360
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1361
|
-
}
|
|
1362
|
-
update(update4) {
|
|
1363
|
-
this.rules = placeholderMatcher.updateDeco(update4, this.rules);
|
|
1364
|
-
}
|
|
1365
|
-
}, {
|
|
1366
|
-
decorations: (instance) => instance.rules,
|
|
1367
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1368
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1369
|
-
return view.plugin(plugin)?.rules || Decoration3.none;
|
|
1370
|
-
})
|
|
1371
|
-
})
|
|
1372
|
-
];
|
|
1373
|
-
|
|
1374
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/image.ts
|
|
1375
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1376
|
-
import { RangeSetBuilder, StateField as StateField4 } from "@codemirror/state";
|
|
1377
|
-
import { Decoration as Decoration4, EditorView as EditorView6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1378
|
-
var image = (options = {}) => {
|
|
1379
|
-
return StateField4.define({
|
|
1380
|
-
create: (state) => update(state, options),
|
|
1381
|
-
update: (_, tr) => update(tr.state, options),
|
|
1382
|
-
provide: (field) => EditorView6.decorations.from(field)
|
|
1383
|
-
});
|
|
1384
|
-
};
|
|
1385
|
-
var update = (state, options) => {
|
|
1386
|
-
const builder = new RangeSetBuilder();
|
|
1387
|
-
const cursor = state.selection.main.head;
|
|
1388
|
-
syntaxTree(state).iterate({
|
|
1389
|
-
enter: (node) => {
|
|
1390
|
-
if (node.name === "Image") {
|
|
1391
|
-
const urlNode = node.node.getChild("URL");
|
|
1392
|
-
if (urlNode) {
|
|
1393
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1394
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1395
|
-
builder.add(hide ? node.from : node.to, node.to, Decoration4.replace({
|
|
1396
|
-
block: true,
|
|
1397
|
-
widget: new ImageWidget(url)
|
|
1398
|
-
}));
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
});
|
|
1403
|
-
return builder.finish();
|
|
1404
|
-
};
|
|
1405
|
-
var ImageWidget = class extends WidgetType3 {
|
|
1406
|
-
constructor(_url) {
|
|
1407
|
-
super();
|
|
1408
|
-
this._url = _url;
|
|
1409
|
-
}
|
|
1410
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1411
|
-
eq(other) {
|
|
1412
|
-
return this._url === other._url;
|
|
1413
|
-
}
|
|
1414
|
-
toDOM(view) {
|
|
1415
|
-
const img = document.createElement("img");
|
|
1416
|
-
img.setAttribute("src", this._url);
|
|
1417
|
-
img.setAttribute("class", "cm-image");
|
|
1418
|
-
return img;
|
|
1419
|
-
}
|
|
1420
|
-
};
|
|
1421
|
-
|
|
1422
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
1423
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1424
|
-
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField5 } from "@codemirror/state";
|
|
1425
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1426
|
-
var link = (options = {}) => {
|
|
1427
|
-
return StateField5.define({
|
|
1428
|
-
create: (state) => update2(state, options),
|
|
1429
|
-
update: (_, tr) => update2(tr.state, options),
|
|
1430
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1431
|
-
});
|
|
1432
|
-
};
|
|
1433
|
-
var LinkButton = class extends WidgetType4 {
|
|
1434
|
-
constructor(_pos, _url, _onAttach) {
|
|
1435
|
-
super();
|
|
1436
|
-
this._pos = _pos;
|
|
1437
|
-
this._url = _url;
|
|
1438
|
-
this._onAttach = _onAttach;
|
|
1439
|
-
}
|
|
1440
|
-
eq(other) {
|
|
1441
|
-
return this._pos === other._pos && this._url === other._url;
|
|
1442
|
-
}
|
|
1443
|
-
toDOM(view) {
|
|
1444
|
-
const el = document.createElement("span");
|
|
1445
|
-
this._onAttach(el, this._url);
|
|
1446
|
-
return el;
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
|
-
var LinkText = class extends WidgetType4 {
|
|
1450
|
-
constructor(_pos, _text, _url) {
|
|
1451
|
-
super();
|
|
1452
|
-
this._pos = _pos;
|
|
1453
|
-
this._text = _text;
|
|
1454
|
-
this._url = _url;
|
|
1455
|
-
}
|
|
1456
|
-
eq(other) {
|
|
1457
|
-
return this._pos === other._pos && this._url === other._url;
|
|
1458
|
-
}
|
|
1459
|
-
toDOM(view) {
|
|
1460
|
-
const link2 = document.createElement("a");
|
|
1461
|
-
link2.setAttribute("class", "cm-link");
|
|
1462
|
-
link2.textContent = this._text;
|
|
1463
|
-
if (this._url) {
|
|
1464
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1465
|
-
link2.setAttribute("target", "_blank");
|
|
1466
|
-
link2.href = this._url;
|
|
1467
|
-
} else {
|
|
1468
|
-
link2.onclick = () => {
|
|
1469
|
-
view.dispatch({
|
|
1470
|
-
selection: {
|
|
1471
|
-
anchor: this._pos
|
|
1304
|
+
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1305
|
+
let mod = false;
|
|
1306
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1307
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1308
|
+
comments2.forEach(({ comment, range }) => {
|
|
1309
|
+
if (from2 === to2) {
|
|
1310
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1311
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1312
|
+
options.onDelete?.(comment.id);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
if (from <= range.to) {
|
|
1316
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1317
|
+
Object.assign(range, newRange);
|
|
1318
|
+
mod = true;
|
|
1472
1319
|
}
|
|
1473
1320
|
});
|
|
1474
|
-
};
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1321
|
+
});
|
|
1322
|
+
if (mod) {
|
|
1323
|
+
view.dispatch({
|
|
1324
|
+
effects: setCommentState.of({
|
|
1325
|
+
comments: comments2,
|
|
1326
|
+
...value
|
|
1327
|
+
})
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
}),
|
|
1331
|
+
//
|
|
1332
|
+
// Track selection/proximity.
|
|
1333
|
+
//
|
|
1334
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1335
|
+
let min = Infinity;
|
|
1336
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1337
|
+
const { head } = state.selection.main;
|
|
1338
|
+
const selection = {};
|
|
1339
|
+
comments2.forEach(({ comment, range }) => {
|
|
1340
|
+
if (head >= range.from && head <= range.to) {
|
|
1341
|
+
selection.current = comment.id;
|
|
1342
|
+
selection.closest = void 0;
|
|
1496
1343
|
}
|
|
1497
|
-
if (
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1344
|
+
if (!selection.current) {
|
|
1345
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1346
|
+
if (d < min) {
|
|
1347
|
+
selection.closest = comment.id;
|
|
1348
|
+
min = d;
|
|
1349
|
+
}
|
|
1501
1350
|
}
|
|
1502
|
-
|
|
1351
|
+
});
|
|
1352
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1353
|
+
view.dispatch({
|
|
1354
|
+
effects: setSelection.of(selection)
|
|
1355
|
+
});
|
|
1356
|
+
handleSelect({
|
|
1357
|
+
selection,
|
|
1358
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1359
|
+
comment,
|
|
1360
|
+
range,
|
|
1361
|
+
location: view.coordsAtPos(range.from)
|
|
1362
|
+
}))
|
|
1363
|
+
});
|
|
1503
1364
|
}
|
|
1365
|
+
}),
|
|
1366
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1367
|
+
];
|
|
1368
|
+
};
|
|
1369
|
+
var useComments = (view, comments2 = []) => {
|
|
1370
|
+
useEffect(() => {
|
|
1371
|
+
if (view) {
|
|
1372
|
+
view.dispatch({
|
|
1373
|
+
effects: setComments.of(comments2)
|
|
1374
|
+
});
|
|
1504
1375
|
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1376
|
+
}, [
|
|
1377
|
+
view,
|
|
1378
|
+
comments2
|
|
1379
|
+
]);
|
|
1507
1380
|
};
|
|
1508
1381
|
|
|
1509
|
-
// packages/ui/react-ui-editor/src/
|
|
1510
|
-
import {
|
|
1511
|
-
var listener = ({ onChange }) => {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1382
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1383
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1384
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1385
|
+
const extensions = [];
|
|
1386
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1387
|
+
onFocus(focused);
|
|
1388
|
+
return null;
|
|
1389
|
+
}));
|
|
1390
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1391
|
+
onChange(update2.state.doc.toString());
|
|
1392
|
+
}));
|
|
1393
|
+
return extensions;
|
|
1521
1394
|
};
|
|
1522
1395
|
|
|
1523
|
-
// packages/ui/react-ui-editor/src/
|
|
1396
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1524
1397
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1525
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1526
|
-
import { markdownLanguage as
|
|
1398
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1399
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1527
1400
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1528
1401
|
import { languages } from "@codemirror/language-data";
|
|
1529
1402
|
import { searchKeymap } from "@codemirror/search";
|
|
1530
1403
|
import { EditorState } from "@codemirror/state";
|
|
1531
1404
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1532
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1405
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1533
1406
|
|
|
1534
|
-
// packages/ui/react-ui-editor/src/
|
|
1535
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1407
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1408
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1536
1409
|
import { HighlightStyle } from "@codemirror/language";
|
|
1537
1410
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1538
1411
|
import { Table } from "@lezer/markdown";
|
|
1539
|
-
import get4 from "lodash.get";
|
|
1540
1412
|
var markdownTags = {
|
|
1541
1413
|
Blockquote: Tag.define(),
|
|
1542
1414
|
CodeMark: Tag.define(),
|
|
1543
1415
|
CodeText: Tag.define(),
|
|
1544
1416
|
EmphasisMark: Tag.define(),
|
|
1545
1417
|
HeaderMark: Tag.define(),
|
|
1546
|
-
// HorizontalRule: Tag.define(),
|
|
1547
1418
|
InlineCode: Tag.define(),
|
|
1548
1419
|
LinkLabel: Tag.define(),
|
|
1549
1420
|
LinkReference: Tag.define(),
|
|
@@ -1628,7 +1499,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1628
1499
|
markdownTags.QuoteMark,
|
|
1629
1500
|
markdownTags.EmphasisMark
|
|
1630
1501
|
],
|
|
1631
|
-
class:
|
|
1502
|
+
class: mark
|
|
1632
1503
|
},
|
|
1633
1504
|
// E.g., code block language (after ```).
|
|
1634
1505
|
{
|
|
@@ -1636,7 +1507,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1636
1507
|
tags.function(tags.variableName),
|
|
1637
1508
|
tags.labelName
|
|
1638
1509
|
],
|
|
1639
|
-
class:
|
|
1510
|
+
class: codeMark
|
|
1640
1511
|
},
|
|
1641
1512
|
{
|
|
1642
1513
|
tag: [
|
|
@@ -1647,27 +1518,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1647
1518
|
// Headings.
|
|
1648
1519
|
{
|
|
1649
1520
|
tag: tags.heading1,
|
|
1650
|
-
class: heading(1
|
|
1521
|
+
class: heading(1)
|
|
1651
1522
|
},
|
|
1652
1523
|
{
|
|
1653
1524
|
tag: tags.heading2,
|
|
1654
|
-
class: heading(2
|
|
1525
|
+
class: heading(2)
|
|
1655
1526
|
},
|
|
1656
1527
|
{
|
|
1657
1528
|
tag: tags.heading3,
|
|
1658
|
-
class: heading(3
|
|
1529
|
+
class: heading(3)
|
|
1659
1530
|
},
|
|
1660
1531
|
{
|
|
1661
1532
|
tag: tags.heading4,
|
|
1662
|
-
class: heading(4
|
|
1533
|
+
class: heading(4)
|
|
1663
1534
|
},
|
|
1664
1535
|
{
|
|
1665
1536
|
tag: tags.heading5,
|
|
1666
|
-
class: heading(5
|
|
1537
|
+
class: heading(5)
|
|
1667
1538
|
},
|
|
1668
1539
|
{
|
|
1669
1540
|
tag: tags.heading6,
|
|
1670
|
-
class: heading(6
|
|
1541
|
+
class: heading(6)
|
|
1671
1542
|
},
|
|
1672
1543
|
// Emphasis.
|
|
1673
1544
|
{
|
|
@@ -1693,7 +1564,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1693
1564
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1694
1565
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1695
1566
|
// the code, but all other CSS properties will be inherited.
|
|
1696
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1567
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1697
1568
|
{
|
|
1698
1569
|
tag: [
|
|
1699
1570
|
markdownTags.CodeText,
|
|
@@ -1707,12 +1578,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1707
1578
|
],
|
|
1708
1579
|
class: blockquote
|
|
1709
1580
|
},
|
|
1710
|
-
// TODO(burdon): Replace with extension.
|
|
1711
|
-
// {
|
|
1712
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1713
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1714
|
-
// },
|
|
1715
|
-
// TODO(burdon): Only if being edited.
|
|
1716
1581
|
{
|
|
1717
1582
|
tag: [
|
|
1718
1583
|
markdownTags.TableCell
|
|
@@ -1720,29 +1585,29 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1720
1585
|
class: "font-mono"
|
|
1721
1586
|
}
|
|
1722
1587
|
], {
|
|
1723
|
-
scope:
|
|
1588
|
+
scope: markdownLanguage2,
|
|
1724
1589
|
all: {
|
|
1725
|
-
fontFamily:
|
|
1590
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1726
1591
|
}
|
|
1727
1592
|
});
|
|
1728
1593
|
};
|
|
1729
1594
|
|
|
1730
|
-
// packages/ui/react-ui-editor/src/
|
|
1731
|
-
var markdownBundle = ({
|
|
1595
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1596
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1732
1597
|
return [
|
|
1733
1598
|
EditorState.allowMultipleSelections.of(true),
|
|
1734
1599
|
EditorState.tabSize.of(2),
|
|
1735
|
-
|
|
1736
|
-
|
|
1600
|
+
EditorView7.lineWrapping,
|
|
1601
|
+
// https://github.com/codemirror/basic-setup
|
|
1737
1602
|
bracketMatching2(),
|
|
1738
1603
|
closeBrackets2(),
|
|
1739
1604
|
crosshairCursor(),
|
|
1740
1605
|
dropCursor(),
|
|
1741
1606
|
drawSelection2(),
|
|
1742
|
-
|
|
1743
|
-
|
|
1607
|
+
highlightActiveLine2(),
|
|
1608
|
+
history2(),
|
|
1744
1609
|
indentOnInput(),
|
|
1745
|
-
_placeholder
|
|
1610
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1746
1611
|
// Main extension.
|
|
1747
1612
|
// https://github.com/codemirror/lang-markdown
|
|
1748
1613
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1752,7 +1617,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1752
1617
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1753
1618
|
// https://github.github.com/gfm
|
|
1754
1619
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1755
|
-
base:
|
|
1620
|
+
base: markdownLanguage3,
|
|
1756
1621
|
// Languages for syntax highlighting fenced code blocks.
|
|
1757
1622
|
codeLanguages: languages,
|
|
1758
1623
|
// Parser extensions.
|
|
@@ -1764,63 +1629,445 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1764
1629
|
// https://github.com/codemirror/theme-one-dark
|
|
1765
1630
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1766
1631
|
// Custom styles.
|
|
1767
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1632
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1633
|
+
keymap4.of([
|
|
1634
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1635
|
+
indentWithTab,
|
|
1636
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1637
|
+
...closeBracketsKeymap,
|
|
1638
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1639
|
+
...historyKeymap,
|
|
1640
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1641
|
+
...searchKeymap,
|
|
1642
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1643
|
+
...standardKeymap
|
|
1644
|
+
])
|
|
1645
|
+
];
|
|
1646
|
+
};
|
|
1782
1647
|
|
|
1783
|
-
// packages/ui/react-ui-editor/src/
|
|
1784
|
-
import {
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1648
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1649
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1650
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1651
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1652
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1653
|
+
var styles3 = EditorView8.baseTheme({
|
|
1654
|
+
"& .cm-code": {
|
|
1655
|
+
paddingInline: "1rem !important",
|
|
1656
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1657
|
+
},
|
|
1658
|
+
"& .cm-codeblock": {
|
|
1659
|
+
display: "inline-block",
|
|
1660
|
+
width: "100%"
|
|
1661
|
+
},
|
|
1662
|
+
"&light .cm-codeblock, &light .cm-codeblock.cm-activeLine": {
|
|
1663
|
+
background: getToken("extend.colors.neutral.25")
|
|
1664
|
+
},
|
|
1665
|
+
"&dark .cm-codeblock, &dark .cm-codeblock.cm-activeLine": {
|
|
1666
|
+
background: getToken("extend.colors.neutral.850")
|
|
1667
|
+
},
|
|
1668
|
+
"& .cm-codeblock-first": {
|
|
1669
|
+
borderTopLeftRadius: ".5rem",
|
|
1670
|
+
borderTopRightRadius: ".5rem"
|
|
1671
|
+
},
|
|
1672
|
+
"& .cm-codeblock-last": {
|
|
1673
|
+
borderBottomLeftRadius: ".5rem",
|
|
1674
|
+
borderBottomRightRadius: ".5rem"
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
var getLineRange = (lines, from, to) => {
|
|
1678
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1679
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1680
|
+
return [
|
|
1681
|
+
start,
|
|
1682
|
+
end
|
|
1683
|
+
];
|
|
1684
|
+
};
|
|
1685
|
+
var LineWidget = class extends WidgetType2 {
|
|
1686
|
+
constructor(_className) {
|
|
1687
|
+
super();
|
|
1688
|
+
this._className = _className;
|
|
1689
|
+
}
|
|
1690
|
+
toDOM() {
|
|
1691
|
+
const el = document.createElement("span");
|
|
1692
|
+
el.innerHTML = " ";
|
|
1693
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1694
|
+
return el;
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1698
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1699
|
+
var buildDecorations = (view) => {
|
|
1700
|
+
const builder = new RangeSetBuilder();
|
|
1701
|
+
const { state } = view;
|
|
1702
|
+
const blocks = view.viewportLineBlocks;
|
|
1703
|
+
const cursor = state.selection.main.head;
|
|
1704
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1705
|
+
syntaxTree(state).iterate({
|
|
1706
|
+
enter: (node) => {
|
|
1707
|
+
if (node.name === "FencedCode") {
|
|
1708
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1709
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1710
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1711
|
+
const block = blocks[i];
|
|
1712
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1713
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1714
|
+
widget: i === range[0] ? top : bottom
|
|
1715
|
+
}));
|
|
1716
|
+
} else {
|
|
1717
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1718
|
+
class: mx2("cm-code cm-codeblock")
|
|
1719
|
+
}));
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
from,
|
|
1725
|
+
to
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
return builder.finish();
|
|
1729
|
+
};
|
|
1730
|
+
var code2 = () => {
|
|
1731
|
+
return [
|
|
1732
|
+
ViewPlugin3.fromClass(class {
|
|
1733
|
+
constructor(view) {
|
|
1734
|
+
this.decorations = buildDecorations(view);
|
|
1735
|
+
}
|
|
1736
|
+
update(update2) {
|
|
1737
|
+
this.decorations = buildDecorations(update2.view);
|
|
1738
|
+
}
|
|
1739
|
+
}, {
|
|
1740
|
+
decorations: (value) => value.decorations
|
|
1741
|
+
}),
|
|
1742
|
+
styles3
|
|
1743
|
+
];
|
|
1744
|
+
};
|
|
1745
|
+
|
|
1746
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1747
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1748
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1749
|
+
import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1750
|
+
var buildDecorations2 = (view) => {
|
|
1751
|
+
const builder = new RangeSetBuilder2();
|
|
1752
|
+
const { state } = view;
|
|
1753
|
+
const cursor = state.selection.main.head;
|
|
1754
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1755
|
+
syntaxTree2(state).iterate({
|
|
1756
|
+
enter: (node) => {
|
|
1757
|
+
switch (node.name) {
|
|
1758
|
+
case "ATXHeading1":
|
|
1759
|
+
case "ATXHeading2":
|
|
1760
|
+
case "ATXHeading3":
|
|
1761
|
+
case "ATXHeading4":
|
|
1762
|
+
case "ATXHeading5":
|
|
1763
|
+
case "ATXHeading6": {
|
|
1764
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1765
|
+
if (mark2) {
|
|
1766
|
+
if (view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1767
|
+
builder.add(mark2.from, mark2.to + 1, Decoration4.replace({}));
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
from,
|
|
1774
|
+
to
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
return builder.finish();
|
|
1778
|
+
};
|
|
1779
|
+
var heading2 = () => {
|
|
1780
|
+
return [
|
|
1781
|
+
ViewPlugin4.fromClass(class {
|
|
1782
|
+
constructor(view) {
|
|
1783
|
+
this.decorations = buildDecorations2(view);
|
|
1784
|
+
}
|
|
1785
|
+
update(update2) {
|
|
1786
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1787
|
+
}
|
|
1788
|
+
}, {
|
|
1789
|
+
decorations: (value) => value.decorations
|
|
1790
|
+
})
|
|
1791
|
+
];
|
|
1792
|
+
};
|
|
1793
|
+
|
|
1794
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
1795
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1796
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1797
|
+
import { Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1798
|
+
var styles4 = EditorView9.baseTheme({
|
|
1799
|
+
"& .cm-hr": {
|
|
1800
|
+
// Note that block-level decorations should not have vertical margins,
|
|
1801
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1804
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1805
|
+
toDOM() {
|
|
1806
|
+
const el = document.createElement("div");
|
|
1807
|
+
el.className = "cm-hr";
|
|
1808
|
+
return el;
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
var decoration = Decoration5.replace({
|
|
1812
|
+
widget: new HorizontalRuleWidget()
|
|
1813
|
+
});
|
|
1814
|
+
var buildDecorations3 = (view) => {
|
|
1815
|
+
const builder = new RangeSetBuilder3();
|
|
1816
|
+
const { state } = view;
|
|
1817
|
+
const cursor = state.selection.main.head;
|
|
1818
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1819
|
+
syntaxTree3(state).iterate({
|
|
1820
|
+
enter: (node) => {
|
|
1821
|
+
if (node.name === "HorizontalRule") {
|
|
1822
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1823
|
+
builder.add(node.from, node.to, decoration);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
from,
|
|
1828
|
+
to
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
return builder.finish();
|
|
1832
|
+
};
|
|
1833
|
+
var hr = () => {
|
|
1834
|
+
return [
|
|
1835
|
+
ViewPlugin5.fromClass(class {
|
|
1836
|
+
constructor(view) {
|
|
1837
|
+
this.decorations = buildDecorations3(view);
|
|
1838
|
+
}
|
|
1839
|
+
update(update2) {
|
|
1840
|
+
this.decorations = buildDecorations3(update2.view);
|
|
1841
|
+
}
|
|
1842
|
+
}, {
|
|
1843
|
+
decorations: (value) => value.decorations
|
|
1844
|
+
}),
|
|
1845
|
+
styles4
|
|
1846
|
+
];
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
1850
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
1851
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1852
|
+
import { Decoration as Decoration6, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1853
|
+
var image = (options = {}) => {
|
|
1854
|
+
return StateField3.define({
|
|
1855
|
+
create: (state) => {
|
|
1856
|
+
return Decoration6.set(buildDecorations4(0, state.doc.length, state));
|
|
1857
|
+
},
|
|
1858
|
+
update: (value, tr) => {
|
|
1859
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1860
|
+
return value;
|
|
1861
|
+
}
|
|
1862
|
+
const cursor = tr.state.selection.main.head;
|
|
1863
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1864
|
+
let from = Math.min(cursor, oldCursor);
|
|
1865
|
+
let to = Math.max(cursor, oldCursor);
|
|
1866
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1867
|
+
from = Math.min(from, fromB);
|
|
1868
|
+
to = Math.max(to, toB);
|
|
1869
|
+
});
|
|
1870
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1871
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1872
|
+
return value.map(tr.changes).update({
|
|
1873
|
+
filterFrom: from,
|
|
1874
|
+
filterTo: to,
|
|
1875
|
+
filter: () => false,
|
|
1876
|
+
add: buildDecorations4(from, to, tr.state)
|
|
1877
|
+
});
|
|
1878
|
+
},
|
|
1879
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
1880
|
+
});
|
|
1881
|
+
};
|
|
1882
|
+
var buildDecorations4 = (from, to, state) => {
|
|
1883
|
+
const decorations = [];
|
|
1884
|
+
const cursor = state.selection.main.head;
|
|
1885
|
+
syntaxTree4(state).iterate({
|
|
1886
|
+
enter: (node) => {
|
|
1887
|
+
if (node.name === "Image") {
|
|
1888
|
+
const urlNode = node.node.getChild("URL");
|
|
1889
|
+
if (urlNode) {
|
|
1890
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1891
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1892
|
+
decorations.push(Decoration6.replace({
|
|
1893
|
+
block: true,
|
|
1894
|
+
widget: new ImageWidget(url)
|
|
1895
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
},
|
|
1899
|
+
from,
|
|
1900
|
+
to
|
|
1901
|
+
});
|
|
1902
|
+
return decorations;
|
|
1903
|
+
};
|
|
1904
|
+
var ImageWidget = class extends WidgetType4 {
|
|
1905
|
+
constructor(_url) {
|
|
1906
|
+
super();
|
|
1907
|
+
this._url = _url;
|
|
1908
|
+
}
|
|
1909
|
+
eq(other) {
|
|
1910
|
+
return this._url === other._url;
|
|
1911
|
+
}
|
|
1912
|
+
toDOM(view) {
|
|
1913
|
+
const img = document.createElement("img");
|
|
1914
|
+
img.setAttribute("src", this._url);
|
|
1915
|
+
img.setAttribute("class", "cm-image");
|
|
1916
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1917
|
+
return img;
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
1922
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
1923
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
1924
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration7, ViewPlugin as ViewPlugin6, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1925
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1926
|
+
var link = (options = {}) => {
|
|
1927
|
+
const extensions = [
|
|
1928
|
+
ViewPlugin6.fromClass(class {
|
|
1929
|
+
constructor(view) {
|
|
1930
|
+
this.decorations = buildDecorations5(view, options);
|
|
1931
|
+
}
|
|
1932
|
+
update(update2) {
|
|
1933
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1934
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}, {
|
|
1938
|
+
decorations: (value) => value.decorations
|
|
1939
|
+
})
|
|
1940
|
+
];
|
|
1941
|
+
if (options.onHover) {
|
|
1942
|
+
extensions.push(
|
|
1943
|
+
// https://codemirror.net/examples/tooltip
|
|
1944
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1945
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1946
|
+
hoverTooltip2((view, pos, side) => {
|
|
1947
|
+
const syntax = syntaxTree5(view.state).resolveInner(pos, side);
|
|
1948
|
+
let link2 = null;
|
|
1949
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1950
|
+
link2 = node.name === "Link" ? node : null;
|
|
1951
|
+
}
|
|
1952
|
+
const url = link2 && link2.getChild("URL");
|
|
1953
|
+
if (!url || !link2) {
|
|
1792
1954
|
return null;
|
|
1793
1955
|
}
|
|
1794
|
-
|
|
1956
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1795
1957
|
return {
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1958
|
+
pos: link2.from,
|
|
1959
|
+
end: link2.to,
|
|
1960
|
+
above: true,
|
|
1961
|
+
create: () => {
|
|
1962
|
+
const el = document.createElement("div");
|
|
1963
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1964
|
+
options.onHover(el, urlText);
|
|
1965
|
+
return {
|
|
1966
|
+
dom: el,
|
|
1967
|
+
offset: {
|
|
1968
|
+
x: 0,
|
|
1969
|
+
y: 4
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1800
1973
|
};
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
}
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
return extensions;
|
|
1978
|
+
};
|
|
1979
|
+
var LinkButton = class extends WidgetType5 {
|
|
1980
|
+
constructor(_url, _onAttach) {
|
|
1981
|
+
super();
|
|
1982
|
+
this._url = _url;
|
|
1983
|
+
this._onAttach = _onAttach;
|
|
1984
|
+
}
|
|
1985
|
+
eq(other) {
|
|
1986
|
+
return this._url === other._url;
|
|
1987
|
+
}
|
|
1988
|
+
toDOM(view) {
|
|
1989
|
+
const el = document.createElement("span");
|
|
1990
|
+
this._onAttach(el, this._url);
|
|
1991
|
+
return el;
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
var LinkText = class extends WidgetType5 {
|
|
1995
|
+
constructor(_text, _url) {
|
|
1996
|
+
super();
|
|
1997
|
+
this._text = _text;
|
|
1998
|
+
this._url = _url;
|
|
1999
|
+
}
|
|
2000
|
+
eq(other) {
|
|
2001
|
+
return this._url === other._url;
|
|
2002
|
+
}
|
|
2003
|
+
toDOM(view) {
|
|
2004
|
+
const link2 = document.createElement("a");
|
|
2005
|
+
link2.setAttribute("class", "cm-link");
|
|
2006
|
+
link2.textContent = this._text;
|
|
2007
|
+
if (this._url) {
|
|
2008
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2009
|
+
link2.setAttribute("target", "_blank");
|
|
2010
|
+
link2.href = this._url;
|
|
2011
|
+
} else {
|
|
2012
|
+
link2.onclick = () => {
|
|
2013
|
+
view.dispatch({
|
|
2014
|
+
selection: {
|
|
2015
|
+
anchor: view.posAtDOM(link2)
|
|
2016
|
+
}
|
|
2017
|
+
});
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
return link2;
|
|
2021
|
+
}
|
|
1804
2022
|
};
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
2023
|
+
var buildDecorations5 = (view, options) => {
|
|
2024
|
+
const builder = new RangeSetBuilder4();
|
|
2025
|
+
const { state } = view;
|
|
2026
|
+
const cursor = state.selection.main.head;
|
|
2027
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2028
|
+
syntaxTree5(state).iterate({
|
|
2029
|
+
enter: (node) => {
|
|
2030
|
+
if (node.name === "Link") {
|
|
2031
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
2032
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
2033
|
+
const urlNode = node.node.getChild("URL");
|
|
2034
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2035
|
+
if (!url) {
|
|
2036
|
+
return false;
|
|
2037
|
+
}
|
|
2038
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2039
|
+
builder.add(node.from, node.to, Decoration7.replace({
|
|
2040
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2041
|
+
}));
|
|
2042
|
+
}
|
|
2043
|
+
if (options.onRender) {
|
|
2044
|
+
builder.add(node.to, node.to, Decoration7.replace({
|
|
2045
|
+
widget: new LinkButton(url, options.onRender)
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
return false;
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
from,
|
|
2052
|
+
to
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
return builder.finish();
|
|
1809
2056
|
};
|
|
1810
2057
|
|
|
1811
|
-
// packages/ui/react-ui-editor/src/
|
|
1812
|
-
import { syntaxTree as
|
|
1813
|
-
import { RangeSetBuilder as
|
|
1814
|
-
import { Decoration as
|
|
2058
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2059
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2060
|
+
import { RangeSetBuilder as RangeSetBuilder5, StateField as StateField4 } from "@codemirror/state";
|
|
2061
|
+
import { Decoration as Decoration8, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1815
2062
|
var table = (options = {}) => {
|
|
1816
|
-
return
|
|
1817
|
-
create: (state) =>
|
|
1818
|
-
update: (_, tr) =>
|
|
1819
|
-
provide: (field) =>
|
|
2063
|
+
return StateField4.define({
|
|
2064
|
+
create: (state) => update(state, options),
|
|
2065
|
+
update: (_, tr) => update(tr.state, options),
|
|
2066
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1820
2067
|
});
|
|
1821
2068
|
};
|
|
1822
|
-
var
|
|
1823
|
-
const builder = new
|
|
2069
|
+
var update = (state, options) => {
|
|
2070
|
+
const builder = new RangeSetBuilder5();
|
|
1824
2071
|
const cursor = state.selection.main.head;
|
|
1825
2072
|
const tables = [];
|
|
1826
2073
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1828,7 +2075,7 @@ var update3 = (state, options) => {
|
|
|
1828
2075
|
const table2 = getTable();
|
|
1829
2076
|
return table2.rows?.[table2.rows.length - 1];
|
|
1830
2077
|
};
|
|
1831
|
-
|
|
2078
|
+
syntaxTree6(state).iterate({
|
|
1832
2079
|
enter: (node) => {
|
|
1833
2080
|
switch (node.name) {
|
|
1834
2081
|
case "Table": {
|
|
@@ -1860,23 +2107,22 @@ var update3 = (state, options) => {
|
|
|
1860
2107
|
});
|
|
1861
2108
|
tables.forEach((table2) => {
|
|
1862
2109
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1863
|
-
hide && builder.add(table2.from, table2.to,
|
|
1864
|
-
block: true,
|
|
2110
|
+
hide && builder.add(table2.from, table2.to, Decoration8.replace({
|
|
1865
2111
|
widget: new TableWidget(table2)
|
|
1866
2112
|
}));
|
|
1867
|
-
builder.add(table2.from, table2.to,
|
|
2113
|
+
builder.add(table2.from, table2.to, Decoration8.mark({
|
|
1868
2114
|
class: "cm-table"
|
|
1869
2115
|
}));
|
|
1870
2116
|
});
|
|
1871
2117
|
return builder.finish();
|
|
1872
2118
|
};
|
|
1873
|
-
var TableWidget = class extends
|
|
2119
|
+
var TableWidget = class extends WidgetType6 {
|
|
1874
2120
|
constructor(_table) {
|
|
1875
2121
|
super();
|
|
1876
2122
|
this._table = _table;
|
|
1877
2123
|
}
|
|
1878
2124
|
eq(other) {
|
|
1879
|
-
return this._table.
|
|
2125
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1880
2126
|
}
|
|
1881
2127
|
toDOM(view) {
|
|
1882
2128
|
const table2 = document.createElement("table");
|
|
@@ -1902,138 +2148,143 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1902
2148
|
}
|
|
1903
2149
|
return table2;
|
|
1904
2150
|
}
|
|
2151
|
+
ignoreEvent(e) {
|
|
2152
|
+
return !/^mouse/.test(e.type);
|
|
2153
|
+
}
|
|
1905
2154
|
};
|
|
1906
2155
|
|
|
1907
|
-
// packages/ui/react-ui-editor/src/
|
|
1908
|
-
import {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2156
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2157
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2158
|
+
import { RangeSetBuilder as RangeSetBuilder6 } from "@codemirror/state";
|
|
2159
|
+
import { EditorView as EditorView12, Decoration as Decoration9, WidgetType as WidgetType7, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
|
|
2160
|
+
var styles5 = EditorView12.baseTheme({
|
|
2161
|
+
"& .cm-task": {
|
|
2162
|
+
color: getToken("extend.colors.blue.500")
|
|
2163
|
+
},
|
|
2164
|
+
"& .cm-task-checkbox": {
|
|
2165
|
+
marginLeft: "4px",
|
|
2166
|
+
marginRight: "4px"
|
|
1913
2167
|
}
|
|
1914
2168
|
});
|
|
1915
|
-
var CheckboxWidget = class extends
|
|
1916
|
-
constructor(
|
|
2169
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2170
|
+
constructor(_checked) {
|
|
1917
2171
|
super();
|
|
1918
|
-
this._pos = _pos;
|
|
1919
2172
|
this._checked = _checked;
|
|
1920
|
-
this._indent = _indent;
|
|
1921
|
-
this._onCheck = _onCheck;
|
|
1922
2173
|
}
|
|
1923
2174
|
eq(other) {
|
|
1924
|
-
return this.
|
|
2175
|
+
return this._checked === other._checked;
|
|
1925
2176
|
}
|
|
1926
2177
|
toDOM(view) {
|
|
1927
|
-
const
|
|
1928
|
-
|
|
1929
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
1930
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
1931
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2178
|
+
const input = document.createElement("input");
|
|
2179
|
+
input.className = "cm-task-checkbox";
|
|
1932
2180
|
input.type = "checkbox";
|
|
1933
2181
|
input.checked = this._checked;
|
|
1934
|
-
if (
|
|
2182
|
+
if (view.state.readOnly) {
|
|
1935
2183
|
input.setAttribute("disabled", "true");
|
|
1936
|
-
}
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2184
|
+
} else {
|
|
2185
|
+
input.onmousedown = (event) => {
|
|
2186
|
+
const pos = view.posAtDOM(input);
|
|
2187
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2188
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2189
|
+
view.dispatch({
|
|
2190
|
+
changes: {
|
|
2191
|
+
from: pos + 1,
|
|
2192
|
+
to: pos + 2,
|
|
2193
|
+
insert: this._checked ? " " : "x"
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
event.preventDefault();
|
|
2197
|
+
}
|
|
1941
2198
|
};
|
|
1942
2199
|
}
|
|
1943
|
-
return
|
|
2200
|
+
return input;
|
|
1944
2201
|
}
|
|
1945
2202
|
ignoreEvent() {
|
|
1946
2203
|
return false;
|
|
1947
2204
|
}
|
|
1948
2205
|
};
|
|
2206
|
+
var checkedDecoration = Decoration9.replace({
|
|
2207
|
+
widget: new CheckboxWidget(true)
|
|
2208
|
+
});
|
|
2209
|
+
var uncheckedDecoration = Decoration9.replace({
|
|
2210
|
+
widget: new CheckboxWidget(false)
|
|
2211
|
+
});
|
|
2212
|
+
var buildDecorations6 = (view) => {
|
|
2213
|
+
const builder = new RangeSetBuilder6();
|
|
2214
|
+
const { state } = view;
|
|
2215
|
+
const cursor = state.selection.main.head;
|
|
2216
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2217
|
+
syntaxTree7(state).iterate({
|
|
2218
|
+
enter: (node) => {
|
|
2219
|
+
if (node.name === "TaskMarker") {
|
|
2220
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2221
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2222
|
+
builder.add(node.from - 2, node.from - 1, Decoration9.mark({
|
|
2223
|
+
class: "cm-task"
|
|
2224
|
+
}));
|
|
2225
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
},
|
|
2229
|
+
from,
|
|
2230
|
+
to
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
return builder.finish();
|
|
2234
|
+
};
|
|
1949
2235
|
var tasklist = (options = {}) => {
|
|
1950
|
-
const taskMatcher = new MatchDecorator3({
|
|
1951
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
1952
|
-
decoration: (match, view, pos) => {
|
|
1953
|
-
const indent = Math.floor(match[1].length / 2);
|
|
1954
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
1955
|
-
return Decoration7.replace({
|
|
1956
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
1957
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
1958
|
-
view.dispatch({
|
|
1959
|
-
changes: {
|
|
1960
|
-
from: idx,
|
|
1961
|
-
to: idx + 1,
|
|
1962
|
-
insert: checked2 ? "x" : " "
|
|
1963
|
-
},
|
|
1964
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
1965
|
-
selection: {
|
|
1966
|
-
anchor: idx + 3
|
|
1967
|
-
}
|
|
1968
|
-
});
|
|
1969
|
-
})
|
|
1970
|
-
});
|
|
1971
|
-
}
|
|
1972
|
-
});
|
|
1973
|
-
const tasks = ViewPlugin5.fromClass(class {
|
|
1974
|
-
constructor(view) {
|
|
1975
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
1976
|
-
}
|
|
1977
|
-
update(update4) {
|
|
1978
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
1979
|
-
}
|
|
1980
|
-
}, {
|
|
1981
|
-
decorations: (value) => value.tasks,
|
|
1982
|
-
provide: (plugin) => EditorView10.atomicRanges.of((view) => {
|
|
1983
|
-
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
1984
|
-
})
|
|
1985
|
-
});
|
|
1986
2236
|
return [
|
|
1987
|
-
|
|
1988
|
-
|
|
2237
|
+
ViewPlugin7.fromClass(class {
|
|
2238
|
+
constructor(view) {
|
|
2239
|
+
this.decorations = buildDecorations6(view);
|
|
2240
|
+
}
|
|
2241
|
+
update(update2) {
|
|
2242
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2243
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}, {
|
|
2247
|
+
decorations: (value) => value.decorations
|
|
2248
|
+
}),
|
|
2249
|
+
styles5
|
|
1989
2250
|
];
|
|
1990
2251
|
};
|
|
1991
2252
|
|
|
1992
|
-
// packages/ui/react-ui-editor/src/
|
|
1993
|
-
import {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
break;
|
|
2010
|
-
}
|
|
2011
|
-
idx += match[0].length;
|
|
2012
|
-
} while (true);
|
|
2013
|
-
if (!match) {
|
|
2014
|
-
return null;
|
|
2015
|
-
}
|
|
2016
|
-
const [, , url] = match ?? [];
|
|
2017
|
-
return {
|
|
2018
|
-
pos: idx + from,
|
|
2019
|
-
end: idx + from + match[0].length,
|
|
2020
|
-
above: true,
|
|
2021
|
-
create: () => {
|
|
2022
|
-
const el = document.createElement("div");
|
|
2023
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2024
|
-
onHover(el, url);
|
|
2025
|
-
return {
|
|
2026
|
-
dom: el,
|
|
2027
|
-
offset: {
|
|
2028
|
-
x: 0,
|
|
2029
|
-
y: 4
|
|
2253
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2254
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2255
|
+
var mention = ({ onSearch }) => {
|
|
2256
|
+
return autocompletion2({
|
|
2257
|
+
// TODO(burdon): Not working.
|
|
2258
|
+
activateOnTyping: true,
|
|
2259
|
+
// activateOnTypingDelay: 100,
|
|
2260
|
+
// selectOnOpen: true,
|
|
2261
|
+
closeOnBlur: false,
|
|
2262
|
+
// defaultKeymap: false,
|
|
2263
|
+
icons: false,
|
|
2264
|
+
override: [
|
|
2265
|
+
(context) => {
|
|
2266
|
+
console.log(context);
|
|
2267
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2268
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2269
|
+
return null;
|
|
2030
2270
|
}
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
}
|
|
2271
|
+
return {
|
|
2272
|
+
from: match.from,
|
|
2273
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2274
|
+
label: `@${value}`
|
|
2275
|
+
}))
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
]
|
|
2279
|
+
});
|
|
2280
|
+
};
|
|
2281
|
+
|
|
2282
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2283
|
+
var outliner = (options = {}) => {
|
|
2284
|
+
return [];
|
|
2285
|
+
};
|
|
2035
2286
|
|
|
2036
|
-
// packages/ui/react-ui-editor/src/
|
|
2287
|
+
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2037
2288
|
import { keymap as keymap5 } from "@codemirror/view";
|
|
2038
2289
|
var defaultItems = [
|
|
2039
2290
|
"hello world!",
|
|
@@ -2090,8 +2341,8 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2090
2341
|
];
|
|
2091
2342
|
};
|
|
2092
2343
|
|
|
2093
|
-
// packages/ui/react-ui-editor/src/
|
|
2094
|
-
import
|
|
2344
|
+
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2345
|
+
import get3 from "lodash.get";
|
|
2095
2346
|
var defaultTheme = {
|
|
2096
2347
|
//
|
|
2097
2348
|
// Main layout:
|
|
@@ -2120,21 +2371,21 @@ var defaultTheme = {
|
|
|
2120
2371
|
"&.cm-focused": {
|
|
2121
2372
|
outline: "none"
|
|
2122
2373
|
},
|
|
2123
|
-
"
|
|
2374
|
+
".cm-scroller": {
|
|
2124
2375
|
overflow: "visible",
|
|
2125
|
-
fontFamily:
|
|
2376
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2126
2377
|
},
|
|
2127
|
-
"
|
|
2378
|
+
".cm-content": {
|
|
2128
2379
|
padding: 0,
|
|
2129
2380
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2130
2381
|
fontSize: "16px"
|
|
2131
2382
|
},
|
|
2132
2383
|
"&light .cm-content": {
|
|
2133
|
-
color:
|
|
2384
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2134
2385
|
caretColor: "black"
|
|
2135
2386
|
},
|
|
2136
2387
|
"&dark .cm-content": {
|
|
2137
|
-
color:
|
|
2388
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2138
2389
|
caretColor: "white"
|
|
2139
2390
|
},
|
|
2140
2391
|
//
|
|
@@ -2146,158 +2397,120 @@ var defaultTheme = {
|
|
|
2146
2397
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2147
2398
|
borderLeft: "2px solid white"
|
|
2148
2399
|
},
|
|
2149
|
-
"
|
|
2400
|
+
".cm-placeholder": {
|
|
2150
2401
|
fontWeight: 100
|
|
2151
2402
|
},
|
|
2152
2403
|
//
|
|
2153
2404
|
// line
|
|
2154
2405
|
//
|
|
2155
|
-
"
|
|
2406
|
+
".cm-line": {
|
|
2156
2407
|
paddingInline: 0
|
|
2157
2408
|
},
|
|
2158
|
-
"
|
|
2409
|
+
".cm-activeLine": {
|
|
2159
2410
|
background: "inherit"
|
|
2160
2411
|
},
|
|
2161
2412
|
//
|
|
2162
2413
|
// Selection
|
|
2163
2414
|
//
|
|
2164
2415
|
"&light .cm-selectionBackground": {
|
|
2165
|
-
background:
|
|
2416
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2166
2417
|
},
|
|
2167
2418
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2168
|
-
background:
|
|
2419
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2169
2420
|
},
|
|
2170
2421
|
"&dark .cm-selectionBackground": {
|
|
2171
|
-
background:
|
|
2422
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2172
2423
|
},
|
|
2173
2424
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2174
|
-
background:
|
|
2425
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2175
2426
|
},
|
|
2176
2427
|
//
|
|
2177
2428
|
// Search
|
|
2178
2429
|
//
|
|
2179
2430
|
"&light .cm-searchMatch": {
|
|
2180
|
-
backgroundColor:
|
|
2431
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2181
2432
|
},
|
|
2182
2433
|
"&dark .cm-searchMatch": {
|
|
2183
|
-
backgroundColor:
|
|
2184
|
-
},
|
|
2185
|
-
//
|
|
2186
|
-
// collaboration
|
|
2187
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2188
|
-
//
|
|
2189
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2190
|
-
mixBlendMode: "multiply"
|
|
2191
|
-
},
|
|
2192
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2193
|
-
mixBlendMode: "screen"
|
|
2194
|
-
},
|
|
2195
|
-
"& .cm-ySelectionInfo": {
|
|
2196
|
-
padding: "2px 4px",
|
|
2197
|
-
marginBlockStart: "-4px"
|
|
2198
|
-
},
|
|
2199
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2200
|
-
paddingBlockStart: ".15em",
|
|
2201
|
-
paddingBlockEnd: ".15em"
|
|
2202
|
-
},
|
|
2203
|
-
"& .cm-ySelectionCaret": {
|
|
2204
|
-
display: "inline-block",
|
|
2205
|
-
insetBlockStart: ".1em",
|
|
2206
|
-
blockSize: "1.4em",
|
|
2207
|
-
verticalAlign: "top"
|
|
2208
|
-
},
|
|
2209
|
-
"& .cm-yLineSelection": {
|
|
2210
|
-
margin: 0
|
|
2434
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2211
2435
|
},
|
|
2212
2436
|
//
|
|
2213
2437
|
// link
|
|
2214
2438
|
//
|
|
2215
|
-
"
|
|
2216
|
-
color:
|
|
2439
|
+
".cm-link": {
|
|
2440
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2217
2441
|
textDecorationLine: "underline",
|
|
2218
2442
|
textDecorationThickness: "1px",
|
|
2219
2443
|
textUnderlineOffset: "2px",
|
|
2220
2444
|
borderRadius: ".125rem",
|
|
2221
|
-
fontFamily:
|
|
2445
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2222
2446
|
},
|
|
2223
2447
|
//
|
|
2224
2448
|
// tooltip
|
|
2225
2449
|
//
|
|
2226
|
-
"
|
|
2450
|
+
".cm-tooltip": {
|
|
2227
2451
|
border: "none"
|
|
2228
2452
|
},
|
|
2229
|
-
"
|
|
2453
|
+
".cm-tooltip-below": {},
|
|
2230
2454
|
//
|
|
2231
2455
|
// autocomplete
|
|
2232
2456
|
//
|
|
2233
|
-
"
|
|
2457
|
+
".cm-tooltip-autocomplete": {
|
|
2234
2458
|
marginTop: "4px",
|
|
2235
2459
|
marginLeft: "-3px"
|
|
2236
2460
|
},
|
|
2237
|
-
"
|
|
2238
|
-
"
|
|
2239
|
-
"
|
|
2461
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2462
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2463
|
+
".cm-completionIcon": {
|
|
2240
2464
|
display: "none"
|
|
2241
2465
|
},
|
|
2242
|
-
"
|
|
2243
|
-
fontFamily:
|
|
2466
|
+
".cm-completionLabel": {
|
|
2467
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2244
2468
|
},
|
|
2245
|
-
"
|
|
2469
|
+
".cm-completionMatchedText": {
|
|
2246
2470
|
textDecoration: "none"
|
|
2247
2471
|
},
|
|
2248
2472
|
//
|
|
2249
|
-
// widgets
|
|
2250
|
-
//
|
|
2251
|
-
"& .cm-widgetBuffer": {
|
|
2252
|
-
display: "none",
|
|
2253
|
-
height: 0
|
|
2254
|
-
},
|
|
2255
|
-
//
|
|
2256
2473
|
// table
|
|
2257
2474
|
//
|
|
2258
|
-
"
|
|
2259
|
-
fontFamily: `${
|
|
2475
|
+
".cm-table *": {
|
|
2476
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2260
2477
|
textDecoration: "none !important"
|
|
2261
2478
|
},
|
|
2262
|
-
"
|
|
2479
|
+
".cm-table-head": {
|
|
2263
2480
|
padding: "2px 16px 2px 0px",
|
|
2264
|
-
borderBottom: `1px solid ${
|
|
2481
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2265
2482
|
fontWeight: 100,
|
|
2266
2483
|
textAlign: "left",
|
|
2267
|
-
color:
|
|
2484
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2268
2485
|
},
|
|
2269
|
-
"
|
|
2486
|
+
".cm-table-cell": {
|
|
2270
2487
|
padding: "2px 16px 2px 0px"
|
|
2271
2488
|
},
|
|
2272
2489
|
//
|
|
2273
2490
|
// image
|
|
2274
2491
|
//
|
|
2275
|
-
"
|
|
2276
|
-
|
|
2492
|
+
".cm-image": {
|
|
2493
|
+
display: "block",
|
|
2494
|
+
height: "0"
|
|
2495
|
+
},
|
|
2496
|
+
".cm-image.cm-loaded-image": {
|
|
2497
|
+
height: "auto",
|
|
2498
|
+
borderTop: "0.5rem solid transparent",
|
|
2499
|
+
borderBottom: "0.5rem solid transparent"
|
|
2277
2500
|
},
|
|
2278
2501
|
//
|
|
2279
2502
|
// font size
|
|
2280
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2503
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2504
|
+
// but it's far more verbose than it needs to be.
|
|
2281
2505
|
//
|
|
2282
|
-
...Object.keys(
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2291
|
-
height
|
|
2292
|
-
};
|
|
2293
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2294
|
-
height
|
|
2295
|
-
};
|
|
2296
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2297
|
-
height
|
|
2298
|
-
};
|
|
2299
|
-
return acc;
|
|
2300
|
-
}, {}),
|
|
2506
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2507
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2508
|
+
//
|
|
2509
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2510
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2511
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2512
|
+
// return acc;
|
|
2513
|
+
// }, {}),
|
|
2301
2514
|
/**
|
|
2302
2515
|
* Panels
|
|
2303
2516
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2314,153 +2527,140 @@ var defaultTheme = {
|
|
|
2314
2527
|
* </div>
|
|
2315
2528
|
* </div
|
|
2316
2529
|
*/
|
|
2317
|
-
"
|
|
2318
|
-
border: `1px solid ${
|
|
2530
|
+
".cm-panels": {
|
|
2531
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2319
2532
|
},
|
|
2320
|
-
"
|
|
2321
|
-
background:
|
|
2322
|
-
fontFamily:
|
|
2533
|
+
".cm-panel": {
|
|
2534
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2535
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2323
2536
|
},
|
|
2324
|
-
"
|
|
2537
|
+
".cm-button": {
|
|
2325
2538
|
margin: "4px",
|
|
2326
|
-
fontFamily:
|
|
2327
|
-
background:
|
|
2539
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2540
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2328
2541
|
backgroundImage: "none",
|
|
2329
2542
|
border: "none",
|
|
2330
2543
|
"&:hover": {
|
|
2331
|
-
background:
|
|
2544
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2332
2545
|
},
|
|
2333
2546
|
"&:active": {
|
|
2334
|
-
background:
|
|
2547
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2335
2548
|
backgroundImage: "none"
|
|
2336
2549
|
}
|
|
2337
2550
|
},
|
|
2338
|
-
"
|
|
2551
|
+
".cm-panel input[type=checkbox]": {
|
|
2339
2552
|
marginRight: "0.4rem !important"
|
|
2340
2553
|
}
|
|
2341
2554
|
};
|
|
2342
2555
|
var textTheme = {
|
|
2343
|
-
"
|
|
2344
|
-
fontFamily:
|
|
2556
|
+
".cm-scroller": {
|
|
2557
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2345
2558
|
},
|
|
2346
|
-
"
|
|
2347
|
-
fontFamily:
|
|
2559
|
+
".cm-placeholder": {
|
|
2560
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2348
2561
|
}
|
|
2349
2562
|
};
|
|
2350
2563
|
var markdownTheme = {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2564
|
+
".cm-scroller": {
|
|
2565
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2566
|
+
},
|
|
2567
|
+
".cm-placeholder": {
|
|
2568
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2354
2569
|
}
|
|
2355
2570
|
};
|
|
2356
2571
|
var codeTheme = {
|
|
2357
|
-
"
|
|
2358
|
-
fontFamily:
|
|
2572
|
+
".cm-scroller": {
|
|
2573
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2359
2574
|
},
|
|
2360
|
-
"
|
|
2361
|
-
fontFamily:
|
|
2575
|
+
".cm-placeholder": {
|
|
2576
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2362
2577
|
}
|
|
2363
2578
|
};
|
|
2364
2579
|
|
|
2365
2580
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2366
|
-
|
|
2367
|
-
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
2368
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
2369
|
-
import { vim } from "@replit/codemirror-vim";
|
|
2370
|
-
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
2371
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState as useState2 } from "react";
|
|
2372
|
-
import { generateName } from "@dxos/display-name";
|
|
2373
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
2374
|
-
import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
2581
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2375
2582
|
var EditorModes = [
|
|
2376
2583
|
"default",
|
|
2377
2584
|
"vim"
|
|
2378
2585
|
];
|
|
2379
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2380
|
-
const { themeMode } = useThemeContext();
|
|
2586
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2381
2587
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2382
2588
|
tabBehavior: "limited"
|
|
2383
2589
|
});
|
|
2384
|
-
const
|
|
2385
|
-
const
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
state,
|
|
2590
|
+
const { themeMode } = useThemeContext();
|
|
2591
|
+
const rootRef = useRef(null);
|
|
2592
|
+
const [view, setView] = useState(null);
|
|
2593
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2389
2594
|
view
|
|
2390
|
-
}), [
|
|
2391
|
-
view,
|
|
2392
|
-
state,
|
|
2393
|
-
root
|
|
2394
|
-
]);
|
|
2395
|
-
const { awareness, peer } = model;
|
|
2396
|
-
useEffect2(() => {
|
|
2397
|
-
if (awareness && peer) {
|
|
2398
|
-
awareness.setLocalStateField("user", {
|
|
2399
|
-
name: peer.name ?? generateName(peer.id),
|
|
2400
|
-
color: getColorForValue({
|
|
2401
|
-
value: peer.id,
|
|
2402
|
-
type: "color"
|
|
2403
|
-
}),
|
|
2404
|
-
colorLight: getColorForValue({
|
|
2405
|
-
value: peer.id,
|
|
2406
|
-
themeMode,
|
|
2407
|
-
type: "highlight"
|
|
2408
|
-
})
|
|
2409
|
-
});
|
|
2410
|
-
}
|
|
2411
|
-
}, [
|
|
2412
|
-
awareness,
|
|
2413
|
-
peer,
|
|
2414
|
-
themeMode
|
|
2415
2595
|
]);
|
|
2416
2596
|
useEffect2(() => {
|
|
2417
|
-
if (
|
|
2418
|
-
view
|
|
2419
|
-
effects: setCommentRange.of({
|
|
2420
|
-
model,
|
|
2421
|
-
comments: comments2
|
|
2422
|
-
})
|
|
2423
|
-
});
|
|
2597
|
+
if (autoFocus) {
|
|
2598
|
+
view?.focus();
|
|
2424
2599
|
}
|
|
2425
2600
|
}, [
|
|
2426
2601
|
view,
|
|
2427
|
-
|
|
2602
|
+
autoFocus
|
|
2428
2603
|
]);
|
|
2429
2604
|
useEffect2(() => {
|
|
2430
|
-
if (!
|
|
2605
|
+
if (!model || !rootRef.current) {
|
|
2431
2606
|
return;
|
|
2432
2607
|
}
|
|
2433
|
-
const
|
|
2608
|
+
const state = EditorState2.create({
|
|
2434
2609
|
doc: model.text(),
|
|
2610
|
+
selection,
|
|
2435
2611
|
extensions: [
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2612
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2613
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2614
|
+
log2.catch(err, void 0, {
|
|
2615
|
+
F: __dxlog_file5,
|
|
2616
|
+
L: 123,
|
|
2617
|
+
S: void 0,
|
|
2618
|
+
C: (f, a) => f(...a)
|
|
2619
|
+
});
|
|
2620
|
+
}),
|
|
2439
2621
|
// Theme.
|
|
2440
|
-
// TODO(burdon): Make
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2622
|
+
// TODO(burdon): Make configurable.
|
|
2623
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2624
|
+
EditorView13.theme(theme ?? {}),
|
|
2625
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2626
|
+
EditorView13.editorAttributes.of({
|
|
2627
|
+
class: slots.editor?.className ?? ""
|
|
2628
|
+
}),
|
|
2629
|
+
EditorView13.contentAttributes.of({
|
|
2630
|
+
class: slots.content?.className ?? ""
|
|
2631
|
+
}),
|
|
2632
|
+
// State.
|
|
2633
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2444
2634
|
// Storage and replication.
|
|
2635
|
+
// NOTE: This must come before user extensions.
|
|
2445
2636
|
model.extension,
|
|
2637
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2638
|
+
editorMode === "vim" && vim(),
|
|
2446
2639
|
// Custom.
|
|
2447
2640
|
...extensions
|
|
2448
2641
|
].filter(Boolean)
|
|
2449
2642
|
});
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2643
|
+
const newView = new EditorView13({
|
|
2644
|
+
state,
|
|
2645
|
+
parent: rootRef.current,
|
|
2646
|
+
scrollTo,
|
|
2647
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2648
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2649
|
+
dispatchTransactions: (trs, view2) => {
|
|
2650
|
+
if (debug) {
|
|
2651
|
+
logChanges(trs);
|
|
2652
|
+
}
|
|
2653
|
+
view2.update(trs);
|
|
2654
|
+
}
|
|
2457
2655
|
});
|
|
2656
|
+
view?.destroy();
|
|
2657
|
+
setView(newView);
|
|
2458
2658
|
return () => {
|
|
2459
|
-
|
|
2460
|
-
|
|
2659
|
+
newView?.destroy();
|
|
2660
|
+
setView(null);
|
|
2461
2661
|
};
|
|
2462
2662
|
}, [
|
|
2463
|
-
|
|
2663
|
+
rootRef,
|
|
2464
2664
|
model,
|
|
2465
2665
|
readonly,
|
|
2466
2666
|
editorMode,
|
|
@@ -2470,11 +2670,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, comments: comments2, r
|
|
|
2470
2670
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2471
2671
|
switch (key) {
|
|
2472
2672
|
case "Enter": {
|
|
2473
|
-
view?.
|
|
2673
|
+
view?.focus();
|
|
2474
2674
|
break;
|
|
2475
2675
|
}
|
|
2476
2676
|
case "Escape": {
|
|
2477
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2677
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2678
|
+
rootRef.current?.focus();
|
|
2679
|
+
}
|
|
2478
2680
|
break;
|
|
2479
2681
|
}
|
|
2480
2682
|
}
|
|
@@ -2484,107 +2686,305 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, comments: comments2, r
|
|
|
2484
2686
|
]);
|
|
2485
2687
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2486
2688
|
key: model.id,
|
|
2487
|
-
|
|
2689
|
+
role: "none",
|
|
2488
2690
|
tabIndex: 0,
|
|
2489
|
-
|
|
2691
|
+
onKeyUp: handleKeyUp,
|
|
2692
|
+
...slots.root,
|
|
2490
2693
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2491
|
-
|
|
2694
|
+
ref: rootRef
|
|
2492
2695
|
});
|
|
2493
2696
|
});
|
|
2494
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2697
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2495
2698
|
const { themeMode } = useThemeContext();
|
|
2496
|
-
const
|
|
2699
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2497
2700
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2498
2701
|
ref: forwardedRef,
|
|
2499
2702
|
readonly,
|
|
2500
2703
|
extensions: [
|
|
2501
2704
|
basicBundle({
|
|
2502
|
-
readonly,
|
|
2503
2705
|
themeMode,
|
|
2504
|
-
placeholder:
|
|
2706
|
+
placeholder: placeholder3,
|
|
2707
|
+
lineWrapping
|
|
2505
2708
|
}),
|
|
2506
2709
|
...extensions
|
|
2507
2710
|
],
|
|
2508
|
-
|
|
2711
|
+
theme,
|
|
2712
|
+
slots: updatedSlots,
|
|
2509
2713
|
...props
|
|
2510
2714
|
});
|
|
2511
2715
|
});
|
|
2512
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2716
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2513
2717
|
const { themeMode } = useThemeContext();
|
|
2514
|
-
const
|
|
2718
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2515
2719
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2516
2720
|
ref: forwardedRef,
|
|
2517
2721
|
readonly,
|
|
2518
2722
|
extensions: [
|
|
2519
2723
|
markdownBundle({
|
|
2520
|
-
readonly,
|
|
2521
2724
|
themeMode,
|
|
2522
|
-
placeholder:
|
|
2725
|
+
placeholder: placeholder3
|
|
2523
2726
|
}),
|
|
2524
2727
|
...extensions
|
|
2525
2728
|
],
|
|
2526
|
-
|
|
2729
|
+
theme,
|
|
2730
|
+
slots: updatedSlots,
|
|
2527
2731
|
...props
|
|
2528
2732
|
});
|
|
2529
2733
|
});
|
|
2530
2734
|
var defaultSlots = {
|
|
2531
2735
|
root: {
|
|
2532
|
-
|
|
2736
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2737
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2738
|
+
},
|
|
2739
|
+
editor: {
|
|
2740
|
+
className: "h-full p-2"
|
|
2533
2741
|
}
|
|
2534
2742
|
};
|
|
2535
2743
|
var defaultTextSlots = {
|
|
2536
|
-
...defaultSlots
|
|
2537
|
-
editor: {
|
|
2538
|
-
theme: textTheme
|
|
2539
|
-
}
|
|
2744
|
+
...defaultSlots
|
|
2540
2745
|
};
|
|
2541
2746
|
var defaultMarkdownSlots = {
|
|
2542
|
-
...defaultSlots
|
|
2543
|
-
|
|
2544
|
-
|
|
2747
|
+
...defaultSlots
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2750
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2751
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2752
|
+
import { Context as Context2 } from "@dxos/context";
|
|
2753
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2754
|
+
import { log as log3 } from "@dxos/log";
|
|
2755
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2756
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
2757
|
+
var SpaceAwarenessProvider = class {
|
|
2758
|
+
constructor(params) {
|
|
2759
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2760
|
+
this.remoteStateChange = new Event2();
|
|
2761
|
+
this._space = params.space;
|
|
2762
|
+
this._channel = params.channel;
|
|
2763
|
+
this._peerId = params.peerId;
|
|
2764
|
+
this._info = params.info;
|
|
2765
|
+
}
|
|
2766
|
+
open() {
|
|
2767
|
+
this._ctx = new Context2();
|
|
2768
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
2769
|
+
if (this._localState) {
|
|
2770
|
+
await this._space.postMessage(this._channel, {
|
|
2771
|
+
kind: "post",
|
|
2772
|
+
state: this._localState
|
|
2773
|
+
});
|
|
2774
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2778
|
+
switch (message.payload.kind) {
|
|
2779
|
+
case "query": {
|
|
2780
|
+
this._handleQueryMessage();
|
|
2781
|
+
break;
|
|
2782
|
+
}
|
|
2783
|
+
case "post": {
|
|
2784
|
+
this._handlePostMessage(message.payload);
|
|
2785
|
+
break;
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}));
|
|
2789
|
+
void this._space.postMessage(this._channel, {
|
|
2790
|
+
kind: "query"
|
|
2791
|
+
}).catch((err) => {
|
|
2792
|
+
log3.debug("failed to query awareness", {
|
|
2793
|
+
err
|
|
2794
|
+
}, {
|
|
2795
|
+
F: __dxlog_file6,
|
|
2796
|
+
L: 89,
|
|
2797
|
+
S: this,
|
|
2798
|
+
C: (f, a) => f(...a)
|
|
2799
|
+
});
|
|
2800
|
+
});
|
|
2801
|
+
}
|
|
2802
|
+
close() {
|
|
2803
|
+
void this._ctx?.dispose();
|
|
2804
|
+
this._ctx = void 0;
|
|
2805
|
+
this._postTask = void 0;
|
|
2806
|
+
}
|
|
2807
|
+
getRemoteStates() {
|
|
2808
|
+
return Array.from(this._remoteStates.values());
|
|
2809
|
+
}
|
|
2810
|
+
update(position) {
|
|
2811
|
+
invariant4(this._postTask, void 0, {
|
|
2812
|
+
F: __dxlog_file6,
|
|
2813
|
+
L: 104,
|
|
2814
|
+
S: this,
|
|
2815
|
+
A: [
|
|
2816
|
+
"this._postTask",
|
|
2817
|
+
""
|
|
2818
|
+
]
|
|
2819
|
+
});
|
|
2820
|
+
this._localState = {
|
|
2821
|
+
peerId: this._peerId,
|
|
2822
|
+
position,
|
|
2823
|
+
info: this._info
|
|
2824
|
+
};
|
|
2825
|
+
this._postTask.schedule();
|
|
2826
|
+
}
|
|
2827
|
+
_handleQueryMessage() {
|
|
2828
|
+
invariant4(this._postTask, void 0, {
|
|
2829
|
+
F: __dxlog_file6,
|
|
2830
|
+
L: 115,
|
|
2831
|
+
S: this,
|
|
2832
|
+
A: [
|
|
2833
|
+
"this._postTask",
|
|
2834
|
+
""
|
|
2835
|
+
]
|
|
2836
|
+
});
|
|
2837
|
+
this._postTask.schedule();
|
|
2838
|
+
}
|
|
2839
|
+
_handlePostMessage(message) {
|
|
2840
|
+
invariant4(message.kind === "post", void 0, {
|
|
2841
|
+
F: __dxlog_file6,
|
|
2842
|
+
L: 120,
|
|
2843
|
+
S: this,
|
|
2844
|
+
A: [
|
|
2845
|
+
"message.kind === 'post'",
|
|
2846
|
+
""
|
|
2847
|
+
]
|
|
2848
|
+
});
|
|
2849
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
2850
|
+
this.remoteStateChange.emit();
|
|
2545
2851
|
}
|
|
2546
2852
|
};
|
|
2853
|
+
|
|
2854
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2855
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
2856
|
+
var modelState = StateField5.define({
|
|
2857
|
+
create: () => void 0,
|
|
2858
|
+
update: (model) => model
|
|
2859
|
+
});
|
|
2860
|
+
|
|
2861
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
2862
|
+
import { useState as useState2 } from "react";
|
|
2863
|
+
var useTextEditor = () => {
|
|
2864
|
+
const [view, setView] = useState2(null);
|
|
2865
|
+
return [
|
|
2866
|
+
(ref) => {
|
|
2867
|
+
setView(ref);
|
|
2868
|
+
},
|
|
2869
|
+
view
|
|
2870
|
+
];
|
|
2871
|
+
};
|
|
2872
|
+
|
|
2873
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2874
|
+
import get4 from "lodash.get";
|
|
2875
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
2876
|
+
import { generateName } from "@dxos/display-name";
|
|
2877
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2878
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2879
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2880
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2881
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2882
|
+
var useTextModel = (props) => {
|
|
2883
|
+
const { identity, space, text } = props;
|
|
2884
|
+
const [model, setModel] = useState3();
|
|
2885
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2886
|
+
identity,
|
|
2887
|
+
space,
|
|
2888
|
+
text
|
|
2889
|
+
]);
|
|
2890
|
+
return model;
|
|
2891
|
+
};
|
|
2892
|
+
var createModel = ({ space, identity, text }) => {
|
|
2893
|
+
invariant5(isAutomergeObject(text), void 0, {
|
|
2894
|
+
F: __dxlog_file7,
|
|
2895
|
+
L: 35,
|
|
2896
|
+
S: void 0,
|
|
2897
|
+
A: [
|
|
2898
|
+
"isAutomergeObject(text)",
|
|
2899
|
+
""
|
|
2900
|
+
]
|
|
2901
|
+
});
|
|
2902
|
+
const obj = text;
|
|
2903
|
+
const doc = getRawDoc(obj, [
|
|
2904
|
+
obj.field
|
|
2905
|
+
]);
|
|
2906
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2907
|
+
space,
|
|
2908
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2909
|
+
info: {
|
|
2910
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2911
|
+
color: cursorColor.color,
|
|
2912
|
+
lightColor: cursorColor.light
|
|
2913
|
+
},
|
|
2914
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2915
|
+
});
|
|
2916
|
+
const model = {
|
|
2917
|
+
id: obj.id,
|
|
2918
|
+
content: doc,
|
|
2919
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2920
|
+
extension: [
|
|
2921
|
+
modelState.init(() => model),
|
|
2922
|
+
automerge3({
|
|
2923
|
+
handle: doc.handle,
|
|
2924
|
+
path: doc.path
|
|
2925
|
+
}),
|
|
2926
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2927
|
+
awareness()
|
|
2928
|
+
].filter(isNotNullOrUndefined),
|
|
2929
|
+
peer: identity ? {
|
|
2930
|
+
id: identity.identityKey.toHex(),
|
|
2931
|
+
name: identity.profile?.displayName
|
|
2932
|
+
} : void 0
|
|
2933
|
+
};
|
|
2934
|
+
return model;
|
|
2935
|
+
};
|
|
2547
2936
|
export {
|
|
2937
|
+
AwarenessProvider,
|
|
2548
2938
|
BaseTextEditor,
|
|
2939
|
+
Cursor,
|
|
2549
2940
|
Doc,
|
|
2550
2941
|
EditorModes,
|
|
2551
2942
|
MarkdownEditor,
|
|
2943
|
+
RemoteSelectionsDecorator,
|
|
2552
2944
|
SpaceAwarenessProvider,
|
|
2553
2945
|
TextEditor,
|
|
2554
2946
|
TextKind,
|
|
2555
2947
|
YText,
|
|
2556
2948
|
YXmlFragment,
|
|
2557
2949
|
autocomplete,
|
|
2950
|
+
automerge3 as automerge,
|
|
2951
|
+
awareness,
|
|
2558
2952
|
basicBundle,
|
|
2559
2953
|
blast,
|
|
2954
|
+
callbackWrapper,
|
|
2560
2955
|
code2 as code,
|
|
2561
2956
|
codeTheme,
|
|
2562
2957
|
comments,
|
|
2563
|
-
cursorColor,
|
|
2564
2958
|
defaultMarkdownSlots,
|
|
2565
2959
|
defaultOptions,
|
|
2566
2960
|
defaultSlots,
|
|
2567
2961
|
defaultTextSlots,
|
|
2568
2962
|
defaultTheme,
|
|
2963
|
+
getToken,
|
|
2964
|
+
heading2 as heading,
|
|
2569
2965
|
hr,
|
|
2570
2966
|
image,
|
|
2571
2967
|
link,
|
|
2572
2968
|
listener,
|
|
2969
|
+
logChanges,
|
|
2573
2970
|
markdownBundle,
|
|
2574
2971
|
markdownHighlightStyle,
|
|
2575
2972
|
markdownTags,
|
|
2576
2973
|
markdownTagsExtensions,
|
|
2577
2974
|
markdownTheme,
|
|
2578
2975
|
mention,
|
|
2579
|
-
mermaid,
|
|
2580
2976
|
modelState,
|
|
2581
|
-
|
|
2977
|
+
outliner,
|
|
2978
|
+
setComments,
|
|
2979
|
+
setFocus,
|
|
2980
|
+
setSelection,
|
|
2582
2981
|
table,
|
|
2583
2982
|
tags2 as tags,
|
|
2584
2983
|
tasklist,
|
|
2585
2984
|
textTheme,
|
|
2586
|
-
tooltip,
|
|
2587
2985
|
typewriter,
|
|
2986
|
+
useComments,
|
|
2987
|
+
useTextEditor,
|
|
2588
2988
|
useTextModel
|
|
2589
2989
|
};
|
|
2590
2990
|
//# sourceMappingURL=index.mjs.map
|