@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
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { EditorView, WidgetType } from '@codemirror/view';
|
|
6
|
+
import { type FunctionComponent } from 'react';
|
|
7
|
+
|
|
8
|
+
import { invariant } from '@dxos/invariant';
|
|
9
|
+
import { log } from '@dxos/log';
|
|
10
|
+
import { Domino } from '@dxos/ui';
|
|
11
|
+
|
|
12
|
+
import { type XmlWidgetProps, type XmlWidgetState } from './xml-tags';
|
|
13
|
+
|
|
14
|
+
export interface XmlWidgetNotifier {
|
|
15
|
+
mounted(widget: XmlWidgetState): void;
|
|
16
|
+
unmounted(id: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Re-render the mounted widget for `id` with updated props. Keyed by id rather than by widget
|
|
19
|
+
* instance: a rebuild constructs fresh widgets, but `StubWidget.eq` (id equality) makes CodeMirror
|
|
20
|
+
* keep the previously-rendered DOM, so the instance in the decoration set is not the one holding
|
|
21
|
+
* the mounted root.
|
|
22
|
+
*/
|
|
23
|
+
updated(id: string, widgetState: any): void;
|
|
24
|
+
/**
|
|
25
|
+
* Drop any mounted widgets whose id is not in `liveIds`. Needed because CM reuses a widget's DOM
|
|
26
|
+
* via `updateDOM` (without calling `destroy`) when a decoration's widget changes in place, so an
|
|
27
|
+
* id that is no longer present — e.g. a position-keyed id after an edit shifted the node — would
|
|
28
|
+
* otherwise leak a stale portal.
|
|
29
|
+
*/
|
|
30
|
+
reconcile(liveIds: Set<string>): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mounts a DOM placeholder that React portals render into.
|
|
35
|
+
* Uses a block <div> for block widgets and an inline <span> for inline widgets.
|
|
36
|
+
*
|
|
37
|
+
* Culling a large block widget out of the viewport and re-showing it tears down and rebuilds the
|
|
38
|
+
* portal, causing a blank frame + flicker. `#keepAlive` (for known-height blocks) caches `#root` and
|
|
39
|
+
* keeps the portal mounted across culls so CM re-shows the same populated node; `toDOM` also gives the
|
|
40
|
+
* placeholder a fixed height so CM's measurement is authoritative and content-independent.
|
|
41
|
+
*
|
|
42
|
+
* NOTE: This does NOT address the separate scroll-*jump* on large/fast scroll deltas. That was verified
|
|
43
|
+
* (Playwright, both async and plain-sync block stories) to be widget-independent: CM's measure-phase
|
|
44
|
+
* scroll re-anchor correcting its content-height *estimate* when a big scroll delta reveals a lot of
|
|
45
|
+
* not-yet-measured content. Gradual scrolling does not jump. That is general CM heightmap behavior, not
|
|
46
|
+
* fixable here — see upstream CM #1727 (https://code.haverbeke.berlin/codemirror/dev/issues/1727).
|
|
47
|
+
*/
|
|
48
|
+
export class StubWidget<TProps extends XmlWidgetProps> extends WidgetType {
|
|
49
|
+
#root: HTMLElement | null = null;
|
|
50
|
+
#view: EditorView | undefined;
|
|
51
|
+
// Throttle the (hot) coordsAt trace to at most once per frame.
|
|
52
|
+
#coordsLoggedThisFrame = false;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
readonly id: string,
|
|
56
|
+
readonly Component: FunctionComponent<TProps>,
|
|
57
|
+
readonly props: TProps,
|
|
58
|
+
readonly notifier: XmlWidgetNotifier,
|
|
59
|
+
readonly streaming?: boolean,
|
|
60
|
+
readonly block?: boolean,
|
|
61
|
+
/**
|
|
62
|
+
* Reserved block height (px). Feeds CodeMirror's off-screen viewport estimate and pre-sizes the
|
|
63
|
+
* placeholder so the block occupies its final height before the portaled content resolves —
|
|
64
|
+
* otherwise it collapses to the 24px minimum, causing scroll jitter and a blank on scroll-back.
|
|
65
|
+
*/
|
|
66
|
+
readonly blockHeight?: number,
|
|
67
|
+
/** When true, trace the widget's DOM lifecycle to diagnose scroll-cull jitter/jump (see PreviewScrollSurface). */
|
|
68
|
+
readonly debug?: boolean,
|
|
69
|
+
) {
|
|
70
|
+
super();
|
|
71
|
+
invariant(id);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get root(): HTMLElement | null {
|
|
75
|
+
return this.#root;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Gated lifecycle trace. Enable per-tag via `XmlWidgetDef.debug` to watch the scroll-cull sequence. */
|
|
79
|
+
#trace(event: string, data?: Record<string, unknown>): void {
|
|
80
|
+
if (this.debug) {
|
|
81
|
+
log.info(`stub-widget: ${event}`, { id: this.id, block: this.block, ...data });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// CodeMirror reserves this height for the block while it is outside the rendered viewport.
|
|
86
|
+
override get estimatedHeight() {
|
|
87
|
+
return this.block && this.blockHeight != null ? this.blockHeight : -1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Report per-position screen coordinates inside the block so CM can anchor scroll correctly. Large
|
|
91
|
+
// block widgets need this alongside `estimatedHeight` (codemirror/dev#761); returning the same rect
|
|
92
|
+
// for every position confuses CM's geometry, so interpolate a vertical position across the widget's
|
|
93
|
+
// range (offset `pos` within `to - from`).
|
|
94
|
+
override coordsAt(dom: HTMLElement, pos: number, side: number) {
|
|
95
|
+
if (!this.block) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const rect = dom.getBoundingClientRect();
|
|
99
|
+
const range = (this.props as XmlWidgetProps).range;
|
|
100
|
+
const length = range ? range.to - range.from : 0;
|
|
101
|
+
const fraction = length > 0 ? Math.min(1, Math.max(0, pos / length)) : side > 0 ? 1 : 0;
|
|
102
|
+
const y = rect.top + rect.height * fraction;
|
|
103
|
+
if (this.debug) {
|
|
104
|
+
const detached = rect.height === 0 || (rect.top === 0 && rect.bottom === 0);
|
|
105
|
+
// A detached / re-parented node reports a zero rect; feeding that to CM's scroll anchor snaps the
|
|
106
|
+
// viewport to the document top. Flag it so the jump-to-top is attributable in the trace.
|
|
107
|
+
if (detached) {
|
|
108
|
+
log.warn('stub-widget: coordsAt on detached node (zero rect)', {
|
|
109
|
+
id: this.id,
|
|
110
|
+
pos,
|
|
111
|
+
side,
|
|
112
|
+
connected: dom.isConnected,
|
|
113
|
+
rect: { top: rect.top, height: rect.height },
|
|
114
|
+
y,
|
|
115
|
+
});
|
|
116
|
+
} else if (!this.#coordsLoggedThisFrame) {
|
|
117
|
+
// CM consults coordsAt to anchor the scroll; log one sample per frame to correlate with jumps.
|
|
118
|
+
this.#coordsLoggedThisFrame = true;
|
|
119
|
+
requestAnimationFrame(() => {
|
|
120
|
+
this.#coordsLoggedThisFrame = false;
|
|
121
|
+
});
|
|
122
|
+
log.info('stub-widget: coordsAt', {
|
|
123
|
+
id: this.id,
|
|
124
|
+
pos,
|
|
125
|
+
side,
|
|
126
|
+
rect: { top: Math.round(rect.top), height: Math.round(rect.height) },
|
|
127
|
+
y: Math.round(y),
|
|
128
|
+
scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { left: rect.left, right: rect.right, top: y, bottom: y };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
override eq(other: this) {
|
|
136
|
+
if (this.streaming) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
// Context too, not just the id: props are captured at build time, so an id-only comparison makes
|
|
140
|
+
// CodeMirror keep the existing widget (and its stale props) when the host publishes the context
|
|
141
|
+
// after the first build — leaving every widget callback bound to `undefined`.
|
|
142
|
+
const context = (props: TProps) => (props as XmlWidgetProps).context;
|
|
143
|
+
return this.id === other.id && context(this.props) === context(other.props);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
override ignoreEvent() {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Keep the root DOM (and its portal) alive across CM viewport culls, for block widgets whose height
|
|
152
|
+
* we know up front. A cull calls `destroy()` then `toDOM()` on the SAME widget instance; reusing the
|
|
153
|
+
* cached, already-rendered node instead of rebuilding it keeps the block's measured geometry stable
|
|
154
|
+
* across the cull boundary, which sidesteps CM's measure-phase scroll re-anchor (upstream #1727) and
|
|
155
|
+
* the blank/flicker from the portal remounting. Genuine removals (the tag edited out) are pruned by
|
|
156
|
+
* `notifier.reconcile` on the next document change, not by cull. Scoped to known-height blocks so
|
|
157
|
+
* ordinary widgets keep CM's normal virtualization (no unbounded retained portals).
|
|
158
|
+
*/
|
|
159
|
+
get #keepAlive(): boolean {
|
|
160
|
+
return !!this.block && this.blockHeight != null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
override toDOM(view: EditorView) {
|
|
164
|
+
this.#view = view;
|
|
165
|
+
const cached = this.#keepAlive && this.#root != null;
|
|
166
|
+
if (!this.#root) {
|
|
167
|
+
this.#root = this.block ? Domino.of('div').classNames('min-h-[24px]').root : Domino.of('span').root;
|
|
168
|
+
if (this.block && this.blockHeight != null) {
|
|
169
|
+
// Fixed (not min) height: give CM an authoritative, content-independent measurement so an async
|
|
170
|
+
// widget that mounts / re-lays-out later cannot perturb the heightmap (we know the height up
|
|
171
|
+
// front). `overflow: hidden` keeps content that briefly overshoots from changing the measured box.
|
|
172
|
+
this.#root.style.height = `${this.blockHeight}px`;
|
|
173
|
+
this.#root.style.overflow = 'hidden';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const props = Object.assign({}, this.props, { view }) as TProps;
|
|
177
|
+
this.notifier.mounted({ id: this.id, root: this.#root, props, Component: this.Component });
|
|
178
|
+
this.#trace(cached ? 'toDOM (reuse cached root)' : 'toDOM (create)', {
|
|
179
|
+
blockHeight: this.blockHeight,
|
|
180
|
+
scrollTop: Math.round(view.scrollDOM.scrollTop),
|
|
181
|
+
});
|
|
182
|
+
this.#measureAfterPaint('toDOM');
|
|
183
|
+
return this.#root;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
override updateDOM(dom: HTMLElement) {
|
|
187
|
+
this.#root = dom;
|
|
188
|
+
const props = Object.assign({}, this.props, { view: this.#view }) as TProps;
|
|
189
|
+
this.notifier.mounted({ id: this.id, root: this.#root, props, Component: this.Component });
|
|
190
|
+
this.#trace('updateDOM (reuse/re-parent)', { connected: dom.isConnected });
|
|
191
|
+
this.#measureAfterPaint('updateDOM');
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
override destroy(_dom: HTMLElement) {
|
|
196
|
+
if (this.#keepAlive) {
|
|
197
|
+
// Cull, not removal: keep #root and the portal mounted so the next toDOM re-shows the identical,
|
|
198
|
+
// already-rendered node. `notifier.reconcile` drops it if the tag is genuinely removed.
|
|
199
|
+
this.#trace('destroy (cull, keep-alive)', { scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1) });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this.#trace('destroy (cull)', { scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1) });
|
|
203
|
+
this.notifier.unmounted(this.id);
|
|
204
|
+
this.#root = null;
|
|
205
|
+
this.#view = undefined;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* After the next paint, compare the measured block height against the reserved `estimatedHeight`.
|
|
210
|
+
* A large discrepancy is what shifts CM's total-height model and drives the scroll jump; logging it
|
|
211
|
+
* pinpoints when (and by how much) the portaled content diverges from the reserved space.
|
|
212
|
+
*/
|
|
213
|
+
#measureAfterPaint(source: string): void {
|
|
214
|
+
if (!this.debug || !this.block) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const root = this.#root;
|
|
218
|
+
requestAnimationFrame(() => {
|
|
219
|
+
if (!root) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const measured = root.getBoundingClientRect().height;
|
|
223
|
+
const reserved = this.blockHeight ?? -1;
|
|
224
|
+
log.info(`stub-widget: measured after ${source}`, {
|
|
225
|
+
id: this.id,
|
|
226
|
+
reserved,
|
|
227
|
+
measured,
|
|
228
|
+
delta: reserved > 0 ? measured - reserved : undefined,
|
|
229
|
+
connected: root.isConnected,
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Extension, type Range } from '@codemirror/state';
|
|
6
|
+
import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
|
|
7
|
+
|
|
8
|
+
import { escapeRegExpSource } from '../../../util';
|
|
9
|
+
|
|
10
|
+
export type XmlBlockDecorationOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Tag name to match (e.g. `'prompt'`).
|
|
13
|
+
*/
|
|
14
|
+
tag: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Class added via `Decoration.line` to each line that intersects the element's content
|
|
18
|
+
* range. Use to style the bubble container (e.g. flex alignment, vertical margin).
|
|
19
|
+
*/
|
|
20
|
+
lineClass?: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Additional class added only to the first line of the content range. Use to round the top
|
|
24
|
+
* of a block bubble and pad its top edge (single line receives both first and last classes).
|
|
25
|
+
*/
|
|
26
|
+
firstLineClass?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Additional class added only to the last line of the content range. Use to round the
|
|
30
|
+
* bottom of a block bubble and pad its bottom edge.
|
|
31
|
+
*/
|
|
32
|
+
lastLineClass?: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Class added via `Decoration.mark` covering the inner content (between the open and
|
|
36
|
+
* close tags). Use to style the bubble surface (background, padding, rounding).
|
|
37
|
+
*/
|
|
38
|
+
contentClass?: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* When true, the open and close tag delimiters are hidden via `Decoration.replace`
|
|
42
|
+
* with no widget, so the rendered text is the inner content only.
|
|
43
|
+
*/
|
|
44
|
+
hideTags?: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Scans the doc for `<tag>…</tag>` blocks and decorates them without replacing them with a
|
|
49
|
+
* widget — the source text remains in the document and can still be matched by other extensions
|
|
50
|
+
* (e.g. `xmlFormatting`). Use this for "bubble"-style styling of XML blocks (chat prompts,
|
|
51
|
+
* callouts, etc.) where the inner content should stay editable/copyable rather than living inside
|
|
52
|
+
* a CodeMirror widget.
|
|
53
|
+
*
|
|
54
|
+
* Matching is done by direct text scan rather than a full-document XML parse: the transcript is
|
|
55
|
+
* mostly markdown, and a single stray `<` anywhere upstream (code, `a < b`, an unclosed streaming
|
|
56
|
+
* widget tag) corrupts a whole-document XML parse — which previously caused a well-formed prompt's
|
|
57
|
+
* `</tag>` to go unrecognised, extending the bubble over the rest of the conversation. An
|
|
58
|
+
* unterminated open tag (no matching `</tag>`, e.g. mid-stream) is left undecorated rather than
|
|
59
|
+
* painting to the end of the document.
|
|
60
|
+
*/
|
|
61
|
+
// TODO(burdon): Change to array to support multiple tags.
|
|
62
|
+
export const xmlBlockDecoration = ({
|
|
63
|
+
tag,
|
|
64
|
+
lineClass,
|
|
65
|
+
firstLineClass,
|
|
66
|
+
lastLineClass,
|
|
67
|
+
contentClass,
|
|
68
|
+
hideTags,
|
|
69
|
+
}: XmlBlockDecorationOptions): Extension => {
|
|
70
|
+
const contentDecoration = contentClass ? Decoration.mark({ class: contentClass }) : undefined;
|
|
71
|
+
const hideDecoration = hideTags ? Decoration.replace({}) : undefined;
|
|
72
|
+
|
|
73
|
+
// Match an opening `<tag>` or `<tag …attrs>` (not self-closing); the paired `</tag>` is located
|
|
74
|
+
// by scanning forward so unrelated markup between blocks cannot break matching. `tag` is escaped
|
|
75
|
+
// so a name containing regex metacharacters (e.g. `foo.bar`) matches literally.
|
|
76
|
+
const escapedTag = escapeRegExpSource(tag);
|
|
77
|
+
const openTagRegExp = new RegExp(`<${escapedTag}(?:\\s[^>]*)?>`, 'g');
|
|
78
|
+
const closeTagStr = `</${tag}>`;
|
|
79
|
+
|
|
80
|
+
const buildDecorations = (view: EditorView): DecorationSet => {
|
|
81
|
+
const docLength = view.state.doc.length;
|
|
82
|
+
const text = view.state.sliceDoc(0, docLength);
|
|
83
|
+
if (!text.includes(`<${tag}`)) {
|
|
84
|
+
return Decoration.none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const ranges: Range<Decoration>[] = [];
|
|
88
|
+
openTagRegExp.lastIndex = 0;
|
|
89
|
+
let match: RegExpExecArray | null;
|
|
90
|
+
while ((match = openTagRegExp.exec(text))) {
|
|
91
|
+
const openFrom = match.index;
|
|
92
|
+
const openTo = openFrom + match[0].length;
|
|
93
|
+
const closeFrom = text.indexOf(closeTagStr, openTo);
|
|
94
|
+
// Skip unterminated blocks: extending decoration to the document end would paint the bubble
|
|
95
|
+
// over everything that follows (e.g. the assistant response streaming in after the prompt).
|
|
96
|
+
if (closeFrom === -1) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
const closeTo = closeFrom + closeTagStr.length;
|
|
100
|
+
const contentFrom = openTo;
|
|
101
|
+
const contentTo = closeFrom;
|
|
102
|
+
|
|
103
|
+
if (hideDecoration) {
|
|
104
|
+
ranges.push(hideDecoration.range(openFrom, openTo));
|
|
105
|
+
ranges.push(hideDecoration.range(closeFrom, closeTo));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (contentDecoration && contentFrom < contentTo) {
|
|
109
|
+
ranges.push(contentDecoration.range(contentFrom, contentTo));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (lineClass || firstLineClass || lastLineClass) {
|
|
113
|
+
// Collect every line that intersects the content range so that the first and last
|
|
114
|
+
// can be styled distinctly (e.g. rounding the top/bottom of a single block bubble).
|
|
115
|
+
const lines = [];
|
|
116
|
+
let pos = contentFrom;
|
|
117
|
+
while (pos < contentTo && pos <= docLength) {
|
|
118
|
+
const line = view.state.doc.lineAt(pos);
|
|
119
|
+
// Only lines that intersect visible content: a hidden close tag on its own line would
|
|
120
|
+
// otherwise get an empty rounded bubble line after the tag is replaced.
|
|
121
|
+
if (line.to > contentFrom && line.from < contentTo) {
|
|
122
|
+
lines.push(line);
|
|
123
|
+
}
|
|
124
|
+
if (line.to >= contentTo) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
pos = line.to + 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
lines.forEach((line, index) => {
|
|
131
|
+
const cls = [lineClass, index === 0 && firstLineClass, index === lines.length - 1 && lastLineClass]
|
|
132
|
+
.filter(Boolean)
|
|
133
|
+
.join(' ');
|
|
134
|
+
if (cls) {
|
|
135
|
+
ranges.push(Decoration.line({ class: cls }).range(line.from));
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Resume scanning past the close tag so content is never re-matched.
|
|
141
|
+
openTagRegExp.lastIndex = closeTo;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return Decoration.set(ranges, true);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return ViewPlugin.fromClass(
|
|
148
|
+
class {
|
|
149
|
+
decorations: DecorationSet;
|
|
150
|
+
|
|
151
|
+
constructor(view: EditorView) {
|
|
152
|
+
this.decorations = buildDecorations(view);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
update(update: ViewUpdate) {
|
|
156
|
+
if (update.docChanged) {
|
|
157
|
+
this.decorations = buildDecorations(update.view);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
decorations: (instance) => instance.decorations,
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
};
|
|
@@ -6,15 +6,6 @@ import { xmlLanguage } from '@codemirror/lang-xml';
|
|
|
6
6
|
import { type Extension, type Range } from '@codemirror/state';
|
|
7
7
|
import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Lezer XML node names that represent the angle-bracket delimited portions of an element.
|
|
11
|
-
*/
|
|
12
|
-
const XML_TAG_NODES = new Set(['OpenTag', 'CloseTag', 'SelfClosingTag', 'MismatchedCloseTag']);
|
|
13
|
-
|
|
14
|
-
const xmlElementMark = Decoration.mark({ class: 'cm-xml-element' });
|
|
15
|
-
const xmlTagMark = Decoration.mark({ class: 'cm-xml-tag' });
|
|
16
|
-
const xmlContentMark = Decoration.mark({ class: 'cm-xml-content' });
|
|
17
|
-
|
|
18
9
|
export type XmlFormattingOptions = {
|
|
19
10
|
/**
|
|
20
11
|
* Tag names whose elements should NOT receive xmlFormatting decorations. Use to
|
|
@@ -47,6 +38,17 @@ export const xmlFormatting = ({ skip }: XmlFormattingOptions = {}): Extension =>
|
|
|
47
38
|
}
|
|
48
39
|
|
|
49
40
|
const tagNameAt = (node: { from: number; to: number }) => text.slice(node.from, node.to);
|
|
41
|
+
// A tag is only decorated when its `TagName` child parses as a real name. This gates out the
|
|
42
|
+
// malformed elements Lezer synthesises from a stray `<` in prose, which would otherwise span
|
|
43
|
+
// to the next `>` and paint the intervening text with `cm-xml-element`/`cm-xml-tag`.
|
|
44
|
+
const tagNameOf = (tagNode: { getChild: (name: string) => { from: number; to: number } | null }) => {
|
|
45
|
+
const tagNameNode = tagNode.getChild('TagName');
|
|
46
|
+
if (!tagNameNode) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const value = tagNameAt(tagNameNode);
|
|
50
|
+
return VALID_TAG_NAME.test(value) ? value : undefined;
|
|
51
|
+
};
|
|
50
52
|
|
|
51
53
|
const tree = xmlLanguage.parser.parse(text);
|
|
52
54
|
const ranges: Range<Decoration>[] = [];
|
|
@@ -54,33 +56,36 @@ export const xmlFormatting = ({ skip }: XmlFormattingOptions = {}): Extension =>
|
|
|
54
56
|
enter: (node) => {
|
|
55
57
|
const name = node.type.name;
|
|
56
58
|
if (name === 'SelfClosingTag' && node.from < node.to) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const tagName = tagNameOf(node.node);
|
|
60
|
+
if (!tagName) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (skipSet?.has(tagName)) {
|
|
64
|
+
return false;
|
|
62
65
|
}
|
|
63
66
|
// Self-closing tag is its own outer block and tag delimiter.
|
|
64
67
|
ranges.push(xmlElementMark.range(node.from, node.to));
|
|
65
68
|
ranges.push(xmlTagMark.range(node.from, node.to));
|
|
66
69
|
return;
|
|
67
70
|
}
|
|
68
|
-
if (XML_TAG_NODES.has(name) && node.from < node.to) {
|
|
69
|
-
ranges.push(xmlTagMark.range(node.from, node.to));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
71
|
if (name === 'Element' && node.from < node.to) {
|
|
73
72
|
const openTag = node.node.getChild('OpenTag');
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
// Require a real matching `CloseTag` (not `MismatchedCloseTag`) with a valid name: an
|
|
74
|
+
// unterminated or malformed element is left undecorated. Keep descending so any
|
|
75
|
+
// well-formed nested elements still get styled.
|
|
76
|
+
const closeTag = node.node.getChild('CloseTag');
|
|
77
|
+
const tagName = openTag ? tagNameOf(openTag) : undefined;
|
|
78
|
+
if (!openTag || !closeTag || !tagName) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (skipSet?.has(tagName)) {
|
|
82
|
+
// Skip this element AND its descendants — another extension owns rendering.
|
|
83
|
+
return false;
|
|
80
84
|
}
|
|
81
|
-
const closeTag = node.node.getChild('CloseTag') ?? node.node.getChild('MismatchedCloseTag');
|
|
82
85
|
ranges.push(xmlElementMark.range(node.from, node.to));
|
|
83
|
-
|
|
86
|
+
ranges.push(xmlTagMark.range(openTag.from, openTag.to));
|
|
87
|
+
ranges.push(xmlTagMark.range(closeTag.from, closeTag.to));
|
|
88
|
+
if (openTag.to < closeTag.from) {
|
|
84
89
|
ranges.push(xmlContentMark.range(openTag.to, closeTag.from));
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -109,17 +114,28 @@ export const xmlFormatting = ({ skip }: XmlFormattingOptions = {}): Extension =>
|
|
|
109
114
|
},
|
|
110
115
|
),
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
'.cm-xml-element': {
|
|
114
|
-
backgroundColor: 'var(--color-current-surface)',
|
|
115
|
-
borderRadius: '0.25rem',
|
|
116
|
-
padding: '0.25rem',
|
|
117
|
-
},
|
|
118
|
-
'.cm-xml-tag': {
|
|
119
|
-
color: 'var(--color-blue-500)',
|
|
120
|
-
fontFamily: 'var(--font-mono)',
|
|
121
|
-
},
|
|
122
|
-
'.cm-xml-content': {},
|
|
123
|
-
}),
|
|
117
|
+
styles,
|
|
124
118
|
];
|
|
125
119
|
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Well-formed XML tag name (a stray `<` in prose — e.g. `a < b` — has none, so it stays undecorated).
|
|
123
|
+
*/
|
|
124
|
+
const VALID_TAG_NAME = /^[A-Za-z_][\w.-]*$/;
|
|
125
|
+
|
|
126
|
+
const xmlElementMark = Decoration.mark({ class: 'cm-xml-element' });
|
|
127
|
+
const xmlTagMark = Decoration.mark({ class: 'cm-xml-tag' });
|
|
128
|
+
const xmlContentMark = Decoration.mark({ class: 'cm-xml-content' });
|
|
129
|
+
|
|
130
|
+
const styles = EditorView.baseTheme({
|
|
131
|
+
'.cm-xml-element': {
|
|
132
|
+
backgroundColor: 'var(--color-current-surface)',
|
|
133
|
+
borderRadius: '0.25rem',
|
|
134
|
+
padding: '0.25rem',
|
|
135
|
+
},
|
|
136
|
+
'.cm-xml-tag': {
|
|
137
|
+
color: 'var(--color-blue-500)',
|
|
138
|
+
fontFamily: 'var(--font-mono)',
|
|
139
|
+
},
|
|
140
|
+
'.cm-xml-content': {},
|
|
141
|
+
});
|