From 1cf4a047f46c16463118e64f32530f788d63c13c Mon Sep 17 00:00:00 2001 From: Clauderic Demers Date: Thu, 13 May 2021 09:46:05 -0400 Subject: [PATCH] Grouping connected pieces of logic together --- .../components/android/android-editable.tsx | 59 ++++++++----------- .../android/android-input-manager.ts | 4 -- .../slate-react/src/components/editable.tsx | 7 +-- packages/slate-react/src/index.ts | 5 +- 4 files changed, 30 insertions(+), 45 deletions(-) diff --git a/packages/slate-react/src/components/android/android-editable.tsx b/packages/slate-react/src/components/android/android-editable.tsx index 9aa8e5a159..6201767033 100644 --- a/packages/slate-react/src/components/android/android-editable.tsx +++ b/packages/slate-react/src/components/android/android-editable.tsx @@ -1,11 +1,4 @@ -import React, { - useCallback, - useEffect, - useLayoutEffect, - useMemo, - useRef, - useState, -} from 'react' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Descendant, Editor, Element, Node, Range, Transforms } from 'slate' import throttle from 'lodash/throttle' import scrollIntoView from 'scroll-into-view-if-needed' @@ -86,21 +79,40 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => { [] ) - // Update element-related weak maps with the DOM element ref. + useEffect(() => { + return () => { + inputManager.onWillUnmount() + } + }, []) + + const prevValue = useRef([]) + + // To-do: updating refs during render phase will eventually be unusafe + // in future versions of React https://github.com/facebook/react/pull/18545 + if (prevValue.current !== editor.children) { + inputManager.onRender() + prevValue.current = editor.children + } + + // Whenever the editor updates... useIsomorphicLayoutEffect(() => { + // Update element-related weak maps with the DOM element ref. let window if (ref.current && (window = getDefaultView(ref.current))) { EDITOR_TO_WINDOW.set(editor, window) EDITOR_TO_ELEMENT.set(editor, ref.current) NODE_TO_ELEMENT.set(editor, ref.current) ELEMENT_TO_NODE.set(ref.current, editor) + EDITOR_TO_RESTORE_DOM.set(editor, onRestoreDOM) } else { NODE_TO_ELEMENT.delete(editor) + EDITOR_TO_RESTORE_DOM.delete(editor) } - }) - // Whenever the editor updates, make sure the DOM selection state is in sync. - useIsomorphicLayoutEffect(() => { + // Let the input manager know that the editor has re-rendered + inputManager.onDidUpdate() + + // Make sure the DOM selection state is in sync. const { selection } = editor const root = ReactEditor.findDocumentOrShadowRoot(editor) const domSelection = root.getSelection() @@ -188,23 +200,6 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => { }) }) - useLayoutEffect(() => { - inputManager.onDidMount() - return () => { - inputManager.onWillUnmount() - } - }, []) - - const prevValue = useRef([]) - if (prevValue.current !== editor.children) { - inputManager.onRender() - prevValue.current = editor.children - } - - useLayoutEffect(() => { - inputManager.onDidUpdate() - }) - // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it // needs to be manually focused. useEffect(() => { @@ -301,12 +296,6 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => { const onRestoreDOM = useCallback(() => { setContentKey(prev => prev + 1) }, [contentKey]) - EDITOR_TO_RESTORE_DOM.set(editor, onRestoreDOM) - useEffect(() => { - return () => { - EDITOR_TO_RESTORE_DOM.delete(editor) - } - }, []) return ( diff --git a/packages/slate-react/src/components/android/android-input-manager.ts b/packages/slate-react/src/components/android/android-input-manager.ts index 972b264b9b..73e265a1c6 100644 --- a/packages/slate-react/src/components/android/android-input-manager.ts +++ b/packages/slate-react/src/components/android/android-input-manager.ts @@ -106,10 +106,6 @@ export class AndroidInputManager { this.observer = new MutationObserver(this.flush) } - onDidMount = () => { - this.connect() - } - onDidUpdate = () => { this.connect() } diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index b2fe5139c1..50d9d8e530 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -138,8 +138,9 @@ export const Editable = (props: EditableProps) => { [] ) - // Update element-related weak maps with the DOM element ref. + // Whenever the editor updates... useIsomorphicLayoutEffect(() => { + // Update element-related weak maps with the DOM element ref. let window if (ref.current && (window = getDefaultView(ref.current))) { EDITOR_TO_WINDOW.set(editor, window) @@ -149,10 +150,8 @@ export const Editable = (props: EditableProps) => { } else { NODE_TO_ELEMENT.delete(editor) } - }) - // Whenever the editor updates, make sure the DOM selection state is in sync. - useIsomorphicLayoutEffect(() => { + // Make sure the DOM selection state is in sync. const { selection } = editor const root = ReactEditor.findDocumentOrShadowRoot(editor) const domSelection = root.getSelection() diff --git a/packages/slate-react/src/index.ts b/packages/slate-react/src/index.ts index 4297ffecc8..7c518c087e 100644 --- a/packages/slate-react/src/index.ts +++ b/packages/slate-react/src/index.ts @@ -4,12 +4,15 @@ import { Editable as DefaultEditable } from './components/editable' import { AndroidEditableNoError as AndroidEditable } from './components/android/android-editable' import { IS_ANDROID } from './utils/environment' +export const Editable = IS_ANDROID ? AndroidEditable : DefaultEditable export { + Editable as DefaultEditable, RenderElementProps, RenderLeafProps, RenderPlaceholderProps, DefaultPlaceholder, } from './components/editable' +export { AndroidEditableNoError as AndroidEditable } from './components/android/android-editable' export { DefaultElement } from './components/element' export { DefaultLeaf } from './components/leaf' export { Slate } from './components/slate' @@ -25,5 +28,3 @@ export { useSlate } from './hooks/use-slate' // Plugin export { ReactEditor } from './plugin/react-editor' export { withReact } from './plugin/with-react' -export const Editable = !IS_ANDROID ? DefaultEditable : AndroidEditable -export { DefaultEditable, AndroidEditable }