これが一般的な問題なのか、私たちのミスなのかはわかりませんが、誰かがアイデアを持っているかもしれません。反応してスレートする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
とオフの色なしで考えることができるはずです。
ドロップダウンが開いているため、エディターの外にフォーカスすると、スレートは選択を保持しません。ボタンを使用すると、選択を再適用するため、ボタンが異なります
手動で選択を適用して取得する必要があるので、これを行う方法は、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の問題 もご覧ください。