mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-20 05:11:53 +02:00
[slate-react]: fix selection bugs when multiple editors share value (#4475)
* [slate-react]: fix selection bugs when multiple editors share value The KEY_TO_ELEMENT weakmap must be scoped to the instance to avoid collisions between multiple editors. This is solved by wrapping it in another WeakMap keyed on the editor object, that returns the KEY_TO_ELEMENT Weakmap for that editor. * Add changeset Co-authored-by: Dylan Schiemann <dylan@dojotoolkit.org>
This commit is contained in:
parent
781b7f795c
commit
c1433f56cf
5
.changeset/calm-books-applaud.md
Normal file
5
.changeset/calm-books-applaud.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'slate-react': patch
|
||||
---
|
||||
|
||||
[slate-react]: fix selection bugs when multiple editors share value
|
@ -11,7 +11,7 @@ import {
|
||||
ELEMENT_TO_NODE,
|
||||
NODE_TO_PARENT,
|
||||
NODE_TO_INDEX,
|
||||
KEY_TO_ELEMENT,
|
||||
EDITOR_TO_KEY_TO_ELEMENT,
|
||||
} from '../utils/weak-maps'
|
||||
import { isDecoratorRangeListEqual } from '../utils/range-list'
|
||||
import {
|
||||
@ -120,12 +120,13 @@ const Element = (props: {
|
||||
|
||||
// Update element-related weak maps with the DOM element ref.
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor)
|
||||
if (ref.current) {
|
||||
KEY_TO_ELEMENT.set(key, ref.current)
|
||||
KEY_TO_ELEMENT?.set(key, ref.current)
|
||||
NODE_TO_ELEMENT.set(element, ref.current)
|
||||
ELEMENT_TO_NODE.set(ref.current, element)
|
||||
} else {
|
||||
KEY_TO_ELEMENT.delete(key)
|
||||
KEY_TO_ELEMENT?.delete(key)
|
||||
NODE_TO_ELEMENT.delete(element)
|
||||
}
|
||||
})
|
||||
|
@ -6,9 +6,9 @@ import { ReactEditor, useSlateStatic } from '..'
|
||||
import { RenderLeafProps, RenderPlaceholderProps } from './editable'
|
||||
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
||||
import {
|
||||
KEY_TO_ELEMENT,
|
||||
NODE_TO_ELEMENT,
|
||||
ELEMENT_TO_NODE,
|
||||
EDITOR_TO_KEY_TO_ELEMENT,
|
||||
} from '../utils/weak-maps'
|
||||
import { isDecoratorRangeListEqual } from '../utils/range-list'
|
||||
|
||||
@ -56,12 +56,13 @@ const Text = (props: {
|
||||
|
||||
// Update element-related weak maps with the DOM element ref.
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor)
|
||||
if (ref.current) {
|
||||
KEY_TO_ELEMENT.set(key, ref.current)
|
||||
KEY_TO_ELEMENT?.set(key, ref.current)
|
||||
NODE_TO_ELEMENT.set(text, ref.current)
|
||||
ELEMENT_TO_NODE.set(ref.current, text)
|
||||
} else {
|
||||
KEY_TO_ELEMENT.delete(key)
|
||||
KEY_TO_ELEMENT?.delete(key)
|
||||
NODE_TO_ELEMENT.delete(text)
|
||||
}
|
||||
})
|
||||
|
@ -6,11 +6,11 @@ import {
|
||||
ELEMENT_TO_NODE,
|
||||
IS_FOCUSED,
|
||||
IS_READ_ONLY,
|
||||
KEY_TO_ELEMENT,
|
||||
NODE_TO_INDEX,
|
||||
NODE_TO_KEY,
|
||||
NODE_TO_PARENT,
|
||||
EDITOR_TO_WINDOW,
|
||||
EDITOR_TO_KEY_TO_ELEMENT,
|
||||
} from '../utils/weak-maps'
|
||||
import {
|
||||
DOMElement,
|
||||
@ -241,9 +241,10 @@ export const ReactEditor = {
|
||||
*/
|
||||
|
||||
toDOMNode(editor: ReactEditor, node: Node): HTMLElement {
|
||||
const KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor)
|
||||
const domNode = Editor.isEditor(node)
|
||||
? EDITOR_TO_ELEMENT.get(editor)
|
||||
: KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node))
|
||||
: KEY_TO_ELEMENT?.get(ReactEditor.findKey(editor, node))
|
||||
|
||||
if (!domNode) {
|
||||
throw new Error(
|
||||
|
@ -3,7 +3,11 @@ import { Editor, Node, Path, Operation, Transforms, Range } from 'slate'
|
||||
|
||||
import { ReactEditor } from './react-editor'
|
||||
import { Key } from '../utils/key'
|
||||
import { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'
|
||||
import {
|
||||
EDITOR_TO_KEY_TO_ELEMENT,
|
||||
EDITOR_TO_ON_CHANGE,
|
||||
NODE_TO_KEY,
|
||||
} from '../utils/weak-maps'
|
||||
import {
|
||||
AS_NATIVE,
|
||||
NATIVE_OPERATIONS,
|
||||
@ -29,6 +33,10 @@ export const withReact = <T extends Editor>(editor: T) => {
|
||||
const e = editor as T & ReactEditor
|
||||
const { apply, onChange, deleteBackward } = e
|
||||
|
||||
// The WeakMap which maps a key to a specific HTMLElement must be scoped to the editor instance to
|
||||
// avoid collisions between editors in the DOM that share the same value.
|
||||
EDITOR_TO_KEY_TO_ELEMENT.set(e, new WeakMap())
|
||||
|
||||
e.deleteBackward = unit => {
|
||||
if (unit !== 'line') {
|
||||
return deleteBackward(unit)
|
||||
|
@ -18,9 +18,12 @@ export const EDITOR_TO_WINDOW: WeakMap<Editor, Window> = new WeakMap()
|
||||
export const EDITOR_TO_ELEMENT: WeakMap<Editor, HTMLElement> = new WeakMap()
|
||||
export const EDITOR_TO_PLACEHOLDER: WeakMap<Editor, string> = new WeakMap()
|
||||
export const ELEMENT_TO_NODE: WeakMap<HTMLElement, Node> = new WeakMap()
|
||||
export const KEY_TO_ELEMENT: WeakMap<Key, HTMLElement> = new WeakMap()
|
||||
export const NODE_TO_ELEMENT: WeakMap<Node, HTMLElement> = new WeakMap()
|
||||
export const NODE_TO_KEY: WeakMap<Node, Key> = new WeakMap()
|
||||
export const EDITOR_TO_KEY_TO_ELEMENT: WeakMap<
|
||||
Editor,
|
||||
WeakMap<Key, HTMLElement>
|
||||
> = new WeakMap()
|
||||
|
||||
/**
|
||||
* Weak maps for storing editor-related state.
|
||||
|
Loading…
x
Reference in New Issue
Block a user