@dxos/react-ui-editor 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d
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 +2979 -2478
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +2979 -2478
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts +37 -21
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +20 -0
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorContent/EditorContent.d.ts +29 -0
- package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +1 -0
- package/dist/types/src/components/EditorContent/EditorContent.stories.d.ts +26 -0
- package/dist/types/src/components/EditorContent/EditorContent.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorContent/controller.d.ts +10 -0
- package/dist/types/src/components/EditorContent/controller.d.ts.map +1 -0
- package/dist/types/src/components/EditorContent/index.d.ts +3 -0
- package/dist/types/src/components/EditorContent/index.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +36 -0
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/index.d.ts +7 -0
- package/dist/types/src/components/EditorMenuProvider/index.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts +4 -0
- package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts +28 -0
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts +47 -0
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts +34 -0
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/util.d.ts +8 -0
- package/dist/types/src/components/EditorMenuProvider/util.d.ts.map +1 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts +16 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -0
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts +2 -0
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +26 -2
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/actions.d.ts +39 -0
- package/dist/types/src/components/EditorToolbar/actions.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +3 -3
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +3 -3
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +3 -3
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +2 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts +11 -0
- package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +3 -3
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +4 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts +17 -0
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts +5 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts +13 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts +20 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts +10 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/sync.d.ts +3 -3
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/autoscroll.d.ts +14 -4
- package/dist/types/src/extensions/autoscroll.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts +4 -4
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/extensions/blocks.d.ts +2 -0
- package/dist/types/src/extensions/blocks.d.ts.map +1 -0
- package/dist/types/src/extensions/bookmarks.d.ts +12 -0
- package/dist/types/src/extensions/bookmarks.d.ts.map +1 -0
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts +7 -6
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/folding.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +8 -3
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/listener.d.ts +8 -6
- package/dist/types/src/extensions/listener.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +1 -3
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/modal.d.ts +7 -0
- package/dist/types/src/extensions/modal.d.ts.map +1 -0
- package/dist/types/src/extensions/modes.d.ts +1 -1
- package/dist/types/src/extensions/modes.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/menu.d.ts +8 -0
- package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/preview.d.ts +6 -3
- package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
- package/dist/types/src/extensions/replacer.d.ts +21 -0
- package/dist/types/src/extensions/replacer.d.ts.map +1 -0
- package/dist/types/src/extensions/replacer.test.d.ts +2 -0
- package/dist/types/src/extensions/replacer.test.d.ts.map +1 -0
- package/dist/types/src/extensions/scrolling.d.ts +78 -0
- package/dist/types/src/extensions/scrolling.d.ts.map +1 -0
- package/dist/types/src/extensions/state.d.ts +2 -0
- package/dist/types/src/extensions/state.d.ts.map +1 -0
- package/dist/types/src/extensions/submit.d.ts +10 -0
- package/dist/types/src/extensions/submit.d.ts.map +1 -0
- package/dist/types/src/extensions/tab.d.ts +4 -0
- package/dist/types/src/extensions/tab.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-tags.d.ts +41 -16
- package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +3 -7
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts +3 -3
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +3 -3
- package/dist/types/src/stories/Markdown.stories.d.ts +3 -3
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/{CommandMenu.stories.d.ts → Popover.stories.d.ts} +6 -5
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Preview.stories.d.ts +4 -3
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts +3 -4
- package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +11 -8
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts.map +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/util/debug.d.ts +4 -0
- package/dist/types/src/util/debug.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +44 -46
- package/src/components/Editor/Editor.stories.tsx +89 -0
- package/src/components/Editor/Editor.tsx +157 -57
- package/src/components/EditorContent/EditorContent.stories.tsx +70 -0
- package/src/components/EditorContent/EditorContent.tsx +70 -0
- package/src/components/EditorContent/controller.ts +50 -0
- package/src/components/EditorContent/index.ts +6 -0
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +233 -0
- package/src/components/EditorMenuProvider/index.ts +11 -0
- package/src/components/EditorMenuProvider/menu-presets.ts +123 -0
- package/src/components/EditorMenuProvider/menu.ts +71 -0
- package/src/components/EditorMenuProvider/popover.ts +287 -0
- package/src/components/EditorMenuProvider/useEditorMenu.ts +175 -0
- package/src/components/EditorMenuProvider/util.ts +31 -0
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +82 -0
- package/src/components/EditorPreviewProvider/index.ts +5 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +101 -92
- package/src/components/EditorToolbar/{lists.ts → actions.ts} +46 -16
- package/src/components/EditorToolbar/blocks.ts +2 -1
- package/src/components/EditorToolbar/formatting.ts +2 -1
- package/src/components/EditorToolbar/headings.ts +8 -5
- package/src/components/EditorToolbar/image.ts +1 -1
- package/src/components/EditorToolbar/index.ts +3 -7
- package/src/components/EditorToolbar/search.ts +1 -1
- package/src/components/EditorToolbar/useEditorToolbar.ts +20 -0
- package/src/components/EditorToolbar/view-mode.ts +2 -1
- package/src/components/index.ts +8 -2
- package/src/extensions/{autocomplete.ts → autocomplete/autocomplete.ts} +8 -76
- package/src/extensions/autocomplete/index.ts +8 -0
- package/src/extensions/autocomplete/match.ts +46 -0
- package/src/extensions/{command-menu → autocomplete}/placeholder.ts +21 -17
- package/src/extensions/{command-dialog → autocomplete}/typeahead.ts +6 -48
- package/src/extensions/automerge/automerge.stories.tsx +4 -3
- package/src/extensions/automerge/automerge.ts +28 -9
- package/src/extensions/automerge/cursor.ts +1 -1
- package/src/extensions/automerge/sync.ts +8 -4
- package/src/extensions/automerge/update-automerge.ts +1 -1
- package/src/extensions/autoscroll.ts +75 -69
- package/src/extensions/awareness/awareness-provider.ts +12 -12
- package/src/extensions/blocks.ts +131 -0
- package/src/extensions/bookmarks.ts +75 -0
- package/src/extensions/comments.ts +2 -1
- package/src/extensions/factories.ts +22 -24
- package/src/extensions/folding.tsx +1 -2
- package/src/extensions/index.ts +8 -3
- package/src/extensions/listener.ts +14 -20
- package/src/extensions/markdown/bundle.ts +14 -2
- package/src/extensions/markdown/decorate.ts +8 -8
- package/src/extensions/markdown/formatting.ts +8 -10
- package/src/extensions/markdown/highlight.ts +1 -1
- package/src/extensions/markdown/image.ts +2 -2
- package/src/extensions/markdown/table.ts +6 -6
- package/src/extensions/modal.ts +24 -0
- package/src/extensions/modes.ts +2 -2
- package/src/extensions/{floating-menu.ts → outliner/menu.ts} +7 -5
- package/src/extensions/outliner/outliner.test.ts +1 -1
- package/src/extensions/outliner/outliner.ts +3 -3
- package/src/extensions/outliner/tree.test.ts +1 -1
- package/src/extensions/preview/index.ts +1 -1
- package/src/extensions/preview/preview.ts +14 -11
- package/src/extensions/replacer.test.ts +75 -0
- package/src/extensions/replacer.ts +93 -0
- package/src/extensions/scrolling.ts +189 -0
- package/src/extensions/selection.ts +1 -1
- package/src/extensions/state.ts +7 -0
- package/src/extensions/submit.ts +62 -0
- package/src/extensions/tab.ts +29 -0
- package/src/extensions/tags/extended-markdown.test.ts +2 -1
- package/src/extensions/tags/xml-tags.ts +310 -203
- package/src/extensions/typewriter.ts +1 -1
- package/src/hooks/useTextEditor.ts +25 -25
- package/src/stories/CommandDialog.stories.tsx +13 -19
- package/src/stories/Comments.stories.tsx +3 -4
- package/src/stories/EditorToolbar.stories.tsx +8 -8
- package/src/stories/Experimental.stories.tsx +1 -1
- package/src/stories/Markdown.stories.tsx +1 -1
- package/src/stories/Outliner.stories.tsx +15 -15
- package/src/stories/Popover.stories.tsx +162 -0
- package/src/stories/Preview.stories.tsx +41 -37
- package/src/stories/Tags.stories.tsx +19 -5
- package/src/stories/TextEditor.stories.tsx +4 -30
- package/src/stories/components/EditorStory.tsx +31 -20
- package/src/stories/components/util.tsx +40 -8
- package/src/styles/markdown.ts +1 -1
- package/src/styles/theme.ts +2 -1
- package/src/util/debug.ts +5 -0
- package/dist/lib/browser/testing/index.mjs +0 -76
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -78
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/components/CommandMenu/CommandMenu.d.ts +0 -38
- package/dist/types/src/components/CommandMenu/CommandMenu.d.ts.map +0 -1
- package/dist/types/src/components/CommandMenu/index.d.ts +0 -2
- package/dist/types/src/components/CommandMenu/index.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts +0 -19
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/util.d.ts +0 -51
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete.d.ts +0 -26
- package/dist/types/src/extensions/autocomplete.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/action.d.ts +0 -17
- package/dist/types/src/extensions/command-dialog/action.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/command-dialog.d.ts +0 -6
- package/dist/types/src/extensions/command-dialog/command-dialog.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/hint.d.ts +0 -19
- package/dist/types/src/extensions/command-dialog/hint.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/index.d.ts +0 -4
- package/dist/types/src/extensions/command-dialog/index.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/state.d.ts +0 -16
- package/dist/types/src/extensions/command-dialog/state.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/typeahead.d.ts +0 -22
- package/dist/types/src/extensions/command-dialog/typeahead.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/command-menu.d.ts +0 -20
- package/dist/types/src/extensions/command-menu/command-menu.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/index.d.ts +0 -3
- package/dist/types/src/extensions/command-menu/index.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/placeholder.d.ts +0 -10
- package/dist/types/src/extensions/command-menu/placeholder.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts +0 -24
- package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts.map +0 -1
- package/dist/types/src/extensions/floating-menu.d.ts +0 -7
- package/dist/types/src/extensions/floating-menu.d.ts.map +0 -1
- package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
- package/dist/types/src/testing/PreviewPopover.d.ts +0 -20
- package/dist/types/src/testing/PreviewPopover.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/util.d.ts +0 -3
- package/dist/types/src/testing/util.d.ts.map +0 -1
- package/src/components/CommandMenu/CommandMenu.tsx +0 -348
- package/src/components/CommandMenu/index.ts +0 -5
- package/src/components/EditorToolbar/util.ts +0 -76
- package/src/extensions/command-dialog/action.ts +0 -55
- package/src/extensions/command-dialog/command-dialog.ts +0 -34
- package/src/extensions/command-dialog/hint.ts +0 -103
- package/src/extensions/command-dialog/index.ts +0 -7
- package/src/extensions/command-dialog/state.ts +0 -90
- package/src/extensions/command-menu/command-menu.ts +0 -210
- package/src/extensions/command-menu/index.ts +0 -6
- package/src/extensions/command-menu/useCommandMenu.ts +0 -134
- package/src/stories/CommandMenu.stories.tsx +0 -158
- package/src/testing/PreviewPopover.tsx +0 -78
- package/src/testing/index.ts +0 -6
- package/src/testing/util.ts +0 -7
|
@@ -11,20 +11,23 @@ import { clientRectsFor, flattenRect } from '../../util';
|
|
|
11
11
|
type Content = string | HTMLElement | ((view: EditorView) => HTMLElement);
|
|
12
12
|
|
|
13
13
|
export type PlaceholderOptions = {
|
|
14
|
-
delay?: number;
|
|
15
14
|
content: Content;
|
|
15
|
+
delay?: number;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Shows a transient placeholder at the current cursor position.
|
|
20
|
+
*/
|
|
21
|
+
export const placeholder = ({ content, delay = 3_000 }: PlaceholderOptions): Extension => {
|
|
19
22
|
const plugin = ViewPlugin.fromClass(
|
|
20
23
|
class {
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
_timeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
+
_decorations = Decoration.none;
|
|
23
26
|
|
|
24
27
|
update(update: ViewUpdate) {
|
|
25
|
-
if (this.
|
|
26
|
-
window.clearTimeout(this.
|
|
27
|
-
this.
|
|
28
|
+
if (this._timeout) {
|
|
29
|
+
window.clearTimeout(this._timeout);
|
|
30
|
+
this._timeout = undefined;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
// Check if the active line (where cursor is) is empty.
|
|
@@ -33,10 +36,10 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
|
|
|
33
36
|
if (isEmpty) {
|
|
34
37
|
// Create widget decoration at the start of the current line.
|
|
35
38
|
const lineStart = activeLine.from;
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
39
|
+
this._timeout = setTimeout(() => {
|
|
40
|
+
this._decorations = Decoration.set([
|
|
38
41
|
Decoration.widget({
|
|
39
|
-
widget: new
|
|
42
|
+
widget: new PlaceholderWidget(content),
|
|
40
43
|
side: 1,
|
|
41
44
|
}).range(lineStart),
|
|
42
45
|
]);
|
|
@@ -45,18 +48,18 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
|
|
|
45
48
|
}, delay);
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
this.
|
|
51
|
+
this._decorations = Decoration.none;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
destroy() {
|
|
52
|
-
if (this.
|
|
53
|
-
clearTimeout(this.
|
|
55
|
+
if (this._timeout) {
|
|
56
|
+
clearTimeout(this._timeout);
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
},
|
|
57
60
|
{
|
|
58
61
|
provide: (plugin) => {
|
|
59
|
-
return [EditorView.decorations.of((view) => view.plugin(plugin)?.
|
|
62
|
+
return [EditorView.decorations.of((view) => view.plugin(plugin)?._decorations ?? Decoration.none)];
|
|
60
63
|
},
|
|
61
64
|
},
|
|
62
65
|
);
|
|
@@ -66,7 +69,7 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
|
|
|
66
69
|
: plugin;
|
|
67
70
|
};
|
|
68
71
|
|
|
69
|
-
class
|
|
72
|
+
export class PlaceholderWidget extends WidgetType {
|
|
70
73
|
constructor(readonly content: Content) {
|
|
71
74
|
super();
|
|
72
75
|
}
|
|
@@ -75,6 +78,7 @@ class Placeholder extends WidgetType {
|
|
|
75
78
|
const wrap = document.createElement('span');
|
|
76
79
|
wrap.className = 'cm-placeholder';
|
|
77
80
|
wrap.style.pointerEvents = 'none';
|
|
81
|
+
wrap.setAttribute('aria-hidden', 'true');
|
|
78
82
|
wrap.appendChild(
|
|
79
83
|
typeof this.content === 'string'
|
|
80
84
|
? document.createTextNode(this.content)
|
|
@@ -82,7 +86,7 @@ class Placeholder extends WidgetType {
|
|
|
82
86
|
? this.content(view)
|
|
83
87
|
: this.content.cloneNode(true),
|
|
84
88
|
);
|
|
85
|
-
|
|
89
|
+
|
|
86
90
|
return wrap;
|
|
87
91
|
}
|
|
88
92
|
|
|
@@ -92,7 +96,7 @@ class Placeholder extends WidgetType {
|
|
|
92
96
|
return null;
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
const style =
|
|
99
|
+
const style = getComputedStyle(dom.parentNode as HTMLElement);
|
|
96
100
|
const rect = flattenRect(rects[0], style.direction !== 'rtl');
|
|
97
101
|
const lineHeight = parseInt(style.lineHeight);
|
|
98
102
|
if (rect.bottom - rect.top > lineHeight * 1.5) {
|
|
@@ -13,17 +13,16 @@ import {
|
|
|
13
13
|
keymap,
|
|
14
14
|
} from '@codemirror/view';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { type CompoetionContext } from './match';
|
|
17
|
+
import { PlaceholderWidget } from './placeholder';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// TODO(burdon): Option to complete only at end of line?
|
|
19
|
+
// TODO(burdon): Option to complete only at end of line.
|
|
21
20
|
export type TypeaheadOptions = {
|
|
22
|
-
onComplete?: (context:
|
|
21
|
+
onComplete?: (context: CompoetionContext) => string | undefined;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
25
|
+
* Shows a completion placeholder.
|
|
27
26
|
*/
|
|
28
27
|
export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
|
|
29
28
|
let hint: string | undefined;
|
|
@@ -57,7 +56,7 @@ export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
|
|
|
57
56
|
const str = update.state.sliceDoc(line.from, selection.from);
|
|
58
57
|
hint = onComplete?.({ line: str });
|
|
59
58
|
if (hint) {
|
|
60
|
-
builder.add(selection.from, selection.to, Decoration.widget({ widget: new
|
|
59
|
+
builder.add(selection.from, selection.to, Decoration.widget({ widget: new PlaceholderWidget(hint) }));
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
|
|
@@ -86,44 +85,3 @@ export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
|
|
|
86
85
|
),
|
|
87
86
|
];
|
|
88
87
|
};
|
|
89
|
-
|
|
90
|
-
type CompletionOptions = {
|
|
91
|
-
default?: string;
|
|
92
|
-
minLength?: number;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Util to match current line to a static list of completions.
|
|
97
|
-
*/
|
|
98
|
-
export const staticCompletion =
|
|
99
|
-
(completions: string[], options: CompletionOptions = {}) =>
|
|
100
|
-
({ line }: TypeaheadContext) => {
|
|
101
|
-
if (line.length === 0 && options.default) {
|
|
102
|
-
return options.default;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const parts = line.split(/\s+/).filter(Boolean);
|
|
106
|
-
if (parts.length) {
|
|
107
|
-
const str = parts.at(-1)!;
|
|
108
|
-
if (str.length >= (options.minLength ?? 0)) {
|
|
109
|
-
for (const completion of completions) {
|
|
110
|
-
const match = matchCompletion(completion, str);
|
|
111
|
-
if (match) {
|
|
112
|
-
return match;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
export const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {
|
|
120
|
-
if (
|
|
121
|
-
str.length >= minLength &&
|
|
122
|
-
completion.length > str.length &&
|
|
123
|
-
completion.startsWith(str)
|
|
124
|
-
// TODO(burdon): If case insensitive, need to replace existing chars.
|
|
125
|
-
// completion.toLowerCase().startsWith(str.toLowerCase())
|
|
126
|
-
) {
|
|
127
|
-
return completion.slice(str.length);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
@@ -10,7 +10,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
10
10
|
import React, { useEffect, useState } from 'react';
|
|
11
11
|
|
|
12
12
|
import { Obj, Ref, Type } from '@dxos/echo';
|
|
13
|
-
import { DocAccessor,
|
|
13
|
+
import { DocAccessor, createDocAccessor } from '@dxos/echo-db';
|
|
14
|
+
import { Query, type Space, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
14
15
|
import { type Identity, useIdentity } from '@dxos/react-client/halo';
|
|
15
16
|
import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
|
|
16
17
|
import { useThemeContext } from '@dxos/react-ui';
|
|
@@ -43,14 +44,14 @@ const Editor = ({ source, autoFocus, space, identity }: EditorProps) => {
|
|
|
43
44
|
extensions: [
|
|
44
45
|
createBasicExtensions({ placeholder: 'Type here...', search: true }),
|
|
45
46
|
createThemeExtensions({ themeMode, slots: editorSlots }),
|
|
46
|
-
createDataExtensions({ id: 'test', text: source, space, identity }),
|
|
47
|
+
createDataExtensions({ id: 'test', text: source, messenger: space, identity }),
|
|
47
48
|
],
|
|
48
49
|
autoFocus,
|
|
49
50
|
}),
|
|
50
51
|
[source, themeMode],
|
|
51
52
|
);
|
|
52
53
|
|
|
53
|
-
return <div ref={parentRef} className='flex
|
|
54
|
+
return <div ref={parentRef} className='flex is-full' />;
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
const DefaultStory = () => {
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
//
|
|
6
6
|
|
|
7
7
|
import { next as A } from '@automerge/automerge';
|
|
8
|
-
import { type Extension, StateField } from '@codemirror/state';
|
|
8
|
+
import { type Extension, StateField, Transaction } from '@codemirror/state';
|
|
9
9
|
import { EditorView, ViewPlugin } from '@codemirror/view';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { DocAccessor } from '@dxos/echo-db';
|
|
12
12
|
|
|
13
13
|
import { Cursor } from '../../util';
|
|
14
|
+
import { initialSync } from '../state';
|
|
14
15
|
|
|
15
16
|
import { cursorConverter } from './cursor';
|
|
16
17
|
import { type State, isReconcile, updateHeadsEffect } from './defs';
|
|
@@ -18,11 +19,13 @@ import { Syncer } from './sync';
|
|
|
18
19
|
|
|
19
20
|
export const automerge = (accessor: DocAccessor): Extension => {
|
|
20
21
|
const syncState = StateField.define<State>({
|
|
21
|
-
create: () =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
create: () => {
|
|
23
|
+
return {
|
|
24
|
+
path: accessor.path.slice(),
|
|
25
|
+
lastHeads: A.getHeads(accessor.handle.doc()!),
|
|
26
|
+
unreconciledTransactions: [],
|
|
27
|
+
};
|
|
28
|
+
},
|
|
26
29
|
|
|
27
30
|
update: (value, tr) => {
|
|
28
31
|
const result: State = {
|
|
@@ -64,6 +67,18 @@ export const automerge = (accessor: DocAccessor): Extension => {
|
|
|
64
67
|
class {
|
|
65
68
|
constructor(private readonly _view: EditorView) {
|
|
66
69
|
accessor.handle.addListener('change', this._handleChange);
|
|
70
|
+
|
|
71
|
+
requestAnimationFrame(() => {
|
|
72
|
+
const value = DocAccessor.getValue<string>(accessor);
|
|
73
|
+
const current = this._view.state.doc.toString();
|
|
74
|
+
if (value !== current) {
|
|
75
|
+
// TODO(burdon): This attempts to set the initial state, but creates problems.
|
|
76
|
+
// this._view.dispatch({
|
|
77
|
+
// changes: { from: 0, to: this._view.state.doc.length, insert: value },
|
|
78
|
+
// annotations: initialSync,
|
|
79
|
+
// });
|
|
80
|
+
}
|
|
81
|
+
});
|
|
67
82
|
}
|
|
68
83
|
|
|
69
84
|
destroy() {
|
|
@@ -77,9 +92,13 @@ export const automerge = (accessor: DocAccessor): Extension => {
|
|
|
77
92
|
),
|
|
78
93
|
|
|
79
94
|
// Reconcile local updates.
|
|
80
|
-
EditorView.updateListener.of(({ view, changes }) => {
|
|
95
|
+
EditorView.updateListener.of(({ view, changes, transactions }) => {
|
|
81
96
|
if (!changes.empty) {
|
|
82
|
-
|
|
97
|
+
// Only reconcile if it's not an initial sync (to avoid loops)
|
|
98
|
+
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
|
|
99
|
+
if (!isInitialSync) {
|
|
100
|
+
syncer.reconcile(view, true);
|
|
101
|
+
}
|
|
83
102
|
}
|
|
84
103
|
}),
|
|
85
104
|
];
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type DocAccessor, fromCursor, toCursor } from '@dxos/echo-db';
|
|
5
6
|
import { log } from '@dxos/log';
|
|
6
|
-
import { type DocAccessor, fromCursor, toCursor } from '@dxos/react-client/echo';
|
|
7
7
|
|
|
8
8
|
import { type CursorConverter } from '../../util';
|
|
9
9
|
|
|
@@ -8,7 +8,8 @@ import { next as A } from '@automerge/automerge';
|
|
|
8
8
|
import { type StateField } from '@codemirror/state';
|
|
9
9
|
import { type EditorView } from '@codemirror/view';
|
|
10
10
|
|
|
11
|
-
import { type IDocHandle } from '@dxos/
|
|
11
|
+
import { type IDocHandle } from '@dxos/echo-db';
|
|
12
|
+
import { log } from '@dxos/log';
|
|
12
13
|
|
|
13
14
|
import { type State, getLastHeads, getPath, isReconcile, reconcileAnnotation, updateHeads } from './defs';
|
|
14
15
|
import { updateAutomerge } from './update-automerge';
|
|
@@ -27,7 +28,6 @@ export class Syncer {
|
|
|
27
28
|
) {}
|
|
28
29
|
|
|
29
30
|
reconcile(view: EditorView, editor: boolean): void {
|
|
30
|
-
// TODO(burdon): Better way to do mutex?
|
|
31
31
|
if (this._pending) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -41,7 +41,9 @@ export class Syncer {
|
|
|
41
41
|
this._pending = false;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
onEditorChange(view: EditorView): void {
|
|
44
|
+
private onEditorChange(view: EditorView): void {
|
|
45
|
+
log('onEditorChange');
|
|
46
|
+
|
|
45
47
|
// Apply the unreconciled transactions to the document.
|
|
46
48
|
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
47
49
|
const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
@@ -54,7 +56,9 @@ export class Syncer {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
onAutomergeChange(view: EditorView): void {
|
|
59
|
+
private onAutomergeChange(view: EditorView): void {
|
|
60
|
+
log('onAutomergeChange');
|
|
61
|
+
|
|
58
62
|
// Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
|
|
59
63
|
const oldHeads = getLastHeads(view.state, this._state);
|
|
60
64
|
const newHeads = A.getHeads(this._handle.doc()!);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { next as A, type Heads } from '@automerge/automerge';
|
|
8
8
|
import { type EditorState, type StateField, type Text, type Transaction } from '@codemirror/state';
|
|
9
9
|
|
|
10
|
-
import { type IDocHandle } from '@dxos/
|
|
10
|
+
import { type IDocHandle } from '@dxos/echo-db';
|
|
11
11
|
|
|
12
12
|
import { type State } from './defs';
|
|
13
13
|
|
|
@@ -5,101 +5,117 @@
|
|
|
5
5
|
import { StateEffect } from '@codemirror/state';
|
|
6
6
|
import { EditorView, ViewPlugin } from '@codemirror/view';
|
|
7
7
|
|
|
8
|
+
import { debounce } from '@dxos/async';
|
|
8
9
|
import { Domino } from '@dxos/react-ui';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
import { scrollToLineEffect } from './scrolling';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
// TODO(burdon): Reconcile with scrollToLineEffect (scrolling).
|
|
14
|
+
export const scrollToBottomEffect = StateEffect.define<ScrollBehavior | undefined>();
|
|
13
15
|
|
|
14
16
|
export type AutoScrollOptions = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
/** Auto-scroll when reaches the bottom. */
|
|
18
|
+
autoScroll?: boolean;
|
|
19
|
+
/** Threshold in px to trigger scroll from bottom. */
|
|
20
|
+
threshold?: number;
|
|
21
|
+
/** Throttle time in ms. */
|
|
22
|
+
throttleDelay?: number;
|
|
23
|
+
/** Callback when auto-scrolling. */
|
|
24
|
+
onAutoScroll?: (props: { view: EditorView; distanceFromBottom: number }) => boolean | void;
|
|
17
25
|
};
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
28
|
* Extension that supports pinning the scroll position and automatically scrolls to the bottom when content is added.
|
|
21
29
|
*/
|
|
22
30
|
// TODO(burdon): Reconcile with transcript-extension.
|
|
23
|
-
export const autoScroll = ({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
export const autoScroll = ({
|
|
32
|
+
autoScroll = true,
|
|
33
|
+
threshold = 100,
|
|
34
|
+
throttleDelay = 1_000,
|
|
35
|
+
onAutoScroll,
|
|
36
|
+
}: Partial<AutoScrollOptions> = {}) => {
|
|
27
37
|
let buttonContainer: HTMLDivElement | undefined;
|
|
38
|
+
let hideTimeout: NodeJS.Timeout | undefined;
|
|
28
39
|
let lastScrollTop = 0;
|
|
29
|
-
let
|
|
40
|
+
let isPinned = true;
|
|
41
|
+
|
|
42
|
+
const setPinned = (pin: boolean) => {
|
|
43
|
+
isPinned = pin;
|
|
44
|
+
buttonContainer?.classList.toggle('opacity-0', pin);
|
|
45
|
+
};
|
|
30
46
|
|
|
47
|
+
// Temporarily hide the scrollbar while auto-scrolling.
|
|
31
48
|
const hideScrollbar = (view: EditorView) => {
|
|
32
49
|
view.scrollDOM.classList.add('cm-hide-scrollbar');
|
|
33
|
-
clearTimeout(
|
|
34
|
-
|
|
50
|
+
clearTimeout(hideTimeout);
|
|
51
|
+
hideTimeout = setTimeout(() => {
|
|
35
52
|
view.scrollDOM.classList.remove('cm-hide-scrollbar');
|
|
36
53
|
}, 1_000);
|
|
37
54
|
};
|
|
38
55
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
behavior: 'smooth',
|
|
48
|
-
});
|
|
56
|
+
// Throttled scroll to bottom.
|
|
57
|
+
const scrollToBottom = (view: EditorView, behavior?: ScrollBehavior) => {
|
|
58
|
+
setPinned(true);
|
|
59
|
+
hideScrollbar(view);
|
|
60
|
+
const line = view.state.doc.lineAt(view.state.doc.length);
|
|
61
|
+
view.dispatch({
|
|
62
|
+
selection: { anchor: line.to, head: line.to },
|
|
63
|
+
effects: scrollToLineEffect.of({ line: line.number, options: { position: 'end', offset: threshold, behavior } }),
|
|
49
64
|
});
|
|
50
65
|
};
|
|
51
66
|
|
|
67
|
+
// Throttled check for distance from bottom (for downward scrolls only).
|
|
68
|
+
const checkDistance = debounce((view: EditorView) => {
|
|
69
|
+
const scrollerRect = view.scrollDOM.getBoundingClientRect();
|
|
70
|
+
const coords = view.coordsAtPos(view.state.doc.length);
|
|
71
|
+
const distanceFromBottom = coords ? coords.bottom - scrollerRect.bottom : 0;
|
|
72
|
+
setPinned(distanceFromBottom < 0);
|
|
73
|
+
}, 1_000);
|
|
74
|
+
|
|
75
|
+
// Debounce scroll updates so rapid edits don't cause clunky scrolling.
|
|
76
|
+
const triggerUpdate = debounce((view: EditorView) => scrollToBottom(view), throttleDelay);
|
|
77
|
+
|
|
52
78
|
return [
|
|
53
79
|
// Update listener for logging when scrolling is needed.
|
|
54
|
-
EditorView.updateListener.of((
|
|
55
|
-
//
|
|
56
|
-
|
|
80
|
+
EditorView.updateListener.of(({ view, transactions, heightChanged }) => {
|
|
81
|
+
// TODO(burdon): Remove and use scrollToLineEffect instead.
|
|
82
|
+
transactions.forEach((transaction) => {
|
|
57
83
|
for (const effect of transaction.effects) {
|
|
58
84
|
if (effect.is(scrollToBottomEffect)) {
|
|
59
|
-
scrollToBottom(
|
|
85
|
+
scrollToBottom(view, effect.value);
|
|
60
86
|
}
|
|
61
87
|
}
|
|
62
88
|
});
|
|
63
89
|
|
|
64
90
|
// Maybe scroll if doc changed and pinned.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}, throttle);
|
|
91
|
+
// NOTE: Geometry changed is triggered when widgets change height (e.g., toggle tool block).
|
|
92
|
+
if (heightChanged && isPinned) {
|
|
93
|
+
const coords = view.coordsAtPos(view.state.doc.length);
|
|
94
|
+
const scrollerRect = view.scrollDOM.getBoundingClientRect();
|
|
95
|
+
const distanceFromBottom = coords ? scrollerRect.bottom - coords.bottom : 0;
|
|
96
|
+
if (autoScroll && distanceFromBottom < threshold) {
|
|
97
|
+
const shouldScroll = onAutoScroll?.({ view, distanceFromBottom }) ?? true;
|
|
98
|
+
if (shouldScroll) {
|
|
99
|
+
triggerUpdate(view);
|
|
100
|
+
}
|
|
101
|
+
} else if (distanceFromBottom < 0) {
|
|
102
|
+
setPinned(false);
|
|
78
103
|
}
|
|
79
104
|
}
|
|
80
105
|
}),
|
|
81
106
|
|
|
82
107
|
// Detect user scroll.
|
|
83
|
-
// NOTE: Multiple scroll events are triggered during programmatic smooth scrolling.
|
|
84
108
|
EditorView.domEventHandlers({
|
|
85
109
|
scroll: (event, view) => {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Pin to bottom.
|
|
96
|
-
isPinned = true;
|
|
97
|
-
buttonContainer?.classList.add('opacity-0');
|
|
98
|
-
scrollCounter = 0;
|
|
99
|
-
} else if (scrollCounter > 3) {
|
|
100
|
-
// Break pin if user scrolls up.
|
|
101
|
-
isPinned = false;
|
|
102
|
-
buttonContainer?.classList.remove('opacity-0');
|
|
110
|
+
const currentScrollTop = view.scrollDOM.scrollTop;
|
|
111
|
+
const scrollingUp = currentScrollTop < lastScrollTop;
|
|
112
|
+
lastScrollTop = currentScrollTop;
|
|
113
|
+
|
|
114
|
+
// If user scrolls up, immediately unpin auto-scroll.
|
|
115
|
+
if (scrollingUp) {
|
|
116
|
+
setPinned(false);
|
|
117
|
+
} else {
|
|
118
|
+
checkDistance(view);
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
}),
|
|
@@ -108,20 +124,20 @@ export const autoScroll = ({ overscroll = 4 * lineHeight, throttle = 2_000 }: Pa
|
|
|
108
124
|
ViewPlugin.fromClass(
|
|
109
125
|
class {
|
|
110
126
|
constructor(view: EditorView) {
|
|
111
|
-
const scroller = view.scrollDOM.parentElement;
|
|
112
127
|
buttonContainer = Domino.of('div')
|
|
113
128
|
.classNames(true && 'cm-scroll-button transition-opacity duration-300 opacity-0')
|
|
114
129
|
.children(
|
|
115
130
|
Domino.of('button')
|
|
116
131
|
.classNames('dx-button bg-accentSurface')
|
|
117
132
|
.data('density', 'fine')
|
|
118
|
-
.children(Domino.of<any>('dx-icon').
|
|
133
|
+
.children(Domino.of<any>('dx-icon').attributes({ icon: 'ph--arrow-down--regular' }))
|
|
119
134
|
.on('click', () => {
|
|
120
135
|
scrollToBottom(view);
|
|
121
136
|
}),
|
|
122
137
|
)
|
|
123
138
|
.build();
|
|
124
|
-
|
|
139
|
+
|
|
140
|
+
view.scrollDOM.parentElement!.appendChild(buttonContainer);
|
|
125
141
|
}
|
|
126
142
|
},
|
|
127
143
|
),
|
|
@@ -129,7 +145,6 @@ export const autoScroll = ({ overscroll = 4 * lineHeight, throttle = 2_000 }: Pa
|
|
|
129
145
|
// Styles.
|
|
130
146
|
EditorView.theme({
|
|
131
147
|
'.cm-scroller': {
|
|
132
|
-
paddingBottom: `${overscroll}px`,
|
|
133
148
|
scrollbarWidth: 'thin',
|
|
134
149
|
},
|
|
135
150
|
'.cm-scroller.cm-hide-scrollbar': {
|
|
@@ -138,7 +153,6 @@ export const autoScroll = ({ overscroll = 4 * lineHeight, throttle = 2_000 }: Pa
|
|
|
138
153
|
'.cm-scroller.cm-hide-scrollbar::-webkit-scrollbar': {
|
|
139
154
|
display: 'none',
|
|
140
155
|
},
|
|
141
|
-
|
|
142
156
|
'.cm-scroll-button': {
|
|
143
157
|
position: 'absolute',
|
|
144
158
|
bottom: '0.5rem',
|
|
@@ -147,11 +161,3 @@ export const autoScroll = ({ overscroll = 4 * lineHeight, throttle = 2_000 }: Pa
|
|
|
147
161
|
}),
|
|
148
162
|
];
|
|
149
163
|
};
|
|
150
|
-
|
|
151
|
-
const calcDistance = (scroller: HTMLElement) => {
|
|
152
|
-
const scrollTop = scroller.scrollTop;
|
|
153
|
-
const scrollHeight = scroller.scrollHeight;
|
|
154
|
-
const clientHeight = scroller.clientHeight;
|
|
155
|
-
const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
|
|
156
|
-
return distanceFromBottom;
|
|
157
|
-
};
|
|
@@ -6,8 +6,8 @@ import { DeferredTask, Event, sleep } from '@dxos/async';
|
|
|
6
6
|
import { Context } from '@dxos/context';
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
|
-
import { type
|
|
10
|
-
import { type GossipMessage } from '@dxos/
|
|
9
|
+
import { type Messenger } from '@dxos/protocols';
|
|
10
|
+
import { type GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';
|
|
11
11
|
|
|
12
12
|
import { type AwarenessInfo, type AwarenessPosition, type AwarenessProvider, type AwarenessState } from './awareness';
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@ type ProtocolMessage =
|
|
|
23
23
|
const DEBOUNCE_INTERVAL = 100; // ms
|
|
24
24
|
|
|
25
25
|
export type AwarenessProviderParams = {
|
|
26
|
-
|
|
26
|
+
messenger: Messenger;
|
|
27
27
|
channel: string;
|
|
28
28
|
peerId: string;
|
|
29
29
|
info: AwarenessInfo;
|
|
@@ -35,7 +35,7 @@ export type AwarenessProviderParams = {
|
|
|
35
35
|
export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
36
36
|
private readonly _remoteStates = new Map<string, AwarenessState>();
|
|
37
37
|
|
|
38
|
-
private readonly
|
|
38
|
+
private readonly _messenger: Messenger;
|
|
39
39
|
private readonly _channel: string;
|
|
40
40
|
private readonly _peerId: string;
|
|
41
41
|
private readonly _info: AwarenessInfo;
|
|
@@ -46,18 +46,18 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
|
46
46
|
|
|
47
47
|
public readonly remoteStateChange = new Event<void>();
|
|
48
48
|
|
|
49
|
-
constructor(
|
|
50
|
-
this.
|
|
51
|
-
this._channel =
|
|
52
|
-
this._peerId =
|
|
53
|
-
this._info =
|
|
49
|
+
constructor({ messenger, channel, peerId, info }: AwarenessProviderParams) {
|
|
50
|
+
this._messenger = messenger;
|
|
51
|
+
this._channel = channel;
|
|
52
|
+
this._peerId = peerId;
|
|
53
|
+
this._info = info;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
open(): void {
|
|
57
57
|
this._ctx = new Context();
|
|
58
58
|
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
59
59
|
if (this._localState) {
|
|
60
|
-
await this.
|
|
60
|
+
await this._messenger.postMessage(this._channel, {
|
|
61
61
|
kind: 'post',
|
|
62
62
|
state: this._localState,
|
|
63
63
|
} satisfies ProtocolMessage);
|
|
@@ -69,7 +69,7 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
this._ctx.onDispose(
|
|
72
|
-
this.
|
|
72
|
+
this._messenger.listen(this._channel, (message: GossipMessage) => {
|
|
73
73
|
switch (message.payload.kind) {
|
|
74
74
|
case 'query': {
|
|
75
75
|
this._handleQueryMessage();
|
|
@@ -83,7 +83,7 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
|
83
83
|
}),
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
-
void this.
|
|
86
|
+
void this._messenger
|
|
87
87
|
.postMessage(this._channel, {
|
|
88
88
|
kind: 'query',
|
|
89
89
|
} satisfies ProtocolMessage)
|