uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.55k stars 126 forks source link

Tab press does not shift to next field in Snippet when used in controlled mode #381

Open utkarsh22garg opened 1 year ago

utkarsh22garg commented 1 year ago

Issue:

I want to add snippet with multiple fields in my code editor. I am able to add snippet but when I am trying to switch to next field using Tab, it does not shift to next field. Instead it shift current line. This only happens when I am trying to use the code mirror in controlled mode.

Reproducer: https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-vikoqq

Try adding <bar> and select the snippet. Notice that it won't switch to second field.

Any help would be appreciated.

utkarsh22garg commented 1 year ago

Hi Team, any updates on this issue ?

jaywcjlove commented 1 year ago

@utkarsh22garg https://codesandbox.io/embed/react-codemirror-example-codemirror-6-https-github-com-uiwjs-react-codemirror-issues-381-06ll0x?fontsize=14&hidenavigation=1&theme=dark

import React, { useCallback, useMemo } from "react";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { snippetCompletion, autocompletion } from "@codemirror/autocomplete";

export default function App() {
  const [value, setValue] = React.useState();

  const onChange = useCallback((value) => setValue(value), []);
  const extensions = useMemo(
    () => [
      javascript({ jsx: true }),
      autocompletion({
        override: [
          (context) => {
            const matchBefore = context.matchBefore(/<\w*/);

            if (!matchBefore) {
              return null;
            }

            console.log({ context });

            return {
              from: matchBefore.from,
              options: [
                snippetCompletion("<bar>#{1:hello} : #{2:okay}</bar>", {
                  label: "<bar></bar> hash empty (works)"
                })
              ]
            };
          }
        ]
      })
    ],
    []
  );
  return (
    <div>
      <CodeMirror
        value={value}
        height="200px"
        theme="dark"
        basicSetup={false}
        extensions={extensions}
        onChange={onChange}
      />
    </div>
  );
}
utkarsh22garg commented 1 year ago

Thanks @jaywcjlove , it works. But I can't figure out the reason. What fix made this work ? Is it basicSetup ?

jaywcjlove commented 1 year ago

https://github.com/uiwjs/react-codemirror/blob/f5f9859c96480819e9f8f49bfdca32d42287ddfa/core/src/useCodeMirror.ts#L158-L179

There is no way to compare extensions.

@utkarsh22garg

charlespwd commented 4 months ago

Running into the same issue. What if ReactCodemirror used a Compartment for the props-provided extensions? What if the view dispatch was a compartment reconfigure instead of entire extension config reconfigure?

This would mean that the config append done by snippet in @codemirror/autocomplete wouldn't get thrown away by an unstable extensions array.