1
0
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:
Per-Kristian Nordnes 2021-08-25 15:59:23 +02:00 committed by GitHub
parent 781b7f795c
commit c1433f56cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 10 deletions

View File

@ -0,0 +1,5 @@
---
'slate-react': patch
---
[slate-react]: fix selection bugs when multiple editors share value

View File

@ -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)
}
})

View File

@ -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)
}
})

View File

@ -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(

View File

@ -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)

View File

@ -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.