web-dev-qa-db-ja.com

ReactフォーカスがReact Select

これが一般的な問題なのか、私たちのミスなのかはわかりませんが、誰かがアイデアを持っているかもしれません。反応してスレートするHTMLエディターを作成しています。ユーザーはテキストボックスを選択して属性を変更できます。これは、単純なボタンでは問題なく機能します。しかし、たとえばフォントサイズを変更するためにドロップダウン(反応選択)を開くと、選択したテキストがマークされなくなります。スレートは選択を維持するため、変更は有効になりますが、そのような悪いUXです。

私見これはテキストをマークしたままにするためのスレート機能であるべきですが、多分それは私が自分で適用する必要があるものです。

一部のスニペット、それらが役立つかどうかわかりません:

エディターコンポーネントは、フォントスタイルプラグインを初期化し、シリアル化を処理します。

class Editor extends React.Component {
  constructor(props) {
    super(props);

    this.config = {
      ...mergePluginConfig(PLUGIN_CONFIG, props),
      getEditor: () => this.editor,
      getValue: () => this.state.value,
    };
    this.plugins = initializePlugins(this.config);
    this.htmlSerializer = new HtmlSerializer({
      rules: getSerializationRulesFromPlugins(this.plugins),
    });
    this.schema = getSchemaFromPlugins(this.plugins);
    this.state = {
      value: this.htmlSerializer.deserialize(props.value)
    };



ref = editor => {
    this.editor = editor;
  };


render() {
    return (
      <div>
        <Toolbar>
            <div className="control">
                {renderToolbarElementWithPlugins(this.plugins, 'font-size')}
            </div>
        <!--- more tools --->
      <SlateEditor
            autoFocus={true}
            spellCheck={true}
            placeholder={this.props.placeholder}
            ref={this.ref}
            value={this.state.value}
            onChange={this.onChange}
            onKeyDown={this.onKeyDown}
            plugins={this.plugins}
            schema={this.schema}
       />


onChange = ({ value }) => {
    const {startInline, endInline, document, selection, fragment} = value;
    // holds the correct information
    console.log(fragment.text);
    // ...
    this.setState({ value });
    this.props.onChange(this.htmlSerializer.serialize(value));
 };

これは他のもので初期化され、ツールバーに表示されるフォントサイズのプラグインです:

export default function initializeFontSizePlugin(options) {
  // this takes care of detecting the current value and applying selected change to the value. 
  // it does not change selection
  const plugin = createStyleBasedMarkPlugin(...); 
  const fontSizeOptions = options.fontSizeOptions || [];

  const handleFontSizeChange = ({value}) => {
    plugin.reapplyFontSize({value: rendererFontSize(value)});
  };

  return {
    ...plugin,

    renderToolbarElement() {
      const {isMixed, fontSize} = plugin.detectFontSize();

      return <Select
        isCreatable={true}
        name='font-size'
        value={isMixed ? undefined : displayFontSize(fontSize)}
        onChange={handleFontSizeChange}
        options={fontSizeOptions}
      />;
    }
  };
}

私の現在の解決策は、selectが開いたらすぐにスレートに焦点を当て、selectを開くように伝えますが、ハックに感じられ、欠点があります(下記を参照)。

const handleFontSizeChange = ({value}) => {
    plugin.reapplyFontSize({value: rendererFontSize(value)});
    handleMenuClose();
  };

  let menuIsOpen = false;
  let firstOpen = false;

  const handleMenuOpen = (editor) => {
    firstOpen = true;
    if(!menuIsOpen) {
      setTimeout(() => {
        if (editor) {
          editor.focus();
        }
        menuIsOpen = true;
      }, 1);
    }
  }
  const handleMenuClose = (editor) => {
    if(!firstOpen) {
      setTimeout(() => {
        if(menuIsOpen) {
          menuIsOpen = false;
          if (editor) {
            editor.focus();
          }
        }
      }, 1);
    } else {
      firstOpen = false;
    }  
  }

<Select
    onMenuOpen={handleMenuOpen.bind(this)}
    onMenuClose={handleMenuClose.bind(this)}
    menuIsOpen={menuIsOpen}

反応のライフサイクルの外に出るにはタイムアウトを使用する必要があり、selectコンポーネントにフォーカスを失うとそれも閉じるため、追加のフラグを追加する必要があります。私が言ったように欠点があります:-フォーカスの切り替え中に選択したテキストに少しちらつき-選択のドロップダウンボックスの色が間違っています(明らかにフォーカスされていません)-別のドロップダウンに切り替え(配置など)は他を閉じませんそれにはすでに焦点がありません:

追加情報:バージョン0.47ではslateおよびslate-reactを使用する必要があります。これは、必要なslate-html-serializerがより高いバージョンをサポートしていないためです。多分これはすでに上位バージョンで解決されていますか?

だから、私はやや機能するバージョンを持っていますが、フォーカスを処理する必要なく、スレートが「自然に」選択を処理するソリューションをはるかに好みます。選択されたテキストflickeringとオフの色なしで考えることができるはずです。

3
Pete

ドロップダウンが開いているため、エディターの外にフォーカスすると、スレートは選択を保持しません。ボタンを使用すると、選択を再適用するため、ボタンが異なります

手動で選択を適用して取得する必要があるので、これを行う方法は、selectからメニューを開こうとするときにエディターの選択を状態に保存することです。メニューが開いているときに、 Transforms.setSelection そして、フォーカスされた値をドロップダウンに表示するために再び状態に保存できるfontSizeを取得します

変更を適用したら、もう一度選択を適用する必要があります

this PR で使用されている概念に従うことができます

const [selection, setSelection] = useState();
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [fontSize, setFontSize] = useState(plugins.detectFontSize());
const handleFontSizeChange = ({value}) => {
    plugin.reapplyFontSize({value: rendererFontSize(value)});
    handleMenuClose();
  };
}
const handleMenuOpen = (editor) => {
    setSelection(editor.selection);
    setMenuIsOpen(true);
    Transforms.setSelection() // pass in the required params here
    setFontSize(plugins.detectFontSize());
}
const handleMenuClose = (editor) => {
    setMenuIsOpen(false);
    Transforms.setSelection() // pass in the required params here based on selection state
}

<Select
    onMenuOpen={handleMenuOpen.bind(this)}
    onMenuClose={handleMenuClose.bind(this)}
    menuIsOpen={menuIsOpen}
    value={fontSize}
    options={options}
/>

フォーカスと選択に関する このgithubの問題 もご覧ください。

1
Shubham Khatri