Skip to content

Commit

Permalink
use useRef for androidInputManager in editable.tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
aciccarello committed Mar 16, 2023
1 parent 19f7ee2 commit 9426621
Showing 1 changed file with 26 additions and 17 deletions.
43 changes: 26 additions & 17 deletions packages/slate-react/src/components/editable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,15 @@ export const Editable = (props: EditableProps) => {
}
}, [autoFocus])

let androidInputManager: AndroidInputManager | null | undefined
/**
* The AndroidInputManager object has a cyclical dependency on onDOMSelectionChange
*
* It is defined as a reference to simplify hook dependencies and clarify that
* it needs to be initialized.
*/
const androidInputManagerRef = useRef<
AndroidInputManager | null | undefined
>()

// Listen on the native `selectionchange` event to be able to update any time
// the selection changes. This is required because React's `onSelect` is leaky
Expand All @@ -192,6 +200,7 @@ export const Editable = (props: EditableProps) => {
const onDOMSelectionChange = useMemo(
() =>
throttle(() => {
const androidInputManager = androidInputManagerRef.current
if (
(IS_ANDROID || !ReactEditor.isComposing(editor)) &&
(!state.isUpdatingSelection || androidInputManager?.isFlushing()) &&
Expand Down Expand Up @@ -248,15 +257,15 @@ export const Editable = (props: EditableProps) => {
}
}
}, 100),
[androidInputManager, editor, readOnly, state]
[editor, readOnly, state]
)

const scheduleOnDOMSelectionChange = useMemo(
() => debounce(onDOMSelectionChange, 0),
[onDOMSelectionChange]
)

androidInputManager = useAndroidInputManager({
androidInputManagerRef.current = useAndroidInputManager({
node: ref,
onDOMSelectionChange,
scheduleOnDOMSelectionChange,
Expand All @@ -282,7 +291,7 @@ export const Editable = (props: EditableProps) => {
if (
!domSelection ||
!ReactEditor.isFocused(editor) ||
androidInputManager?.hasPendingAction()
androidInputManagerRef.current?.hasPendingAction()
) {
return
}
Expand Down Expand Up @@ -380,7 +389,8 @@ export const Editable = (props: EditableProps) => {
}

const newDomRange = setDomSelection()
const ensureSelection = androidInputManager?.isFlushing() === 'action'
const ensureSelection =
androidInputManagerRef.current?.isFlushing() === 'action'

if (!IS_ANDROID || !ensureSelection) {
setTimeout(() => {
Expand Down Expand Up @@ -448,8 +458,8 @@ export const Editable = (props: EditableProps) => {
!isDOMEventHandled(event, propsOnDOMBeforeInput)
) {
// COMPAT: BeforeInput events aren't cancelable on android, so we have to handle them differently using the android input manager.
if (androidInputManager) {
return androidInputManager.handleDOMBeforeInput(event)
if (androidInputManagerRef.current) {
return androidInputManagerRef.current.handleDOMBeforeInput(event)
}

// Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
Expand Down Expand Up @@ -704,7 +714,6 @@ export const Editable = (props: EditableProps) => {
}
},
[
androidInputManager,
editor,
onDOMSelectionChange,
onUserInput,
Expand Down Expand Up @@ -924,8 +933,8 @@ export const Editable = (props: EditableProps) => {
return
}

if (androidInputManager) {
androidInputManager.handleInput()
if (androidInputManagerRef.current) {
androidInputManagerRef.current.handleInput()
return
}

Expand All @@ -938,7 +947,7 @@ export const Editable = (props: EditableProps) => {
}
deferredOperations.current = []
},
[androidInputManager, attributes.onInput]
[attributes.onInput]
)}
onBlur={useCallback(
(event: React.FocusEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -1081,7 +1090,7 @@ export const Editable = (props: EditableProps) => {
IS_COMPOSING.set(editor, false)
}

androidInputManager?.handleCompositionEnd(event)
androidInputManagerRef.current?.handleCompositionEnd(event)

if (
isEventHandled(event, attributes.onCompositionEnd) ||
Expand Down Expand Up @@ -1123,7 +1132,7 @@ export const Editable = (props: EditableProps) => {
}
}
},
[androidInputManager, attributes.onCompositionEnd, editor]
[attributes.onCompositionEnd, editor]
)}
onCompositionUpdate={useCallback(
(event: React.CompositionEvent<HTMLDivElement>) => {
Expand All @@ -1142,7 +1151,7 @@ export const Editable = (props: EditableProps) => {
onCompositionStart={useCallback(
(event: React.CompositionEvent<HTMLDivElement>) => {
if (ReactEditor.hasSelectableTarget(editor, event.target)) {
androidInputManager?.handleCompositionStart(event)
androidInputManagerRef.current?.handleCompositionStart(event)

if (
isEventHandled(event, attributes.onCompositionStart) ||
Expand Down Expand Up @@ -1177,7 +1186,7 @@ export const Editable = (props: EditableProps) => {
}
}
},
[androidInputManager, attributes.onCompositionStart, editor]
[attributes.onCompositionStart, editor]
)}
onCopy={useCallback(
(event: React.ClipboardEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -1365,7 +1374,7 @@ export const Editable = (props: EditableProps) => {
!readOnly &&
ReactEditor.hasEditableTarget(editor, event.target)
) {
androidInputManager?.handleKeyDown(event)
androidInputManagerRef.current?.handleKeyDown(event)

const { nativeEvent } = event

Expand Down Expand Up @@ -1632,7 +1641,7 @@ export const Editable = (props: EditableProps) => {
}
}
},
[readOnly, editor, androidInputManager, attributes.onKeyDown]
[readOnly, editor, attributes.onKeyDown]
)}
onPaste={useCallback(
(event: React.ClipboardEvent<HTMLDivElement>) => {
Expand Down

0 comments on commit 9426621

Please sign in to comment.