@dxos/ui-editor 0.10.0 → 0.11.0
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/chunk-diff.mjs +935 -0
- package/dist/lib/chunk-diff.mjs.map +1 -0
- package/dist/lib/headless.mjs +2 -0
- package/dist/lib/index.mjs +9937 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/types.mjs +18 -0
- package/dist/lib/types.mjs.map +1 -0
- package/dist/types/src/extensions/{bookmarks.d.ts → behavior/bookmarks.d.ts} +3 -0
- package/dist/types/src/extensions/behavior/bookmarks.d.ts.map +1 -0
- package/dist/types/src/extensions/behavior/dnd.d.ts.map +1 -0
- package/dist/types/src/extensions/behavior/index.d.ts +6 -0
- package/dist/types/src/extensions/behavior/index.d.ts.map +1 -0
- package/dist/types/src/extensions/{listener.d.ts → behavior/listener.d.ts} +3 -0
- package/dist/types/src/extensions/behavior/listener.d.ts.map +1 -0
- package/dist/types/src/extensions/{spacing.d.ts → behavior/spacing.d.ts} +3 -0
- package/dist/types/src/extensions/behavior/spacing.d.ts.map +1 -0
- package/dist/types/src/extensions/behavior/submit.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/cursor.d.ts +1 -1
- package/dist/types/src/extensions/collab/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/defs.d.ts +3 -1
- package/dist/types/src/extensions/collab/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/collab/automerge/index.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/automerge/sync.d.ts.map +1 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/update-automerge.d.ts +4 -0
- package/dist/types/src/extensions/collab/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/update-codemirror.d.ts +4 -0
- package/dist/types/src/extensions/collab/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/awareness/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/extensions/{awareness → collab/awareness}/awareness.d.ts +4 -1
- package/dist/types/src/extensions/collab/awareness/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/awareness/index.d.ts.map +1 -0
- package/dist/types/src/extensions/collab/index.d.ts +3 -0
- package/dist/types/src/extensions/collab/index.d.ts.map +1 -0
- package/dist/types/src/extensions/completion/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/{autocomplete → completion}/index.d.ts +1 -0
- package/dist/types/src/extensions/completion/index.d.ts.map +1 -0
- package/dist/types/src/extensions/{autocomplete → completion}/match.d.ts +2 -2
- package/dist/types/src/extensions/completion/match.d.ts.map +1 -0
- package/dist/types/src/extensions/{mention.d.ts → completion/mention.d.ts} +3 -0
- package/dist/types/src/extensions/completion/mention.d.ts.map +1 -0
- package/dist/types/src/extensions/completion/placeholder.d.ts.map +1 -0
- package/dist/types/src/extensions/{autocomplete → completion}/typeahead.d.ts +2 -2
- package/dist/types/src/extensions/completion/typeahead.d.ts.map +1 -0
- package/dist/types/src/extensions/{factories.d.ts → core/factories.d.ts} +23 -2
- package/dist/types/src/extensions/core/factories.d.ts.map +1 -0
- package/dist/types/src/extensions/core/factories.test.d.ts.map +1 -0
- package/dist/types/src/extensions/core/index.d.ts +3 -0
- package/dist/types/src/extensions/core/index.d.ts.map +1 -0
- package/dist/types/src/extensions/{modes.d.ts → core/modes.d.ts} +3 -0
- package/dist/types/src/extensions/core/modes.d.ts.map +1 -0
- package/dist/types/src/extensions/{debug.d.ts → debug/debug.d.ts} +3 -0
- package/dist/types/src/extensions/debug/debug.d.ts.map +1 -0
- package/dist/types/src/extensions/debug/index.d.ts +2 -0
- package/dist/types/src/extensions/debug/index.d.ts.map +1 -0
- package/dist/types/src/extensions/{annotations.d.ts → decoration/annotations.d.ts} +1 -1
- package/dist/types/src/extensions/decoration/annotations.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/assistant.d.ts +27 -0
- package/dist/types/src/extensions/decoration/assistant.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/fader.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/hashtag.d.ts +6 -0
- package/dist/types/src/extensions/decoration/hashtag.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/index.d.ts +8 -0
- package/dist/types/src/extensions/decoration/index.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/marker.d.ts.map +1 -0
- package/dist/types/src/extensions/{pos.d.ts → decoration/pos.d.ts} +40 -14
- package/dist/types/src/extensions/decoration/pos.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/pos.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{replacer.d.ts → decoration/replacer.d.ts} +8 -8
- package/dist/types/src/extensions/decoration/replacer.d.ts.map +1 -0
- package/dist/types/src/extensions/decoration/replacer.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{blast.d.ts → demo/blast.d.ts} +3 -0
- package/dist/types/src/extensions/demo/blast.d.ts.map +1 -0
- package/dist/types/src/extensions/demo/index.d.ts +3 -0
- package/dist/types/src/extensions/demo/index.d.ts.map +1 -0
- package/dist/types/src/extensions/demo/snippets.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +10 -33
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/language/index.d.ts +5 -0
- package/dist/types/src/extensions/language/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/json/index.d.ts +2 -0
- package/dist/types/src/extensions/language/json/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/json/json.d.ts +12 -0
- package/dist/types/src/extensions/language/json/json.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/action.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/changes.d.ts +1 -1
- package/dist/types/src/extensions/language/markdown/changes.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/changes.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/debug.d.ts +3 -0
- package/dist/types/src/extensions/language/markdown/debug.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/decorate.d.ts +5 -1
- package/dist/types/src/extensions/language/markdown/decorate.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/formatting.d.ts +11 -2
- package/dist/types/src/extensions/language/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/formatting.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/highlight.d.ts +16 -12
- package/dist/types/src/extensions/language/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/image.test.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/link.d.ts +25 -0
- package/dist/types/src/extensions/language/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/link.test.d.ts +2 -0
- package/dist/types/src/extensions/language/markdown/link.test.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/parser.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/styles.d.ts +3 -0
- package/dist/types/src/extensions/language/markdown/styles.d.ts.map +1 -0
- package/dist/types/src/extensions/language/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/language/mermaid/index.d.ts +2 -0
- package/dist/types/src/extensions/language/mermaid/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/mermaid/mermaid.d.ts +18 -0
- package/dist/types/src/extensions/language/mermaid/mermaid.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/extended-markdown.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/extended-markdown.test.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/stub.d.ts +76 -0
- package/dist/types/src/extensions/language/xml/stub.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/widgets/anchor.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/widgets/index.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts +48 -0
- package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/xml-formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/{tags → language/xml}/xml-tags.d.ts +12 -1
- package/dist/types/src/extensions/language/xml/xml-tags.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts +2 -0
- package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/xml-util.d.ts.map +1 -0
- package/dist/types/src/extensions/language/xml/xml-util.test.d.ts.map +1 -0
- package/dist/types/src/extensions/review/change-bar.d.ts +29 -0
- package/dist/types/src/extensions/review/change-bar.d.ts.map +1 -0
- package/dist/types/src/extensions/{comments.d.ts → review/comments.d.ts} +56 -38
- package/dist/types/src/extensions/review/comments.d.ts.map +1 -0
- package/dist/types/src/extensions/review/comments.test.d.ts +2 -0
- package/dist/types/src/extensions/review/comments.test.d.ts.map +1 -0
- package/dist/types/src/extensions/review/diff.d.ts +131 -0
- package/dist/types/src/extensions/review/diff.d.ts.map +1 -0
- package/dist/types/src/extensions/review/diff.test.d.ts +2 -0
- package/dist/types/src/extensions/review/diff.test.d.ts.map +1 -0
- package/dist/types/src/extensions/review/index.d.ts +7 -0
- package/dist/types/src/extensions/review/index.d.ts.map +1 -0
- package/dist/types/src/extensions/review/suggest.d.ts +89 -0
- package/dist/types/src/extensions/review/suggest.d.ts.map +1 -0
- package/dist/types/src/extensions/review/suggest.test.d.ts +2 -0
- package/dist/types/src/extensions/review/suggest.test.d.ts.map +1 -0
- package/dist/types/src/extensions/review/suggestions-overlay.d.ts +25 -0
- package/dist/types/src/extensions/review/suggestions-overlay.d.ts.map +1 -0
- package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts +2 -0
- package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts.map +1 -0
- package/dist/types/src/extensions/review/track-changes.d.ts +27 -0
- package/dist/types/src/extensions/review/track-changes.d.ts.map +1 -0
- package/dist/types/src/extensions/review/track-changes.test.d.ts +2 -0
- package/dist/types/src/extensions/review/track-changes.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{busy.d.ts → state/busy.d.ts} +1 -0
- package/dist/types/src/extensions/state/busy.d.ts.map +1 -0
- package/dist/types/src/extensions/{focus.d.ts → state/focus.d.ts} +4 -0
- package/dist/types/src/extensions/state/focus.d.ts.map +1 -0
- package/dist/types/src/extensions/state/index.d.ts +5 -0
- package/dist/types/src/extensions/state/index.d.ts.map +1 -0
- package/dist/types/src/extensions/state/modal.d.ts.map +1 -0
- package/dist/types/src/extensions/{selection.d.ts → state/selection.d.ts} +1 -1
- package/dist/types/src/extensions/state/selection.d.ts.map +1 -0
- package/dist/types/src/extensions/state/selection.test.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/index.d.ts +4 -0
- package/dist/types/src/extensions/streaming/index.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/pending/index.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/pending/pending-text-stream.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/pending/pending-text-stream.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.d.ts +1 -0
- package/dist/types/src/extensions/streaming/pending/pending-text.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/pending/pending-text.test.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/auto-scroll.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/crawler.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/index.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts +4 -0
- package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/scrollbar-autohide.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/scrolling/scroller.d.ts.map +1 -0
- package/dist/types/src/extensions/{typewriter.d.ts → streaming/typewriter.d.ts} +12 -12
- package/dist/types/src/extensions/streaming/typewriter.d.ts.map +1 -0
- package/dist/types/src/extensions/streaming/typewriter.test.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/blocks.d.ts +52 -0
- package/dist/types/src/extensions/structure/blocks/blocks.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts +2 -0
- package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/drag.d.ts +57 -0
- package/dist/types/src/extensions/structure/blocks/drag.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/index.d.ts +5 -0
- package/dist/types/src/extensions/structure/blocks/index.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/selection.d.ts +47 -0
- package/dist/types/src/extensions/structure/blocks/selection.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/selection.test.d.ts +2 -0
- package/dist/types/src/extensions/structure/blocks/selection.test.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/blocks/types.d.ts +17 -0
- package/dist/types/src/extensions/structure/blocks/types.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/folding/folding.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/folding/index.d.ts +3 -0
- package/dist/types/src/extensions/structure/folding/index.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/folding/turns.d.ts +55 -0
- package/dist/types/src/extensions/structure/folding/turns.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/folding/turns.test.d.ts +2 -0
- package/dist/types/src/extensions/structure/folding/turns.test.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/index.d.ts +4 -0
- package/dist/types/src/extensions/structure/index.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/commands.d.ts +31 -0
- package/dist/types/src/extensions/structure/outliner/commands.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/dnd.d.ts +43 -0
- package/dist/types/src/extensions/structure/outliner/dnd.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts +2 -0
- package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/editor.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/editor.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/index.d.ts +1 -0
- package/dist/types/src/extensions/structure/outliner/index.d.ts.map +1 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/menu.d.ts +1 -0
- package/dist/types/src/extensions/structure/outliner/menu.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/outliner.test.d.ts.map +1 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/tree.d.ts +1 -1
- package/dist/types/src/extensions/structure/outliner/tree.d.ts.map +1 -0
- package/dist/types/src/extensions/structure/outliner/tree.test.d.ts.map +1 -0
- package/dist/types/src/headless.d.ts +4 -0
- package/dist/types/src/headless.d.ts.map +1 -0
- package/dist/types/src/styles/theme.d.ts +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/util/util.d.ts +2 -0
- package/dist/types/src/util/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +48 -42
- package/src/defaults.ts +1 -1
- package/src/extensions/{bookmarks.ts → behavior/bookmarks.ts} +24 -14
- package/src/extensions/behavior/index.ts +9 -0
- package/src/extensions/{listener.ts → behavior/listener.ts} +4 -1
- package/src/extensions/{spacing.ts → behavior/spacing.ts} +8 -2
- package/src/extensions/{submit.ts → behavior/submit.ts} +2 -10
- package/src/extensions/{automerge → collab/automerge}/automerge.test.tsx +4 -4
- package/src/extensions/{automerge → collab/automerge}/automerge.ts +7 -4
- package/src/extensions/{automerge → collab/automerge}/cursor.ts +1 -1
- package/src/extensions/{automerge → collab/automerge}/defs.ts +4 -1
- package/src/extensions/{automerge → collab/automerge}/index.ts +1 -0
- package/src/extensions/{automerge → collab/automerge}/sync.ts +1 -2
- package/src/extensions/{automerge → collab/automerge}/update-automerge.ts +4 -0
- package/src/extensions/{automerge → collab/automerge}/update-codemirror.ts +5 -1
- package/src/extensions/{awareness → collab/awareness}/awareness-provider.ts +3 -4
- package/src/extensions/{awareness → collab/awareness}/awareness.ts +19 -16
- package/src/extensions/collab/index.ts +6 -0
- package/src/extensions/{autocomplete → completion}/autocomplete.ts +7 -5
- package/src/extensions/{autocomplete → completion}/index.ts +2 -1
- package/src/extensions/{autocomplete → completion}/match.ts +2 -2
- package/src/extensions/{mention.ts → completion/mention.ts} +3 -0
- package/src/extensions/{autocomplete → completion}/placeholder.ts +1 -1
- package/src/extensions/completion/typeahead.ts +97 -0
- package/src/extensions/{factories.ts → core/factories.ts} +35 -13
- package/src/extensions/core/index.ts +6 -0
- package/src/extensions/{modes.ts → core/modes.ts} +4 -1
- package/src/extensions/{debug.ts → debug/debug.ts} +3 -0
- package/src/extensions/debug/index.ts +5 -0
- package/src/extensions/{annotations.ts → decoration/annotations.ts} +12 -10
- package/src/extensions/decoration/assistant.ts +225 -0
- package/src/extensions/{fader.ts → decoration/fader.ts} +17 -19
- package/src/extensions/{hashtag.ts → decoration/hashtag.ts} +35 -28
- package/src/extensions/decoration/index.ts +11 -0
- package/src/extensions/{marker.ts → decoration/marker.ts} +18 -18
- package/src/extensions/{pos.test.ts → decoration/pos.test.ts} +57 -1
- package/src/extensions/{pos.ts → decoration/pos.ts} +165 -31
- package/src/extensions/{blast.ts → demo/blast.ts} +3 -0
- package/src/extensions/demo/index.ts +6 -0
- package/src/extensions/{snippets.ts → demo/snippets.ts} +5 -1
- package/src/extensions/index.ts +10 -33
- package/src/extensions/language/index.ts +8 -0
- package/src/extensions/language/json/index.ts +5 -0
- package/src/extensions/{json.ts → language/json/json.ts} +11 -6
- package/src/extensions/{markdown → language/markdown}/action.ts +1 -1
- package/src/extensions/{markdown → language/markdown}/bundle.ts +7 -1
- package/src/extensions/{markdown → language/markdown}/changes.test.ts +2 -2
- package/src/extensions/{markdown → language/markdown}/changes.ts +2 -2
- package/src/extensions/{markdown → language/markdown}/debug.ts +3 -0
- package/src/extensions/{markdown → language/markdown}/decorate.ts +96 -85
- package/src/extensions/{markdown → language/markdown}/formatting.test.ts +88 -1
- package/src/extensions/{markdown → language/markdown}/formatting.ts +193 -74
- package/src/extensions/{markdown → language/markdown}/highlight.ts +42 -41
- package/src/extensions/{markdown → language/markdown}/image.test.ts +1 -1
- package/src/extensions/{markdown → language/markdown}/image.ts +6 -6
- package/src/extensions/language/markdown/link.test.ts +58 -0
- package/src/extensions/language/markdown/link.ts +109 -0
- package/src/extensions/{markdown → language/markdown}/parser.test.ts +0 -28
- package/src/extensions/{markdown → language/markdown}/styles.ts +38 -7
- package/src/extensions/{markdown → language/markdown}/table.ts +5 -5
- package/src/extensions/language/mermaid/index.ts +5 -0
- package/src/extensions/language/mermaid/mermaid.ts +44 -0
- package/src/extensions/{tags → language/xml}/DESIGN.md +3 -3
- package/src/extensions/{tags → language/xml}/extended-markdown.test.ts +2 -1
- package/src/extensions/{tags → language/xml}/extended-markdown.ts +2 -4
- package/src/extensions/language/xml/stub.ts +233 -0
- package/src/extensions/language/xml/xml-block-decoration.ts +165 -0
- package/src/extensions/{tags → language/xml}/xml-formatting.ts +54 -38
- package/src/extensions/language/xml/xml-tags.test.ts +588 -0
- package/src/extensions/{tags → language/xml}/xml-tags.ts +165 -66
- package/src/extensions/{tags → language/xml}/xml-util.test.ts +2 -2
- package/src/extensions/review/change-bar.ts +94 -0
- package/src/extensions/review/comments.test.ts +72 -0
- package/src/extensions/{comments.ts → review/comments.ts} +395 -267
- package/src/extensions/review/diff.test.ts +405 -0
- package/src/extensions/review/diff.ts +502 -0
- package/src/extensions/review/index.ts +10 -0
- package/src/extensions/review/suggest.test.ts +170 -0
- package/src/extensions/review/suggest.ts +512 -0
- package/src/extensions/review/suggestions-overlay.test.ts +58 -0
- package/src/extensions/review/suggestions-overlay.ts +50 -0
- package/src/extensions/review/track-changes.test.ts +101 -0
- package/src/extensions/review/track-changes.ts +215 -0
- package/src/extensions/{busy.ts → state/busy.ts} +1 -0
- package/src/extensions/{focus.ts → state/focus.ts} +4 -0
- package/src/extensions/state/index.ts +8 -0
- package/src/extensions/{selection.ts → state/selection.ts} +3 -3
- package/src/extensions/streaming/index.ts +7 -0
- package/src/extensions/{pending → streaming/pending}/pending-text-stream.ts +10 -3
- package/src/extensions/{pending → streaming/pending}/pending-text.test.ts +1 -1
- package/src/extensions/{pending → streaming/pending}/pending-text.ts +20 -19
- package/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.ts +9 -6
- package/src/extensions/{scrolling → streaming/scrolling}/scroll-past-end.ts +1 -0
- package/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.ts +13 -11
- package/src/extensions/{typewriter.ts → streaming/typewriter.ts} +46 -47
- package/src/extensions/structure/blocks/DESIGN.md +134 -0
- package/src/extensions/structure/blocks/blocks.test.ts +147 -0
- package/src/extensions/structure/blocks/blocks.ts +219 -0
- package/src/extensions/structure/blocks/drag.ts +996 -0
- package/src/extensions/structure/blocks/index.ts +8 -0
- package/src/extensions/structure/blocks/selection.test.ts +56 -0
- package/src/extensions/structure/blocks/selection.ts +279 -0
- package/src/extensions/structure/blocks/types.ts +22 -0
- package/src/extensions/{folding.ts → structure/folding/folding.ts} +12 -10
- package/src/extensions/structure/folding/index.ts +6 -0
- package/src/extensions/structure/folding/turns.test.ts +72 -0
- package/src/extensions/structure/folding/turns.ts +209 -0
- package/src/extensions/structure/index.ts +7 -0
- package/src/extensions/structure/outliner/DESIGN.md +183 -0
- package/src/extensions/structure/outliner/SPEC.mdl +305 -0
- package/src/extensions/{outliner → structure/outliner}/commands.ts +125 -42
- package/src/extensions/structure/outliner/dnd.test.ts +142 -0
- package/src/extensions/structure/outliner/dnd.ts +375 -0
- package/src/extensions/structure/outliner/editor.test.ts +85 -0
- package/src/extensions/{outliner → structure/outliner}/editor.ts +14 -9
- package/src/extensions/{outliner → structure/outliner}/index.ts +1 -0
- package/src/extensions/{outliner → structure/outliner}/menu.ts +48 -25
- package/src/extensions/structure/outliner/outliner.test.ts +193 -0
- package/src/extensions/structure/outliner/outliner.ts +183 -0
- package/src/extensions/{outliner → structure/outliner}/tree.test.ts +2 -2
- package/src/extensions/{outliner → structure/outliner}/tree.ts +1 -1
- package/src/headless.ts +13 -0
- package/src/styles/theme.ts +3 -1
- package/src/util/util.ts +3 -0
- package/dist/lib/browser/index.mjs +0 -9594
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/types/index.mjs +0 -33
- package/dist/lib/browser/types/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -9596
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/types/index.mjs +0 -35
- package/dist/lib/node-esm/types/index.mjs.map +0 -7
- package/dist/types/src/extensions/annotations.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete/index.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete/match.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/defs.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/index.d.ts +0 -2
- package/dist/types/src/extensions/automerge/index.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/sync.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
- package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
- package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
- package/dist/types/src/extensions/blast.d.ts.map +0 -1
- package/dist/types/src/extensions/blocks.d.ts +0 -2
- package/dist/types/src/extensions/blocks.d.ts.map +0 -1
- package/dist/types/src/extensions/bookmarks.d.ts.map +0 -1
- package/dist/types/src/extensions/busy.d.ts.map +0 -1
- package/dist/types/src/extensions/comments.d.ts.map +0 -1
- package/dist/types/src/extensions/debug.d.ts.map +0 -1
- package/dist/types/src/extensions/dnd.d.ts.map +0 -1
- package/dist/types/src/extensions/factories.d.ts.map +0 -1
- package/dist/types/src/extensions/factories.test.d.ts.map +0 -1
- package/dist/types/src/extensions/fader.d.ts.map +0 -1
- package/dist/types/src/extensions/focus.d.ts.map +0 -1
- package/dist/types/src/extensions/folding.d.ts.map +0 -1
- package/dist/types/src/extensions/hashtag.d.ts +0 -3
- package/dist/types/src/extensions/hashtag.d.ts.map +0 -1
- package/dist/types/src/extensions/json.d.ts +0 -7
- package/dist/types/src/extensions/json.d.ts.map +0 -1
- package/dist/types/src/extensions/listener.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/changes.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/changes.test.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/debug.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/image.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/image.test.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/index.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/link.d.ts +0 -7
- package/dist/types/src/extensions/markdown/link.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/parser.test.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/styles.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/table.d.ts.map +0 -1
- package/dist/types/src/extensions/marker.d.ts.map +0 -1
- package/dist/types/src/extensions/mention.d.ts.map +0 -1
- package/dist/types/src/extensions/modal.d.ts.map +0 -1
- package/dist/types/src/extensions/modes.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/commands.d.ts +0 -10
- package/dist/types/src/extensions/outliner/commands.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/editor.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/editor.test.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/index.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/menu.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/outliner.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/selection.d.ts +0 -12
- package/dist/types/src/extensions/outliner/selection.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/tree.d.ts.map +0 -1
- package/dist/types/src/extensions/outliner/tree.test.d.ts.map +0 -1
- package/dist/types/src/extensions/pending/index.d.ts.map +0 -1
- package/dist/types/src/extensions/pending/pending-text-stream.d.ts.map +0 -1
- package/dist/types/src/extensions/pending/pending-text-stream.test.d.ts.map +0 -1
- package/dist/types/src/extensions/pending/pending-text.d.ts.map +0 -1
- package/dist/types/src/extensions/pending/pending-text.test.d.ts.map +0 -1
- package/dist/types/src/extensions/pos.d.ts.map +0 -1
- package/dist/types/src/extensions/pos.test.d.ts.map +0 -1
- package/dist/types/src/extensions/replacer.d.ts.map +0 -1
- package/dist/types/src/extensions/replacer.test.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/crawler.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/index.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts +0 -3
- package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/scrollbar-autohide.d.ts.map +0 -1
- package/dist/types/src/extensions/scrolling/scroller.d.ts.map +0 -1
- package/dist/types/src/extensions/selection.d.ts.map +0 -1
- package/dist/types/src/extensions/selection.test.d.ts.map +0 -1
- package/dist/types/src/extensions/snippets.d.ts.map +0 -1
- package/dist/types/src/extensions/spacing.d.ts.map +0 -1
- package/dist/types/src/extensions/state.d.ts +0 -2
- package/dist/types/src/extensions/state.d.ts.map +0 -1
- package/dist/types/src/extensions/submit.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/index.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/stub.d.ts +0 -35
- package/dist/types/src/extensions/tags/stub.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/widgets/anchor.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/widgets/index.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +0 -31
- package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/xml-tags.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/xml-util.d.ts.map +0 -1
- package/dist/types/src/extensions/tags/xml-util.test.d.ts.map +0 -1
- package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
- package/dist/types/src/extensions/typewriter.test.d.ts.map +0 -1
- package/src/extensions/autocomplete/typeahead.ts +0 -87
- package/src/extensions/blocks.ts +0 -131
- package/src/extensions/markdown/link.ts +0 -49
- package/src/extensions/outliner/editor.test.ts +0 -33
- package/src/extensions/outliner/outliner.test.ts +0 -99
- package/src/extensions/outliner/outliner.ts +0 -166
- package/src/extensions/outliner/selection.ts +0 -50
- package/src/extensions/state.ts +0 -7
- package/src/extensions/tags/stub.ts +0 -80
- package/src/extensions/tags/xml-block-decoration.ts +0 -123
- package/dist/types/src/extensions/{dnd.d.ts → behavior/dnd.d.ts} +0 -0
- package/dist/types/src/extensions/{submit.d.ts → behavior/submit.d.ts} +0 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.d.ts +0 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.test.d.ts +0 -0
- package/dist/types/src/extensions/{automerge → collab/automerge}/sync.d.ts +0 -0
- package/dist/types/src/extensions/{awareness → collab/awareness}/awareness-provider.d.ts +0 -0
- package/dist/types/src/extensions/{awareness → collab/awareness}/index.d.ts +0 -0
- package/dist/types/src/extensions/{autocomplete → completion}/autocomplete.d.ts +0 -0
- package/dist/types/src/extensions/{autocomplete → completion}/placeholder.d.ts +0 -0
- package/dist/types/src/extensions/{factories.test.d.ts → core/factories.test.d.ts} +0 -0
- package/dist/types/src/extensions/{fader.d.ts → decoration/fader.d.ts} +0 -0
- package/dist/types/src/extensions/{marker.d.ts → decoration/marker.d.ts} +0 -0
- package/dist/types/src/extensions/{pos.test.d.ts → decoration/pos.test.d.ts} +0 -0
- package/dist/types/src/extensions/{replacer.test.d.ts → decoration/replacer.test.d.ts} +0 -0
- package/dist/types/src/extensions/{snippets.d.ts → demo/snippets.d.ts} +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/action.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/bundle.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/changes.test.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/formatting.test.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/image.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/image.test.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/index.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/parser.test.d.ts +0 -0
- package/dist/types/src/extensions/{markdown → language/markdown}/table.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.test.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/index.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/widgets/anchor.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/widgets/index.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/xml-formatting.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/xml-util.d.ts +0 -0
- package/dist/types/src/extensions/{tags → language/xml}/xml-util.test.d.ts +0 -0
- package/dist/types/src/extensions/{modal.d.ts → state/modal.d.ts} +0 -0
- package/dist/types/src/extensions/{selection.test.d.ts → state/selection.test.d.ts} +0 -0
- package/dist/types/src/extensions/{pending → streaming/pending}/index.d.ts +0 -0
- package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.d.ts +0 -0
- package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.test.d.ts +0 -0
- package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.test.d.ts +0 -0
- package/dist/types/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.d.ts +0 -0
- package/dist/types/src/extensions/{scrolling → streaming/scrolling}/crawler.d.ts +0 -0
- package/dist/types/src/extensions/{scrolling → streaming/scrolling}/index.d.ts +0 -0
- package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.d.ts +0 -0
- package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scroller.d.ts +0 -0
- package/dist/types/src/extensions/{typewriter.test.d.ts → streaming/typewriter.test.d.ts} +0 -0
- package/dist/types/src/extensions/{folding.d.ts → structure/folding/folding.d.ts} +0 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/editor.d.ts +0 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/editor.test.d.ts +0 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.d.ts +0 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.test.d.ts +0 -0
- package/dist/types/src/extensions/{outliner → structure/outliner}/tree.test.d.ts +0 -0
- package/src/extensions/{dnd.ts → behavior/dnd.ts} +29 -29
- package/src/extensions/{awareness → collab/awareness}/index.ts +0 -0
- package/src/extensions/{factories.test.ts → core/factories.test.ts} +0 -0
- package/src/extensions/{replacer.test.ts → decoration/replacer.test.ts} +0 -0
- package/src/extensions/{replacer.ts → decoration/replacer.ts} +25 -25
- /package/src/extensions/{markdown → language/markdown}/index.ts +0 -0
- /package/src/extensions/{tags → language/xml}/index.ts +0 -0
- /package/src/extensions/{tags → language/xml}/testing/text.md +0 -0
- /package/src/extensions/{tags → language/xml}/testing/text.txt +0 -0
- /package/src/extensions/{tags → language/xml}/widgets/anchor.ts +0 -0
- /package/src/extensions/{tags → language/xml}/widgets/index.ts +0 -0
- /package/src/extensions/{tags → language/xml}/xml-util.ts +0 -0
- /package/src/extensions/{modal.ts → state/modal.ts} +0 -0
- /package/src/extensions/{selection.test.ts → state/selection.test.ts} +0 -0
- /package/src/extensions/{pending → streaming/pending}/index.ts +0 -0
- /package/src/extensions/{pending → streaming/pending}/pending-text-stream.test.ts +0 -0
- /package/src/extensions/{scrolling → streaming/scrolling}/crawler.ts +0 -0
- /package/src/extensions/{scrolling → streaming/scrolling}/index.ts +0 -0
- /package/src/extensions/{scrolling → streaming/scrolling}/scroller.ts +0 -0
- /package/src/extensions/{typewriter.test.ts → streaming/typewriter.test.ts} +0 -0
|
@@ -3,16 +3,24 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { invertedEffects } from '@codemirror/commands';
|
|
6
|
-
import {
|
|
6
|
+
import { getChunks } from '@codemirror/merge';
|
|
7
|
+
import {
|
|
8
|
+
type ChangeDesc,
|
|
9
|
+
EditorSelection,
|
|
10
|
+
type Extension,
|
|
11
|
+
StateEffect,
|
|
12
|
+
StateField,
|
|
13
|
+
type Text,
|
|
14
|
+
} from '@codemirror/state';
|
|
7
15
|
import {
|
|
8
16
|
type Command,
|
|
9
17
|
Decoration,
|
|
10
18
|
EditorView,
|
|
11
|
-
type PluginValue,
|
|
12
19
|
type Rect,
|
|
20
|
+
RectangleMarker,
|
|
13
21
|
ViewPlugin,
|
|
14
|
-
hoverTooltip,
|
|
15
22
|
keymap,
|
|
23
|
+
layer,
|
|
16
24
|
} from '@codemirror/view';
|
|
17
25
|
import sortBy from 'lodash.sortby';
|
|
18
26
|
|
|
@@ -20,10 +28,219 @@ import { type CleanupFn, debounce } from '@dxos/async';
|
|
|
20
28
|
import { log } from '@dxos/log';
|
|
21
29
|
import { isNonNullable } from '@dxos/util';
|
|
22
30
|
|
|
23
|
-
import { type Comment, type Range
|
|
24
|
-
import { Cursor, singleValueFacet, wrapWithCatch } from '
|
|
25
|
-
import {
|
|
26
|
-
|
|
31
|
+
import { type Comment, type Range } from '../../types';
|
|
32
|
+
import { Cursor, singleValueFacet, wrapWithCatch } from '../../util';
|
|
33
|
+
import { documentId } from '../state/selection';
|
|
34
|
+
|
|
35
|
+
//
|
|
36
|
+
// Options
|
|
37
|
+
//
|
|
38
|
+
|
|
39
|
+
export type CommentsOptions = {
|
|
40
|
+
/**
|
|
41
|
+
* Document id.
|
|
42
|
+
*/
|
|
43
|
+
id: string;
|
|
44
|
+
/**
|
|
45
|
+
* Key shortcut to create a new thread.
|
|
46
|
+
*/
|
|
47
|
+
key?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Get the current comments.
|
|
50
|
+
*/
|
|
51
|
+
getComments?: () => Comment[];
|
|
52
|
+
/**
|
|
53
|
+
* Subscribe to external comment updates.
|
|
54
|
+
*/
|
|
55
|
+
subscribe?: (sink: () => void) => CleanupFn;
|
|
56
|
+
/**
|
|
57
|
+
* The branch under review; new comments are tagged with it (undefined = main/unbranched). Scopes
|
|
58
|
+
* a comment to the branch being reviewed so its visibility tracks the active diff.
|
|
59
|
+
*/
|
|
60
|
+
reviewBranch?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Prohibit creating new comments (e.g. on a per-user suggestion branch). Existing comments still
|
|
63
|
+
* render; the create command becomes a no-op.
|
|
64
|
+
*/
|
|
65
|
+
readonly?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Called to create a new thread and return the thread id.
|
|
68
|
+
*/
|
|
69
|
+
onCreate?: (params: { cursor: string; from: number; location?: Rect | null; branch?: string }) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Selection cut/deleted.
|
|
72
|
+
*/
|
|
73
|
+
onDelete?: (params: { id: string }) => void;
|
|
74
|
+
/**
|
|
75
|
+
* Called when a comment is moved.
|
|
76
|
+
*/
|
|
77
|
+
onUpdate?: (params: { id: string; cursor: string }) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Called to notify which thread is currently closest to the cursor.
|
|
80
|
+
*/
|
|
81
|
+
onSelect?: (state: CommentsState) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Called when a comment is deliberately activated (clicked). Distinct from `onSelect` (passive
|
|
84
|
+
* cursor-proximity): a click is an explicit user intent, e.g. to reveal the thread in a companion.
|
|
85
|
+
* The editor-side selection/highlight is already applied by the time this fires.
|
|
86
|
+
*/
|
|
87
|
+
onActivate?: (id: string) => void;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Comment threads.
|
|
92
|
+
* 1). Updates the EditorModel to store relative selections for a set of comments threads.
|
|
93
|
+
* Since the selections are relative, they do not need to be updated when the document is edited.
|
|
94
|
+
* 2). Implements a StateField to track absolute selections corresponding to the comments (i.e., when the document is edited).
|
|
95
|
+
* 3). Creates decoration marks to apply classes to each selection.
|
|
96
|
+
* 4). Tracks the current cursor position to:
|
|
97
|
+
* a). Update the decoration to show if the cursor is within a current selection.
|
|
98
|
+
* b). Calls a handler to indicate which is the closest selection (e.g., to update the thread sidebar).
|
|
99
|
+
* 5). Optionally, implements a hoverTooltip to show hints when creating a selection range.
|
|
100
|
+
*/
|
|
101
|
+
export const comments = (options: CommentsOptions): Extension => {
|
|
102
|
+
const { key: shortcut = "meta-'" } = options;
|
|
103
|
+
|
|
104
|
+
const handleSelect = debounce((state: CommentsState) => options.onSelect?.(state), 200);
|
|
105
|
+
|
|
106
|
+
return [
|
|
107
|
+
optionsFacet.of(options),
|
|
108
|
+
options.id ? documentId.of(options.id) : undefined,
|
|
109
|
+
commentsState,
|
|
110
|
+
commentsDecorations,
|
|
111
|
+
commentsHighlightLayer,
|
|
112
|
+
handleCommentClick,
|
|
113
|
+
styles,
|
|
114
|
+
|
|
115
|
+
//
|
|
116
|
+
// External comment synchronization.
|
|
117
|
+
//
|
|
118
|
+
ViewPlugin.fromClass(
|
|
119
|
+
class {
|
|
120
|
+
private readonly unsubscribe: () => void;
|
|
121
|
+
constructor(view: EditorView) {
|
|
122
|
+
const { id } = options;
|
|
123
|
+
const updateComments = () => {
|
|
124
|
+
const comments = options.getComments?.() ?? [];
|
|
125
|
+
// Local `id` const so the truthiness narrowing survives into the microtask closure.
|
|
126
|
+
if (id && id === view.state.facet(documentId)) {
|
|
127
|
+
queueMicrotask(() => view.dispatch({ effects: setComments.of({ id, comments }) }));
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
this.unsubscribe = options.subscribe?.(updateComments) ?? (() => {});
|
|
132
|
+
// Prime the initial decoration pass: `subscribe` may not emit for an already-resolved source
|
|
133
|
+
// (e.g. an ECHO query whose results resolved before mount), so read once now that the source is
|
|
134
|
+
// subscribed. Owning this here means adapters never have to prime manually.
|
|
135
|
+
updateComments();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
destroy = () => {
|
|
139
|
+
this.unsubscribe();
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
),
|
|
143
|
+
|
|
144
|
+
//
|
|
145
|
+
// Keymap.
|
|
146
|
+
//
|
|
147
|
+
options.onCreate &&
|
|
148
|
+
keymap.of([
|
|
149
|
+
{
|
|
150
|
+
key: shortcut,
|
|
151
|
+
run: wrapWithCatch(createComment),
|
|
152
|
+
},
|
|
153
|
+
]),
|
|
154
|
+
|
|
155
|
+
//
|
|
156
|
+
// Track deleted ranges and update ranges for decorations.
|
|
157
|
+
//
|
|
158
|
+
EditorView.updateListener.of(({ view, state, changes }) => {
|
|
159
|
+
let mod = false;
|
|
160
|
+
const { comments, ...value } = state.field(commentsState);
|
|
161
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
162
|
+
comments.forEach(({ comment, range }) => {
|
|
163
|
+
// Only comments with a cursor reach this state (setComments filters cursor-less ones).
|
|
164
|
+
if (!comment.cursor) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Test if range deleted.
|
|
169
|
+
if (from2 === to2) {
|
|
170
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
171
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
172
|
+
options.onDelete?.({ id: comment.id });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Update range.
|
|
177
|
+
if (from <= range.to) {
|
|
178
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
179
|
+
Object.assign(range, newRange);
|
|
180
|
+
mod = true;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (mod) {
|
|
186
|
+
view.dispatch({ effects: setCommentState.of({ comments, ...value }) });
|
|
187
|
+
}
|
|
188
|
+
}),
|
|
189
|
+
|
|
190
|
+
//
|
|
191
|
+
// Track selection/proximity.
|
|
192
|
+
//
|
|
193
|
+
EditorView.updateListener.of(({ view, state, transactions }) => {
|
|
194
|
+
let min = Infinity;
|
|
195
|
+
const { selection: applied, comments } = state.field(commentsState);
|
|
196
|
+
const { current, closest } = applied;
|
|
197
|
+
|
|
198
|
+
const notify = (selection: SelectionState) =>
|
|
199
|
+
handleSelect({
|
|
200
|
+
selection,
|
|
201
|
+
id: state.facet(documentId),
|
|
202
|
+
comments: comments.map(({ comment, range }) => ({
|
|
203
|
+
comment,
|
|
204
|
+
range,
|
|
205
|
+
location: view.coordsAtPos(range.from),
|
|
206
|
+
})),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// An explicit `setSelection` is authoritative: selecting a thread in the comments companion sets
|
|
210
|
+
// `current` and moves the caret in one transaction, and the caret does not always land inside the
|
|
211
|
+
// tracked range — proximity would then clear the very selection that transaction just made. Report
|
|
212
|
+
// the applied selection so the app still learns which thread is current, but leave it as set.
|
|
213
|
+
if (transactions.some((tr) => tr.effects.some((effect) => effect.is(setSelection)))) {
|
|
214
|
+
notify(applied);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const { head } = state.selection.main;
|
|
219
|
+
const selection: SelectionState = {};
|
|
220
|
+
comments.forEach(({ comment, range }) => {
|
|
221
|
+
if (head >= range.from && head <= range.to) {
|
|
222
|
+
selection.current = comment.id;
|
|
223
|
+
selection.closest = undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!selection.current) {
|
|
227
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
228
|
+
if (d < min) {
|
|
229
|
+
selection.closest = comment.id;
|
|
230
|
+
min = d;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
236
|
+
view.dispatch({ effects: setSelection.of(selection) });
|
|
237
|
+
notify(selection);
|
|
238
|
+
}
|
|
239
|
+
}),
|
|
240
|
+
|
|
241
|
+
options.onUpdate && trackPastedComments(options.onUpdate),
|
|
242
|
+
].filter(isNonNullable);
|
|
243
|
+
};
|
|
27
244
|
|
|
28
245
|
//
|
|
29
246
|
// State management.
|
|
@@ -55,6 +272,7 @@ const setCommentState = StateEffect.define<CommentsState>();
|
|
|
55
272
|
/**
|
|
56
273
|
* State field (reducer) that tracks comment ranges.
|
|
57
274
|
* The ranges are tracked as Automerge cursors from which the absolute indexed ranges can be computed.
|
|
275
|
+
* Included by {@link comments}; exported for direct state reads.
|
|
58
276
|
*/
|
|
59
277
|
export const commentsState = StateField.define<CommentsState>({
|
|
60
278
|
create: (state) => ({
|
|
@@ -97,19 +315,8 @@ export const commentsState = StateField.define<CommentsState>({
|
|
|
97
315
|
},
|
|
98
316
|
});
|
|
99
317
|
|
|
100
|
-
/**
|
|
101
|
-
* NOTE: Matches search.
|
|
102
|
-
*/
|
|
103
|
-
// Surface/box-shadow come from the shared `markerTheme`, tinted by the mark's `data-hue`; the comment
|
|
104
|
-
// just adds the pointer affordance.
|
|
105
|
-
const styles = EditorView.theme({
|
|
106
|
-
'.cm-comment > span': {
|
|
107
|
-
cursor: 'pointer',
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
318
|
const createCommentMark = (id: string, isCurrent: boolean) =>
|
|
112
|
-
|
|
319
|
+
Decoration.mark({
|
|
113
320
|
class: 'cm-comment',
|
|
114
321
|
attributes: {
|
|
115
322
|
'data-testid': 'cm-comment',
|
|
@@ -119,7 +326,8 @@ const createCommentMark = (id: string, isCurrent: boolean) =>
|
|
|
119
326
|
});
|
|
120
327
|
|
|
121
328
|
/**
|
|
122
|
-
*
|
|
329
|
+
* Transparent inline marks that carry `data-comment-id` for click routing (see `handleCommentClick`).
|
|
330
|
+
* The colour comes from `commentsHighlightLayer`.
|
|
123
331
|
*/
|
|
124
332
|
const commentsDecorations = EditorView.decorations.compute([commentsState], (state) => {
|
|
125
333
|
const {
|
|
@@ -146,32 +354,87 @@ const commentsDecorations = EditorView.decorations.compute([commentsState], (sta
|
|
|
146
354
|
return Decoration.set(decorations);
|
|
147
355
|
});
|
|
148
356
|
|
|
149
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Selection-style highlight: draws each comment range as a layer of rectangle markers below the text.
|
|
359
|
+
* `RectangleMarker.forRange` extends wrapped (non-final) lines to the line edge, so a multi-line comment
|
|
360
|
+
* reads as one continuous block rather than ragged per-word inline backgrounds.
|
|
361
|
+
*/
|
|
362
|
+
const commentsHighlightLayer = layer({
|
|
363
|
+
above: false,
|
|
364
|
+
class: 'cm-commentsHighlightLayer',
|
|
365
|
+
update: (update) =>
|
|
366
|
+
update.docChanged ||
|
|
367
|
+
update.viewportChanged ||
|
|
368
|
+
update.geometryChanged ||
|
|
369
|
+
update.selectionSet ||
|
|
370
|
+
update.transactions.some((tr) =>
|
|
371
|
+
tr.effects.some((effect) => effect.is(setSelection) || effect.is(setComments) || effect.is(setCommentState)),
|
|
372
|
+
),
|
|
373
|
+
markers: (view) => {
|
|
374
|
+
const {
|
|
375
|
+
selection: { current },
|
|
376
|
+
comments,
|
|
377
|
+
} = view.state.field(commentsState);
|
|
378
|
+
|
|
379
|
+
return sortBy(comments ?? [], (comment) => comment.range.from).flatMap((comment) => {
|
|
380
|
+
const { from, to } = comment.range;
|
|
381
|
+
if (from >= to) {
|
|
382
|
+
return [];
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const className =
|
|
386
|
+
comment.comment.id === current ? 'cm-comment-highlight cm-comment-highlight-current' : 'cm-comment-highlight';
|
|
387
|
+
const range = EditorSelection.range(from, to);
|
|
388
|
+
const markers = RectangleMarker.forRange(view, className, range);
|
|
389
|
+
// A single rectangle means the comment fits on one visual line — round its corners.
|
|
390
|
+
return markers.length === 1
|
|
391
|
+
? RectangleMarker.forRange(view, `${className} cm-comment-highlight-single`, range)
|
|
392
|
+
: markers;
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
});
|
|
150
396
|
|
|
151
397
|
const handleCommentClick = EditorView.domEventHandlers({
|
|
152
398
|
click: (event, view) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
// Traverse up the DOM tree looking for an element with data-comment-id
|
|
157
|
-
// Stop if we reach the editor root or find the comment id
|
|
158
|
-
while (target && target !== editorRoot && !target.hasAttribute('data-comment-id')) {
|
|
159
|
-
target = target.parentElement as HTMLElement;
|
|
399
|
+
const id = commentIdAtClick(event, view);
|
|
400
|
+
if (!id) {
|
|
401
|
+
return false;
|
|
160
402
|
}
|
|
161
403
|
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return false;
|
|
404
|
+
// Select the clicked thread in the editor (moves the caret into the range so the proximity tracker
|
|
405
|
+
// keeps it current) and notify the app for deliberate-click behaviour (e.g. reveal in a companion).
|
|
406
|
+
scrollCommentIntoView(view, id);
|
|
407
|
+
view.state.facet(optionsFacet).onActivate?.(id);
|
|
408
|
+
return true;
|
|
172
409
|
},
|
|
173
410
|
});
|
|
174
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Resolve the comment id under a click. Prefers the DOM target (a direct hit on the `.cm-comment`
|
|
414
|
+
* span), then falls back to a document-position hit-test: the highlight-layer rectangles
|
|
415
|
+
* (pointer-events: none) sit over the text, so a click often lands on the `.cm-line` (an ancestor of
|
|
416
|
+
* the span) and an upward target walk would miss it.
|
|
417
|
+
*/
|
|
418
|
+
const commentIdAtClick = (event: MouseEvent, view: EditorView): string | undefined => {
|
|
419
|
+
let target = event.target as HTMLElement | null;
|
|
420
|
+
const editorRoot = view.dom;
|
|
421
|
+
while (target && target !== editorRoot && !target.hasAttribute?.('data-comment-id')) {
|
|
422
|
+
target = target.parentElement;
|
|
423
|
+
}
|
|
424
|
+
const domId = target && target !== editorRoot ? target.getAttribute('data-comment-id') : null;
|
|
425
|
+
if (domId) {
|
|
426
|
+
return domId;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
|
430
|
+
if (pos != null) {
|
|
431
|
+
const commentState = view.state.field(commentsState, false);
|
|
432
|
+
return commentState?.comments.find(({ range }) => pos >= range.from && pos <= range.to)?.comment.id;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return undefined;
|
|
436
|
+
};
|
|
437
|
+
|
|
175
438
|
//
|
|
176
439
|
// Cut-and-paste.
|
|
177
440
|
//
|
|
@@ -290,218 +553,65 @@ const mapTrackedComment = (comment: TrackedComment, changes: ChangeDesc) => ({
|
|
|
290
553
|
* These are attached to undone/redone transactions in the editor for the purpose of restoring comments
|
|
291
554
|
* that were deleted by the original changes.
|
|
292
555
|
*/
|
|
293
|
-
const restoreCommentEffect = StateEffect.define<TrackedComment>({
|
|
556
|
+
const restoreCommentEffect = StateEffect.define<TrackedComment>({
|
|
557
|
+
map: mapTrackedComment,
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const optionsFacet = singleValueFacet<CommentsOptions>();
|
|
294
561
|
|
|
295
562
|
/**
|
|
296
563
|
* Create comment thread action.
|
|
297
564
|
*/
|
|
298
565
|
export const createComment: Command = (view) => {
|
|
299
566
|
const options = view.state.facet(optionsFacet);
|
|
300
|
-
|
|
301
|
-
if (
|
|
567
|
+
// Comment creation is prohibited on this surface (e.g. a suggestion branch).
|
|
568
|
+
if (options.readonly) {
|
|
302
569
|
return false;
|
|
303
570
|
}
|
|
304
571
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
572
|
+
let { from, to } = view.state.selection.main;
|
|
573
|
+
|
|
574
|
+
// Snap to the largest logical region so commenting never depends on a precise selection. Inside a
|
|
575
|
+
// (unified) diff hunk the comment covers the whole changed hunk (a bare cursor in the hunk is
|
|
576
|
+
// enough); otherwise, with no selection, it expands to the word under the cursor. The diff case
|
|
577
|
+
// takes precedence so a comment on a change visibly covers it.
|
|
578
|
+
const merge = getChunks(view.state);
|
|
579
|
+
const chunk = merge?.chunks.find((candidate) => candidate.fromB <= to && candidate.endB >= from);
|
|
580
|
+
if (chunk) {
|
|
581
|
+
from = chunk.fromB;
|
|
582
|
+
to = Math.min(chunk.endB, view.state.doc.length);
|
|
583
|
+
} else if (from === to) {
|
|
584
|
+
const word = view.state.wordAt(from);
|
|
585
|
+
if (word) {
|
|
586
|
+
from = word.from;
|
|
587
|
+
to = word.to;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Exclude trailing newlines so the anchor stays within content and never reaches the document end.
|
|
592
|
+
// Anchoring at the very end previously required inserting a newline to stabilise the end cursor — a
|
|
593
|
+
// visible, unwanted mutation; the end cursor instead associates with the preceding character.
|
|
594
|
+
while (to > from && view.state.doc.sliceString(to - 1, to) === '\n') {
|
|
595
|
+
to--;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (from === to) {
|
|
599
|
+
return false;
|
|
313
600
|
}
|
|
314
601
|
|
|
315
602
|
const cursor = Cursor.getCursorFromRange(view.state, { from, to });
|
|
316
603
|
if (cursor) {
|
|
317
|
-
//
|
|
318
|
-
|
|
604
|
+
// Collapse the text selection now that the range is captured by the comment (the caret stays within
|
|
605
|
+
// the new comment, keeping it the current thread).
|
|
606
|
+
view.dispatch({ selection: { anchor: from } });
|
|
607
|
+
// Create thread via callback; branch-tag it with the branch under review (undefined = main).
|
|
608
|
+
options.onCreate?.({ cursor, from, location: view.coordsAtPos(from), branch: options.reviewBranch });
|
|
319
609
|
return true;
|
|
320
610
|
}
|
|
321
611
|
|
|
322
612
|
return false;
|
|
323
613
|
};
|
|
324
614
|
|
|
325
|
-
//
|
|
326
|
-
// Options
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
export type CommentsOptions = {
|
|
330
|
-
/**
|
|
331
|
-
* Document id.
|
|
332
|
-
*/
|
|
333
|
-
id?: string;
|
|
334
|
-
/**
|
|
335
|
-
* Key shortcut to create a new thread.
|
|
336
|
-
*/
|
|
337
|
-
key?: string;
|
|
338
|
-
/**
|
|
339
|
-
* Called to render tooltip.
|
|
340
|
-
*/
|
|
341
|
-
renderTooltip?: RenderCallback<{ shortcut: string }>;
|
|
342
|
-
/**
|
|
343
|
-
* Called to create a new thread and return the thread id.
|
|
344
|
-
*/
|
|
345
|
-
onCreate?: (params: { cursor: string; from: number; location?: Rect | null }) => void;
|
|
346
|
-
/**
|
|
347
|
-
* Selection cut/deleted.
|
|
348
|
-
*/
|
|
349
|
-
onDelete?: (params: { id: string }) => void;
|
|
350
|
-
/**
|
|
351
|
-
* Called when a comment is moved.
|
|
352
|
-
*/
|
|
353
|
-
onUpdate?: (params: { id: string; cursor: string }) => void;
|
|
354
|
-
/**
|
|
355
|
-
* Called to notify which thread is currently closest to the cursor.
|
|
356
|
-
*/
|
|
357
|
-
onSelect?: (state: CommentsState) => void;
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
const optionsFacet = singleValueFacet<CommentsOptions>();
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Comment threads.
|
|
364
|
-
* 1). Updates the EditorModel to store relative selections for a set of comments threads.
|
|
365
|
-
* Since the selections are relative, they do not need to be updated when the document is edited.
|
|
366
|
-
* 2). Implements a StateField to track absolute selections corresponding to the comments (i.e., when the document is edited).
|
|
367
|
-
* 3). Creates decoration marks to apply classes to each selection.
|
|
368
|
-
* 4). Tracks the current cursor position to:
|
|
369
|
-
* a). Update the decoration to show if the cursor is within a current selection.
|
|
370
|
-
* b). Calls a handler to indicate which is the closest selection (e.g., to update the thread sidebar).
|
|
371
|
-
* 5). Optionally, implements a hoverTooltip to show hints when creating a selection range.
|
|
372
|
-
*/
|
|
373
|
-
export const comments = (options: CommentsOptions = {}): Extension => {
|
|
374
|
-
const { key: shortcut = "meta-'" } = options;
|
|
375
|
-
|
|
376
|
-
const handleSelect = debounce((state: CommentsState) => options.onSelect?.(state), 200);
|
|
377
|
-
|
|
378
|
-
return [
|
|
379
|
-
optionsFacet.of(options),
|
|
380
|
-
options.id ? documentId.of(options.id) : undefined,
|
|
381
|
-
commentsState,
|
|
382
|
-
commentsDecorations,
|
|
383
|
-
handleCommentClick,
|
|
384
|
-
markerTheme(),
|
|
385
|
-
styles,
|
|
386
|
-
|
|
387
|
-
//
|
|
388
|
-
// Keymap.
|
|
389
|
-
//
|
|
390
|
-
options.onCreate &&
|
|
391
|
-
keymap.of([
|
|
392
|
-
{
|
|
393
|
-
key: shortcut,
|
|
394
|
-
run: wrapWithCatch(createComment),
|
|
395
|
-
},
|
|
396
|
-
]),
|
|
397
|
-
|
|
398
|
-
//
|
|
399
|
-
// Hover tooltip (for key shortcut hints, etc.)
|
|
400
|
-
// TODO(burdon): Factor out to generic hints extension for current selection/line.
|
|
401
|
-
//
|
|
402
|
-
options.renderTooltip &&
|
|
403
|
-
hoverTooltip(
|
|
404
|
-
(view, pos) => {
|
|
405
|
-
const selection = view.state.selection.main;
|
|
406
|
-
if (selection && pos >= selection.from && pos <= selection.to) {
|
|
407
|
-
return {
|
|
408
|
-
pos: selection.from,
|
|
409
|
-
end: selection.to,
|
|
410
|
-
above: true,
|
|
411
|
-
create: () => {
|
|
412
|
-
const el = document.createElement('div');
|
|
413
|
-
options.renderTooltip!(el, { shortcut }, view);
|
|
414
|
-
return { dom: el, offset: { x: 0, y: 8 } };
|
|
415
|
-
},
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
return null;
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
// TODO(burdon): Hide on change triggered immediately?
|
|
423
|
-
// hideOnChange: true,
|
|
424
|
-
hoverTime: 1_000,
|
|
425
|
-
},
|
|
426
|
-
),
|
|
427
|
-
|
|
428
|
-
//
|
|
429
|
-
// Track deleted ranges and update ranges for decorations.
|
|
430
|
-
//
|
|
431
|
-
EditorView.updateListener.of(({ view, state, changes }) => {
|
|
432
|
-
let mod = false;
|
|
433
|
-
const { comments, ...value } = state.field(commentsState);
|
|
434
|
-
changes.iterChanges((from, to, from2, to2) => {
|
|
435
|
-
comments.forEach(({ comment, range }) => {
|
|
436
|
-
// Test if range deleted.
|
|
437
|
-
if (from2 === to2) {
|
|
438
|
-
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor!);
|
|
439
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
440
|
-
options.onDelete?.({ id: comment.id });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Update range.
|
|
445
|
-
if (from <= range.to) {
|
|
446
|
-
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor!);
|
|
447
|
-
Object.assign(range, newRange);
|
|
448
|
-
mod = true;
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
if (mod) {
|
|
454
|
-
view.dispatch({ effects: setCommentState.of({ comments, ...value }) });
|
|
455
|
-
}
|
|
456
|
-
}),
|
|
457
|
-
|
|
458
|
-
//
|
|
459
|
-
// Track selection/proximity.
|
|
460
|
-
//
|
|
461
|
-
EditorView.updateListener.of(({ view, state }) => {
|
|
462
|
-
let min = Infinity;
|
|
463
|
-
const {
|
|
464
|
-
selection: { current, closest },
|
|
465
|
-
comments,
|
|
466
|
-
} = state.field(commentsState);
|
|
467
|
-
|
|
468
|
-
const { head } = state.selection.main;
|
|
469
|
-
const selection: SelectionState = {};
|
|
470
|
-
comments.forEach(({ comment, range }) => {
|
|
471
|
-
if (head >= range.from && head <= range.to) {
|
|
472
|
-
selection.current = comment.id;
|
|
473
|
-
selection.closest = undefined;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if (!selection.current) {
|
|
477
|
-
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
478
|
-
if (d < min) {
|
|
479
|
-
selection.closest = comment.id;
|
|
480
|
-
min = d;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
if (selection.current !== current || selection.closest !== closest) {
|
|
486
|
-
view.dispatch({ effects: setSelection.of(selection) });
|
|
487
|
-
|
|
488
|
-
// Update callback.
|
|
489
|
-
handleSelect({
|
|
490
|
-
selection,
|
|
491
|
-
id: state.facet(documentId),
|
|
492
|
-
comments: comments.map(({ comment, range }) => ({
|
|
493
|
-
comment,
|
|
494
|
-
range,
|
|
495
|
-
location: view.coordsAtPos(range.from),
|
|
496
|
-
})),
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
}),
|
|
500
|
-
|
|
501
|
-
options.onUpdate && trackPastedComments(options.onUpdate),
|
|
502
|
-
].filter(isNonNullable);
|
|
503
|
-
};
|
|
504
|
-
|
|
505
615
|
//
|
|
506
616
|
// Utils.
|
|
507
617
|
//
|
|
@@ -532,7 +642,7 @@ export type ScrollThreadOptions = {
|
|
|
532
642
|
* Scroll the comment thread with the given id into view (if not already entirely
|
|
533
643
|
* visible) and mark it the current comment so the editor highlights it.
|
|
534
644
|
*/
|
|
535
|
-
export const
|
|
645
|
+
export const scrollCommentIntoView = (
|
|
536
646
|
view: EditorView,
|
|
537
647
|
id: string,
|
|
538
648
|
{ y = 'center', yMargin }: ScrollThreadOptions = {},
|
|
@@ -548,7 +658,9 @@ export const scrollThreadIntoView = (
|
|
|
548
658
|
}
|
|
549
659
|
|
|
550
660
|
const { from, to } = view.state.selection.main;
|
|
551
|
-
|
|
661
|
+
// Never collapse a live selection: an attention change in the comments companion can land while the
|
|
662
|
+
// user is selecting text, and moving the caret would silently retarget the comment they create next.
|
|
663
|
+
const needsSelectionUpdate = from === to && from !== range.from;
|
|
552
664
|
view.dispatch({
|
|
553
665
|
selection: needsSelectionUpdate ? { anchor: range.from } : undefined,
|
|
554
666
|
effects: [
|
|
@@ -560,38 +672,54 @@ export const scrollThreadIntoView = (
|
|
|
560
672
|
};
|
|
561
673
|
|
|
562
674
|
/**
|
|
563
|
-
*
|
|
564
|
-
* This class subscribes to external comment updates and applies them to the editor view.
|
|
675
|
+
* NOTE: Matches search.
|
|
565
676
|
*/
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
677
|
+
// The visible highlight is drawn by `commentsHighlightLayer` (below) as a layer of rectangle markers,
|
|
678
|
+
// so — like a text selection — it fills wrapped lines to the line edge instead of stopping at the last
|
|
679
|
+
// glyph. The inline `cm-comment` mark is now transparent and exists only to carry `data-comment-id`
|
|
680
|
+
// (click routing) and the pointer affordance. No `border-radius`: the per-line rectangles abut, so
|
|
681
|
+
// rounding each would pinch the interior edges into notches on a multi-line comment.
|
|
682
|
+
const styles = EditorView.theme({
|
|
683
|
+
// The layer only paints the background; text colour comes from the inline mark, which wraps exactly
|
|
684
|
+
// the comment text. `!important` and the descendant selector win over markdown syntax-highlight tokens
|
|
685
|
+
// nested inside the range.
|
|
686
|
+
'.cm-comment, .cm-comment *': {
|
|
687
|
+
color: 'var(--color-teal-fg) !important',
|
|
688
|
+
},
|
|
689
|
+
'.cm-comment[data-current="1"], .cm-comment[data-current="1"] *': {
|
|
690
|
+
color: 'var(--color-orange-fg) !important',
|
|
691
|
+
},
|
|
692
|
+
'.cm-comment': {
|
|
693
|
+
cursor: 'pointer',
|
|
694
|
+
},
|
|
695
|
+
// Layer wrapper: sit behind the text and never swallow clicks meant for the `cm-comment` mark.
|
|
696
|
+
'.cm-commentsHighlightLayer': {
|
|
697
|
+
pointerEvents: 'none',
|
|
698
|
+
},
|
|
699
|
+
// `box-shadow` with a 1px spread extends the block 1px on every side in the same colour — visual
|
|
700
|
+
// padding without changing layout. Vertically adjacent line rectangles paint into each other's gap
|
|
701
|
+
// with the same colour, so a multi-line comment stays seamless.
|
|
702
|
+
// 2px horizontal breathing room around the text: `padding-inline` widens the background box and the
|
|
703
|
+
// compensating negative `margin-inline` keeps it aligned to the text; `content-box` makes the padding
|
|
704
|
+
// grow the box (rather than shrink the content) so the fill and border-radius extend with it.
|
|
705
|
+
// `pointer-events: none` on the rectangles themselves (not only the layer wrapper) so a click over a
|
|
706
|
+
// comment passes through to the `.cm-comment` mark's `data-comment-id` (and reaches `handleCommentClick`)
|
|
707
|
+
// instead of landing on a highlight rectangle that carries no id.
|
|
708
|
+
'.cm-comment-highlight': {
|
|
709
|
+
backgroundColor: 'var(--color-teal-bg)',
|
|
710
|
+
boxShadow: '0 0 0 1px var(--color-teal-bg)',
|
|
711
|
+
boxSizing: 'content-box',
|
|
712
|
+
marginInline: '-2px',
|
|
713
|
+
paddingInline: '2px',
|
|
714
|
+
pointerEvents: 'none',
|
|
715
|
+
},
|
|
716
|
+
'.cm-comment-highlight-current': {
|
|
717
|
+
backgroundColor: 'var(--color-orange-bg)',
|
|
718
|
+
boxShadow: '0 0 0 1px var(--color-orange-bg)',
|
|
719
|
+
},
|
|
720
|
+
// Only round a comment that occupies a single visual line: a multi-line comment is drawn as several
|
|
721
|
+
// abutting rectangles, so rounding each would notch the interior edges.
|
|
722
|
+
'.cm-comment-highlight-single': {
|
|
723
|
+
borderRadius: '0.25rem',
|
|
724
|
+
},
|
|
725
|
+
});
|