Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue where cursor position is lost when shortcuts are used #3

Open
tom-leamon opened this issue Jan 18, 2023 · 1 comment
Open
Labels
bug Something isn't working

Comments

@tom-leamon
Copy link
Owner

No description provided.

@tom-leamon tom-leamon added the bug Something isn't working label Jan 18, 2023
@tom-leamon
Copy link
Owner Author

In this given code, it looks like you're using the react-simple-code-editor library along with prismjs for syntax highlighting to create a code editor for HTML, CSS, and JavaScript. There's a Symbols component that, presumably, lets the user insert specific symbols into the code at the cursor's position.

However, you're trying to update the cursor's position manually using direct DOM manipulation, which is not recommended in React. Instead, we should use React's mechanisms to control the state of the component.

For the react-simple-code-editor library, unfortunately, it does not expose a mechanism to control the cursor position, but we can work around this by using a useEffect hook to apply our cursor movement after each render.

Here is your updated Code component with this mechanism:

import './Code.css'
import React, { useState, useEffect } from 'react';
import Editor from 'react-simple-code-editor';
import { highlight, languages } from 'prismjs/components/prism-core';
import 'prismjs/components/prism-clike';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-markup';
import Symbols from './Symbols'

const Code = ({type, tab, callback}) => {
  const [currentCode, setCurrentCode] = useState(
    JSON.parse(localStorage.getItem(type)) || ''
  )
  const [cursorPosition, setCursorPosition] = useState(null);

  const visible = tab === type

  useEffect(() => {
    localStorage.setItem(type, JSON.stringify(currentCode))
    callback(currentCode)
  }, [currentCode])
  
  useEffect(() => {
    if(cursorPosition !== null){
      const el = document.querySelector(`#${tab} textarea`)
      el.selectionStart = el.selectionEnd = cursorPosition;
      el.focus();
    }
  }, [cursorPosition])

  const insertSymbol = (symbol) => {
    const el = document.querySelector(`#${tab} textarea`)
    const start = el.selectionStart
    const end = el.selectionEnd
    const text = el.value
    const before = text.substring(0, start)
    const after  = text.substring(end, text.length)
    setCurrentCode(before + symbol + after)
    setCursorPosition(start + symbol.length)
  }

  const renderEditor = () => {
    // Editor rendering code...
  }

  return (
    <div className={visible ? 'visible' : 'hidden'}>
      <Symbols className='symbols' insertSymbol={insertSymbol} />
      { renderEditor() }
    </div>
  )
}

export default Code;

In this code:

  • We added a new state variable cursorPosition to track the desired cursor position.
  • We updated the insertSymbol function to set this state variable after inserting a symbol.
  • We added a new useEffect hook that sets the cursor position whenever cursorPosition changes. This hook runs after each render, so it will run after the render triggered by setCurrentCode in insertSymbol.
  • This way, we maintain the React way of updating the component state while achieving the desired behavior.

Remember that direct DOM manipulation in React should be the last resort as it breaks the normal flow of React's virtual DOM diffing and re-rendering process. It's better to use the React's lifecycle methods (like useEffect) to achieve the desired effects whenever possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant