@dxos/react-ui-editor 0.3.11-main.3f845e1 → 0.3.11-main.463e5cd
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 +2578 -1622
- 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 -15
- 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/hooks.stories.d.ts +23 -0
- package/dist/types/src/components/TextEditor/hooks.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/components/Toolbar/Toolbar.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +23 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/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/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.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 +15 -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/extensions/comments.d.ts +67 -0
- 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/formatting.d.ts +13 -0
- package/dist/types/src/extensions/markdown/formatting.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 +11 -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 +5 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +14 -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 +48 -36
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +93 -102
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -34
- package/src/components/TextEditor/TextEditor.tsx +137 -97
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +65 -6
- package/src/components/TextEditor/hooks.stories.tsx +106 -0
- package/src/components/TextEditor/index.ts +0 -3
- package/src/components/Toolbar/Toolbar.stories.tsx +90 -0
- package/src/components/Toolbar/Toolbar.tsx +166 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/{components/TextEditor/extensions → extensions}/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +103 -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/extensions/automerge/semaphore.ts +81 -0
- package/src/extensions/automerge/update-automerge.ts +49 -0
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +17 -9
- package/src/extensions/awareness.ts +313 -0
- package/src/{components/TextEditor/extensions → extensions}/basic.ts +17 -10
- package/src/{components/TextEditor/extensions → extensions}/blast.ts +4 -1
- package/src/extensions/comments.ts +476 -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 +23 -28
- package/src/extensions/markdown/code.ts +150 -0
- package/src/extensions/markdown/formatting.ts +188 -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 +14 -0
- package/src/{components/TextEditor/extensions → extensions/markdown}/link.ts +121 -58
- 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 +6 -1
- package/src/hooks/useActionHandler.ts +62 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +48 -114
- 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 +58 -82
- 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 +0 -48
- 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/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/automerge/semaphore.ts +0 -78
- package/src/hooks/automerge/update-automerge.ts +0 -44
- 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/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{components/TextEditor/themes → themes}/index.ts +0 -0
|
@@ -1,65 +1,661 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
3
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
4
5
|
|
|
5
6
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
7
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
8
|
|
|
8
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/
|
|
9
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
10
|
+
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
11
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
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 { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
19
|
+
|
|
20
|
+
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
9
21
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
22
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
10
23
|
import { keymap } from "@codemirror/view";
|
|
11
24
|
var autocomplete = ({ onSearch }) => {
|
|
12
25
|
return [
|
|
13
26
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
14
27
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
28
|
+
// TODO(burdon): Set custom keymap.
|
|
15
29
|
keymap.of(completionKeymap),
|
|
16
30
|
// https://codemirror.net/examples/autocompletion
|
|
17
31
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
18
32
|
autocompletion({
|
|
19
|
-
|
|
33
|
+
activateOnTyping: true,
|
|
34
|
+
// closeOnBlur: false,
|
|
20
35
|
// 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
|
-
};
|
|
36
|
+
// TODO(burdon): Styles/fragments.
|
|
37
|
+
tooltipClass: () => "shadow rounded"
|
|
38
|
+
}),
|
|
39
|
+
// TODO(burdon): Option to create new page?
|
|
40
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
41
|
+
markdownLanguage.data.of({
|
|
42
|
+
autocomplete: (context) => {
|
|
43
|
+
const match = context.matchBefore(/\w*/);
|
|
44
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
45
|
+
return null;
|
|
35
46
|
}
|
|
36
|
-
|
|
47
|
+
return {
|
|
48
|
+
from: match.from,
|
|
49
|
+
options: onSearch(match.text.toLowerCase())
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
61
|
+
|
|
62
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
63
|
+
import get from "lodash.get";
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
65
|
+
var cursorConverter = (handle, path) => ({
|
|
66
|
+
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
67
|
+
toCursor: (pos) => {
|
|
68
|
+
const doc = handle.docSync();
|
|
69
|
+
if (!doc) {
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
const value = get(doc, path);
|
|
73
|
+
if (typeof value === "string" && value.length <= pos) {
|
|
74
|
+
return "end";
|
|
75
|
+
}
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
77
|
+
},
|
|
78
|
+
fromCursor: (cursor) => {
|
|
79
|
+
if (cursor === "") {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const doc = handle.docSync();
|
|
83
|
+
if (!doc) {
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
if (cursor === "end") {
|
|
87
|
+
const value = get(doc, path);
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
return value.length;
|
|
90
|
+
} else {
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
99
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
104
|
+
newHeads
|
|
105
|
+
});
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
113
|
+
|
|
114
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
116
|
+
var updateAutomerge = (field, handle, transactions, state) => {
|
|
117
|
+
const { lastHeads, path } = state.field(field);
|
|
118
|
+
let hasChanges = false;
|
|
119
|
+
for (const tr of transactions) {
|
|
120
|
+
tr.changes.iterChanges(() => {
|
|
121
|
+
hasChanges = true;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!hasChanges) {
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
129
|
+
for (const tr of transactions) {
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
return newHeads ?? void 0;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-codemirror.ts
|
|
146
|
+
import { ChangeSet } from "@codemirror/state";
|
|
147
|
+
var updateCodeMirror = (view, selection, target, patches) => {
|
|
148
|
+
for (const patch of patches) {
|
|
149
|
+
const changeSpec = handlePatch(patch, target, view.state);
|
|
150
|
+
if (changeSpec != null) {
|
|
151
|
+
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
152
|
+
selection = selection.map(changeSet, 1);
|
|
153
|
+
view.dispatch({
|
|
154
|
+
changes: changeSet,
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
view.dispatch({
|
|
160
|
+
selection,
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
var handlePatch = (patch, target, state) => {
|
|
165
|
+
if (patch.action === "insert") {
|
|
166
|
+
return handleInsert(target, patch);
|
|
167
|
+
} else if (patch.action === "splice") {
|
|
168
|
+
return handleSplice(target, patch);
|
|
169
|
+
} else if (patch.action === "del") {
|
|
170
|
+
return handleDel(target, patch);
|
|
171
|
+
} else if (patch.action === "put") {
|
|
172
|
+
return handlePut(target, patch, state);
|
|
173
|
+
} else {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var handleInsert = (target, patch) => {
|
|
178
|
+
const index = charPath(target, patch.path);
|
|
179
|
+
if (index == null) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
183
|
+
return [
|
|
184
|
+
{
|
|
185
|
+
from: index,
|
|
186
|
+
to: index,
|
|
187
|
+
insert: text
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
};
|
|
191
|
+
var handleSplice = (target, patch) => {
|
|
192
|
+
const index = charPath(target, patch.path);
|
|
193
|
+
if (index == null) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
return [
|
|
197
|
+
{
|
|
198
|
+
from: index,
|
|
199
|
+
insert: patch.value
|
|
200
|
+
}
|
|
201
|
+
];
|
|
202
|
+
};
|
|
203
|
+
var handleDel = (target, patch) => {
|
|
204
|
+
const index = charPath(target, patch.path);
|
|
205
|
+
if (index == null) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const length = patch.length || 1;
|
|
209
|
+
return [
|
|
210
|
+
{
|
|
211
|
+
from: index,
|
|
212
|
+
to: index + length
|
|
213
|
+
}
|
|
214
|
+
];
|
|
215
|
+
};
|
|
216
|
+
var handlePut = (target, patch, state) => {
|
|
217
|
+
const index = charPath(target, [
|
|
218
|
+
...patch.path,
|
|
219
|
+
0
|
|
220
|
+
]);
|
|
221
|
+
if (index == null) {
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
const length = state.doc.length;
|
|
225
|
+
if (typeof patch.value !== "string") {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
return [
|
|
229
|
+
{
|
|
230
|
+
from: 0,
|
|
231
|
+
to: length,
|
|
232
|
+
insert: patch.value
|
|
233
|
+
}
|
|
234
|
+
];
|
|
235
|
+
};
|
|
236
|
+
var charPath = (textPath, candidatePath) => {
|
|
237
|
+
if (candidatePath.length !== textPath.length + 1) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
241
|
+
if (textPath[i] !== candidatePath[i]) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
246
|
+
if (typeof index === "number") {
|
|
247
|
+
return index;
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
253
|
+
var PatchSemaphore = class {
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
256
|
+
this._handle = _handle;
|
|
257
|
+
this._state = _state;
|
|
258
|
+
this._inReconcile = false;
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
262
|
+
this._inReconcile = true;
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
276
|
+
view.dispatch({
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
295
|
+
import { Facet } from "@codemirror/state";
|
|
296
|
+
var defaultCursorConverter = {
|
|
297
|
+
toCursor: (position) => position.toString(),
|
|
298
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
299
|
+
};
|
|
300
|
+
var Cursor = class _Cursor {
|
|
301
|
+
static {
|
|
302
|
+
this.converter = Facet.define({
|
|
303
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
static {
|
|
307
|
+
this.getCursorFromRange = (state, range) => {
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
311
|
+
return [
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
].join(":");
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
static {
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
320
|
+
const parts = cursor.split(":");
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
323
|
+
return from !== void 0 && to !== void 0 ? {
|
|
324
|
+
from,
|
|
325
|
+
to
|
|
326
|
+
} : void 0;
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
334
|
+
create: () => ({
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
338
|
+
}),
|
|
339
|
+
update: (value, tr) => {
|
|
340
|
+
const result = {
|
|
341
|
+
path: path.slice(),
|
|
342
|
+
lastHeads: value.lastHeads,
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
344
|
+
};
|
|
345
|
+
let clearUnreconciled = false;
|
|
346
|
+
for (const effect of tr.effects) {
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
348
|
+
result.lastHeads = effect.value.newHeads;
|
|
349
|
+
clearUnreconciled = true;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (clearUnreconciled) {
|
|
353
|
+
result.unreconciledTransactions = [];
|
|
354
|
+
} else {
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
356
|
+
result.unreconciledTransactions.push(tr);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
363
|
+
return [
|
|
364
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
366
|
+
// Reconcile external updates.
|
|
367
|
+
ViewPlugin.fromClass(class {
|
|
368
|
+
constructor(_view) {
|
|
369
|
+
this._view = _view;
|
|
370
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
destroy() {
|
|
373
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
374
|
+
}
|
|
375
|
+
_handleChange() {
|
|
376
|
+
semaphore.reconcile(this._view);
|
|
377
|
+
}
|
|
378
|
+
}),
|
|
379
|
+
// Reconcile local updates.
|
|
380
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
381
|
+
if (!changes.empty) {
|
|
382
|
+
semaphore.reconcile(view);
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
385
|
+
// TODO(burdon): Record undo transactions.
|
|
386
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
387
|
+
// https://codemirror.net/examples/inverted-effect
|
|
388
|
+
invertedEffects.of((tr) => {
|
|
389
|
+
const effects = [];
|
|
390
|
+
if (!tr.changes.empty) {
|
|
391
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return effects;
|
|
37
395
|
})
|
|
38
396
|
];
|
|
39
397
|
};
|
|
40
398
|
|
|
41
|
-
// packages/ui/react-ui-editor/src/
|
|
399
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
400
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
401
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
402
|
+
import { Event } from "@dxos/async";
|
|
403
|
+
import { Context } from "@dxos/context";
|
|
404
|
+
var dummyProvider = {
|
|
405
|
+
remoteStateChange: new Event(),
|
|
406
|
+
open: () => {
|
|
407
|
+
},
|
|
408
|
+
close: () => {
|
|
409
|
+
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
411
|
+
update: () => {
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
415
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
416
|
+
});
|
|
417
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
418
|
+
var awareness = (provider = dummyProvider) => {
|
|
419
|
+
return [
|
|
420
|
+
awarenessProvider.of(provider),
|
|
421
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
422
|
+
decorations: (value) => value.decorations
|
|
423
|
+
}),
|
|
424
|
+
styles
|
|
425
|
+
];
|
|
426
|
+
};
|
|
427
|
+
var RemoteSelectionsDecorator = class {
|
|
428
|
+
constructor(view) {
|
|
429
|
+
this.decorations = RangeSet.of([]);
|
|
430
|
+
this._ctx = new Context();
|
|
431
|
+
this._lastAnchor = void 0;
|
|
432
|
+
this._lastHead = void 0;
|
|
433
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
435
|
+
this._provider.open();
|
|
436
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
437
|
+
view.dispatch({
|
|
438
|
+
annotations: [
|
|
439
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
440
|
+
]
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
destroy() {
|
|
445
|
+
void this._ctx.dispose();
|
|
446
|
+
this._provider.close();
|
|
447
|
+
}
|
|
448
|
+
update(update2) {
|
|
449
|
+
this._updateLocalSelection(update2);
|
|
450
|
+
this._updateRemoteSelections(update2);
|
|
451
|
+
}
|
|
452
|
+
_updateLocalSelection(update2) {
|
|
453
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
454
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
455
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
this._lastAnchor = anchor;
|
|
459
|
+
this._lastHead = head;
|
|
460
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
461
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
462
|
+
head: this._cursorConverter.toCursor(head)
|
|
463
|
+
} : void 0);
|
|
464
|
+
}
|
|
465
|
+
_updateRemoteSelections(update2) {
|
|
466
|
+
const decorations = [];
|
|
467
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
468
|
+
for (const state of awarenessStates) {
|
|
469
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
470
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
471
|
+
if (anchor == null || head == null) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
475
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
476
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
477
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
478
|
+
const color = state.info.color ?? "#30bced";
|
|
479
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
480
|
+
if (startLine.number === endLine.number) {
|
|
481
|
+
decorations.push({
|
|
482
|
+
from: start,
|
|
483
|
+
to: end,
|
|
484
|
+
value: Decoration.mark({
|
|
485
|
+
attributes: {
|
|
486
|
+
style: `background-color: ${lightColor}`
|
|
487
|
+
},
|
|
488
|
+
class: "cm-collab-selection"
|
|
489
|
+
})
|
|
490
|
+
});
|
|
491
|
+
} else {
|
|
492
|
+
decorations.push({
|
|
493
|
+
from: start,
|
|
494
|
+
to: startLine.from + startLine.length,
|
|
495
|
+
value: Decoration.mark({
|
|
496
|
+
attributes: {
|
|
497
|
+
style: `background-color: ${color}`
|
|
498
|
+
},
|
|
499
|
+
class: "cm-collab-selection"
|
|
500
|
+
})
|
|
501
|
+
});
|
|
502
|
+
decorations.push({
|
|
503
|
+
from: endLine.from,
|
|
504
|
+
to: end,
|
|
505
|
+
value: Decoration.mark({
|
|
506
|
+
attributes: {
|
|
507
|
+
style: `background-color: ${color}`
|
|
508
|
+
},
|
|
509
|
+
class: "cm-collab-selection"
|
|
510
|
+
})
|
|
511
|
+
});
|
|
512
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
513
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
514
|
+
decorations.push({
|
|
515
|
+
from: linePos,
|
|
516
|
+
to: linePos,
|
|
517
|
+
value: Decoration.line({
|
|
518
|
+
attributes: {
|
|
519
|
+
style: `background-color: ${color}`,
|
|
520
|
+
class: "cm-collab-selectionLine"
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
decorations.push({
|
|
527
|
+
from: head,
|
|
528
|
+
to: head,
|
|
529
|
+
value: Decoration.widget({
|
|
530
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
531
|
+
block: false,
|
|
532
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
this.decorations = Decoration.set(decorations, true);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
540
|
+
constructor(_name, _color) {
|
|
541
|
+
super();
|
|
542
|
+
this._name = _name;
|
|
543
|
+
this._color = _color;
|
|
544
|
+
}
|
|
545
|
+
toDOM() {
|
|
546
|
+
const span = document.createElement("span");
|
|
547
|
+
span.className = "cm-collab-selectionCaret";
|
|
548
|
+
span.style.backgroundColor = this._color;
|
|
549
|
+
span.style.borderColor = this._color;
|
|
550
|
+
const dot = document.createElement("div");
|
|
551
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
552
|
+
const info = document.createElement("div");
|
|
553
|
+
info.className = "cm-collab-selectionInfo";
|
|
554
|
+
info.innerText = this._name;
|
|
555
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
556
|
+
span.appendChild(dot);
|
|
557
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
558
|
+
span.appendChild(info);
|
|
559
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
560
|
+
return span;
|
|
561
|
+
}
|
|
562
|
+
updateDOM() {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
eq(widget) {
|
|
566
|
+
return widget._color === this._color;
|
|
567
|
+
}
|
|
568
|
+
get estimatedHeight() {
|
|
569
|
+
return -1;
|
|
570
|
+
}
|
|
571
|
+
ignoreEvent() {
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
576
|
+
".cm-collab-selection": {},
|
|
577
|
+
".cm-collab-selectionLine": {
|
|
578
|
+
padding: 0,
|
|
579
|
+
margin: "0px 2px 0px 4px"
|
|
580
|
+
},
|
|
581
|
+
".cm-collab-selectionCaret": {
|
|
582
|
+
position: "relative",
|
|
583
|
+
borderLeft: "1px solid black",
|
|
584
|
+
borderRight: "1px solid black",
|
|
585
|
+
marginLeft: "-1px",
|
|
586
|
+
marginRight: "-1px",
|
|
587
|
+
boxSizing: "border-box",
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
590
|
+
},
|
|
591
|
+
".cm-collab-selectionCaretDot": {
|
|
592
|
+
borderRadius: "50%",
|
|
593
|
+
position: "absolute",
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
598
|
+
backgroundColor: "inherit",
|
|
599
|
+
transition: "transform .3s ease-in-out",
|
|
600
|
+
boxSizing: "border-box"
|
|
601
|
+
},
|
|
602
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
605
|
+
},
|
|
606
|
+
".cm-collab-selectionInfo": {
|
|
607
|
+
position: "absolute",
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
611
|
+
fontSize: ".75em",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
613
|
+
fontStyle: "normal",
|
|
614
|
+
fontWeight: "normal",
|
|
615
|
+
lineHeight: "normal",
|
|
616
|
+
userSelect: "none",
|
|
617
|
+
color: "white",
|
|
618
|
+
padding: "2px",
|
|
619
|
+
zIndex: 101,
|
|
620
|
+
transition: "opacity .3s ease-in-out",
|
|
621
|
+
backgroundColor: "inherit",
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
624
|
+
opacity: 0,
|
|
625
|
+
transitionDelay: "0s",
|
|
626
|
+
whiteSpace: "nowrap"
|
|
627
|
+
},
|
|
628
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
629
|
+
opacity: 1,
|
|
630
|
+
transitionDelay: "0s"
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
42
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
43
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
44
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
45
|
-
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
639
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
49
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
50
644
|
bracketMatching(),
|
|
51
645
|
closeBrackets(),
|
|
52
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
53
649
|
_placeholder && placeholder(_placeholder),
|
|
54
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
55
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
56
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
57
653
|
|
|
58
|
-
// packages/ui/react-ui-editor/src/
|
|
59
|
-
import { EditorView as
|
|
654
|
+
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
60
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
61
657
|
import { invariant } from "@dxos/invariant";
|
|
62
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/
|
|
658
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
63
659
|
var defaultOptions = {
|
|
64
660
|
effect: 2,
|
|
65
661
|
maxParticles: 200,
|
|
@@ -92,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
92
688
|
const getPoint = (view, pos) => {
|
|
93
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
94
690
|
const element = document.elementFromPoint(x, y);
|
|
95
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
96
692
|
const point = {
|
|
97
693
|
x: x - left,
|
|
98
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
99
695
|
};
|
|
100
696
|
return {
|
|
101
697
|
element,
|
|
@@ -104,12 +700,12 @@ var blast = (options = defaultOptions) => {
|
|
|
104
700
|
};
|
|
105
701
|
return [
|
|
106
702
|
// Cursor moved.
|
|
107
|
-
|
|
108
|
-
if (blaster?.node !==
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
704
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
109
705
|
if (blaster) {
|
|
110
706
|
blaster.destroy();
|
|
111
707
|
}
|
|
112
|
-
blaster = new Blaster(
|
|
708
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
113
709
|
particleGravity: 0.2,
|
|
114
710
|
particleShrinkRate: 0.995,
|
|
115
711
|
color: () => [
|
|
@@ -123,10 +719,10 @@ var blast = (options = defaultOptions) => {
|
|
|
123
719
|
} else {
|
|
124
720
|
blaster.resize();
|
|
125
721
|
}
|
|
126
|
-
const current =
|
|
722
|
+
const current = update2.state.selection.main.head;
|
|
127
723
|
if (current !== last) {
|
|
128
724
|
last = current;
|
|
129
|
-
const { element, point } = getPoint(
|
|
725
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
130
726
|
if (element && point) {
|
|
131
727
|
blaster.spawn({
|
|
132
728
|
element,
|
|
@@ -187,7 +783,7 @@ var Blaster = class {
|
|
|
187
783
|
initialize() {
|
|
188
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
189
785
|
F: __dxlog_file,
|
|
190
|
-
L:
|
|
786
|
+
L: 141,
|
|
191
787
|
S: this,
|
|
192
788
|
A: [
|
|
193
789
|
"!this._canvas && !this._ctx",
|
|
@@ -224,7 +820,7 @@ var Blaster = class {
|
|
|
224
820
|
start() {
|
|
225
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
226
822
|
F: __dxlog_file,
|
|
227
|
-
L:
|
|
823
|
+
L: 180,
|
|
228
824
|
S: this,
|
|
229
825
|
A: [
|
|
230
826
|
"this._canvas && this._ctx",
|
|
@@ -260,519 +856,121 @@ var Blaster = class {
|
|
|
260
856
|
drawParticles() {
|
|
261
857
|
for (let i = this._particles.length; i--; i > 0) {
|
|
262
858
|
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
|
-
}
|
|
569
|
-
}
|
|
570
|
-
view.dispatch({
|
|
571
|
-
selection,
|
|
572
|
-
annotations: reconcileAnnotationType.of({})
|
|
573
|
-
});
|
|
574
|
-
};
|
|
575
|
-
var handlePatch = (patch, target, state) => {
|
|
576
|
-
if (patch.action === "insert") {
|
|
577
|
-
return handleInsert(target, patch);
|
|
578
|
-
} else if (patch.action === "splice") {
|
|
579
|
-
return handleSplice(target, patch);
|
|
580
|
-
} else if (patch.action === "del") {
|
|
581
|
-
return handleDel(target, patch);
|
|
582
|
-
} else if (patch.action === "put") {
|
|
583
|
-
return handlePut(target, patch, state);
|
|
584
|
-
} else {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
var handleInsert = (target, patch) => {
|
|
589
|
-
const index = charPath(target, patch.path);
|
|
590
|
-
if (index == null) {
|
|
591
|
-
return [];
|
|
592
|
-
}
|
|
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
|
-
};
|
|
602
|
-
var handleSplice = (target, patch) => {
|
|
603
|
-
const index = charPath(target, patch.path);
|
|
604
|
-
if (index == null) {
|
|
605
|
-
return [];
|
|
606
|
-
}
|
|
607
|
-
return [
|
|
608
|
-
{
|
|
609
|
-
from: index,
|
|
610
|
-
insert: patch.value
|
|
859
|
+
if (!particle) {
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
this._effect.update(this._ctx, particle);
|
|
611
866
|
}
|
|
612
|
-
|
|
867
|
+
}
|
|
613
868
|
};
|
|
614
|
-
var
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
return [];
|
|
869
|
+
var Effect = class {
|
|
870
|
+
constructor(_options) {
|
|
871
|
+
this._options = _options;
|
|
618
872
|
}
|
|
619
|
-
const length = patch.length || 1;
|
|
620
|
-
return [
|
|
621
|
-
{
|
|
622
|
-
from: index,
|
|
623
|
-
to: index + length
|
|
624
|
-
}
|
|
625
|
-
];
|
|
626
873
|
};
|
|
627
|
-
var
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
874
|
+
var Effect1 = class extends Effect {
|
|
875
|
+
create(x, y, color) {
|
|
876
|
+
return {
|
|
877
|
+
x,
|
|
878
|
+
y: y + 10,
|
|
879
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
880
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
881
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
882
|
+
color,
|
|
883
|
+
alpha: 1
|
|
884
|
+
};
|
|
634
885
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
886
|
+
update(ctx, particle) {
|
|
887
|
+
particle.vy += this._options.particleGravity;
|
|
888
|
+
particle.x += particle.vx;
|
|
889
|
+
particle.y += particle.vy;
|
|
890
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
891
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
892
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
638
893
|
}
|
|
639
|
-
return [
|
|
640
|
-
{
|
|
641
|
-
from: 0,
|
|
642
|
-
to: length,
|
|
643
|
-
insert: patch.value
|
|
644
|
-
}
|
|
645
|
-
];
|
|
646
894
|
};
|
|
647
|
-
var
|
|
648
|
-
|
|
649
|
-
return
|
|
895
|
+
var Effect2 = class extends Effect {
|
|
896
|
+
create(x, y, color) {
|
|
897
|
+
return {
|
|
898
|
+
x,
|
|
899
|
+
y: y + 10,
|
|
900
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
901
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
902
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
903
|
+
color,
|
|
904
|
+
alpha: 1,
|
|
905
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
906
|
+
drag: 0.92,
|
|
907
|
+
wander: 0.15
|
|
908
|
+
};
|
|
650
909
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
910
|
+
update(ctx, particle) {
|
|
911
|
+
particle.vy += this._options.particleGravity;
|
|
912
|
+
particle.x += particle.vx;
|
|
913
|
+
particle.y += particle.vy;
|
|
914
|
+
particle.vx *= particle.drag;
|
|
915
|
+
particle.vy *= particle.drag;
|
|
916
|
+
particle.theta += random(-0.5, 0.5);
|
|
917
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
918
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
919
|
+
particle.size *= this._options.particleShrinkRate;
|
|
920
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
921
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
922
|
+
ctx.beginPath();
|
|
923
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
924
|
+
ctx.fill();
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
function throttle(callback, limit) {
|
|
928
|
+
let wait = false;
|
|
929
|
+
return function(...args) {
|
|
930
|
+
if (!wait) {
|
|
931
|
+
callback.apply(this, args);
|
|
932
|
+
wait = true;
|
|
933
|
+
setTimeout(() => {
|
|
934
|
+
wait = false;
|
|
935
|
+
}, limit);
|
|
654
936
|
}
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
var getRGBComponents = (node, color) => {
|
|
940
|
+
if (typeof color === "function") {
|
|
941
|
+
return color();
|
|
655
942
|
}
|
|
656
|
-
const
|
|
657
|
-
if (
|
|
658
|
-
|
|
943
|
+
const bgColor = getComputedStyle(node).color;
|
|
944
|
+
if (bgColor) {
|
|
945
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
946
|
+
if (x) {
|
|
947
|
+
return x;
|
|
948
|
+
}
|
|
659
949
|
}
|
|
660
|
-
return
|
|
950
|
+
return [
|
|
951
|
+
50,
|
|
952
|
+
50,
|
|
953
|
+
50
|
|
954
|
+
];
|
|
661
955
|
};
|
|
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
|
-
}
|
|
956
|
+
var random = (min, max) => {
|
|
957
|
+
if (!max) {
|
|
958
|
+
max = min;
|
|
959
|
+
min = 0;
|
|
701
960
|
}
|
|
961
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
702
962
|
};
|
|
703
963
|
|
|
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);
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
774
972
|
|
|
775
|
-
// packages/ui/react-ui-editor/src/
|
|
973
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
776
974
|
import * as random2 from "lib0/random";
|
|
777
975
|
var cursorColors = [
|
|
778
976
|
{
|
|
@@ -810,258 +1008,138 @@ var cursorColors = [
|
|
|
810
1008
|
];
|
|
811
1009
|
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
812
1010
|
|
|
813
|
-
// packages/ui/react-ui-editor/src/
|
|
814
|
-
import
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
var SpaceAwarenessProvider = class extends Observable {
|
|
823
|
-
constructor({ space, doc, channel, awareness }) {
|
|
824
|
-
super();
|
|
825
|
-
this._space = space;
|
|
826
|
-
this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
|
|
827
|
-
this._channel = channel;
|
|
828
|
-
this._clientId = doc.clientID;
|
|
829
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
830
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
831
|
-
if (typeof window !== "undefined") {
|
|
832
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
833
|
-
} else if (typeof process !== "undefined") {
|
|
834
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
835
|
-
}
|
|
836
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
837
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
838
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
839
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
840
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
841
|
-
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
842
|
-
this._clientId
|
|
843
|
-
]));
|
|
844
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
845
|
-
}
|
|
846
|
-
get awareness() {
|
|
847
|
-
return this._awareness;
|
|
848
|
-
}
|
|
849
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
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, {
|
|
869
|
-
F: __dxlog_file3,
|
|
870
|
-
L: 79,
|
|
871
|
-
S: this,
|
|
872
|
-
C: (f, a) => f(...a)
|
|
873
|
-
});
|
|
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
|
-
}
|
|
911
|
-
};
|
|
912
|
-
|
|
913
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
914
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
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;
|
|
1011
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
1012
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
1013
|
+
var headings = {
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
928
1020
|
};
|
|
929
|
-
var
|
|
930
|
-
|
|
931
|
-
if (isActualAutomergeObject(text)) {
|
|
932
|
-
return createAutomergeModel(props);
|
|
933
|
-
} else {
|
|
934
|
-
if (!text?.doc) {
|
|
935
|
-
return void 0;
|
|
936
|
-
}
|
|
937
|
-
return createYjsModel(props);
|
|
938
|
-
}
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
939
1023
|
};
|
|
940
|
-
var
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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;
|
|
1024
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1025
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1026
|
+
var bold = "font-bold";
|
|
1027
|
+
var italic = "italic";
|
|
1028
|
+
var strikethrough = "line-through";
|
|
1029
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1030
|
+
var codeMark = "font-mono text-primary-500";
|
|
1031
|
+
var inlineUrl = mx(code, "px-1");
|
|
1032
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1033
|
+
|
|
1034
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1035
|
+
import get2 from "lodash.get";
|
|
1036
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1037
|
+
var tokens = tailwindConfig({}).theme;
|
|
1038
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1039
|
+
|
|
1040
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1041
|
+
import { log } from "@dxos/log";
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1043
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1044
|
+
try {
|
|
1045
|
+
return fn(...args);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1048
|
+
F: __dxlog_file2,
|
|
1049
|
+
L: 18,
|
|
1050
|
+
S: void 0,
|
|
1051
|
+
C: (f, a) => f(...a)
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
988
1054
|
};
|
|
989
|
-
var
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
};
|
|
1008
|
-
return model;
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1059
|
+
}
|
|
1060
|
+
const changes2 = [];
|
|
1061
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1062
|
+
fromA,
|
|
1063
|
+
toA,
|
|
1064
|
+
fromB,
|
|
1065
|
+
toB,
|
|
1066
|
+
inserted: inserted.toString()
|
|
1067
|
+
})));
|
|
1068
|
+
return changes2;
|
|
1069
|
+
}).filter(Boolean);
|
|
1070
|
+
if (changes.length) {
|
|
1071
|
+
console.log("changes", changes);
|
|
1072
|
+
}
|
|
1009
1073
|
};
|
|
1010
1074
|
|
|
1011
|
-
// packages/ui/react-ui-editor/src/
|
|
1012
|
-
var
|
|
1013
|
-
var styles2 = EditorView4.baseTheme({
|
|
1014
|
-
"& .cm-bookmark": {
|
|
1015
|
-
cursor: "pointer",
|
|
1016
|
-
margin: "4px",
|
|
1017
|
-
padding: "4px",
|
|
1018
|
-
backgroundColor: "yellow"
|
|
1019
|
-
},
|
|
1020
|
-
"& .cm-bookmark-selected": {
|
|
1021
|
-
backgroundColor: "orange"
|
|
1022
|
-
},
|
|
1075
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1023
1077
|
"& .cm-comment": {
|
|
1024
|
-
backgroundColor: "yellow"
|
|
1078
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1025
1079
|
},
|
|
1026
|
-
"& .cm-comment-
|
|
1027
|
-
backgroundColor: "
|
|
1080
|
+
"& .cm-comment-current": {
|
|
1081
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1028
1082
|
}
|
|
1029
1083
|
});
|
|
1030
|
-
var
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1084
|
+
var commentMark = Decoration2.mark({
|
|
1085
|
+
class: "cm-comment"
|
|
1086
|
+
});
|
|
1087
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1088
|
+
class: "cm-comment-current"
|
|
1089
|
+
});
|
|
1090
|
+
var focusComment = (view, id, center = true) => {
|
|
1091
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1092
|
+
if (!comment?.comment.cursor) {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1096
|
+
if (range) {
|
|
1097
|
+
view.dispatch({
|
|
1098
|
+
selection: {
|
|
1099
|
+
anchor: range.from
|
|
1100
|
+
},
|
|
1101
|
+
effects: [
|
|
1102
|
+
//
|
|
1103
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1104
|
+
y: "center"
|
|
1105
|
+
} : void 0),
|
|
1106
|
+
setSelection.of({
|
|
1107
|
+
current: id
|
|
1108
|
+
})
|
|
1109
|
+
]
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1037
1112
|
};
|
|
1038
|
-
var
|
|
1113
|
+
var setComments = StateEffect2.define();
|
|
1039
1114
|
var setSelection = StateEffect2.define();
|
|
1040
1115
|
var setCommentState = StateEffect2.define();
|
|
1041
|
-
var
|
|
1116
|
+
var commentsState = StateField2.define({
|
|
1042
1117
|
create: () => ({
|
|
1043
|
-
|
|
1118
|
+
comments: [],
|
|
1119
|
+
selection: {}
|
|
1044
1120
|
}),
|
|
1045
1121
|
update: (value, tr) => {
|
|
1046
1122
|
for (const effect of tr.effects) {
|
|
1047
1123
|
if (effect.is(setSelection)) {
|
|
1048
1124
|
return {
|
|
1049
1125
|
...value,
|
|
1050
|
-
|
|
1126
|
+
selection: effect.value
|
|
1051
1127
|
};
|
|
1052
1128
|
}
|
|
1053
|
-
if (effect.is(
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1129
|
+
if (effect.is(setComments)) {
|
|
1130
|
+
const comments2 = effect.value.map((comment) => {
|
|
1131
|
+
if (!comment.cursor) {
|
|
1132
|
+
return void 0;
|
|
1133
|
+
}
|
|
1134
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1135
|
+
return range && {
|
|
1136
|
+
comment,
|
|
1137
|
+
range
|
|
1060
1138
|
};
|
|
1061
|
-
});
|
|
1139
|
+
}).filter(nonNullable);
|
|
1062
1140
|
return {
|
|
1063
1141
|
...value,
|
|
1064
|
-
|
|
1142
|
+
comments: comments2
|
|
1065
1143
|
};
|
|
1066
1144
|
}
|
|
1067
1145
|
if (effect.is(setCommentState)) {
|
|
@@ -1071,143 +1149,174 @@ var commentsStateField = StateField3.define({
|
|
|
1071
1149
|
return value;
|
|
1072
1150
|
}
|
|
1073
1151
|
});
|
|
1074
|
-
var
|
|
1075
|
-
|
|
1152
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1153
|
+
commentsState
|
|
1076
1154
|
], (state) => {
|
|
1077
|
-
const {
|
|
1078
|
-
const decorations = sortBy(
|
|
1079
|
-
|
|
1155
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1156
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1157
|
+
const range = comment.range;
|
|
1158
|
+
if (!range || range.from === range.to) {
|
|
1159
|
+
console.warn("Invalid range:", range);
|
|
1080
1160
|
return void 0;
|
|
1081
1161
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
to: selection.to
|
|
1085
|
-
};
|
|
1086
|
-
if (selection.id === active) {
|
|
1087
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1162
|
+
if (comment.comment.id === current) {
|
|
1163
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1088
1164
|
} else {
|
|
1089
|
-
return
|
|
1165
|
+
return commentMark.range(range.from, range.to);
|
|
1090
1166
|
}
|
|
1091
|
-
}).filter(nonNullable)
|
|
1167
|
+
}).filter(nonNullable);
|
|
1092
1168
|
return Decoration2.set(decorations);
|
|
1093
1169
|
});
|
|
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();
|
|
1119
|
-
}
|
|
1120
|
-
return span;
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
var comments = (options = {}) => {
|
|
1124
|
-
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1125
|
-
const createCommentThread = (view) => {
|
|
1126
|
-
invariant3(options.onCreate, void 0, {
|
|
1127
|
-
F: __dxlog_file5,
|
|
1128
|
-
L: 204,
|
|
1129
|
-
S: void 0,
|
|
1130
|
-
A: [
|
|
1131
|
-
"options.onCreate",
|
|
1132
|
-
""
|
|
1133
|
-
]
|
|
1134
|
-
});
|
|
1135
|
-
const { head, from, to } = view.state.selection.main;
|
|
1136
|
-
if (from === to) {
|
|
1137
|
-
return false;
|
|
1170
|
+
var trackPastedComments = (onUpdate) => {
|
|
1171
|
+
let tracked = null;
|
|
1172
|
+
const handleTrack = (event, view) => {
|
|
1173
|
+
const comments2 = view.state.field(commentsState);
|
|
1174
|
+
const { main } = view.state.selection;
|
|
1175
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1176
|
+
if (!selectedRanges.length) {
|
|
1177
|
+
tracked = null;
|
|
1178
|
+
} else {
|
|
1179
|
+
tracked = {
|
|
1180
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1181
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1182
|
+
id: comment.id,
|
|
1183
|
+
from: range.from - main.from,
|
|
1184
|
+
to: range.to - main.from
|
|
1185
|
+
}))
|
|
1186
|
+
};
|
|
1138
1187
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1188
|
+
};
|
|
1189
|
+
return [
|
|
1190
|
+
EditorView5.domEventHandlers({
|
|
1191
|
+
cut: handleTrack,
|
|
1192
|
+
copy: handleTrack
|
|
1193
|
+
}),
|
|
1194
|
+
// Track deleted comments.
|
|
1195
|
+
invertedEffects2.of((tr) => {
|
|
1196
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1197
|
+
const effects = [];
|
|
1198
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1199
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1200
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1201
|
+
effects.push(restoreCommentEffect.of({
|
|
1202
|
+
id,
|
|
1203
|
+
from,
|
|
1204
|
+
to
|
|
1205
|
+
}));
|
|
1153
1206
|
}
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1209
|
+
return effects;
|
|
1210
|
+
}),
|
|
1211
|
+
// Handle paste or the undo of comment deletion.
|
|
1212
|
+
EditorView5.updateListener.of((update2) => {
|
|
1213
|
+
const restore = [];
|
|
1214
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1215
|
+
const tr = update2.transactions[i];
|
|
1216
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1217
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1218
|
+
}
|
|
1219
|
+
for (const effect of tr.effects) {
|
|
1220
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1221
|
+
restore.push(effect.value);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (tracked) {
|
|
1226
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1227
|
+
if (paste) {
|
|
1228
|
+
let found = -1;
|
|
1229
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1230
|
+
if (text.eq(tracked.text)) {
|
|
1231
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1232
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1233
|
+
}
|
|
1234
|
+
found = fromB;
|
|
1164
1235
|
}
|
|
1165
1236
|
});
|
|
1237
|
+
if (found > -1) {
|
|
1238
|
+
for (const moved of tracked.comments) {
|
|
1239
|
+
restore.push({
|
|
1240
|
+
id: moved.id,
|
|
1241
|
+
from: found + moved.from,
|
|
1242
|
+
to: found + moved.to
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
tracked = null;
|
|
1166
1247
|
}
|
|
1167
|
-
return true;
|
|
1168
1248
|
}
|
|
1169
|
-
|
|
1249
|
+
for (const comment of restore) {
|
|
1250
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1251
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1252
|
+
if (!exists) {
|
|
1253
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1254
|
+
onUpdate(comment.id, cursor);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
})
|
|
1258
|
+
];
|
|
1259
|
+
};
|
|
1260
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1261
|
+
id: comment.id,
|
|
1262
|
+
from: changes.mapPos(comment.from, 1),
|
|
1263
|
+
to: changes.mapPos(comment.to, 1)
|
|
1264
|
+
});
|
|
1265
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1266
|
+
map: mapTrackedComment
|
|
1267
|
+
});
|
|
1268
|
+
var optionsFacet = Facet3.define({
|
|
1269
|
+
combine: (providers) => providers[0]
|
|
1270
|
+
});
|
|
1271
|
+
var createComment = (view) => {
|
|
1272
|
+
const options = view.state.facet(optionsFacet);
|
|
1273
|
+
const { from, to } = view.state.selection.main;
|
|
1274
|
+
if (from === to) {
|
|
1170
1275
|
return false;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1276
|
+
}
|
|
1277
|
+
if (to === view.state.doc.length) {
|
|
1278
|
+
view.dispatch({
|
|
1279
|
+
changes: {
|
|
1280
|
+
from: to,
|
|
1281
|
+
insert: "\n"
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1286
|
+
from,
|
|
1287
|
+
to
|
|
1288
|
+
});
|
|
1289
|
+
if (cursor) {
|
|
1290
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1291
|
+
if (id) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
effects: setSelection.of({
|
|
1294
|
+
current: id
|
|
1295
|
+
}),
|
|
1296
|
+
selection: {
|
|
1297
|
+
anchor: to
|
|
1184
1298
|
}
|
|
1185
1299
|
});
|
|
1300
|
+
return true;
|
|
1186
1301
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
}, {
|
|
1194
|
-
decorations: (instance) => instance.bookmarks,
|
|
1195
|
-
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
1196
|
-
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
1197
|
-
})
|
|
1198
|
-
});
|
|
1302
|
+
}
|
|
1303
|
+
return false;
|
|
1304
|
+
};
|
|
1305
|
+
var comments = (options = {}) => {
|
|
1306
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1307
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1199
1308
|
return [
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1309
|
+
optionsFacet.of(options),
|
|
1310
|
+
commentsState,
|
|
1311
|
+
commentsDecorations,
|
|
1203
1312
|
styles2,
|
|
1204
1313
|
//
|
|
1205
1314
|
// Keymap.
|
|
1206
1315
|
//
|
|
1207
1316
|
options.onCreate ? keymap3.of([
|
|
1208
1317
|
{
|
|
1209
|
-
key:
|
|
1210
|
-
run:
|
|
1318
|
+
key: shortcut,
|
|
1319
|
+
run: callbackWrapper(createComment)
|
|
1211
1320
|
}
|
|
1212
1321
|
]) : [],
|
|
1213
1322
|
//
|
|
@@ -1223,327 +1332,141 @@ var comments = (options = {}) => {
|
|
|
1223
1332
|
above: true,
|
|
1224
1333
|
create: () => {
|
|
1225
1334
|
const el = document.createElement("div");
|
|
1226
|
-
options.onHover
|
|
1335
|
+
options.onHover(el, shortcut);
|
|
1227
1336
|
return {
|
|
1228
1337
|
dom: el,
|
|
1229
1338
|
offset: {
|
|
1230
1339
|
x: 0,
|
|
1231
1340
|
y: 8
|
|
1232
1341
|
}
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
return null;
|
|
1238
|
-
}, {
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
//
|
|
1244
|
-
//
|
|
1245
|
-
//
|
|
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
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
return null;
|
|
1347
|
+
}, {
|
|
1348
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1349
|
+
// hideOnChange: true,
|
|
1350
|
+
hoverTime: 1e3
|
|
1351
|
+
}) : [],
|
|
1352
|
+
//
|
|
1353
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1354
|
+
//
|
|
1355
|
+
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1356
|
+
let mod = false;
|
|
1357
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1358
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1359
|
+
comments2.forEach(({ comment, range }) => {
|
|
1360
|
+
if (from2 === to2) {
|
|
1361
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1362
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1363
|
+
options.onDelete?.(comment.id);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
if (from <= range.to) {
|
|
1367
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1368
|
+
Object.assign(range, newRange);
|
|
1369
|
+
mod = true;
|
|
1472
1370
|
}
|
|
1473
1371
|
});
|
|
1474
|
-
};
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1372
|
+
});
|
|
1373
|
+
if (mod) {
|
|
1374
|
+
view.dispatch({
|
|
1375
|
+
effects: setCommentState.of({
|
|
1376
|
+
comments: comments2,
|
|
1377
|
+
...value
|
|
1378
|
+
})
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
}),
|
|
1382
|
+
//
|
|
1383
|
+
// Track selection/proximity.
|
|
1384
|
+
//
|
|
1385
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1386
|
+
let min = Infinity;
|
|
1387
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1388
|
+
const { head } = state.selection.main;
|
|
1389
|
+
const selection = {};
|
|
1390
|
+
comments2.forEach(({ comment, range }) => {
|
|
1391
|
+
if (head >= range.from && head <= range.to) {
|
|
1392
|
+
selection.current = comment.id;
|
|
1393
|
+
selection.closest = void 0;
|
|
1496
1394
|
}
|
|
1497
|
-
if (
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1395
|
+
if (!selection.current) {
|
|
1396
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1397
|
+
if (d < min) {
|
|
1398
|
+
selection.closest = comment.id;
|
|
1399
|
+
min = d;
|
|
1400
|
+
}
|
|
1501
1401
|
}
|
|
1502
|
-
|
|
1402
|
+
});
|
|
1403
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1404
|
+
view.dispatch({
|
|
1405
|
+
effects: setSelection.of(selection)
|
|
1406
|
+
});
|
|
1407
|
+
handleSelect({
|
|
1408
|
+
selection,
|
|
1409
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1410
|
+
comment,
|
|
1411
|
+
range,
|
|
1412
|
+
location: view.coordsAtPos(range.from)
|
|
1413
|
+
}))
|
|
1414
|
+
});
|
|
1503
1415
|
}
|
|
1416
|
+
}),
|
|
1417
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1418
|
+
];
|
|
1419
|
+
};
|
|
1420
|
+
var useComments = (view, comments2 = []) => {
|
|
1421
|
+
useEffect(() => {
|
|
1422
|
+
if (view) {
|
|
1423
|
+
view.dispatch({
|
|
1424
|
+
effects: setComments.of(comments2)
|
|
1425
|
+
});
|
|
1504
1426
|
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1427
|
+
}, [
|
|
1428
|
+
view,
|
|
1429
|
+
comments2
|
|
1430
|
+
]);
|
|
1507
1431
|
};
|
|
1508
1432
|
|
|
1509
|
-
// packages/ui/react-ui-editor/src/
|
|
1510
|
-
import {
|
|
1511
|
-
var listener = ({ onChange }) => {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1433
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1434
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1435
|
+
var listener = ({ onFocus, onChange }) => {
|
|
1436
|
+
const extensions = [];
|
|
1437
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1438
|
+
onFocus(focused);
|
|
1439
|
+
return null;
|
|
1440
|
+
}));
|
|
1441
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1442
|
+
onChange(update2.state.doc.toString());
|
|
1443
|
+
}));
|
|
1444
|
+
return extensions;
|
|
1521
1445
|
};
|
|
1522
1446
|
|
|
1523
|
-
// packages/ui/react-ui-editor/src/
|
|
1447
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1524
1448
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1525
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1526
|
-
import { markdownLanguage as
|
|
1449
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1450
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1527
1451
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1528
1452
|
import { languages } from "@codemirror/language-data";
|
|
1529
1453
|
import { searchKeymap } from "@codemirror/search";
|
|
1530
1454
|
import { EditorState } from "@codemirror/state";
|
|
1531
1455
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1532
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1456
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1457
|
+
import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1533
1458
|
|
|
1534
|
-
// packages/ui/react-ui-editor/src/
|
|
1535
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1459
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1460
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1536
1461
|
import { HighlightStyle } from "@codemirror/language";
|
|
1537
1462
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1538
1463
|
import { Table } from "@lezer/markdown";
|
|
1539
|
-
import get4 from "lodash.get";
|
|
1540
1464
|
var markdownTags = {
|
|
1541
1465
|
Blockquote: Tag.define(),
|
|
1542
1466
|
CodeMark: Tag.define(),
|
|
1543
1467
|
CodeText: Tag.define(),
|
|
1544
1468
|
EmphasisMark: Tag.define(),
|
|
1545
1469
|
HeaderMark: Tag.define(),
|
|
1546
|
-
// HorizontalRule: Tag.define(),
|
|
1547
1470
|
InlineCode: Tag.define(),
|
|
1548
1471
|
LinkLabel: Tag.define(),
|
|
1549
1472
|
LinkReference: Tag.define(),
|
|
@@ -1628,7 +1551,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1628
1551
|
markdownTags.QuoteMark,
|
|
1629
1552
|
markdownTags.EmphasisMark
|
|
1630
1553
|
],
|
|
1631
|
-
class:
|
|
1554
|
+
class: mark
|
|
1632
1555
|
},
|
|
1633
1556
|
// E.g., code block language (after ```).
|
|
1634
1557
|
{
|
|
@@ -1636,7 +1559,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1636
1559
|
tags.function(tags.variableName),
|
|
1637
1560
|
tags.labelName
|
|
1638
1561
|
],
|
|
1639
|
-
class:
|
|
1562
|
+
class: codeMark
|
|
1640
1563
|
},
|
|
1641
1564
|
{
|
|
1642
1565
|
tag: [
|
|
@@ -1647,27 +1570,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1647
1570
|
// Headings.
|
|
1648
1571
|
{
|
|
1649
1572
|
tag: tags.heading1,
|
|
1650
|
-
class: heading(1
|
|
1573
|
+
class: heading(1)
|
|
1651
1574
|
},
|
|
1652
1575
|
{
|
|
1653
1576
|
tag: tags.heading2,
|
|
1654
|
-
class: heading(2
|
|
1577
|
+
class: heading(2)
|
|
1655
1578
|
},
|
|
1656
1579
|
{
|
|
1657
1580
|
tag: tags.heading3,
|
|
1658
|
-
class: heading(3
|
|
1581
|
+
class: heading(3)
|
|
1659
1582
|
},
|
|
1660
1583
|
{
|
|
1661
1584
|
tag: tags.heading4,
|
|
1662
|
-
class: heading(4
|
|
1585
|
+
class: heading(4)
|
|
1663
1586
|
},
|
|
1664
1587
|
{
|
|
1665
1588
|
tag: tags.heading5,
|
|
1666
|
-
class: heading(5
|
|
1589
|
+
class: heading(5)
|
|
1667
1590
|
},
|
|
1668
1591
|
{
|
|
1669
1592
|
tag: tags.heading6,
|
|
1670
|
-
class: heading(6
|
|
1593
|
+
class: heading(6)
|
|
1671
1594
|
},
|
|
1672
1595
|
// Emphasis.
|
|
1673
1596
|
{
|
|
@@ -1689,138 +1612,671 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1689
1612
|
],
|
|
1690
1613
|
class: inlineUrl
|
|
1691
1614
|
},
|
|
1692
|
-
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
1693
|
-
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1694
|
-
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1695
|
-
// the code, but all other CSS properties will be inherited.
|
|
1696
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1697
|
-
{
|
|
1698
|
-
tag: [
|
|
1699
|
-
markdownTags.CodeText,
|
|
1700
|
-
markdownTags.InlineCode
|
|
1701
|
-
],
|
|
1702
|
-
class: code
|
|
1615
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
1616
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1617
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1618
|
+
// the code, but all other CSS properties will be inherited.
|
|
1619
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1620
|
+
{
|
|
1621
|
+
tag: [
|
|
1622
|
+
markdownTags.CodeText,
|
|
1623
|
+
markdownTags.InlineCode
|
|
1624
|
+
],
|
|
1625
|
+
class: code
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
tag: [
|
|
1629
|
+
markdownTags.QuoteMark
|
|
1630
|
+
],
|
|
1631
|
+
class: blockquote
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
tag: [
|
|
1635
|
+
markdownTags.TableCell
|
|
1636
|
+
],
|
|
1637
|
+
class: "font-mono"
|
|
1638
|
+
}
|
|
1639
|
+
], {
|
|
1640
|
+
scope: markdownLanguage2,
|
|
1641
|
+
all: {
|
|
1642
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1647
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1648
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1649
|
+
return [
|
|
1650
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1651
|
+
EditorState.allowMultipleSelections.of(true),
|
|
1652
|
+
EditorState.tabSize.of(2),
|
|
1653
|
+
// https://github.com/codemirror/basic-setup
|
|
1654
|
+
bracketMatching2(),
|
|
1655
|
+
closeBrackets2(),
|
|
1656
|
+
crosshairCursor(),
|
|
1657
|
+
dropCursor(),
|
|
1658
|
+
drawSelection2(),
|
|
1659
|
+
highlightActiveLine2(),
|
|
1660
|
+
history2(),
|
|
1661
|
+
indentOnInput(),
|
|
1662
|
+
_placeholder && placeholder2(_placeholder),
|
|
1663
|
+
// Main extension.
|
|
1664
|
+
// https://github.com/codemirror/lang-markdown
|
|
1665
|
+
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
1666
|
+
markdown({
|
|
1667
|
+
// GRM by default (vs strict CommonMark):
|
|
1668
|
+
// Table, TaskList, Strikethrough, and Autolink.
|
|
1669
|
+
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1670
|
+
// https://github.github.com/gfm
|
|
1671
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1672
|
+
base: markdownLanguage3,
|
|
1673
|
+
// Languages for syntax highlighting fenced code blocks.
|
|
1674
|
+
codeLanguages: languages,
|
|
1675
|
+
// Parser extensions.
|
|
1676
|
+
extensions: [
|
|
1677
|
+
// GFM provided by default.
|
|
1678
|
+
markdownTagsExtensions
|
|
1679
|
+
]
|
|
1680
|
+
}),
|
|
1681
|
+
// https://github.com/codemirror/theme-one-dark
|
|
1682
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1683
|
+
// Custom styles.
|
|
1684
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1685
|
+
keymap4.of([
|
|
1686
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1687
|
+
indentWithTab,
|
|
1688
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1689
|
+
...closeBracketsKeymap,
|
|
1690
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1691
|
+
...historyKeymap,
|
|
1692
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1693
|
+
...searchKeymap,
|
|
1694
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1695
|
+
...standardKeymap
|
|
1696
|
+
])
|
|
1697
|
+
].filter(isNotFalsy2);
|
|
1698
|
+
};
|
|
1699
|
+
|
|
1700
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1701
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1702
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1703
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1704
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1705
|
+
var styles3 = EditorView8.baseTheme({
|
|
1706
|
+
"& .cm-code": {
|
|
1707
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1708
|
+
},
|
|
1709
|
+
"& .cm-codeblock": {
|
|
1710
|
+
width: "100%",
|
|
1711
|
+
paddingInline: "1rem !important",
|
|
1712
|
+
position: "relative",
|
|
1713
|
+
"&::after": {
|
|
1714
|
+
content: '""',
|
|
1715
|
+
position: "absolute",
|
|
1716
|
+
inset: 0
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
"&light .cm-codeblock": {
|
|
1720
|
+
"&::after": {
|
|
1721
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1722
|
+
mixBlendMode: "darken"
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
"&dark .cm-codeblock": {
|
|
1726
|
+
"&::after": {
|
|
1727
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1728
|
+
mixBlendMode: "lighten"
|
|
1729
|
+
}
|
|
1730
|
+
},
|
|
1731
|
+
"& .cm-codeblock-first": {
|
|
1732
|
+
display: "inline-block",
|
|
1733
|
+
"&::after": {
|
|
1734
|
+
borderTopLeftRadius: ".5rem",
|
|
1735
|
+
borderTopRightRadius: ".5rem"
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
"& .cm-codeblock-last": {
|
|
1739
|
+
display: "inline-block",
|
|
1740
|
+
"&::after": {
|
|
1741
|
+
borderBottomLeftRadius: ".5rem",
|
|
1742
|
+
borderBottomRightRadius: ".5rem"
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
});
|
|
1746
|
+
var getLineRange = (lines, from, to) => {
|
|
1747
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1748
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1749
|
+
return [
|
|
1750
|
+
start,
|
|
1751
|
+
end
|
|
1752
|
+
];
|
|
1753
|
+
};
|
|
1754
|
+
var LineWidget = class extends WidgetType2 {
|
|
1755
|
+
constructor(_className) {
|
|
1756
|
+
super();
|
|
1757
|
+
this._className = _className;
|
|
1758
|
+
}
|
|
1759
|
+
toDOM() {
|
|
1760
|
+
const el = document.createElement("span");
|
|
1761
|
+
el.innerHTML = " ";
|
|
1762
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1763
|
+
return el;
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1767
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1768
|
+
var buildDecorations = (view) => {
|
|
1769
|
+
const builder = new RangeSetBuilder();
|
|
1770
|
+
const { state } = view;
|
|
1771
|
+
const blocks = view.viewportLineBlocks;
|
|
1772
|
+
const cursor = state.selection.main.head;
|
|
1773
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1774
|
+
syntaxTree(state).iterate({
|
|
1775
|
+
enter: (node) => {
|
|
1776
|
+
if (node.name === "FencedCode") {
|
|
1777
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1778
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1779
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1780
|
+
const block = blocks[i];
|
|
1781
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1782
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1783
|
+
widget: i === range[0] ? top : bottom
|
|
1784
|
+
}));
|
|
1785
|
+
} else {
|
|
1786
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1787
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1788
|
+
}));
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
from,
|
|
1794
|
+
to
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
return builder.finish();
|
|
1798
|
+
};
|
|
1799
|
+
var code2 = () => {
|
|
1800
|
+
return [
|
|
1801
|
+
ViewPlugin3.fromClass(class {
|
|
1802
|
+
constructor(view) {
|
|
1803
|
+
this.decorations = buildDecorations(view);
|
|
1804
|
+
}
|
|
1805
|
+
update(update2) {
|
|
1806
|
+
this.decorations = buildDecorations(update2.view);
|
|
1807
|
+
}
|
|
1808
|
+
}, {
|
|
1809
|
+
decorations: (value) => value.decorations
|
|
1810
|
+
}),
|
|
1811
|
+
styles3
|
|
1812
|
+
];
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1816
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1817
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1818
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1819
|
+
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1820
|
+
var setHeading = (level) => (view) => {
|
|
1821
|
+
const { selection: { ranges }, doc } = view.state;
|
|
1822
|
+
const changes = [];
|
|
1823
|
+
for (const range of ranges) {
|
|
1824
|
+
const { number } = doc.lineAt(range.anchor);
|
|
1825
|
+
const { from, to } = doc.line(number);
|
|
1826
|
+
const line = doc.sliceString(from, to);
|
|
1827
|
+
const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
|
|
1828
|
+
const current = marks?.length ?? 0;
|
|
1829
|
+
if (level !== current) {
|
|
1830
|
+
changes.push({
|
|
1831
|
+
from,
|
|
1832
|
+
to: from + current + (spaces?.length ?? 0),
|
|
1833
|
+
insert: "#".repeat(level) + (level > 0 ? " " : "")
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
if (changes.length) {
|
|
1838
|
+
view.dispatch({
|
|
1839
|
+
changes
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
return true;
|
|
1843
|
+
};
|
|
1844
|
+
var toggleStyle = (mark2) => (view) => {
|
|
1845
|
+
const { ranges } = view.state.selection;
|
|
1846
|
+
for (const range of ranges) {
|
|
1847
|
+
if (range.from === range.to) {
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
view.dispatch({
|
|
1851
|
+
changes: [
|
|
1852
|
+
{
|
|
1853
|
+
from: range.from,
|
|
1854
|
+
insert: mark2
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
from: range.to,
|
|
1858
|
+
insert: mark2
|
|
1859
|
+
}
|
|
1860
|
+
]
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
return true;
|
|
1864
|
+
};
|
|
1865
|
+
var snippets = {
|
|
1866
|
+
codeblock: snippet([
|
|
1867
|
+
"```#{lang}",
|
|
1868
|
+
" #{}",
|
|
1869
|
+
"```"
|
|
1870
|
+
].join("\n")),
|
|
1871
|
+
table: snippet([
|
|
1872
|
+
"| #{col1} | #{col2} |",
|
|
1873
|
+
"| ---- | ---- |",
|
|
1874
|
+
"| #{val1} | #{val2} |",
|
|
1875
|
+
"| #{val3} | #{val4} |"
|
|
1876
|
+
].join("\n"))
|
|
1877
|
+
};
|
|
1878
|
+
var insertCodeblock = (view) => {
|
|
1879
|
+
const { selection: { main }, doc } = view.state;
|
|
1880
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1881
|
+
const { from } = doc.line(number);
|
|
1882
|
+
snippets.codeblock(view, null, from, from);
|
|
1883
|
+
};
|
|
1884
|
+
var insertTable = (view) => {
|
|
1885
|
+
const { selection: { main }, doc } = view.state;
|
|
1886
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1887
|
+
const { from } = doc.line(number);
|
|
1888
|
+
snippets.table(view, null, from, from);
|
|
1889
|
+
};
|
|
1890
|
+
var toggleBold = toggleStyle("**");
|
|
1891
|
+
var toggleItalic = toggleStyle("_");
|
|
1892
|
+
var toggleStrikethrough = toggleStyle("~~");
|
|
1893
|
+
var toggleList = (view) => {
|
|
1894
|
+
};
|
|
1895
|
+
var formatting = (options = {}) => {
|
|
1896
|
+
return [
|
|
1897
|
+
keymap5.of([
|
|
1898
|
+
{
|
|
1899
|
+
key: "meta-b",
|
|
1900
|
+
run: toggleBold
|
|
1901
|
+
}
|
|
1902
|
+
]),
|
|
1903
|
+
styling()
|
|
1904
|
+
];
|
|
1905
|
+
};
|
|
1906
|
+
var styling = () => {
|
|
1907
|
+
const buildDecorations7 = (view) => {
|
|
1908
|
+
const builder = new RangeSetBuilder2();
|
|
1909
|
+
const { state } = view;
|
|
1910
|
+
const cursor = state.selection.main.head;
|
|
1911
|
+
const replace = (node, marks) => {
|
|
1912
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1913
|
+
for (const mark2 of marks) {
|
|
1914
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1919
|
+
syntaxTree2(state).iterate({
|
|
1920
|
+
enter: (node) => {
|
|
1921
|
+
switch (node.name) {
|
|
1922
|
+
case "Emphasis":
|
|
1923
|
+
case "StrongEmphasis": {
|
|
1924
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
1925
|
+
replace(node, marks);
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
case "Strikethrough": {
|
|
1929
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
1930
|
+
replace(node, marks);
|
|
1931
|
+
break;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
},
|
|
1935
|
+
from,
|
|
1936
|
+
to
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
return builder.finish();
|
|
1940
|
+
};
|
|
1941
|
+
return [
|
|
1942
|
+
ViewPlugin4.fromClass(class {
|
|
1943
|
+
constructor(view) {
|
|
1944
|
+
this.decorations = buildDecorations7(view);
|
|
1945
|
+
}
|
|
1946
|
+
update(update2) {
|
|
1947
|
+
this.decorations = buildDecorations7(update2.view);
|
|
1948
|
+
}
|
|
1949
|
+
}, {
|
|
1950
|
+
decorations: (value) => value.decorations
|
|
1951
|
+
})
|
|
1952
|
+
];
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1956
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1957
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1958
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1959
|
+
var buildDecorations2 = (view) => {
|
|
1960
|
+
const builder = new RangeSetBuilder3();
|
|
1961
|
+
const { state } = view;
|
|
1962
|
+
const cursor = state.selection.main.head;
|
|
1963
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1964
|
+
syntaxTree3(state).iterate({
|
|
1965
|
+
enter: (node) => {
|
|
1966
|
+
switch (node.name) {
|
|
1967
|
+
case "ATXHeading1":
|
|
1968
|
+
case "ATXHeading2":
|
|
1969
|
+
case "ATXHeading3":
|
|
1970
|
+
case "ATXHeading4":
|
|
1971
|
+
case "ATXHeading5":
|
|
1972
|
+
case "ATXHeading6": {
|
|
1973
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1974
|
+
if (mark2) {
|
|
1975
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1976
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
from,
|
|
1983
|
+
to
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
return builder.finish();
|
|
1987
|
+
};
|
|
1988
|
+
var heading2 = () => {
|
|
1989
|
+
return [
|
|
1990
|
+
ViewPlugin5.fromClass(class {
|
|
1991
|
+
constructor(view) {
|
|
1992
|
+
this.decorations = buildDecorations2(view);
|
|
1993
|
+
}
|
|
1994
|
+
update(update2) {
|
|
1995
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1996
|
+
}
|
|
1997
|
+
}, {
|
|
1998
|
+
decorations: (value) => value.decorations
|
|
1999
|
+
})
|
|
2000
|
+
];
|
|
2001
|
+
};
|
|
2002
|
+
|
|
2003
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2004
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2005
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2006
|
+
import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2007
|
+
var styles4 = EditorView9.baseTheme({
|
|
2008
|
+
"& .cm-hr": {
|
|
2009
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2010
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2014
|
+
toDOM() {
|
|
2015
|
+
const el = document.createElement("div");
|
|
2016
|
+
el.className = "cm-hr";
|
|
2017
|
+
return el;
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
var decoration = Decoration6.replace({
|
|
2021
|
+
widget: new HorizontalRuleWidget()
|
|
2022
|
+
});
|
|
2023
|
+
var buildDecorations3 = (view) => {
|
|
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
|
+
syntaxTree4(state).iterate({
|
|
2029
|
+
enter: (node) => {
|
|
2030
|
+
if (node.name === "HorizontalRule") {
|
|
2031
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2032
|
+
builder.add(node.from, node.to, decoration);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
from,
|
|
2037
|
+
to
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
return builder.finish();
|
|
2041
|
+
};
|
|
2042
|
+
var hr = () => {
|
|
2043
|
+
return [
|
|
2044
|
+
ViewPlugin6.fromClass(class {
|
|
2045
|
+
constructor(view) {
|
|
2046
|
+
this.decorations = buildDecorations3(view);
|
|
2047
|
+
}
|
|
2048
|
+
update(update2) {
|
|
2049
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2050
|
+
}
|
|
2051
|
+
}, {
|
|
2052
|
+
decorations: (value) => value.decorations
|
|
2053
|
+
}),
|
|
2054
|
+
styles4
|
|
2055
|
+
];
|
|
2056
|
+
};
|
|
2057
|
+
|
|
2058
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2059
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2060
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
2061
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2062
|
+
var image = (options = {}) => {
|
|
2063
|
+
return StateField3.define({
|
|
2064
|
+
create: (state) => {
|
|
2065
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
2066
|
+
},
|
|
2067
|
+
update: (value, tr) => {
|
|
2068
|
+
if (!tr.docChanged && !tr.selection) {
|
|
2069
|
+
return value;
|
|
2070
|
+
}
|
|
2071
|
+
const cursor = tr.state.selection.main.head;
|
|
2072
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
2073
|
+
let from = Math.min(cursor, oldCursor);
|
|
2074
|
+
let to = Math.max(cursor, oldCursor);
|
|
2075
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
2076
|
+
from = Math.min(from, fromB);
|
|
2077
|
+
to = Math.max(to, toB);
|
|
2078
|
+
});
|
|
2079
|
+
from = tr.state.doc.lineAt(from).from;
|
|
2080
|
+
to = tr.state.doc.lineAt(to).to;
|
|
2081
|
+
return value.map(tr.changes).update({
|
|
2082
|
+
filterFrom: from,
|
|
2083
|
+
filterTo: to,
|
|
2084
|
+
filter: () => false,
|
|
2085
|
+
add: buildDecorations4(from, to, tr.state)
|
|
2086
|
+
});
|
|
1703
2087
|
},
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
2088
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
2089
|
+
});
|
|
2090
|
+
};
|
|
2091
|
+
var buildDecorations4 = (from, to, state) => {
|
|
2092
|
+
const decorations = [];
|
|
2093
|
+
const cursor = state.selection.main.head;
|
|
2094
|
+
syntaxTree5(state).iterate({
|
|
2095
|
+
enter: (node) => {
|
|
2096
|
+
if (node.name === "Image") {
|
|
2097
|
+
const urlNode = node.node.getChild("URL");
|
|
2098
|
+
if (urlNode) {
|
|
2099
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
2100
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2101
|
+
decorations.push(Decoration7.replace({
|
|
2102
|
+
block: true,
|
|
2103
|
+
widget: new ImageWidget(url)
|
|
2104
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
1709
2107
|
},
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1713
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1714
|
-
// },
|
|
1715
|
-
// TODO(burdon): Only if being edited.
|
|
1716
|
-
{
|
|
1717
|
-
tag: [
|
|
1718
|
-
markdownTags.TableCell
|
|
1719
|
-
],
|
|
1720
|
-
class: "font-mono"
|
|
1721
|
-
}
|
|
1722
|
-
], {
|
|
1723
|
-
scope: markdownLanguage,
|
|
1724
|
-
all: {
|
|
1725
|
-
fontFamily: get4(tokens, "fontFamily.body", []).join(",")
|
|
1726
|
-
}
|
|
2108
|
+
from,
|
|
2109
|
+
to
|
|
1727
2110
|
});
|
|
2111
|
+
return decorations;
|
|
2112
|
+
};
|
|
2113
|
+
var ImageWidget = class extends WidgetType4 {
|
|
2114
|
+
constructor(_url) {
|
|
2115
|
+
super();
|
|
2116
|
+
this._url = _url;
|
|
2117
|
+
}
|
|
2118
|
+
eq(other) {
|
|
2119
|
+
return this._url === other._url;
|
|
2120
|
+
}
|
|
2121
|
+
toDOM(view) {
|
|
2122
|
+
const img = document.createElement("img");
|
|
2123
|
+
img.setAttribute("src", this._url);
|
|
2124
|
+
img.setAttribute("class", "cm-image");
|
|
2125
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
2126
|
+
return img;
|
|
2127
|
+
}
|
|
1728
2128
|
};
|
|
1729
2129
|
|
|
1730
|
-
// packages/ui/react-ui-editor/src/
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
//
|
|
1753
|
-
// https://
|
|
1754
|
-
// https://github.com/
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
}),
|
|
1764
|
-
// https://github.com/codemirror/theme-one-dark
|
|
1765
|
-
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1766
|
-
// Custom styles.
|
|
1767
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1768
|
-
].filter(Boolean);
|
|
1769
|
-
};
|
|
1770
|
-
var customKeymap = () => keymap4.of([
|
|
1771
|
-
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1772
|
-
indentWithTab,
|
|
1773
|
-
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1774
|
-
...standardKeymap,
|
|
1775
|
-
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1776
|
-
...historyKeymap,
|
|
1777
|
-
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1778
|
-
...closeBracketsKeymap,
|
|
1779
|
-
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1780
|
-
...searchKeymap
|
|
1781
|
-
]);
|
|
1782
|
-
|
|
1783
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1784
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1785
|
-
var mention = ({ onSearch }) => {
|
|
1786
|
-
return autocompletion2({
|
|
1787
|
-
closeOnBlur: false,
|
|
1788
|
-
override: [
|
|
1789
|
-
(context) => {
|
|
1790
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1791
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
2130
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
2131
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2132
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
2133
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
2134
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
2135
|
+
var link = (options = {}) => {
|
|
2136
|
+
const extensions = [
|
|
2137
|
+
ViewPlugin7.fromClass(class {
|
|
2138
|
+
constructor(view) {
|
|
2139
|
+
this.decorations = buildDecorations5(view, options);
|
|
2140
|
+
}
|
|
2141
|
+
update(update2) {
|
|
2142
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2143
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}, {
|
|
2147
|
+
decorations: (value) => value.decorations
|
|
2148
|
+
})
|
|
2149
|
+
];
|
|
2150
|
+
if (options.onHover) {
|
|
2151
|
+
extensions.push(
|
|
2152
|
+
// https://codemirror.net/examples/tooltip
|
|
2153
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
2154
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
2155
|
+
hoverTooltip2((view, pos, side) => {
|
|
2156
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
2157
|
+
let link2 = null;
|
|
2158
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
2159
|
+
link2 = node.name === "Link" ? node : null;
|
|
2160
|
+
}
|
|
2161
|
+
const url = link2 && link2.getChild("URL");
|
|
2162
|
+
if (!url || !link2) {
|
|
1792
2163
|
return null;
|
|
1793
2164
|
}
|
|
1794
|
-
|
|
2165
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1795
2166
|
return {
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
2167
|
+
pos: link2.from,
|
|
2168
|
+
end: link2.to,
|
|
2169
|
+
above: true,
|
|
2170
|
+
create: () => {
|
|
2171
|
+
const el = document.createElement("div");
|
|
2172
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2173
|
+
options.onHover(el, urlText);
|
|
2174
|
+
return {
|
|
2175
|
+
dom: el,
|
|
2176
|
+
offset: {
|
|
2177
|
+
x: 0,
|
|
2178
|
+
y: 4
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
1800
2182
|
};
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
}
|
|
2183
|
+
})
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2186
|
+
return extensions;
|
|
1804
2187
|
};
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
2188
|
+
var LinkButton = class extends WidgetType5 {
|
|
2189
|
+
constructor(_url, _onAttach) {
|
|
2190
|
+
super();
|
|
2191
|
+
this._url = _url;
|
|
2192
|
+
this._onAttach = _onAttach;
|
|
2193
|
+
}
|
|
2194
|
+
eq(other) {
|
|
2195
|
+
return this._url === other._url;
|
|
2196
|
+
}
|
|
2197
|
+
toDOM(view) {
|
|
2198
|
+
const el = document.createElement("span");
|
|
2199
|
+
this._onAttach(el, this._url);
|
|
2200
|
+
return el;
|
|
2201
|
+
}
|
|
2202
|
+
};
|
|
2203
|
+
var LinkText = class extends WidgetType5 {
|
|
2204
|
+
constructor(_text, _url) {
|
|
2205
|
+
super();
|
|
2206
|
+
this._text = _text;
|
|
2207
|
+
this._url = _url;
|
|
2208
|
+
}
|
|
2209
|
+
eq(other) {
|
|
2210
|
+
return this._url === other._url;
|
|
2211
|
+
}
|
|
2212
|
+
toDOM(view) {
|
|
2213
|
+
const link2 = document.createElement("a");
|
|
2214
|
+
link2.setAttribute("class", "cm-link");
|
|
2215
|
+
link2.textContent = this._text;
|
|
2216
|
+
if (this._url) {
|
|
2217
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2218
|
+
link2.setAttribute("target", "_blank");
|
|
2219
|
+
link2.href = this._url;
|
|
2220
|
+
} else {
|
|
2221
|
+
link2.onclick = () => {
|
|
2222
|
+
view.dispatch({
|
|
2223
|
+
selection: {
|
|
2224
|
+
anchor: view.posAtDOM(link2)
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
return link2;
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
var buildDecorations5 = (view, options) => {
|
|
2233
|
+
const builder = new RangeSetBuilder5();
|
|
2234
|
+
const { state } = view;
|
|
2235
|
+
const cursor = state.selection.main.head;
|
|
2236
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2237
|
+
syntaxTree6(state).iterate({
|
|
2238
|
+
enter: (node) => {
|
|
2239
|
+
if (node.name === "Link") {
|
|
2240
|
+
const marks = node.node.getChildren("LinkMark");
|
|
2241
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2242
|
+
const urlNode = node.node.getChild("URL");
|
|
2243
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2244
|
+
if (!url) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2248
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2249
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2250
|
+
}));
|
|
2251
|
+
}
|
|
2252
|
+
if (options.onRender) {
|
|
2253
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2254
|
+
widget: new LinkButton(url, options.onRender)
|
|
2255
|
+
}));
|
|
2256
|
+
}
|
|
2257
|
+
return false;
|
|
2258
|
+
}
|
|
2259
|
+
},
|
|
2260
|
+
from,
|
|
2261
|
+
to
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
return builder.finish();
|
|
1809
2265
|
};
|
|
1810
2266
|
|
|
1811
|
-
// packages/ui/react-ui-editor/src/
|
|
1812
|
-
import { syntaxTree as
|
|
1813
|
-
import { RangeSetBuilder as
|
|
1814
|
-
import { Decoration as
|
|
2267
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2268
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2269
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2270
|
+
import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1815
2271
|
var table = (options = {}) => {
|
|
1816
|
-
return
|
|
1817
|
-
create: (state) =>
|
|
1818
|
-
update: (_, tr) =>
|
|
1819
|
-
provide: (field) =>
|
|
2272
|
+
return StateField4.define({
|
|
2273
|
+
create: (state) => update(state, options),
|
|
2274
|
+
update: (_, tr) => update(tr.state, options),
|
|
2275
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1820
2276
|
});
|
|
1821
2277
|
};
|
|
1822
|
-
var
|
|
1823
|
-
const builder = new
|
|
2278
|
+
var update = (state, options) => {
|
|
2279
|
+
const builder = new RangeSetBuilder6();
|
|
1824
2280
|
const cursor = state.selection.main.head;
|
|
1825
2281
|
const tables = [];
|
|
1826
2282
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1828,7 +2284,7 @@ var update3 = (state, options) => {
|
|
|
1828
2284
|
const table2 = getTable();
|
|
1829
2285
|
return table2.rows?.[table2.rows.length - 1];
|
|
1830
2286
|
};
|
|
1831
|
-
|
|
2287
|
+
syntaxTree7(state).iterate({
|
|
1832
2288
|
enter: (node) => {
|
|
1833
2289
|
switch (node.name) {
|
|
1834
2290
|
case "Table": {
|
|
@@ -1860,23 +2316,22 @@ var update3 = (state, options) => {
|
|
|
1860
2316
|
});
|
|
1861
2317
|
tables.forEach((table2) => {
|
|
1862
2318
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1863
|
-
hide && builder.add(table2.from, table2.to,
|
|
1864
|
-
block: true,
|
|
2319
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
1865
2320
|
widget: new TableWidget(table2)
|
|
1866
2321
|
}));
|
|
1867
|
-
builder.add(table2.from, table2.to,
|
|
2322
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
1868
2323
|
class: "cm-table"
|
|
1869
2324
|
}));
|
|
1870
2325
|
});
|
|
1871
2326
|
return builder.finish();
|
|
1872
2327
|
};
|
|
1873
|
-
var TableWidget = class extends
|
|
2328
|
+
var TableWidget = class extends WidgetType6 {
|
|
1874
2329
|
constructor(_table) {
|
|
1875
2330
|
super();
|
|
1876
2331
|
this._table = _table;
|
|
1877
2332
|
}
|
|
1878
2333
|
eq(other) {
|
|
1879
|
-
return this._table.
|
|
2334
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1880
2335
|
}
|
|
1881
2336
|
toDOM(view) {
|
|
1882
2337
|
const table2 = document.createElement("table");
|
|
@@ -1902,139 +2357,144 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1902
2357
|
}
|
|
1903
2358
|
return table2;
|
|
1904
2359
|
}
|
|
2360
|
+
ignoreEvent(e) {
|
|
2361
|
+
return !/^mouse/.test(e.type);
|
|
2362
|
+
}
|
|
1905
2363
|
};
|
|
1906
2364
|
|
|
1907
|
-
// packages/ui/react-ui-editor/src/
|
|
1908
|
-
import {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2365
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2366
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2367
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2368
|
+
import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
2369
|
+
var styles5 = EditorView12.baseTheme({
|
|
2370
|
+
"& .cm-task": {
|
|
2371
|
+
color: getToken("extend.colors.blue.500")
|
|
2372
|
+
},
|
|
2373
|
+
"& .cm-task-checkbox": {
|
|
2374
|
+
marginLeft: "4px",
|
|
2375
|
+
marginRight: "4px"
|
|
1913
2376
|
}
|
|
1914
2377
|
});
|
|
1915
|
-
var CheckboxWidget = class extends
|
|
1916
|
-
constructor(
|
|
2378
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2379
|
+
constructor(_checked) {
|
|
1917
2380
|
super();
|
|
1918
|
-
this._pos = _pos;
|
|
1919
2381
|
this._checked = _checked;
|
|
1920
|
-
this._indent = _indent;
|
|
1921
|
-
this._onCheck = _onCheck;
|
|
1922
2382
|
}
|
|
1923
2383
|
eq(other) {
|
|
1924
|
-
return this.
|
|
2384
|
+
return this._checked === other._checked;
|
|
1925
2385
|
}
|
|
1926
2386
|
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"));
|
|
2387
|
+
const input = document.createElement("input");
|
|
2388
|
+
input.className = "cm-task-checkbox";
|
|
1932
2389
|
input.type = "checkbox";
|
|
1933
2390
|
input.checked = this._checked;
|
|
1934
|
-
if (
|
|
2391
|
+
if (view.state.readOnly) {
|
|
1935
2392
|
input.setAttribute("disabled", "true");
|
|
1936
|
-
}
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2393
|
+
} else {
|
|
2394
|
+
input.onmousedown = (event) => {
|
|
2395
|
+
const pos = view.posAtDOM(input);
|
|
2396
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2397
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2398
|
+
view.dispatch({
|
|
2399
|
+
changes: {
|
|
2400
|
+
from: pos + 1,
|
|
2401
|
+
to: pos + 2,
|
|
2402
|
+
insert: this._checked ? " " : "x"
|
|
2403
|
+
}
|
|
2404
|
+
});
|
|
2405
|
+
event.preventDefault();
|
|
2406
|
+
}
|
|
1941
2407
|
};
|
|
1942
2408
|
}
|
|
1943
|
-
return
|
|
2409
|
+
return input;
|
|
1944
2410
|
}
|
|
1945
2411
|
ignoreEvent() {
|
|
1946
2412
|
return false;
|
|
1947
2413
|
}
|
|
1948
2414
|
};
|
|
2415
|
+
var checkedDecoration = Decoration10.replace({
|
|
2416
|
+
widget: new CheckboxWidget(true)
|
|
2417
|
+
});
|
|
2418
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2419
|
+
widget: new CheckboxWidget(false)
|
|
2420
|
+
});
|
|
2421
|
+
var buildDecorations6 = (view) => {
|
|
2422
|
+
const builder = new RangeSetBuilder7();
|
|
2423
|
+
const { state } = view;
|
|
2424
|
+
const cursor = state.selection.main.head;
|
|
2425
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2426
|
+
syntaxTree8(state).iterate({
|
|
2427
|
+
enter: (node) => {
|
|
2428
|
+
if (node.name === "TaskMarker") {
|
|
2429
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2430
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2431
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2432
|
+
class: "cm-task"
|
|
2433
|
+
}));
|
|
2434
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
},
|
|
2438
|
+
from,
|
|
2439
|
+
to
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
return builder.finish();
|
|
2443
|
+
};
|
|
1949
2444
|
var tasklist = (options = {}) => {
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2445
|
+
return [
|
|
2446
|
+
ViewPlugin8.fromClass(class {
|
|
2447
|
+
constructor(view) {
|
|
2448
|
+
this.decorations = buildDecorations6(view);
|
|
2449
|
+
}
|
|
2450
|
+
update(update2) {
|
|
2451
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2452
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}, {
|
|
2456
|
+
decorations: (value) => value.decorations
|
|
2457
|
+
}),
|
|
2458
|
+
styles5
|
|
2459
|
+
];
|
|
2460
|
+
};
|
|
2461
|
+
|
|
2462
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2463
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2464
|
+
var mention = ({ onSearch }) => {
|
|
2465
|
+
return autocompletion2({
|
|
2466
|
+
// TODO(burdon): Not working.
|
|
2467
|
+
activateOnTyping: true,
|
|
2468
|
+
// activateOnTypingDelay: 100,
|
|
2469
|
+
// selectOnOpen: true,
|
|
2470
|
+
closeOnBlur: false,
|
|
2471
|
+
// defaultKeymap: false,
|
|
2472
|
+
icons: false,
|
|
2473
|
+
override: [
|
|
2474
|
+
(context) => {
|
|
2475
|
+
console.log(context);
|
|
2476
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2477
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2478
|
+
return null;
|
|
2479
|
+
}
|
|
2480
|
+
return {
|
|
2481
|
+
from: match.from,
|
|
2482
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2483
|
+
label: `@${value}`
|
|
2484
|
+
}))
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
]
|
|
1985
2488
|
});
|
|
1986
|
-
return [
|
|
1987
|
-
tasks,
|
|
1988
|
-
styles4
|
|
1989
|
-
];
|
|
1990
2489
|
};
|
|
1991
2490
|
|
|
1992
|
-
// packages/ui/react-ui-editor/src/
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip2((view, pos) => {
|
|
1997
|
-
const { from, text } = view.state.doc.lineAt(pos);
|
|
1998
|
-
const p = pos - from;
|
|
1999
|
-
let idx = 0;
|
|
2000
|
-
let match;
|
|
2001
|
-
do {
|
|
2002
|
-
match = text.substring(idx).match(regexp);
|
|
2003
|
-
if (!match) {
|
|
2004
|
-
match = void 0;
|
|
2005
|
-
break;
|
|
2006
|
-
}
|
|
2007
|
-
idx = text.indexOf(match[0]);
|
|
2008
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
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
|
|
2030
|
-
}
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
};
|
|
2034
|
-
});
|
|
2491
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2492
|
+
var outliner = (options = {}) => {
|
|
2493
|
+
return [];
|
|
2494
|
+
};
|
|
2035
2495
|
|
|
2036
|
-
// packages/ui/react-ui-editor/src/
|
|
2037
|
-
import { keymap as
|
|
2496
|
+
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2497
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2038
2498
|
var defaultItems = [
|
|
2039
2499
|
"hello world!",
|
|
2040
2500
|
"this is a test.",
|
|
@@ -2044,7 +2504,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2044
2504
|
let t;
|
|
2045
2505
|
let idx = 0;
|
|
2046
2506
|
return [
|
|
2047
|
-
|
|
2507
|
+
keymap6.of([
|
|
2048
2508
|
{
|
|
2049
2509
|
// Reset.
|
|
2050
2510
|
key: "alt-meta-'",
|
|
@@ -2090,8 +2550,8 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2090
2550
|
];
|
|
2091
2551
|
};
|
|
2092
2552
|
|
|
2093
|
-
// packages/ui/react-ui-editor/src/
|
|
2094
|
-
import
|
|
2553
|
+
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2554
|
+
import get3 from "lodash.get";
|
|
2095
2555
|
var defaultTheme = {
|
|
2096
2556
|
//
|
|
2097
2557
|
// Main layout:
|
|
@@ -2120,21 +2580,22 @@ var defaultTheme = {
|
|
|
2120
2580
|
"&.cm-focused": {
|
|
2121
2581
|
outline: "none"
|
|
2122
2582
|
},
|
|
2123
|
-
"
|
|
2124
|
-
overflow:
|
|
2125
|
-
fontFamily:
|
|
2583
|
+
".cm-scroller": {
|
|
2584
|
+
// overflow: 'visible',
|
|
2585
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
2586
|
+
lineHeight: 1.4
|
|
2126
2587
|
},
|
|
2127
|
-
"
|
|
2588
|
+
".cm-content": {
|
|
2128
2589
|
padding: 0,
|
|
2129
2590
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2130
2591
|
fontSize: "16px"
|
|
2131
2592
|
},
|
|
2132
2593
|
"&light .cm-content": {
|
|
2133
|
-
color:
|
|
2594
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2134
2595
|
caretColor: "black"
|
|
2135
2596
|
},
|
|
2136
2597
|
"&dark .cm-content": {
|
|
2137
|
-
color:
|
|
2598
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2138
2599
|
caretColor: "white"
|
|
2139
2600
|
},
|
|
2140
2601
|
//
|
|
@@ -2146,158 +2607,123 @@ var defaultTheme = {
|
|
|
2146
2607
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2147
2608
|
borderLeft: "2px solid white"
|
|
2148
2609
|
},
|
|
2149
|
-
"& .cm-placeholder": {
|
|
2150
|
-
|
|
2610
|
+
"&light .cm-placeholder": {
|
|
2611
|
+
color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
|
|
2612
|
+
},
|
|
2613
|
+
"&dark .cm-placeholder": {
|
|
2614
|
+
color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
|
|
2151
2615
|
},
|
|
2152
2616
|
//
|
|
2153
2617
|
// line
|
|
2154
2618
|
//
|
|
2155
|
-
"
|
|
2619
|
+
".cm-line": {
|
|
2156
2620
|
paddingInline: 0
|
|
2157
2621
|
},
|
|
2158
|
-
"
|
|
2159
|
-
background: "
|
|
2622
|
+
".cm-activeLine": {
|
|
2623
|
+
background: "transparent"
|
|
2160
2624
|
},
|
|
2161
2625
|
//
|
|
2162
2626
|
// Selection
|
|
2163
2627
|
//
|
|
2164
2628
|
"&light .cm-selectionBackground": {
|
|
2165
|
-
background:
|
|
2629
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2166
2630
|
},
|
|
2167
2631
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2168
|
-
background:
|
|
2632
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2169
2633
|
},
|
|
2170
2634
|
"&dark .cm-selectionBackground": {
|
|
2171
|
-
background:
|
|
2635
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2172
2636
|
},
|
|
2173
2637
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2174
|
-
background:
|
|
2638
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2175
2639
|
},
|
|
2176
2640
|
//
|
|
2177
2641
|
// Search
|
|
2178
2642
|
//
|
|
2179
2643
|
"&light .cm-searchMatch": {
|
|
2180
|
-
backgroundColor:
|
|
2644
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2181
2645
|
},
|
|
2182
2646
|
"&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
|
|
2647
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2211
2648
|
},
|
|
2212
2649
|
//
|
|
2213
2650
|
// link
|
|
2214
2651
|
//
|
|
2215
|
-
"
|
|
2216
|
-
color:
|
|
2652
|
+
".cm-link": {
|
|
2653
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2217
2654
|
textDecorationLine: "underline",
|
|
2218
2655
|
textDecorationThickness: "1px",
|
|
2219
2656
|
textUnderlineOffset: "2px",
|
|
2220
2657
|
borderRadius: ".125rem",
|
|
2221
|
-
fontFamily:
|
|
2658
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2222
2659
|
},
|
|
2223
2660
|
//
|
|
2224
2661
|
// tooltip
|
|
2225
2662
|
//
|
|
2226
|
-
"
|
|
2663
|
+
".cm-tooltip": {
|
|
2227
2664
|
border: "none"
|
|
2228
2665
|
},
|
|
2229
|
-
"
|
|
2666
|
+
".cm-tooltip-below": {},
|
|
2230
2667
|
//
|
|
2231
2668
|
// autocomplete
|
|
2232
2669
|
//
|
|
2233
|
-
"
|
|
2670
|
+
".cm-tooltip-autocomplete": {
|
|
2234
2671
|
marginTop: "4px",
|
|
2235
2672
|
marginLeft: "-3px"
|
|
2236
2673
|
},
|
|
2237
|
-
"
|
|
2238
|
-
"
|
|
2239
|
-
"
|
|
2674
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2675
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2676
|
+
".cm-completionIcon": {
|
|
2240
2677
|
display: "none"
|
|
2241
2678
|
},
|
|
2242
|
-
"
|
|
2243
|
-
fontFamily:
|
|
2679
|
+
".cm-completionLabel": {
|
|
2680
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2244
2681
|
},
|
|
2245
|
-
"
|
|
2682
|
+
".cm-completionMatchedText": {
|
|
2246
2683
|
textDecoration: "none"
|
|
2247
2684
|
},
|
|
2248
2685
|
//
|
|
2249
|
-
// widgets
|
|
2250
|
-
//
|
|
2251
|
-
"& .cm-widgetBuffer": {
|
|
2252
|
-
display: "none",
|
|
2253
|
-
height: 0
|
|
2254
|
-
},
|
|
2255
|
-
//
|
|
2256
2686
|
// table
|
|
2257
2687
|
//
|
|
2258
|
-
"
|
|
2259
|
-
fontFamily: `${
|
|
2688
|
+
".cm-table *": {
|
|
2689
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2260
2690
|
textDecoration: "none !important"
|
|
2261
2691
|
},
|
|
2262
|
-
"
|
|
2692
|
+
".cm-table-head": {
|
|
2263
2693
|
padding: "2px 16px 2px 0px",
|
|
2264
|
-
borderBottom: `1px solid ${
|
|
2694
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2265
2695
|
fontWeight: 100,
|
|
2266
2696
|
textAlign: "left",
|
|
2267
|
-
color:
|
|
2697
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2268
2698
|
},
|
|
2269
|
-
"
|
|
2699
|
+
".cm-table-cell": {
|
|
2270
2700
|
padding: "2px 16px 2px 0px"
|
|
2271
2701
|
},
|
|
2272
2702
|
//
|
|
2273
2703
|
// image
|
|
2274
2704
|
//
|
|
2275
|
-
"
|
|
2276
|
-
|
|
2705
|
+
".cm-image": {
|
|
2706
|
+
display: "block",
|
|
2707
|
+
height: "0"
|
|
2708
|
+
},
|
|
2709
|
+
".cm-image.cm-loaded-image": {
|
|
2710
|
+
height: "auto",
|
|
2711
|
+
borderTop: "0.5rem solid transparent",
|
|
2712
|
+
borderBottom: "0.5rem solid transparent"
|
|
2277
2713
|
},
|
|
2278
2714
|
//
|
|
2279
2715
|
// font size
|
|
2280
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2716
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2717
|
+
// but it's far more verbose than it needs to be.
|
|
2281
2718
|
//
|
|
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
|
-
}, {}),
|
|
2719
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2720
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2721
|
+
//
|
|
2722
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2723
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2724
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2725
|
+
// return acc;
|
|
2726
|
+
// }, {}),
|
|
2301
2727
|
/**
|
|
2302
2728
|
* Panels
|
|
2303
2729
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2314,153 +2740,146 @@ var defaultTheme = {
|
|
|
2314
2740
|
* </div>
|
|
2315
2741
|
* </div
|
|
2316
2742
|
*/
|
|
2317
|
-
"
|
|
2318
|
-
border: `1px solid ${
|
|
2743
|
+
".cm-panels": {
|
|
2744
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2319
2745
|
},
|
|
2320
|
-
"
|
|
2321
|
-
background:
|
|
2322
|
-
fontFamily:
|
|
2746
|
+
".cm-panel": {
|
|
2747
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2748
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2323
2749
|
},
|
|
2324
|
-
"
|
|
2750
|
+
".cm-button": {
|
|
2325
2751
|
margin: "4px",
|
|
2326
|
-
fontFamily:
|
|
2327
|
-
background:
|
|
2752
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2753
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2328
2754
|
backgroundImage: "none",
|
|
2329
2755
|
border: "none",
|
|
2330
2756
|
"&:hover": {
|
|
2331
|
-
background:
|
|
2757
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2332
2758
|
},
|
|
2333
2759
|
"&:active": {
|
|
2334
|
-
background:
|
|
2760
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2335
2761
|
backgroundImage: "none"
|
|
2336
2762
|
}
|
|
2337
2763
|
},
|
|
2338
|
-
"
|
|
2764
|
+
".cm-panel input[type=checkbox]": {
|
|
2339
2765
|
marginRight: "0.4rem !important"
|
|
2340
2766
|
}
|
|
2341
2767
|
};
|
|
2342
2768
|
var textTheme = {
|
|
2343
|
-
"
|
|
2344
|
-
fontFamily:
|
|
2769
|
+
".cm-scroller": {
|
|
2770
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2345
2771
|
},
|
|
2346
|
-
"
|
|
2347
|
-
fontFamily:
|
|
2772
|
+
".cm-placeholder": {
|
|
2773
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2348
2774
|
}
|
|
2349
2775
|
};
|
|
2350
2776
|
var markdownTheme = {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2777
|
+
".cm-scroller": {
|
|
2778
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2779
|
+
},
|
|
2780
|
+
".cm-placeholder": {
|
|
2781
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2354
2782
|
}
|
|
2355
2783
|
};
|
|
2356
2784
|
var codeTheme = {
|
|
2357
|
-
"
|
|
2358
|
-
fontFamily:
|
|
2785
|
+
".cm-scroller": {
|
|
2786
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2359
2787
|
},
|
|
2360
|
-
"
|
|
2361
|
-
fontFamily:
|
|
2788
|
+
".cm-placeholder": {
|
|
2789
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2362
2790
|
}
|
|
2363
2791
|
};
|
|
2364
2792
|
|
|
2365
2793
|
// 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";
|
|
2794
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2375
2795
|
var EditorModes = [
|
|
2376
2796
|
"default",
|
|
2377
2797
|
"vim"
|
|
2378
2798
|
];
|
|
2379
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model,
|
|
2799
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2380
2800
|
const { themeMode } = useThemeContext();
|
|
2381
|
-
const
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
const [root, setRoot] = useState2(null);
|
|
2385
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState2();
|
|
2386
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2387
|
-
root,
|
|
2388
|
-
state,
|
|
2801
|
+
const rootRef = useRef(null);
|
|
2802
|
+
const [view, setView] = useState(null);
|
|
2803
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2389
2804
|
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
2805
|
]);
|
|
2416
2806
|
useEffect2(() => {
|
|
2417
|
-
if (
|
|
2418
|
-
view.
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2807
|
+
if (autoFocus && !view?.hasFocus) {
|
|
2808
|
+
if (view?.state.selection.main?.from === 0) {
|
|
2809
|
+
const { to } = view.state.doc.lineAt(0);
|
|
2810
|
+
view?.dispatch({
|
|
2811
|
+
selection: {
|
|
2812
|
+
anchor: to
|
|
2813
|
+
}
|
|
2814
|
+
});
|
|
2815
|
+
}
|
|
2816
|
+
view?.focus();
|
|
2424
2817
|
}
|
|
2425
2818
|
}, [
|
|
2426
2819
|
view,
|
|
2427
|
-
|
|
2820
|
+
autoFocus
|
|
2428
2821
|
]);
|
|
2429
2822
|
useEffect2(() => {
|
|
2430
|
-
if (!
|
|
2823
|
+
if (!model || !rootRef.current) {
|
|
2431
2824
|
return;
|
|
2432
2825
|
}
|
|
2433
|
-
const
|
|
2826
|
+
const state = EditorState2.create({
|
|
2434
2827
|
doc: model.text(),
|
|
2828
|
+
selection,
|
|
2435
2829
|
extensions: [
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2830
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2831
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2832
|
+
log2.catch(err, void 0, {
|
|
2833
|
+
F: __dxlog_file3,
|
|
2834
|
+
L: 134,
|
|
2835
|
+
S: void 0,
|
|
2836
|
+
C: (f, a) => f(...a)
|
|
2837
|
+
});
|
|
2838
|
+
}),
|
|
2439
2839
|
// Theme.
|
|
2440
|
-
// TODO(burdon): Make
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2840
|
+
// TODO(burdon): Make configurable.
|
|
2841
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2842
|
+
EditorView13.theme(theme ?? {}),
|
|
2843
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2844
|
+
EditorView13.editorAttributes.of({
|
|
2845
|
+
class: slots.editor?.className ?? ""
|
|
2846
|
+
}),
|
|
2847
|
+
EditorView13.contentAttributes.of({
|
|
2848
|
+
class: slots.content?.className ?? ""
|
|
2849
|
+
}),
|
|
2850
|
+
// State.
|
|
2851
|
+
EditorView13.editable.of(!readonly),
|
|
2852
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2444
2853
|
// Storage and replication.
|
|
2854
|
+
// NOTE: This must come before user extensions.
|
|
2445
2855
|
model.extension,
|
|
2856
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2857
|
+
editorMode === "vim" && vim(),
|
|
2446
2858
|
// Custom.
|
|
2447
2859
|
...extensions
|
|
2448
|
-
].filter(
|
|
2860
|
+
].filter(isNotFalsy3)
|
|
2449
2861
|
});
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2862
|
+
const newView = new EditorView13({
|
|
2863
|
+
state,
|
|
2864
|
+
parent: rootRef.current,
|
|
2865
|
+
scrollTo,
|
|
2866
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2867
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2868
|
+
dispatchTransactions: (trs, view2) => {
|
|
2869
|
+
if (debug) {
|
|
2870
|
+
logChanges(trs);
|
|
2871
|
+
}
|
|
2872
|
+
view2.update(trs);
|
|
2873
|
+
}
|
|
2457
2874
|
});
|
|
2875
|
+
view?.destroy();
|
|
2876
|
+
setView(newView);
|
|
2458
2877
|
return () => {
|
|
2459
|
-
|
|
2460
|
-
|
|
2878
|
+
newView?.destroy();
|
|
2879
|
+
setView(null);
|
|
2461
2880
|
};
|
|
2462
2881
|
}, [
|
|
2463
|
-
|
|
2882
|
+
rootRef,
|
|
2464
2883
|
model,
|
|
2465
2884
|
readonly,
|
|
2466
2885
|
editorMode,
|
|
@@ -2470,11 +2889,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, comments: comments2, r
|
|
|
2470
2889
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2471
2890
|
switch (key) {
|
|
2472
2891
|
case "Enter": {
|
|
2473
|
-
view?.
|
|
2892
|
+
view?.focus();
|
|
2474
2893
|
break;
|
|
2475
2894
|
}
|
|
2476
2895
|
case "Escape": {
|
|
2477
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2896
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2897
|
+
view?.focus();
|
|
2898
|
+
}
|
|
2478
2899
|
break;
|
|
2479
2900
|
}
|
|
2480
2901
|
}
|
|
@@ -2484,107 +2905,642 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, comments: comments2, r
|
|
|
2484
2905
|
]);
|
|
2485
2906
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2486
2907
|
key: model.id,
|
|
2487
|
-
|
|
2908
|
+
role: "none",
|
|
2488
2909
|
tabIndex: 0,
|
|
2489
|
-
...slots
|
|
2490
|
-
...editorMode !==
|
|
2491
|
-
onKeyUp: handleKeyUp
|
|
2910
|
+
...slots.root,
|
|
2911
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2912
|
+
onKeyUp: handleKeyUp,
|
|
2913
|
+
ref: rootRef
|
|
2492
2914
|
});
|
|
2493
2915
|
});
|
|
2494
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2916
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2495
2917
|
const { themeMode } = useThemeContext();
|
|
2496
|
-
const
|
|
2918
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2497
2919
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2498
2920
|
ref: forwardedRef,
|
|
2499
2921
|
readonly,
|
|
2500
2922
|
extensions: [
|
|
2501
|
-
|
|
2502
|
-
readonly,
|
|
2923
|
+
createBasicBundle({
|
|
2503
2924
|
themeMode,
|
|
2504
|
-
placeholder:
|
|
2925
|
+
placeholder: placeholder3,
|
|
2926
|
+
lineWrapping
|
|
2505
2927
|
}),
|
|
2506
2928
|
...extensions
|
|
2507
2929
|
],
|
|
2508
|
-
|
|
2930
|
+
theme,
|
|
2931
|
+
slots: updatedSlots,
|
|
2509
2932
|
...props
|
|
2510
2933
|
});
|
|
2511
2934
|
});
|
|
2512
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2935
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2513
2936
|
const { themeMode } = useThemeContext();
|
|
2514
|
-
const
|
|
2937
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2515
2938
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2516
2939
|
ref: forwardedRef,
|
|
2517
2940
|
readonly,
|
|
2518
2941
|
extensions: [
|
|
2519
|
-
|
|
2520
|
-
readonly,
|
|
2942
|
+
createMarkdownExtensions({
|
|
2521
2943
|
themeMode,
|
|
2522
|
-
placeholder:
|
|
2944
|
+
placeholder: placeholder3
|
|
2523
2945
|
}),
|
|
2524
2946
|
...extensions
|
|
2525
2947
|
],
|
|
2526
|
-
|
|
2948
|
+
theme,
|
|
2949
|
+
slots: updatedSlots,
|
|
2527
2950
|
...props
|
|
2528
2951
|
});
|
|
2529
2952
|
});
|
|
2530
2953
|
var defaultSlots = {
|
|
2531
2954
|
root: {
|
|
2532
|
-
className: mx3("
|
|
2955
|
+
className: mx3("grow", focusRing)
|
|
2956
|
+
},
|
|
2957
|
+
editor: {
|
|
2958
|
+
className: "bs-full"
|
|
2533
2959
|
}
|
|
2534
2960
|
};
|
|
2535
2961
|
var defaultTextSlots = {
|
|
2536
|
-
...defaultSlots
|
|
2537
|
-
editor: {
|
|
2538
|
-
theme: textTheme
|
|
2539
|
-
}
|
|
2962
|
+
...defaultSlots
|
|
2540
2963
|
};
|
|
2541
2964
|
var defaultMarkdownSlots = {
|
|
2542
|
-
...defaultSlots
|
|
2543
|
-
|
|
2544
|
-
|
|
2965
|
+
...defaultSlots
|
|
2966
|
+
};
|
|
2967
|
+
|
|
2968
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
2969
|
+
import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, ListNumbers, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
|
|
2970
|
+
import { createContext } from "@radix-ui/react-context";
|
|
2971
|
+
import React2 from "react";
|
|
2972
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
2973
|
+
import { getSize } from "@dxos/react-ui-theme";
|
|
2974
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
2975
|
+
var ToolbarRoot = ({ children, onAction }) => {
|
|
2976
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
2977
|
+
onAction
|
|
2978
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
2979
|
+
density: "fine"
|
|
2980
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
2981
|
+
role: "toolbar",
|
|
2982
|
+
className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
|
|
2983
|
+
}, children)));
|
|
2984
|
+
};
|
|
2985
|
+
var ToolbarButton = ({ Icon, onClick, title }) => {
|
|
2986
|
+
const { onAction } = useToolbarContext("ToolbarButton");
|
|
2987
|
+
const handleClick = () => {
|
|
2988
|
+
const action = onClick();
|
|
2989
|
+
if (action) {
|
|
2990
|
+
onAction?.(action);
|
|
2991
|
+
}
|
|
2992
|
+
};
|
|
2993
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
2994
|
+
variant: "ghost",
|
|
2995
|
+
classNames: "p-2",
|
|
2996
|
+
onClick: handleClick,
|
|
2997
|
+
title
|
|
2998
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
2999
|
+
className: getSize(5)
|
|
3000
|
+
}));
|
|
3001
|
+
};
|
|
3002
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3003
|
+
className: "grow"
|
|
3004
|
+
});
|
|
3005
|
+
var MarkdownHeading = () => {
|
|
3006
|
+
const { onAction } = useToolbarContext("MarkdownFormatting");
|
|
3007
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3008
|
+
defaultValue: "0",
|
|
3009
|
+
onValueChange: (value) => onAction?.({
|
|
3010
|
+
type: "heading",
|
|
3011
|
+
data: parseInt(value)
|
|
3012
|
+
})
|
|
3013
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
|
|
3014
|
+
classNames: "w-[8rem]"
|
|
3015
|
+
}), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3016
|
+
value: "0"
|
|
3017
|
+
}, "Paragraph"), [
|
|
3018
|
+
1,
|
|
3019
|
+
2,
|
|
3020
|
+
3,
|
|
3021
|
+
4,
|
|
3022
|
+
5,
|
|
3023
|
+
6
|
|
3024
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3025
|
+
key: level,
|
|
3026
|
+
value: String(level)
|
|
3027
|
+
}, "Heading ", level))))));
|
|
3028
|
+
};
|
|
3029
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3030
|
+
role: "none"
|
|
3031
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3032
|
+
Icon: TextB,
|
|
3033
|
+
title: "Bold",
|
|
3034
|
+
onClick: () => ({
|
|
3035
|
+
type: "bold"
|
|
3036
|
+
})
|
|
3037
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3038
|
+
Icon: TextItalic,
|
|
3039
|
+
title: "Italic",
|
|
3040
|
+
onClick: () => ({
|
|
3041
|
+
type: "italic"
|
|
3042
|
+
})
|
|
3043
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3044
|
+
Icon: TextStrikethrough,
|
|
3045
|
+
title: "Strike-through",
|
|
3046
|
+
onClick: () => ({
|
|
3047
|
+
type: "strikethrough"
|
|
3048
|
+
})
|
|
3049
|
+
}));
|
|
3050
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3051
|
+
role: "none"
|
|
3052
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3053
|
+
Icon: ListBullets,
|
|
3054
|
+
title: "Bullet list",
|
|
3055
|
+
onClick: () => ({
|
|
3056
|
+
type: "list"
|
|
3057
|
+
})
|
|
3058
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3059
|
+
Icon: ListNumbers,
|
|
3060
|
+
title: "Numbered list",
|
|
3061
|
+
onClick: () => ({
|
|
3062
|
+
type: "list-ordered"
|
|
3063
|
+
})
|
|
3064
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3065
|
+
Icon: ListChecks,
|
|
3066
|
+
title: "Task list",
|
|
3067
|
+
onClick: () => ({
|
|
3068
|
+
type: "list-tasks"
|
|
3069
|
+
})
|
|
3070
|
+
}));
|
|
3071
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3072
|
+
role: "none"
|
|
3073
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3074
|
+
Icon: CaretRight,
|
|
3075
|
+
title: "Block quite",
|
|
3076
|
+
onClick: () => ({
|
|
3077
|
+
type: "blockquote"
|
|
3078
|
+
})
|
|
3079
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3080
|
+
Icon: Code,
|
|
3081
|
+
title: "Code block",
|
|
3082
|
+
onClick: () => ({
|
|
3083
|
+
type: "codeblock"
|
|
3084
|
+
})
|
|
3085
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3086
|
+
Icon: Table2,
|
|
3087
|
+
title: "Table",
|
|
3088
|
+
onClick: () => ({
|
|
3089
|
+
type: "table"
|
|
3090
|
+
})
|
|
3091
|
+
}));
|
|
3092
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3093
|
+
role: "none"
|
|
3094
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3095
|
+
Icon: Link,
|
|
3096
|
+
title: "Link",
|
|
3097
|
+
onClick: () => ({
|
|
3098
|
+
type: "link"
|
|
3099
|
+
})
|
|
3100
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3101
|
+
Icon: At,
|
|
3102
|
+
title: "Mention",
|
|
3103
|
+
onClick: () => ({
|
|
3104
|
+
type: "mention"
|
|
3105
|
+
})
|
|
3106
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3107
|
+
Icon: Image,
|
|
3108
|
+
title: "Image",
|
|
3109
|
+
onClick: () => ({
|
|
3110
|
+
type: "image"
|
|
3111
|
+
})
|
|
3112
|
+
}));
|
|
3113
|
+
var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
|
|
3114
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
3115
|
+
Icon: ChatText,
|
|
3116
|
+
title: "Create comment",
|
|
3117
|
+
onClick: () => ({
|
|
3118
|
+
type: "comment"
|
|
3119
|
+
})
|
|
3120
|
+
});
|
|
3121
|
+
var Toolbar = {
|
|
3122
|
+
Root: ToolbarRoot,
|
|
3123
|
+
Button: ToolbarButton,
|
|
3124
|
+
Separator: ToolbarSeparator,
|
|
3125
|
+
Markdown: MarkdownStandard,
|
|
3126
|
+
Extended: MarkdownExtended
|
|
3127
|
+
};
|
|
3128
|
+
|
|
3129
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
3130
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
3131
|
+
import { Context as Context2 } from "@dxos/context";
|
|
3132
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
3133
|
+
import { log as log3 } from "@dxos/log";
|
|
3134
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
3135
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
3136
|
+
var SpaceAwarenessProvider = class {
|
|
3137
|
+
constructor(params) {
|
|
3138
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
3139
|
+
this.remoteStateChange = new Event2();
|
|
3140
|
+
this._space = params.space;
|
|
3141
|
+
this._channel = params.channel;
|
|
3142
|
+
this._peerId = params.peerId;
|
|
3143
|
+
this._info = params.info;
|
|
3144
|
+
}
|
|
3145
|
+
open() {
|
|
3146
|
+
this._ctx = new Context2();
|
|
3147
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
3148
|
+
if (this._localState) {
|
|
3149
|
+
await this._space.postMessage(this._channel, {
|
|
3150
|
+
kind: "post",
|
|
3151
|
+
state: this._localState
|
|
3152
|
+
});
|
|
3153
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
3154
|
+
}
|
|
3155
|
+
});
|
|
3156
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
3157
|
+
switch (message.payload.kind) {
|
|
3158
|
+
case "query": {
|
|
3159
|
+
this._handleQueryMessage();
|
|
3160
|
+
break;
|
|
3161
|
+
}
|
|
3162
|
+
case "post": {
|
|
3163
|
+
this._handlePostMessage(message.payload);
|
|
3164
|
+
break;
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
}));
|
|
3168
|
+
void this._space.postMessage(this._channel, {
|
|
3169
|
+
kind: "query"
|
|
3170
|
+
}).catch((err) => {
|
|
3171
|
+
log3.debug("failed to query awareness", {
|
|
3172
|
+
err
|
|
3173
|
+
}, {
|
|
3174
|
+
F: __dxlog_file4,
|
|
3175
|
+
L: 89,
|
|
3176
|
+
S: this,
|
|
3177
|
+
C: (f, a) => f(...a)
|
|
3178
|
+
});
|
|
3179
|
+
});
|
|
3180
|
+
}
|
|
3181
|
+
close() {
|
|
3182
|
+
void this._ctx?.dispose();
|
|
3183
|
+
this._ctx = void 0;
|
|
3184
|
+
this._postTask = void 0;
|
|
3185
|
+
}
|
|
3186
|
+
getRemoteStates() {
|
|
3187
|
+
return Array.from(this._remoteStates.values());
|
|
3188
|
+
}
|
|
3189
|
+
update(position) {
|
|
3190
|
+
invariant2(this._postTask, void 0, {
|
|
3191
|
+
F: __dxlog_file4,
|
|
3192
|
+
L: 104,
|
|
3193
|
+
S: this,
|
|
3194
|
+
A: [
|
|
3195
|
+
"this._postTask",
|
|
3196
|
+
""
|
|
3197
|
+
]
|
|
3198
|
+
});
|
|
3199
|
+
this._localState = {
|
|
3200
|
+
peerId: this._peerId,
|
|
3201
|
+
position,
|
|
3202
|
+
info: this._info
|
|
3203
|
+
};
|
|
3204
|
+
this._postTask.schedule();
|
|
3205
|
+
}
|
|
3206
|
+
_handleQueryMessage() {
|
|
3207
|
+
invariant2(this._postTask, void 0, {
|
|
3208
|
+
F: __dxlog_file4,
|
|
3209
|
+
L: 115,
|
|
3210
|
+
S: this,
|
|
3211
|
+
A: [
|
|
3212
|
+
"this._postTask",
|
|
3213
|
+
""
|
|
3214
|
+
]
|
|
3215
|
+
});
|
|
3216
|
+
this._postTask.schedule();
|
|
3217
|
+
}
|
|
3218
|
+
_handlePostMessage(message) {
|
|
3219
|
+
invariant2(message.kind === "post", void 0, {
|
|
3220
|
+
F: __dxlog_file4,
|
|
3221
|
+
L: 120,
|
|
3222
|
+
S: this,
|
|
3223
|
+
A: [
|
|
3224
|
+
"message.kind === 'post'",
|
|
3225
|
+
""
|
|
3226
|
+
]
|
|
3227
|
+
});
|
|
3228
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
3229
|
+
this.remoteStateChange.emit();
|
|
3230
|
+
}
|
|
3231
|
+
};
|
|
3232
|
+
|
|
3233
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
3234
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
3235
|
+
var modelState = StateField5.define({
|
|
3236
|
+
create: () => void 0,
|
|
3237
|
+
update: (model) => model
|
|
3238
|
+
});
|
|
3239
|
+
|
|
3240
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3241
|
+
var useActionHandler = (view) => {
|
|
3242
|
+
return (action) => {
|
|
3243
|
+
if (!view) {
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3246
|
+
switch (action.type) {
|
|
3247
|
+
case "heading":
|
|
3248
|
+
setHeading(parseInt(action.data))(view);
|
|
3249
|
+
break;
|
|
3250
|
+
case "bold":
|
|
3251
|
+
toggleBold(view);
|
|
3252
|
+
break;
|
|
3253
|
+
case "italic":
|
|
3254
|
+
toggleItalic(view);
|
|
3255
|
+
break;
|
|
3256
|
+
case "strikethrough":
|
|
3257
|
+
toggleStrikethrough(view);
|
|
3258
|
+
break;
|
|
3259
|
+
case "list":
|
|
3260
|
+
toggleList(view);
|
|
3261
|
+
break;
|
|
3262
|
+
case "codeblock":
|
|
3263
|
+
insertCodeblock(view);
|
|
3264
|
+
break;
|
|
3265
|
+
case "table":
|
|
3266
|
+
insertTable(view);
|
|
3267
|
+
break;
|
|
3268
|
+
case "comment":
|
|
3269
|
+
createComment(view);
|
|
3270
|
+
break;
|
|
3271
|
+
}
|
|
3272
|
+
setTimeout(() => {
|
|
3273
|
+
view.focus();
|
|
3274
|
+
view.dispatch({
|
|
3275
|
+
selection: view.state.selection
|
|
3276
|
+
});
|
|
3277
|
+
});
|
|
3278
|
+
};
|
|
3279
|
+
};
|
|
3280
|
+
|
|
3281
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
3282
|
+
import { useState as useState2 } from "react";
|
|
3283
|
+
var useEditorView = () => {
|
|
3284
|
+
const [view, setView] = useState2(null);
|
|
3285
|
+
return [
|
|
3286
|
+
(ref) => {
|
|
3287
|
+
setView(ref);
|
|
3288
|
+
},
|
|
3289
|
+
view
|
|
3290
|
+
];
|
|
3291
|
+
};
|
|
3292
|
+
|
|
3293
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3294
|
+
import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
|
|
3295
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
3296
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
3297
|
+
import { log as log4 } from "@dxos/log";
|
|
3298
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
3299
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
3300
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
3301
|
+
const onUpdate = useRef2();
|
|
3302
|
+
const [view, setView] = useState3();
|
|
3303
|
+
const parentRef = useRef2(null);
|
|
3304
|
+
useEffect3(() => {
|
|
3305
|
+
if (parentRef.current) {
|
|
3306
|
+
const state = EditorState3.create({
|
|
3307
|
+
doc,
|
|
3308
|
+
selection,
|
|
3309
|
+
extensions: [
|
|
3310
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3311
|
+
EditorView14.exceptionSink.of((err) => {
|
|
3312
|
+
log4.catch(err, void 0, {
|
|
3313
|
+
F: __dxlog_file5,
|
|
3314
|
+
L: 57,
|
|
3315
|
+
S: void 0,
|
|
3316
|
+
C: (f, a) => f(...a)
|
|
3317
|
+
});
|
|
3318
|
+
}),
|
|
3319
|
+
extensions,
|
|
3320
|
+
EditorView14.updateListener.of(() => {
|
|
3321
|
+
onUpdate.current?.();
|
|
3322
|
+
})
|
|
3323
|
+
].filter(isNotFalsy4)
|
|
3324
|
+
});
|
|
3325
|
+
const view2 = new EditorView14({
|
|
3326
|
+
parent: parentRef.current,
|
|
3327
|
+
scrollTo,
|
|
3328
|
+
state,
|
|
3329
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
3330
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
3331
|
+
dispatchTransactions: (trs, view3) => {
|
|
3332
|
+
if (debug) {
|
|
3333
|
+
logChanges(trs);
|
|
3334
|
+
}
|
|
3335
|
+
view3.update(trs);
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3338
|
+
setView(view2);
|
|
3339
|
+
}
|
|
3340
|
+
return () => {
|
|
3341
|
+
view?.destroy();
|
|
3342
|
+
};
|
|
3343
|
+
}, [
|
|
3344
|
+
parentRef
|
|
3345
|
+
]);
|
|
3346
|
+
useEffect3(() => {
|
|
3347
|
+
if (view) {
|
|
3348
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
3349
|
+
selection = EditorSelection.single(view.state.doc.line(1).to);
|
|
3350
|
+
}
|
|
3351
|
+
if (selection || scrollTo) {
|
|
3352
|
+
onUpdate.current = () => {
|
|
3353
|
+
onUpdate.current = void 0;
|
|
3354
|
+
view.dispatch({
|
|
3355
|
+
selection,
|
|
3356
|
+
effects: scrollTo && [
|
|
3357
|
+
scrollTo
|
|
3358
|
+
],
|
|
3359
|
+
scrollIntoView: !scrollTo
|
|
3360
|
+
});
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
if (autoFocus) {
|
|
3364
|
+
view.focus();
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}, [
|
|
3368
|
+
view,
|
|
3369
|
+
autoFocus,
|
|
3370
|
+
selection,
|
|
3371
|
+
scrollTo
|
|
3372
|
+
]);
|
|
3373
|
+
return {
|
|
3374
|
+
parentRef,
|
|
3375
|
+
view
|
|
3376
|
+
};
|
|
3377
|
+
};
|
|
3378
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
3379
|
+
return [
|
|
3380
|
+
//
|
|
3381
|
+
EditorState3.readOnly.of(readonly),
|
|
3382
|
+
EditorView14.editable.of(!readonly)
|
|
3383
|
+
];
|
|
3384
|
+
};
|
|
3385
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
3386
|
+
return [
|
|
3387
|
+
//
|
|
3388
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3389
|
+
theme && EditorView14.theme(theme),
|
|
3390
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3391
|
+
EditorView14.editorAttributes.of({
|
|
3392
|
+
class: slots?.editor?.className ?? ""
|
|
3393
|
+
}),
|
|
3394
|
+
EditorView14.contentAttributes.of({
|
|
3395
|
+
class: slots?.content?.className ?? ""
|
|
3396
|
+
})
|
|
3397
|
+
].filter(isNotFalsy4);
|
|
3398
|
+
};
|
|
3399
|
+
|
|
3400
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
3401
|
+
import get4 from "lodash.get";
|
|
3402
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
3403
|
+
import { generateName } from "@dxos/display-name";
|
|
3404
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
3405
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
3406
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3407
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
3408
|
+
var useTextModel = (props) => {
|
|
3409
|
+
const { identity, space, text } = props;
|
|
3410
|
+
const [model, setModel] = useState4();
|
|
3411
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
3412
|
+
identity,
|
|
3413
|
+
space,
|
|
3414
|
+
text
|
|
3415
|
+
]);
|
|
3416
|
+
return model;
|
|
3417
|
+
};
|
|
3418
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
3419
|
+
const [content, setContent] = useState4(defaultContent ?? "");
|
|
3420
|
+
return {
|
|
3421
|
+
id,
|
|
3422
|
+
content,
|
|
3423
|
+
setContent,
|
|
3424
|
+
text: () => content
|
|
3425
|
+
};
|
|
3426
|
+
};
|
|
3427
|
+
var createModel = ({ space, identity, text }) => {
|
|
3428
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
3429
|
+
F: __dxlog_file6,
|
|
3430
|
+
L: 50,
|
|
3431
|
+
S: void 0,
|
|
3432
|
+
A: [
|
|
3433
|
+
"isAutomergeObject(text)",
|
|
3434
|
+
""
|
|
3435
|
+
]
|
|
3436
|
+
});
|
|
3437
|
+
const obj = text;
|
|
3438
|
+
const doc = getRawDoc(obj, [
|
|
3439
|
+
obj.field
|
|
3440
|
+
]);
|
|
3441
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
3442
|
+
space,
|
|
3443
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
3444
|
+
info: {
|
|
3445
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
3446
|
+
color: cursorColor.color,
|
|
3447
|
+
lightColor: cursorColor.light
|
|
3448
|
+
},
|
|
3449
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3450
|
+
});
|
|
3451
|
+
const extensions = [
|
|
3452
|
+
//
|
|
3453
|
+
modelState.init(() => model),
|
|
3454
|
+
automerge({
|
|
3455
|
+
handle: doc.handle,
|
|
3456
|
+
path: doc.path
|
|
3457
|
+
})
|
|
3458
|
+
];
|
|
3459
|
+
if (awarenessProvider2) {
|
|
3460
|
+
extensions.push(awareness(awarenessProvider2));
|
|
2545
3461
|
}
|
|
3462
|
+
const model = {
|
|
3463
|
+
id: obj.id,
|
|
3464
|
+
content: doc,
|
|
3465
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3466
|
+
extension: extensions,
|
|
3467
|
+
peer: identity ? {
|
|
3468
|
+
id: identity.identityKey.toHex(),
|
|
3469
|
+
name: identity.profile?.displayName
|
|
3470
|
+
} : void 0
|
|
3471
|
+
};
|
|
3472
|
+
return model;
|
|
2546
3473
|
};
|
|
2547
3474
|
export {
|
|
2548
3475
|
BaseTextEditor,
|
|
3476
|
+
Cursor,
|
|
2549
3477
|
Doc,
|
|
2550
3478
|
EditorModes,
|
|
2551
3479
|
MarkdownEditor,
|
|
3480
|
+
RemoteSelectionsDecorator,
|
|
2552
3481
|
SpaceAwarenessProvider,
|
|
2553
3482
|
TextEditor,
|
|
2554
3483
|
TextKind,
|
|
3484
|
+
Toolbar,
|
|
2555
3485
|
YText,
|
|
2556
3486
|
YXmlFragment,
|
|
2557
3487
|
autocomplete,
|
|
2558
|
-
|
|
3488
|
+
automerge,
|
|
3489
|
+
awareness,
|
|
3490
|
+
awarenessProvider,
|
|
2559
3491
|
blast,
|
|
3492
|
+
callbackWrapper,
|
|
2560
3493
|
code2 as code,
|
|
2561
3494
|
codeTheme,
|
|
2562
3495
|
comments,
|
|
2563
|
-
|
|
3496
|
+
createBasicBundle,
|
|
3497
|
+
createComment,
|
|
3498
|
+
createDataExtensions,
|
|
3499
|
+
createMarkdownExtensions,
|
|
3500
|
+
createThemeExtensions,
|
|
2564
3501
|
defaultMarkdownSlots,
|
|
2565
3502
|
defaultOptions,
|
|
2566
3503
|
defaultSlots,
|
|
2567
3504
|
defaultTextSlots,
|
|
2568
3505
|
defaultTheme,
|
|
3506
|
+
focusComment,
|
|
3507
|
+
formatting,
|
|
3508
|
+
getToken,
|
|
3509
|
+
heading2 as heading,
|
|
2569
3510
|
hr,
|
|
2570
3511
|
image,
|
|
3512
|
+
insertCodeblock,
|
|
3513
|
+
insertTable,
|
|
3514
|
+
keymap7 as keymap,
|
|
2571
3515
|
link,
|
|
2572
3516
|
listener,
|
|
2573
|
-
|
|
3517
|
+
logChanges,
|
|
2574
3518
|
markdownHighlightStyle,
|
|
2575
3519
|
markdownTags,
|
|
2576
3520
|
markdownTagsExtensions,
|
|
2577
3521
|
markdownTheme,
|
|
2578
3522
|
mention,
|
|
2579
|
-
mermaid,
|
|
2580
3523
|
modelState,
|
|
2581
|
-
|
|
3524
|
+
outliner,
|
|
3525
|
+
setComments,
|
|
3526
|
+
setHeading,
|
|
3527
|
+
setSelection,
|
|
2582
3528
|
table,
|
|
2583
3529
|
tags2 as tags,
|
|
2584
3530
|
tasklist,
|
|
2585
3531
|
textTheme,
|
|
2586
|
-
|
|
3532
|
+
toggleBold,
|
|
3533
|
+
toggleItalic,
|
|
3534
|
+
toggleList,
|
|
3535
|
+
toggleStrikethrough,
|
|
3536
|
+
toggleStyle,
|
|
2587
3537
|
typewriter,
|
|
2588
|
-
|
|
3538
|
+
useActionHandler,
|
|
3539
|
+
useComments,
|
|
3540
|
+
useEditorView,
|
|
3541
|
+
useInMemoryTextModel,
|
|
3542
|
+
useTextEditor,
|
|
3543
|
+
useTextModel,
|
|
3544
|
+
useToolbarContext
|
|
2589
3545
|
};
|
|
2590
3546
|
//# sourceMappingURL=index.mjs.map
|