@dxos/react-ui-editor 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe
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/{chunk-22UMM3QJ.mjs → chunk-HL3YF6WC.mjs} +2 -2
- package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +5638 -5200
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node-esm/{chunk-YXYQPV6R.mjs → chunk-YJZGD3LY.mjs} +2 -2
- package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +5638 -5200
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts +37 -15
- 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 +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 +1 -1
- 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 +10 -5
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/focus.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 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/json.d.ts +1 -1
- package/dist/types/src/extensions/json.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/decorate.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/markdown/link.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 -4
- 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/streamer.d.ts.map +1 -1
- package/dist/types/src/extensions/tags/xml-tags.d.ts +42 -16
- package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +5 -9
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/{Command.stories.d.ts → CommandDialog.stories.d.ts} +2 -3
- package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Comments.stories.d.ts +3 -4
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/EditorToolbar.stories.d.ts +1 -2
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +3 -4
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +3 -4
- package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Outliner.stories.d.ts +0 -1
- 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 -6
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Preview.stories.d.ts +4 -4
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Tags.stories.d.ts +0 -1
- package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts +3 -5
- package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +7 -5
- 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/types/types.d.ts +1 -1
- package/dist/types/src/types/types.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/src/util/index.d.ts +0 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +58 -59
- package/src/components/Editor/Editor.stories.tsx +89 -0
- package/src/components/Editor/Editor.tsx +160 -25
- 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 -91
- 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 → autocomplete}/placeholder.ts +21 -17
- package/src/extensions/{command → autocomplete}/typeahead.ts +6 -48
- package/src/extensions/automerge/automerge.stories.tsx +9 -9
- 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 +98 -86
- package/src/extensions/awareness/awareness-provider.ts +2 -2
- 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 +47 -16
- package/src/extensions/focus.ts +5 -4
- package/src/extensions/folding.tsx +3 -6
- package/src/extensions/hashtag.tsx +2 -2
- package/src/extensions/index.ts +8 -1
- package/src/extensions/json.ts +1 -1
- package/src/extensions/listener.ts +14 -20
- package/src/extensions/markdown/bundle.ts +16 -4
- package/src/extensions/markdown/decorate.ts +9 -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/link.ts +3 -0
- 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/{command/floating-menu.ts → outliner/menu.ts} +15 -20
- package/src/extensions/outliner/outliner.test.ts +1 -1
- package/src/extensions/outliner/outliner.ts +4 -4
- package/src/extensions/outliner/tree.test.ts +1 -1
- package/src/extensions/preview/index.ts +1 -1
- package/src/extensions/preview/preview.ts +14 -14
- 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 +3 -3
- 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/streamer.ts +4 -5
- package/src/extensions/tags/xml-tags.ts +320 -155
- package/src/extensions/typewriter.ts +1 -1
- package/src/hooks/useTextEditor.ts +31 -43
- package/src/stories/{Command.stories.tsx → CommandDialog.stories.tsx} +20 -27
- package/src/stories/Comments.stories.tsx +8 -9
- package/src/stories/EditorToolbar.stories.tsx +14 -13
- package/src/stories/Experimental.stories.tsx +7 -7
- package/src/stories/Markdown.stories.tsx +6 -6
- package/src/stories/Outliner.stories.tsx +40 -31
- package/src/stories/Popover.stories.tsx +162 -0
- package/src/stories/Preview.stories.tsx +46 -42
- package/src/stories/Tags.stories.tsx +24 -10
- package/src/stories/TextEditor.stories.tsx +10 -35
- package/src/stories/components/EditorStory.tsx +29 -16
- package/src/stories/components/util.tsx +40 -8
- package/src/styles/markdown.ts +1 -1
- package/src/styles/theme.ts +13 -11
- package/src/types/types.ts +1 -1
- package/src/util/debug.ts +5 -0
- package/src/util/index.ts +0 -1
- package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -6
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -8
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- 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/components/Popover/CommandMenu.d.ts +0 -34
- package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
- package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -14
- package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
- package/dist/types/src/components/Popover/RefPopover.d.ts +0 -37
- package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
- package/dist/types/src/components/Popover/index.d.ts +0 -4
- package/dist/types/src/components/Popover/index.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/action.d.ts +0 -17
- package/dist/types/src/extensions/command/action.d.ts.map +0 -1
- package/dist/types/src/extensions/command/command-menu.d.ts +0 -20
- package/dist/types/src/extensions/command/command-menu.d.ts.map +0 -1
- package/dist/types/src/extensions/command/command.d.ts +0 -6
- package/dist/types/src/extensions/command/command.d.ts.map +0 -1
- package/dist/types/src/extensions/command/floating-menu.d.ts +0 -7
- package/dist/types/src/extensions/command/floating-menu.d.ts.map +0 -1
- package/dist/types/src/extensions/command/hint.d.ts +0 -19
- package/dist/types/src/extensions/command/hint.d.ts.map +0 -1
- package/dist/types/src/extensions/command/index.d.ts +0 -7
- package/dist/types/src/extensions/command/index.d.ts.map +0 -1
- package/dist/types/src/extensions/command/placeholder.d.ts +0 -10
- package/dist/types/src/extensions/command/placeholder.d.ts.map +0 -1
- package/dist/types/src/extensions/command/state.d.ts +0 -16
- package/dist/types/src/extensions/command/state.d.ts.map +0 -1
- package/dist/types/src/extensions/command/typeahead.d.ts +0 -22
- package/dist/types/src/extensions/command/typeahead.d.ts.map +0 -1
- package/dist/types/src/extensions/command/useCommandMenu.d.ts +0 -26
- package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +0 -1
- package/dist/types/src/stories/Command.stories.d.ts.map +0 -1
- package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- 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/dist/types/src/util/domino.d.ts +0 -18
- package/dist/types/src/util/domino.d.ts.map +0 -1
- package/src/components/EditorToolbar/util.ts +0 -76
- package/src/components/Popover/CommandMenu.tsx +0 -279
- package/src/components/Popover/RefDropdownMenu.tsx +0 -89
- package/src/components/Popover/RefPopover.tsx +0 -117
- package/src/components/Popover/index.ts +0 -7
- package/src/extensions/command/action.ts +0 -56
- package/src/extensions/command/command-menu.ts +0 -211
- package/src/extensions/command/command.ts +0 -34
- package/src/extensions/command/hint.ts +0 -103
- package/src/extensions/command/index.ts +0 -10
- package/src/extensions/command/state.ts +0 -90
- package/src/extensions/command/useCommandMenu.ts +0 -119
- package/src/stories/CommandMenu.stories.tsx +0 -160
- package/src/testing/index.ts +0 -5
- package/src/testing/util.ts +0 -7
- package/src/util/domino.ts +0 -51
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { RangeSetBuilder } from '@codemirror/state';
|
|
6
|
+
import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
|
|
7
|
+
|
|
8
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
9
|
+
|
|
10
|
+
const paragraphBlockPlugin = ViewPlugin.fromClass(
|
|
11
|
+
class {
|
|
12
|
+
decorations: DecorationSet;
|
|
13
|
+
|
|
14
|
+
constructor(view: EditorView) {
|
|
15
|
+
this.decorations = this.build(view);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
update(update: ViewUpdate) {
|
|
19
|
+
if (update.docChanged || update.viewportChanged) {
|
|
20
|
+
this.decorations = this.build(update.view);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
build({ state }: EditorView) {
|
|
25
|
+
const builder = new RangeSetBuilder<Decoration>();
|
|
26
|
+
|
|
27
|
+
// Helper: commit a block from blockStart to endLine (inclusive).
|
|
28
|
+
const pushBlock = (fromLine: number, toLine: number) => {
|
|
29
|
+
// Add line decorations for each line in the block.
|
|
30
|
+
for (let lineNum = fromLine; lineNum <= toLine; lineNum++) {
|
|
31
|
+
const line = state.doc.line(lineNum);
|
|
32
|
+
builder.add(
|
|
33
|
+
line.from,
|
|
34
|
+
line.from,
|
|
35
|
+
Decoration.line({
|
|
36
|
+
class: mx(
|
|
37
|
+
'block-line',
|
|
38
|
+
fromLine === toLine && 'block-single',
|
|
39
|
+
lineNum === fromLine && 'block-first',
|
|
40
|
+
lineNum > fromLine && lineNum < toLine && 'block-middle',
|
|
41
|
+
lineNum === toLine && 'block-last',
|
|
42
|
+
),
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let blockStart: number | null = null;
|
|
49
|
+
let consecutiveBlankLines = 0;
|
|
50
|
+
const totalLines = state.doc.lines;
|
|
51
|
+
for (let i = 1; i <= totalLines; i++) {
|
|
52
|
+
const line = state.doc.line(i);
|
|
53
|
+
const isBlank = /^\s*$/.test(line.text);
|
|
54
|
+
|
|
55
|
+
if (!isBlank) {
|
|
56
|
+
// Reset blank line counter.
|
|
57
|
+
consecutiveBlankLines = 0;
|
|
58
|
+
// Start a new block if we're not already in one.
|
|
59
|
+
if (blockStart === null) {
|
|
60
|
+
blockStart = i;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
// Increment blank line counter.
|
|
64
|
+
consecutiveBlankLines++;
|
|
65
|
+
|
|
66
|
+
// End the current block if we have 2+ consecutive blank lines.
|
|
67
|
+
if (consecutiveBlankLines >= 2 && blockStart !== null) {
|
|
68
|
+
pushBlock(blockStart, i - consecutiveBlankLines);
|
|
69
|
+
blockStart = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Handle any remaining block at the end of the document.
|
|
75
|
+
if (blockStart !== null) {
|
|
76
|
+
// Find the last non-blank line for the block end.
|
|
77
|
+
let lastNonBlankLine = totalLines;
|
|
78
|
+
while (lastNonBlankLine >= blockStart) {
|
|
79
|
+
const line = state.doc.line(lastNonBlankLine);
|
|
80
|
+
if (!/^\s*$/.test(line.text)) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
lastNonBlankLine--;
|
|
84
|
+
}
|
|
85
|
+
if (lastNonBlankLine >= blockStart) {
|
|
86
|
+
pushBlock(blockStart, lastNonBlankLine);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return builder.finish();
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
decorations: (v) => v.decorations,
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export const blocks = () => [
|
|
99
|
+
paragraphBlockPlugin,
|
|
100
|
+
EditorView.baseTheme({
|
|
101
|
+
'.cm-line.block-line': {
|
|
102
|
+
paddingLeft: '0.75rem',
|
|
103
|
+
paddingRight: '0.75rem',
|
|
104
|
+
borderLeft: '1px solid var(--dx-subduedSeparator)',
|
|
105
|
+
borderRight: '1px solid var(--dx-subduedSeparator)',
|
|
106
|
+
},
|
|
107
|
+
'.cm-line.block-single': {
|
|
108
|
+
border: '1px solid var(--dx-subduedSeparator)',
|
|
109
|
+
borderRadius: '6px',
|
|
110
|
+
paddingTop: '0.5rem',
|
|
111
|
+
paddingBottom: '0.5rem',
|
|
112
|
+
marginTop: '0.5rem',
|
|
113
|
+
marginBottom: '0.5rem',
|
|
114
|
+
},
|
|
115
|
+
'.cm-line.block-first': {
|
|
116
|
+
borderTop: '1px solid var(--dx-subduedSeparator)',
|
|
117
|
+
borderTopLeftRadius: '6px',
|
|
118
|
+
borderTopRightRadius: '6px',
|
|
119
|
+
paddingTop: '0.5rem',
|
|
120
|
+
marginTop: '0.5rem',
|
|
121
|
+
},
|
|
122
|
+
'.cm-line.block-middle': {},
|
|
123
|
+
'.cm-line.block-last': {
|
|
124
|
+
borderBottom: '1px solid var(--dx-subduedSeparator)',
|
|
125
|
+
borderBottomLeftRadius: '6px',
|
|
126
|
+
borderBottomRightRadius: '6px',
|
|
127
|
+
paddingBottom: '0.5rem',
|
|
128
|
+
marginBottom: '0.5rem',
|
|
129
|
+
},
|
|
130
|
+
}),
|
|
131
|
+
];
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Extension, Prec, StateEffect, StateField } from '@codemirror/state';
|
|
6
|
+
import { keymap } from '@codemirror/view';
|
|
7
|
+
|
|
8
|
+
type Bookmark = {
|
|
9
|
+
id: string;
|
|
10
|
+
pos: number;
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const addBookmark = StateEffect.define<Bookmark>();
|
|
15
|
+
export const removeBookmark = StateEffect.define<string>();
|
|
16
|
+
export const clearBookmarks = StateEffect.define<void>();
|
|
17
|
+
|
|
18
|
+
export const bookmarks = (): Extension => {
|
|
19
|
+
return [
|
|
20
|
+
bookmarksField,
|
|
21
|
+
Prec.highest(
|
|
22
|
+
keymap.of([
|
|
23
|
+
{
|
|
24
|
+
key: 'Mod-ArrowUp',
|
|
25
|
+
run: (view) => {
|
|
26
|
+
const bookmarks = view.state.field(bookmarksField);
|
|
27
|
+
console.log('up', bookmarks);
|
|
28
|
+
return true;
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: 'Mod-ArrowDown',
|
|
33
|
+
run: (view) => {
|
|
34
|
+
const bookmarks = view.state.field(bookmarksField);
|
|
35
|
+
console.log('down', bookmarks);
|
|
36
|
+
return true;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
]),
|
|
40
|
+
),
|
|
41
|
+
];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type BookmarkFieldState = {
|
|
45
|
+
bookmarks: Bookmark[];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const bookmarksField = StateField.define<BookmarkFieldState>({
|
|
49
|
+
create: (): BookmarkFieldState => ({
|
|
50
|
+
bookmarks: [],
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
update: (value: BookmarkFieldState, tr): BookmarkFieldState => {
|
|
54
|
+
// Map bookmark positions through document changes.
|
|
55
|
+
let bookmarks = value.bookmarks.map((bookmark) => ({
|
|
56
|
+
...bookmark,
|
|
57
|
+
pos: tr.changes.mapPos(bookmark.pos),
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
// Process effects.
|
|
61
|
+
for (const effect of tr.effects) {
|
|
62
|
+
if (effect.is(addBookmark)) {
|
|
63
|
+
bookmarks = [...bookmarks, effect.value];
|
|
64
|
+
} else if (effect.is(removeBookmark)) {
|
|
65
|
+
bookmarks = bookmarks.filter((b) => b.id !== effect.value);
|
|
66
|
+
} else if (effect.is(clearBookmarks)) {
|
|
67
|
+
bookmarks = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Sort bookmarks by position.
|
|
72
|
+
bookmarks.sort(({ pos: a }, { pos: b }) => a - b);
|
|
73
|
+
return { bookmarks };
|
|
74
|
+
},
|
|
75
|
+
});
|
|
@@ -104,13 +104,14 @@ export const commentsState = StateField.define<CommentsState>({
|
|
|
104
104
|
const styles = EditorView.theme({
|
|
105
105
|
'.cm-comment, .cm-comment-current': {
|
|
106
106
|
padding: '3px 0',
|
|
107
|
+
color: 'var(--dx-cmCommentText)',
|
|
107
108
|
backgroundColor: 'var(--dx-cmCommentSurface)',
|
|
108
109
|
},
|
|
109
110
|
'.cm-comment > span, .cm-comment-current > span': {
|
|
110
111
|
boxDecorationBreak: 'clone',
|
|
111
112
|
boxShadow: '0 0 1px 3px var(--dx-cmCommentSurface)',
|
|
112
113
|
backgroundColor: 'var(--dx-cmCommentSurface)',
|
|
113
|
-
color: 'var(--dx-
|
|
114
|
+
color: 'var(--dx-cmCommentText)',
|
|
114
115
|
cursor: 'pointer',
|
|
115
116
|
},
|
|
116
117
|
});
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
|
6
6
|
import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';
|
|
7
|
-
import {
|
|
7
|
+
import { HighlightStyle, bracketMatching, syntaxHighlighting } from '@codemirror/language';
|
|
8
8
|
import { searchKeymap } from '@codemirror/search';
|
|
9
|
-
import { EditorState, type Extension } from '@codemirror/state';
|
|
10
|
-
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
|
9
|
+
import { type ChangeSpec, EditorState, type Extension, type TransactionSpec } from '@codemirror/state';
|
|
11
10
|
import {
|
|
12
11
|
EditorView,
|
|
13
12
|
type KeyBinding,
|
|
@@ -20,16 +19,17 @@ import {
|
|
|
20
19
|
placeholder,
|
|
21
20
|
scrollPastEnd,
|
|
22
21
|
} from '@codemirror/view';
|
|
22
|
+
import { vscodeDarkStyle, vscodeLightStyle } from '@uiw/codemirror-theme-vscode';
|
|
23
23
|
import defaultsDeep from 'lodash.defaultsdeep';
|
|
24
24
|
import merge from 'lodash.merge';
|
|
25
25
|
|
|
26
|
+
import { type DocAccessor, type Space } from '@dxos/client/echo';
|
|
27
|
+
import { type Identity } from '@dxos/client/halo';
|
|
26
28
|
import { generateName } from '@dxos/display-name';
|
|
27
29
|
import { log } from '@dxos/log';
|
|
28
|
-
import { type DocAccessor, type Space } from '@dxos/react-client/echo';
|
|
29
|
-
import { type Identity } from '@dxos/react-client/halo';
|
|
30
30
|
import { type ThemeMode } from '@dxos/react-ui';
|
|
31
31
|
import { type HuePalette } from '@dxos/react-ui-theme';
|
|
32
|
-
import { hexToHue,
|
|
32
|
+
import { hexToHue, isTruthy } from '@dxos/util';
|
|
33
33
|
|
|
34
34
|
import { editorGutter, editorMonospace } from '../defaults';
|
|
35
35
|
import { type ThemeStyles, defaultTheme } from '../styles';
|
|
@@ -42,7 +42,29 @@ import { focus } from './focus';
|
|
|
42
42
|
// Basic
|
|
43
43
|
//
|
|
44
44
|
|
|
45
|
-
export const
|
|
45
|
+
export const filterChars = (chars: RegExp) => {
|
|
46
|
+
return EditorState.transactionFilter.of((transaction) => {
|
|
47
|
+
if (!transaction.docChanged) return transaction;
|
|
48
|
+
|
|
49
|
+
const changes: ChangeSpec[] = [];
|
|
50
|
+
transaction.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
51
|
+
const inserted = text.toString();
|
|
52
|
+
const filtered = inserted.replace(chars, '');
|
|
53
|
+
if (inserted !== filtered) {
|
|
54
|
+
changes.push({
|
|
55
|
+
from: fromB,
|
|
56
|
+
to: toB,
|
|
57
|
+
insert: filtered,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (changes.length) {
|
|
63
|
+
return [transaction, { changes, sequential: true } as TransactionSpec];
|
|
64
|
+
}
|
|
65
|
+
return transaction;
|
|
66
|
+
});
|
|
67
|
+
};
|
|
46
68
|
|
|
47
69
|
/**
|
|
48
70
|
* https://codemirror.net/docs/extensions
|
|
@@ -65,11 +87,11 @@ export type BasicExtensionsOptions = {
|
|
|
65
87
|
lineNumbers?: boolean;
|
|
66
88
|
/** If false then do not set a max-width or side margin on the editor. */
|
|
67
89
|
lineWrapping?: boolean;
|
|
68
|
-
monospace?: boolean;
|
|
69
90
|
placeholder?: string;
|
|
70
91
|
/** If true user cannot edit the text, but they can still select and copy it. */
|
|
71
92
|
readOnly?: boolean;
|
|
72
93
|
search?: boolean;
|
|
94
|
+
/** NOTE: Do not use with stack sections. */
|
|
73
95
|
scrollPastEnd?: boolean;
|
|
74
96
|
standardKeymap?: boolean;
|
|
75
97
|
tabSize?: number;
|
|
@@ -113,7 +135,6 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
|
|
|
113
135
|
props.history && history(),
|
|
114
136
|
props.lineNumbers && [lineNumbers(), editorGutter],
|
|
115
137
|
props.lineWrapping && EditorView.lineWrapping,
|
|
116
|
-
props.monospace && editorMonospace,
|
|
117
138
|
props.placeholder && placeholder(props.placeholder),
|
|
118
139
|
props.readOnly !== undefined && EditorState.readOnly.of(props.readOnly),
|
|
119
140
|
props.scrollPastEnd && scrollPastEnd(),
|
|
@@ -139,9 +160,9 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
|
|
|
139
160
|
preventDefault: true,
|
|
140
161
|
run: () => true,
|
|
141
162
|
},
|
|
142
|
-
].filter(
|
|
163
|
+
].filter(isTruthy),
|
|
143
164
|
),
|
|
144
|
-
].filter(
|
|
165
|
+
].filter(isTruthy);
|
|
145
166
|
};
|
|
146
167
|
|
|
147
168
|
//
|
|
@@ -150,6 +171,7 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
|
|
|
150
171
|
|
|
151
172
|
export type ThemeExtensionsOptions = {
|
|
152
173
|
themeMode?: ThemeMode;
|
|
174
|
+
monospace?: boolean;
|
|
153
175
|
styles?: ThemeStyles;
|
|
154
176
|
syntaxHighlighting?: boolean;
|
|
155
177
|
slots?: {
|
|
@@ -157,6 +179,7 @@ export type ThemeExtensionsOptions = {
|
|
|
157
179
|
className?: string;
|
|
158
180
|
};
|
|
159
181
|
scroll?: {
|
|
182
|
+
// NOTE: Do not apply vertical padding to scroll container.
|
|
160
183
|
className?: string;
|
|
161
184
|
};
|
|
162
185
|
content?: {
|
|
@@ -179,20 +202,28 @@ export const fullWidth: ThemeExtensionsOptions['slots'] = {
|
|
|
179
202
|
|
|
180
203
|
export const defaultThemeSlots = grow;
|
|
181
204
|
|
|
205
|
+
export const defaultStyles = {
|
|
206
|
+
dark: vscodeDarkStyle,
|
|
207
|
+
light: vscodeLightStyle,
|
|
208
|
+
};
|
|
209
|
+
|
|
182
210
|
/**
|
|
183
211
|
* https://codemirror.net/examples/styling
|
|
184
212
|
*/
|
|
185
213
|
export const createThemeExtensions = ({
|
|
186
214
|
themeMode,
|
|
215
|
+
monospace,
|
|
187
216
|
styles,
|
|
188
|
-
syntaxHighlighting:
|
|
189
|
-
slots:
|
|
217
|
+
syntaxHighlighting: syntaxHighlightingProp,
|
|
218
|
+
slots: slotsParam,
|
|
190
219
|
}: ThemeExtensionsOptions = {}): Extension => {
|
|
191
|
-
const slots = defaultsDeep({},
|
|
220
|
+
const slots = defaultsDeep({}, slotsParam, defaultThemeSlots);
|
|
192
221
|
return [
|
|
193
222
|
EditorView.darkTheme.of(themeMode === 'dark'),
|
|
194
223
|
EditorView.baseTheme(styles ? merge({}, defaultTheme, styles) : defaultTheme),
|
|
195
|
-
|
|
224
|
+
monospace && editorMonospace,
|
|
225
|
+
syntaxHighlightingProp &&
|
|
226
|
+
syntaxHighlighting(HighlightStyle.define(themeMode === 'dark' ? defaultStyles.dark : defaultStyles.light)),
|
|
196
227
|
slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
|
|
197
228
|
slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
|
|
198
229
|
slots.scroll?.className &&
|
|
@@ -203,7 +234,7 @@ export const createThemeExtensions = ({
|
|
|
203
234
|
}
|
|
204
235
|
},
|
|
205
236
|
),
|
|
206
|
-
].filter(
|
|
237
|
+
].filter(isTruthy);
|
|
207
238
|
};
|
|
208
239
|
|
|
209
240
|
//
|
package/src/extensions/focus.ts
CHANGED
|
@@ -15,6 +15,7 @@ export const focusField = StateField.define<boolean>({
|
|
|
15
15
|
return effect.value;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
|
|
18
19
|
return value;
|
|
19
20
|
},
|
|
20
21
|
});
|
|
@@ -25,11 +26,11 @@ export const focusField = StateField.define<boolean>({
|
|
|
25
26
|
export const focus = [
|
|
26
27
|
focusField,
|
|
27
28
|
EditorView.domEventHandlers({
|
|
28
|
-
focus: (
|
|
29
|
-
|
|
29
|
+
focus: (_event, view) => {
|
|
30
|
+
requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(true) }));
|
|
30
31
|
},
|
|
31
|
-
blur: (
|
|
32
|
-
|
|
32
|
+
blur: (_event, view) => {
|
|
33
|
+
requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(false) }));
|
|
33
34
|
},
|
|
34
35
|
}),
|
|
35
36
|
];
|
|
@@ -7,16 +7,15 @@ import { type Extension } from '@codemirror/state';
|
|
|
7
7
|
import { EditorView } from '@codemirror/view';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
|
|
10
|
-
import { Icon } from '@dxos/react-ui';
|
|
10
|
+
import { Domino, Icon } from '@dxos/react-ui';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { renderRoot } from '../util';
|
|
13
13
|
|
|
14
14
|
export type FoldingOptions = {};
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* https://codemirror.net/examples/gutter
|
|
18
18
|
*/
|
|
19
|
-
// TODO(burdon): Remember folding state (to state).
|
|
20
19
|
export const folding = (_props: FoldingOptions = {}): Extension => [
|
|
21
20
|
codeFolding({
|
|
22
21
|
placeholderDOM: () => {
|
|
@@ -25,10 +24,8 @@ export const folding = (_props: FoldingOptions = {}): Extension => [
|
|
|
25
24
|
}),
|
|
26
25
|
foldGutter({
|
|
27
26
|
markerDOM: (open) => {
|
|
28
|
-
// TODO(burdon): Use sprite directly.
|
|
29
|
-
const el = Domino.of('div').classNames('flex h-full items-center').build();
|
|
30
27
|
return renderRoot(
|
|
31
|
-
|
|
28
|
+
Domino.of('div').classNames('flex bs-full items-center').build(),
|
|
32
29
|
<Icon icon='ph--caret-right--bold' size={3} classNames={['mx-3 cursor-pointer', open && 'rotate-90']} />,
|
|
33
30
|
);
|
|
34
31
|
},
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
WidgetType,
|
|
14
14
|
} from '@codemirror/view';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { getHashStyles, mx } from '@dxos/react-ui-theme';
|
|
17
17
|
|
|
18
18
|
class TagWidget extends WidgetType {
|
|
19
19
|
constructor(private _text: string) {
|
|
@@ -22,7 +22,7 @@ class TagWidget extends WidgetType {
|
|
|
22
22
|
|
|
23
23
|
toDOM(): HTMLSpanElement {
|
|
24
24
|
const span = document.createElement('span');
|
|
25
|
-
span.className = mx('cm-tag',
|
|
25
|
+
span.className = mx('cm-tag', getHashStyles(this._text).surface);
|
|
26
26
|
span.textContent = this._text;
|
|
27
27
|
return span;
|
|
28
28
|
}
|
package/src/extensions/index.ts
CHANGED
|
@@ -8,7 +8,8 @@ export * from './autoscroll';
|
|
|
8
8
|
export * from './automerge';
|
|
9
9
|
export * from './awareness';
|
|
10
10
|
export * from './blast';
|
|
11
|
-
export * from './
|
|
11
|
+
export * from './blocks';
|
|
12
|
+
export * from './bookmarks';
|
|
12
13
|
export * from './comments';
|
|
13
14
|
export * from './debug';
|
|
14
15
|
export * from './dnd';
|
|
@@ -20,9 +21,15 @@ export * from './json';
|
|
|
20
21
|
export * from './listener';
|
|
21
22
|
export * from './markdown';
|
|
22
23
|
export * from './mention';
|
|
24
|
+
export * from './modal';
|
|
23
25
|
export * from './modes';
|
|
24
26
|
export * from './outliner';
|
|
25
27
|
export * from './preview';
|
|
28
|
+
export * from './replacer';
|
|
26
29
|
export * from './selection';
|
|
30
|
+
export * from './scrolling';
|
|
31
|
+
export * from './state';
|
|
32
|
+
export * from './submit';
|
|
33
|
+
export * from './tab';
|
|
27
34
|
export * from './tags';
|
|
28
35
|
export * from './typewriter';
|
package/src/extensions/json.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { type LintSource, linter } from '@codemirror/lint';
|
|
|
7
7
|
import { type Extension } from '@codemirror/state';
|
|
8
8
|
import Ajv, { type ValidateFunction } from 'ajv';
|
|
9
9
|
|
|
10
|
-
import { type JsonSchemaType } from '@dxos/echo
|
|
10
|
+
import { type JsonSchemaType } from '@dxos/echo/internal';
|
|
11
11
|
|
|
12
12
|
export type JsonExtensionsOptions = {
|
|
13
13
|
schema?: JsonSchemaType;
|
|
@@ -5,34 +5,28 @@
|
|
|
5
5
|
import { type Extension } from '@codemirror/state';
|
|
6
6
|
import { EditorView } from '@codemirror/view';
|
|
7
7
|
|
|
8
|
+
import { isNonNullable } from '@dxos/util';
|
|
9
|
+
|
|
8
10
|
import { documentId } from './selection';
|
|
9
11
|
|
|
10
12
|
export type ListenerOptions = {
|
|
11
|
-
onFocus?: (focusing: boolean) => void;
|
|
12
|
-
onChange?: (
|
|
13
|
+
onFocus?: (event: { id: string; focusing: boolean }) => void;
|
|
14
|
+
onChange?: (event: { id: string; text: string }) => void;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
/**
|
|
16
|
-
* Event listener.
|
|
17
|
-
* @deprecated Use EditorView.updateListener and listen for specific update events.
|
|
18
|
-
*/
|
|
19
17
|
export const listener = ({ onFocus, onChange }: ListenerOptions): Extension => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
EditorView.focusChangeEffect.of((_, focusing) => {
|
|
25
|
-
onFocus(focusing);
|
|
18
|
+
return [
|
|
19
|
+
onFocus &&
|
|
20
|
+
EditorView.focusChangeEffect.of((state, focusing) => {
|
|
21
|
+
onFocus({ id: state.facet(documentId), focusing });
|
|
26
22
|
return null;
|
|
27
23
|
}),
|
|
28
|
-
);
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
onChange &&
|
|
26
|
+
EditorView.updateListener.of(({ state, docChanged }) => {
|
|
27
|
+
if (docChanged) {
|
|
28
|
+
onChange({ id: state.facet(documentId), text: state.doc.toString() });
|
|
29
|
+
}
|
|
34
30
|
}),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return extensions;
|
|
31
|
+
].filter(isNonNullable);
|
|
38
32
|
};
|
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { completionKeymap } from '@codemirror/autocomplete';
|
|
6
6
|
import { defaultKeymap, indentWithTab } from '@codemirror/commands';
|
|
7
|
+
import { jsonLanguage } from '@codemirror/lang-json';
|
|
7
8
|
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
|
8
|
-
import {
|
|
9
|
+
import { xml } from '@codemirror/lang-xml';
|
|
10
|
+
import { LanguageDescription, syntaxHighlighting } from '@codemirror/language';
|
|
9
11
|
import { languages } from '@codemirror/language-data';
|
|
10
12
|
import { type Extension } from '@codemirror/state';
|
|
11
13
|
import { keymap } from '@codemirror/view';
|
|
12
14
|
import { type MarkdownConfig } from '@lezer/markdown';
|
|
13
15
|
|
|
14
|
-
import {
|
|
16
|
+
import { isTruthy } from '@dxos/util';
|
|
15
17
|
|
|
16
18
|
import { markdownHighlightStyle, markdownTagsExtensions } from './highlight';
|
|
17
19
|
|
|
@@ -43,6 +45,7 @@ export const createMarkdownExtensions = (options: MarkdownBundleOptions = {}): E
|
|
|
43
45
|
base: markdownLanguage,
|
|
44
46
|
|
|
45
47
|
// Languages for syntax highlighting fenced code blocks.
|
|
48
|
+
defaultCodeLanguage: jsonLanguage,
|
|
46
49
|
codeLanguages: languages,
|
|
47
50
|
|
|
48
51
|
// Don't complete HTML tags.
|
|
@@ -66,12 +69,21 @@ export const createMarkdownExtensions = (options: MarkdownBundleOptions = {}): E
|
|
|
66
69
|
|
|
67
70
|
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
|
68
71
|
...defaultKeymap,
|
|
72
|
+
|
|
73
|
+
// TODO(burdon): Remove?
|
|
69
74
|
...completionKeymap,
|
|
70
|
-
].filter(
|
|
75
|
+
].filter(isTruthy),
|
|
71
76
|
),
|
|
72
77
|
];
|
|
73
78
|
};
|
|
74
79
|
|
|
80
|
+
const xmlLanguageDesc = LanguageDescription.of({
|
|
81
|
+
name: 'xml',
|
|
82
|
+
alias: ['html', 'xhtml'],
|
|
83
|
+
extensions: ['xml', 'xhtml'],
|
|
84
|
+
load: async () => xml(),
|
|
85
|
+
});
|
|
86
|
+
|
|
75
87
|
/**
|
|
76
88
|
* Default customizations.
|
|
77
89
|
* https://github.com/lezer-parser/markdown/blob/main/src/markdown.ts
|
|
@@ -89,5 +101,5 @@ const noSetExtHeading: MarkdownConfig = {
|
|
|
89
101
|
* Remove HTML and XML parsing.
|
|
90
102
|
*/
|
|
91
103
|
const noHtml: MarkdownConfig = {
|
|
92
|
-
remove: ['HTMLBlock', 'HTMLTag'],
|
|
104
|
+
// remove: ['HTMLBlock', 'HTMLTag'],
|
|
93
105
|
};
|
|
@@ -52,12 +52,12 @@ class LinkButton extends WidgetType {
|
|
|
52
52
|
super();
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
override eq(other: this)
|
|
55
|
+
override eq(other: this) {
|
|
56
56
|
return this.url === other.url;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// TODO(burdon): Create icon and link directly without react?
|
|
60
|
-
override toDOM(view: EditorView)
|
|
60
|
+
override toDOM(view: EditorView) {
|
|
61
61
|
const el = document.createElement('span');
|
|
62
62
|
this.render(el, { url: this.url }, view);
|
|
63
63
|
return el;
|
|
@@ -69,11 +69,15 @@ class CheckboxWidget extends WidgetType {
|
|
|
69
69
|
super();
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
override eq(other: this)
|
|
72
|
+
override eq(other: this) {
|
|
73
73
|
return this._checked === other._checked;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
override
|
|
76
|
+
override ignoreEvent() {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override toDOM(view: EditorView) {
|
|
77
81
|
const input = document.createElement('input');
|
|
78
82
|
input.className = 'cm-task-checkbox dx-checkbox';
|
|
79
83
|
input.type = 'checkbox';
|
|
@@ -105,10 +109,6 @@ class CheckboxWidget extends WidgetType {
|
|
|
105
109
|
span.appendChild(input);
|
|
106
110
|
return span;
|
|
107
111
|
}
|
|
108
|
-
|
|
109
|
-
override ignoreEvent(): boolean {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
class TextWidget extends WidgetType {
|
|
@@ -447,6 +447,7 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
|
|
|
447
447
|
},
|
|
448
448
|
}),
|
|
449
449
|
);
|
|
450
|
+
|
|
450
451
|
if (!editing) {
|
|
451
452
|
atomicDeco.add(
|
|
452
453
|
marks[1].from,
|
|
@@ -15,12 +15,8 @@ import {
|
|
|
15
15
|
} from '@codemirror/state';
|
|
16
16
|
import { EditorView, type ViewUpdate, keymap } from '@codemirror/view';
|
|
17
17
|
import { type SyntaxNode, type SyntaxNodeRef } from '@lezer/common';
|
|
18
|
-
import { useCallback, useMemo } from 'react';
|
|
19
18
|
|
|
20
19
|
import { debounceAndThrottle } from '@dxos/async';
|
|
21
|
-
import { type Live } from '@dxos/live-object';
|
|
22
|
-
|
|
23
|
-
import { type EditorToolbarState } from '../../components';
|
|
24
20
|
|
|
25
21
|
// Markdown refs:
|
|
26
22
|
// https://github.github.com/gfm
|
|
@@ -1251,17 +1247,19 @@ export const getFormatting = (state: EditorState): Formatting => {
|
|
|
1251
1247
|
/**
|
|
1252
1248
|
* Hook provides an extension to compute the current formatting state.
|
|
1253
1249
|
*/
|
|
1254
|
-
export const
|
|
1255
|
-
|
|
1250
|
+
export const formattingListener = (stateProvider: () => Formatting | undefined, delay = 100): Extension => {
|
|
1251
|
+
return EditorView.updateListener.of(
|
|
1256
1252
|
debounceAndThrottle((update: ViewUpdate) => {
|
|
1257
1253
|
if (update.docChanged || update.selectionSet) {
|
|
1254
|
+
const state = stateProvider();
|
|
1255
|
+
if (!state) {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1258
1259
|
Object.entries(getFormatting(update.state)).forEach(([key, active]) => {
|
|
1259
1260
|
state[key as keyof Formatting] = active as any;
|
|
1260
1261
|
});
|
|
1261
1262
|
}
|
|
1262
|
-
},
|
|
1263
|
-
[state],
|
|
1263
|
+
}, delay),
|
|
1264
1264
|
);
|
|
1265
|
-
|
|
1266
|
-
return useMemo(() => EditorView.updateListener.of(handleUpdate), [handleUpdate]);
|
|
1267
1265
|
};
|