From 7391c6e5fc896eb9b937323f918562beef694061 Mon Sep 17 00:00:00 2001 From: Danilo Woznica Date: Wed, 27 Apr 2022 15:07:36 +0100 Subject: [PATCH] fix(codeeditor): ensure selections are inside of the document length (#452) --- .../src/components/CodeEditor/CodeMirror.tsx | 16 +++++++++++----- website/docs/docs/advanced-usage/components.md | 7 +++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/sandpack-react/src/components/CodeEditor/CodeMirror.tsx b/sandpack-react/src/components/CodeEditor/CodeMirror.tsx index 4b4fcc8fa..e148a91f6 100644 --- a/sandpack-react/src/components/CodeEditor/CodeMirror.tsx +++ b/sandpack-react/src/components/CodeEditor/CodeMirror.tsx @@ -11,7 +11,7 @@ import { lineNumbers } from "@codemirror/gutter"; import { defaultHighlightStyle } from "@codemirror/highlight"; import { history, historyKeymap } from "@codemirror/history"; import { bracketMatching } from "@codemirror/matchbrackets"; -import { EditorState } from "@codemirror/state"; +import { EditorState, EditorSelection } from "@codemirror/state"; import type { Annotation, Extension } from "@codemirror/state"; import { highlightSpecialChars, @@ -311,10 +311,16 @@ export const CodeMirror = React.forwardRef( React.useEffect(() => { if (cmView.current && code !== internalCode) { const view = cmView.current; - view.dispatch({ - changes: { from: 0, to: view.state.doc.length, insert: code }, - selection: view.state.selection, - }); + + const selection = view.state.selection.ranges.some( + ({ to, from }) => to > code.length || from > code.length + ) + ? EditorSelection.cursor(code.length) + : view.state.selection; + + const changes = { from: 0, to: view.state.doc.length, insert: code }; + + view.dispatch({ changes, selection }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [code]); diff --git a/website/docs/docs/advanced-usage/components.md b/website/docs/docs/advanced-usage/components.md index 3705d744f..948413edb 100644 --- a/website/docs/docs/advanced-usage/components.md +++ b/website/docs/docs/advanced-usage/components.md @@ -262,6 +262,8 @@ import { autocompletion, completionKeymap } from "@codemirror/autocomplete"; If you want to interact directly with CodeMirror, use the component ref to access the `getCodemirror` function, which will return the CodeMirror instance. Check out how to use it: ```jsx +import { EditorSelection } from "@codemirror/state"; + const App = () => { const codemirrorInstance = useRef(); @@ -272,17 +274,18 @@ const App = () => { if(!cmInstance) return // Current position - const currentPosition = cmInstance.state.selection; + const currentPosition = cmInstance.state.selection.ranges[0].to; // Setting a new position const trans = cmInstance.state.update({ - selection: currentPosition + 1, + selection: EditorSelection.cursor(currentPosition + 1), changes: { from: 0, to: cmInstance.state.doc.length, insert: code } }); + cmInstance.update([trans]); }, []);