mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-12 02:03:59 +02:00
enable eslint hooks rules (#5363)
This commit is contained in:
committed by
GitHub
parent
556a4565d2
commit
d42cd005db
11
.changeset/shaggy-donuts-applaud.md
Normal file
11
.changeset/shaggy-donuts-applaud.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
'slate-react': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
update dependencies on react hooks to be more senstive to changes
|
||||||
|
|
||||||
|
The code should now meet eslint react hook standards
|
||||||
|
|
||||||
|
This could result in more renders
|
||||||
|
|
||||||
|
closes #3886
|
@@ -4,7 +4,8 @@
|
|||||||
"plugin:import/typescript",
|
"plugin:import/typescript",
|
||||||
"prettier",
|
"prettier",
|
||||||
"prettier/@typescript-eslint",
|
"prettier/@typescript-eslint",
|
||||||
"prettier/react"
|
"prettier/react",
|
||||||
|
"plugin:react-hooks/recommended"
|
||||||
],
|
],
|
||||||
"plugins": ["@typescript-eslint", "import", "react", "prettier"],
|
"plugins": ["@typescript-eslint", "import", "react", "prettier"],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
"settings": {
|
"settings": {
|
||||||
"import/extensions": [".js", ".ts", ".jsx", ".tsx"],
|
"import/extensions": [".js", ".ts", ".jsx", ".tsx"],
|
||||||
"react": {
|
"react": {
|
||||||
"version": "detect"
|
"version": "16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
|
@@ -74,6 +74,7 @@
|
|||||||
"eslint-plugin-import": "^2.18.2",
|
"eslint-plugin-import": "^2.18.2",
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
"eslint-plugin-prettier": "^3.1.1",
|
||||||
"eslint-plugin-react": "^7.16.0",
|
"eslint-plugin-react": "^7.16.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"faker": "^4.1.0",
|
"faker": "^4.1.0",
|
||||||
"image-extensions": "^1.1.0",
|
"image-extensions": "^1.1.0",
|
||||||
"is-hotkey": "^0.1.6",
|
"is-hotkey": "^0.1.6",
|
||||||
|
@@ -69,6 +69,7 @@ import {
|
|||||||
import { RestoreDOM } from './restore-dom/restore-dom'
|
import { RestoreDOM } from './restore-dom/restore-dom'
|
||||||
import { useAndroidInputManager } from '../hooks/android-input-manager/use-android-input-manager'
|
import { useAndroidInputManager } from '../hooks/android-input-manager/use-android-input-manager'
|
||||||
import { useTrackUserInput } from '../hooks/use-track-user-input'
|
import { useTrackUserInput } from '../hooks/use-track-user-input'
|
||||||
|
import { AndroidInputManager } from '../hooks/android-input-manager/android-input-manager'
|
||||||
|
|
||||||
type DeferredOperation = () => void
|
type DeferredOperation = () => void
|
||||||
|
|
||||||
@@ -181,13 +182,25 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}, [autoFocus])
|
}, [autoFocus])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
// 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
|
// the selection changes. This is required because React's `onSelect` is leaky
|
||||||
// and non-standard so it doesn't fire until after a selection has been
|
// and non-standard so it doesn't fire until after a selection has been
|
||||||
// released. This causes issues in situations where another change happens
|
// released. This causes issues in situations where another change happens
|
||||||
// while a selection is being dragged.
|
// while a selection is being dragged.
|
||||||
const onDOMSelectionChange = useCallback(
|
const onDOMSelectionChange = useMemo(
|
||||||
|
() =>
|
||||||
throttle(() => {
|
throttle(() => {
|
||||||
|
const androidInputManager = androidInputManagerRef.current
|
||||||
if (
|
if (
|
||||||
(IS_ANDROID || !ReactEditor.isComposing(editor)) &&
|
(IS_ANDROID || !ReactEditor.isComposing(editor)) &&
|
||||||
(!state.isUpdatingSelection || androidInputManager?.isFlushing()) &&
|
(!state.isUpdatingSelection || androidInputManager?.isFlushing()) &&
|
||||||
@@ -244,7 +257,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100),
|
}, 100),
|
||||||
[readOnly]
|
[editor, readOnly, state]
|
||||||
)
|
)
|
||||||
|
|
||||||
const scheduleOnDOMSelectionChange = useMemo(
|
const scheduleOnDOMSelectionChange = useMemo(
|
||||||
@@ -252,7 +265,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
[onDOMSelectionChange]
|
[onDOMSelectionChange]
|
||||||
)
|
)
|
||||||
|
|
||||||
const androidInputManager = useAndroidInputManager({
|
androidInputManagerRef.current = useAndroidInputManager({
|
||||||
node: ref,
|
node: ref,
|
||||||
onDOMSelectionChange,
|
onDOMSelectionChange,
|
||||||
scheduleOnDOMSelectionChange,
|
scheduleOnDOMSelectionChange,
|
||||||
@@ -278,7 +291,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
if (
|
if (
|
||||||
!domSelection ||
|
!domSelection ||
|
||||||
!ReactEditor.isFocused(editor) ||
|
!ReactEditor.isFocused(editor) ||
|
||||||
androidInputManager?.hasPendingAction()
|
androidInputManagerRef.current?.hasPendingAction()
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -376,7 +389,8 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newDomRange = setDomSelection()
|
const newDomRange = setDomSelection()
|
||||||
const ensureSelection = androidInputManager?.isFlushing() === 'action'
|
const ensureSelection =
|
||||||
|
androidInputManagerRef.current?.isFlushing() === 'action'
|
||||||
|
|
||||||
if (!IS_ANDROID || !ensureSelection) {
|
if (!IS_ANDROID || !ensureSelection) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -444,8 +458,8 @@ export const Editable = (props: EditableProps) => {
|
|||||||
!isDOMEventHandled(event, propsOnDOMBeforeInput)
|
!isDOMEventHandled(event, propsOnDOMBeforeInput)
|
||||||
) {
|
) {
|
||||||
// COMPAT: BeforeInput events aren't cancelable on android, so we have to handle them differently using the android input manager.
|
// COMPAT: BeforeInput events aren't cancelable on android, so we have to handle them differently using the android input manager.
|
||||||
if (androidInputManager) {
|
if (androidInputManagerRef.current) {
|
||||||
return androidInputManager.handleDOMBeforeInput(event)
|
return androidInputManagerRef.current.handleDOMBeforeInput(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
|
// Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
|
||||||
@@ -699,7 +713,14 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, propsOnDOMBeforeInput]
|
[
|
||||||
|
editor,
|
||||||
|
onDOMSelectionChange,
|
||||||
|
onUserInput,
|
||||||
|
propsOnDOMBeforeInput,
|
||||||
|
readOnly,
|
||||||
|
scheduleOnDOMSelectionChange,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
const callbackRef = useCallback(
|
const callbackRef = useCallback(
|
||||||
@@ -728,7 +749,12 @@ export const Editable = (props: EditableProps) => {
|
|||||||
|
|
||||||
ref.current = node
|
ref.current = node
|
||||||
},
|
},
|
||||||
[ref, onDOMBeforeInput, onDOMSelectionChange, scheduleOnDOMSelectionChange]
|
[
|
||||||
|
onDOMSelectionChange,
|
||||||
|
scheduleOnDOMSelectionChange,
|
||||||
|
editor,
|
||||||
|
onDOMBeforeInput,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Attach a native DOM event handler for `selectionchange`, because React's
|
// Attach a native DOM event handler for `selectionchange`, because React's
|
||||||
@@ -899,15 +925,16 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly]
|
[attributes.onBeforeInput, editor, readOnly]
|
||||||
)}
|
)}
|
||||||
onInput={useCallback((event: React.FormEvent<HTMLDivElement>) => {
|
onInput={useCallback(
|
||||||
|
(event: React.FormEvent<HTMLDivElement>) => {
|
||||||
if (isEventHandled(event, attributes.onInput)) {
|
if (isEventHandled(event, attributes.onInput)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (androidInputManager) {
|
if (androidInputManagerRef.current) {
|
||||||
androidInputManager.handleInput()
|
androidInputManagerRef.current.handleInput()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -919,7 +946,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
op()
|
op()
|
||||||
}
|
}
|
||||||
deferredOperations.current = []
|
deferredOperations.current = []
|
||||||
}, [])}
|
},
|
||||||
|
[attributes.onInput]
|
||||||
|
)}
|
||||||
onBlur={useCallback(
|
onBlur={useCallback(
|
||||||
(event: React.FocusEvent<HTMLDivElement>) => {
|
(event: React.FocusEvent<HTMLDivElement>) => {
|
||||||
if (
|
if (
|
||||||
@@ -984,7 +1013,13 @@ export const Editable = (props: EditableProps) => {
|
|||||||
|
|
||||||
IS_FOCUSED.delete(editor)
|
IS_FOCUSED.delete(editor)
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onBlur]
|
[
|
||||||
|
readOnly,
|
||||||
|
state.isUpdatingSelection,
|
||||||
|
state.latestElement,
|
||||||
|
editor,
|
||||||
|
attributes.onBlur,
|
||||||
|
]
|
||||||
)}
|
)}
|
||||||
onClick={useCallback(
|
onClick={useCallback(
|
||||||
(event: React.MouseEvent<HTMLDivElement>) => {
|
(event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
@@ -1045,7 +1080,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onClick]
|
[editor, attributes.onClick, readOnly]
|
||||||
)}
|
)}
|
||||||
onCompositionEnd={useCallback(
|
onCompositionEnd={useCallback(
|
||||||
(event: React.CompositionEvent<HTMLDivElement>) => {
|
(event: React.CompositionEvent<HTMLDivElement>) => {
|
||||||
@@ -1055,7 +1090,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
IS_COMPOSING.set(editor, false)
|
IS_COMPOSING.set(editor, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
androidInputManager?.handleCompositionEnd(event)
|
androidInputManagerRef.current?.handleCompositionEnd(event)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isEventHandled(event, attributes.onCompositionEnd) ||
|
isEventHandled(event, attributes.onCompositionEnd) ||
|
||||||
@@ -1097,7 +1132,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[attributes.onCompositionEnd]
|
[attributes.onCompositionEnd, editor]
|
||||||
)}
|
)}
|
||||||
onCompositionUpdate={useCallback(
|
onCompositionUpdate={useCallback(
|
||||||
(event: React.CompositionEvent<HTMLDivElement>) => {
|
(event: React.CompositionEvent<HTMLDivElement>) => {
|
||||||
@@ -1111,12 +1146,12 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[attributes.onCompositionUpdate]
|
[attributes.onCompositionUpdate, editor]
|
||||||
)}
|
)}
|
||||||
onCompositionStart={useCallback(
|
onCompositionStart={useCallback(
|
||||||
(event: React.CompositionEvent<HTMLDivElement>) => {
|
(event: React.CompositionEvent<HTMLDivElement>) => {
|
||||||
if (ReactEditor.hasSelectableTarget(editor, event.target)) {
|
if (ReactEditor.hasSelectableTarget(editor, event.target)) {
|
||||||
androidInputManager?.handleCompositionStart(event)
|
androidInputManagerRef.current?.handleCompositionStart(event)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isEventHandled(event, attributes.onCompositionStart) ||
|
isEventHandled(event, attributes.onCompositionStart) ||
|
||||||
@@ -1151,7 +1186,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[attributes.onCompositionStart]
|
[attributes.onCompositionStart, editor]
|
||||||
)}
|
)}
|
||||||
onCopy={useCallback(
|
onCopy={useCallback(
|
||||||
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
||||||
@@ -1168,7 +1203,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[attributes.onCopy]
|
[attributes.onCopy, editor]
|
||||||
)}
|
)}
|
||||||
onCut={useCallback(
|
onCut={useCallback(
|
||||||
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
||||||
@@ -1198,7 +1233,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onCut]
|
[readOnly, editor, attributes.onCut]
|
||||||
)}
|
)}
|
||||||
onDragOver={useCallback(
|
onDragOver={useCallback(
|
||||||
(event: React.DragEvent<HTMLDivElement>) => {
|
(event: React.DragEvent<HTMLDivElement>) => {
|
||||||
@@ -1216,7 +1251,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[attributes.onDragOver]
|
[attributes.onDragOver, editor]
|
||||||
)}
|
)}
|
||||||
onDragStart={useCallback(
|
onDragStart={useCallback(
|
||||||
(event: React.DragEvent<HTMLDivElement>) => {
|
(event: React.DragEvent<HTMLDivElement>) => {
|
||||||
@@ -1247,7 +1282,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onDragStart]
|
[readOnly, editor, attributes.onDragStart, state]
|
||||||
)}
|
)}
|
||||||
onDrop={useCallback(
|
onDrop={useCallback(
|
||||||
(event: React.DragEvent<HTMLDivElement>) => {
|
(event: React.DragEvent<HTMLDivElement>) => {
|
||||||
@@ -1290,7 +1325,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
|
|
||||||
state.isDraggingInternally = false
|
state.isDraggingInternally = false
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onDrop]
|
[readOnly, editor, attributes.onDrop, state]
|
||||||
)}
|
)}
|
||||||
onDragEnd={useCallback(
|
onDragEnd={useCallback(
|
||||||
(event: React.DragEvent<HTMLDivElement>) => {
|
(event: React.DragEvent<HTMLDivElement>) => {
|
||||||
@@ -1308,7 +1343,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// Note: `onDragEnd` is only called when `onDrop` is not called
|
// Note: `onDragEnd` is only called when `onDrop` is not called
|
||||||
state.isDraggingInternally = false
|
state.isDraggingInternally = false
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onDragEnd]
|
[readOnly, state, attributes, editor]
|
||||||
)}
|
)}
|
||||||
onFocus={useCallback(
|
onFocus={useCallback(
|
||||||
(event: React.FocusEvent<HTMLDivElement>) => {
|
(event: React.FocusEvent<HTMLDivElement>) => {
|
||||||
@@ -1333,7 +1368,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
IS_FOCUSED.set(editor, true)
|
IS_FOCUSED.set(editor, true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onFocus]
|
[readOnly, state, editor, attributes.onFocus]
|
||||||
)}
|
)}
|
||||||
onKeyDown={useCallback(
|
onKeyDown={useCallback(
|
||||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
@@ -1341,7 +1376,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
!readOnly &&
|
!readOnly &&
|
||||||
ReactEditor.hasEditableTarget(editor, event.target)
|
ReactEditor.hasEditableTarget(editor, event.target)
|
||||||
) {
|
) {
|
||||||
androidInputManager?.handleKeyDown(event)
|
androidInputManagerRef.current?.handleKeyDown(event)
|
||||||
|
|
||||||
const { nativeEvent } = event
|
const { nativeEvent } = event
|
||||||
|
|
||||||
@@ -1608,7 +1643,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onKeyDown]
|
[readOnly, editor, attributes.onKeyDown]
|
||||||
)}
|
)}
|
||||||
onPaste={useCallback(
|
onPaste={useCallback(
|
||||||
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
||||||
@@ -1634,7 +1669,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[readOnly, attributes.onPaste]
|
[readOnly, editor, attributes.onPaste]
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Children
|
<Children
|
||||||
|
@@ -83,7 +83,7 @@ const Leaf = (props: {
|
|||||||
return () => {
|
return () => {
|
||||||
EDITOR_TO_PLACEHOLDER_ELEMENT.delete(editor)
|
EDITOR_TO_PLACEHOLDER_ELEMENT.delete(editor)
|
||||||
}
|
}
|
||||||
}, [placeholderRef, leaf])
|
}, [placeholderRef, leaf, editor])
|
||||||
|
|
||||||
let children = (
|
let children = (
|
||||||
<String isLast={isLast} leaf={leaf} parent={parent} text={text} />
|
<String isLast={isLast} leaf={leaf} parent={parent} text={text} />
|
||||||
|
@@ -5,7 +5,7 @@ import { FocusedContext } from '../hooks/use-focused'
|
|||||||
import { EditorContext } from '../hooks/use-slate-static'
|
import { EditorContext } from '../hooks/use-slate-static'
|
||||||
import { SlateContext, SlateContextValue } from '../hooks/use-slate'
|
import { SlateContext, SlateContextValue } from '../hooks/use-slate'
|
||||||
import {
|
import {
|
||||||
getSelectorContext,
|
useSelectorContext,
|
||||||
SlateSelectorContext,
|
SlateSelectorContext,
|
||||||
} from '../hooks/use-slate-selector'
|
} from '../hooks/use-slate-selector'
|
||||||
import { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'
|
import { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'
|
||||||
@@ -47,7 +47,7 @@ export const Slate = (props: {
|
|||||||
const {
|
const {
|
||||||
selectorContext,
|
selectorContext,
|
||||||
onChange: handleSelectorChange,
|
onChange: handleSelectorChange,
|
||||||
} = getSelectorContext(editor)
|
} = useSelectorContext(editor)
|
||||||
|
|
||||||
const onContextChange = useCallback(() => {
|
const onContextChange = useCallback(() => {
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
@@ -59,7 +59,7 @@ export const Slate = (props: {
|
|||||||
editor,
|
editor,
|
||||||
}))
|
}))
|
||||||
handleSelectorChange(editor)
|
handleSelectorChange(editor)
|
||||||
}, [onChange])
|
}, [editor, handleSelectorChange, onChange])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
EDITOR_TO_ON_CHANGE.set(editor, onContextChange)
|
EDITOR_TO_ON_CHANGE.set(editor, onContextChange)
|
||||||
@@ -68,13 +68,13 @@ export const Slate = (props: {
|
|||||||
EDITOR_TO_ON_CHANGE.set(editor, () => {})
|
EDITOR_TO_ON_CHANGE.set(editor, () => {})
|
||||||
unmountRef.current = true
|
unmountRef.current = true
|
||||||
}
|
}
|
||||||
}, [onContextChange])
|
}, [editor, onContextChange])
|
||||||
|
|
||||||
const [isFocused, setIsFocused] = useState(ReactEditor.isFocused(editor))
|
const [isFocused, setIsFocused] = useState(ReactEditor.isFocused(editor))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsFocused(ReactEditor.isFocused(editor))
|
setIsFocused(ReactEditor.isFocused(editor))
|
||||||
})
|
}, [editor])
|
||||||
|
|
||||||
useIsomorphicLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
const fn = () => setIsFocused(ReactEditor.isFocused(editor))
|
const fn = () => setIsFocused(ReactEditor.isFocused(editor))
|
||||||
|
@@ -22,10 +22,9 @@ const MUTATION_OBSERVER_CONFIG: MutationObserverInit = {
|
|||||||
characterData: true,
|
characterData: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAndroidInputManager({
|
export const useAndroidInputManager = !IS_ANDROID
|
||||||
node,
|
? () => null
|
||||||
...options
|
: ({ node, ...options }: UseAndroidInputManagerOptions) => {
|
||||||
}: UseAndroidInputManagerOptions) {
|
|
||||||
if (!IS_ANDROID) {
|
if (!IS_ANDROID) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@@ -23,5 +23,5 @@ export function useMutationObserver(
|
|||||||
|
|
||||||
mutationObserver.observe(node.current, options)
|
mutationObserver.observe(node.current, options)
|
||||||
return () => mutationObserver.disconnect()
|
return () => mutationObserver.disconnect()
|
||||||
}, [])
|
}, [mutationObserver, node, options])
|
||||||
}
|
}
|
||||||
|
@@ -112,17 +112,22 @@ export function useSlateSelector<T>(
|
|||||||
/**
|
/**
|
||||||
* Create selector context with editor updating on every editor change
|
* Create selector context with editor updating on every editor change
|
||||||
*/
|
*/
|
||||||
export function getSelectorContext(editor: Editor) {
|
export function useSelectorContext(editor: Editor) {
|
||||||
const eventListeners = useRef<EditorChangeHandler[]>([]).current
|
const eventListeners = useRef<EditorChangeHandler[]>([]).current
|
||||||
const slateRef = useRef<{
|
const slateRef = useRef<{
|
||||||
editor: Editor
|
editor: Editor
|
||||||
}>({
|
}>({
|
||||||
editor,
|
editor,
|
||||||
}).current
|
}).current
|
||||||
const onChange = useCallback((editor: Editor) => {
|
const onChange = useCallback(
|
||||||
|
(editor: Editor) => {
|
||||||
slateRef.editor = editor
|
slateRef.editor = editor
|
||||||
eventListeners.forEach((listener: EditorChangeHandler) => listener(editor))
|
eventListeners.forEach((listener: EditorChangeHandler) =>
|
||||||
}, [])
|
listener(editor)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[eventListeners, slateRef]
|
||||||
|
)
|
||||||
|
|
||||||
const selectorContext = useMemo(() => {
|
const selectorContext = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
|
@@ -21,7 +21,7 @@ export function useTrackUserInput() {
|
|||||||
animationFrameIdRef.current = window.requestAnimationFrame(() => {
|
animationFrameIdRef.current = window.requestAnimationFrame(() => {
|
||||||
receivedUserInput.current = false
|
receivedUserInput.current = false
|
||||||
})
|
})
|
||||||
}, [])
|
}, [editor])
|
||||||
|
|
||||||
useEffect(() => () => cancelAnimationFrame(animationFrameIdRef.current), [])
|
useEffect(() => () => cancelAnimationFrame(animationFrameIdRef.current), [])
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { createEditor, Element, Transforms } from 'slate'
|
import { createEditor, Element, Transforms } from 'slate'
|
||||||
import { create, act, ReactTestRenderer } from 'react-test-renderer'
|
import { create, act, ReactTestRenderer } from 'react-test-renderer'
|
||||||
import { Slate, withReact, Editable } from '../src'
|
import { Slate, withReact, Editable } from '../src'
|
||||||
@@ -22,7 +22,7 @@ describe('slate-react', () => {
|
|||||||
test('should not unmount the node that gets split on a split_node operation', async () => {
|
test('should not unmount the node that gets split on a split_node operation', async () => {
|
||||||
const editor = withReact(createEditor())
|
const editor = withReact(createEditor())
|
||||||
const value = [{ type: 'block', children: [{ text: 'test' }] }]
|
const value = [{ type: 'block', children: [{ text: 'test' }] }]
|
||||||
const mounts = jest.fn<void, [Element]>()
|
const mounts = jest.fn()
|
||||||
|
|
||||||
let el: ReactTestRenderer
|
let el: ReactTestRenderer
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ describe('slate-react', () => {
|
|||||||
el = create(
|
el = create(
|
||||||
<Slate editor={editor} value={value} onChange={() => {}}>
|
<Slate editor={editor} value={value} onChange={() => {}}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={({ element, children }) => {
|
renderElement={({ children }) => {
|
||||||
React.useEffect(() => mounts(element), [])
|
useEffect(() => mounts(), [])
|
||||||
|
|
||||||
return children
|
return children
|
||||||
}}
|
}}
|
||||||
@@ -56,7 +56,7 @@ describe('slate-react', () => {
|
|||||||
{ type: 'block', children: [{ text: 'te' }] },
|
{ type: 'block', children: [{ text: 'te' }] },
|
||||||
{ type: 'block', children: [{ text: 'st' }] },
|
{ type: 'block', children: [{ text: 'st' }] },
|
||||||
]
|
]
|
||||||
const mounts = jest.fn<void, [Element]>()
|
const mounts = jest.fn()
|
||||||
|
|
||||||
let el: ReactTestRenderer
|
let el: ReactTestRenderer
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ describe('slate-react', () => {
|
|||||||
el = create(
|
el = create(
|
||||||
<Slate editor={editor} value={value} onChange={() => {}}>
|
<Slate editor={editor} value={value} onChange={() => {}}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={({ element, children }) => {
|
renderElement={({ children }) => {
|
||||||
React.useEffect(() => mounts(element), [])
|
useEffect(() => mounts(), [])
|
||||||
|
|
||||||
return children
|
return children
|
||||||
}}
|
}}
|
||||||
|
@@ -8,7 +8,7 @@ import 'prismjs/components/prism-python'
|
|||||||
import 'prismjs/components/prism-php'
|
import 'prismjs/components/prism-php'
|
||||||
import 'prismjs/components/prism-sql'
|
import 'prismjs/components/prism-sql'
|
||||||
import 'prismjs/components/prism-java'
|
import 'prismjs/components/prism-java'
|
||||||
import React, { useCallback, useMemo, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
createEditor,
|
createEditor,
|
||||||
Node,
|
Node,
|
||||||
@@ -51,7 +51,7 @@ const CodeHighlightingExample = () => {
|
|||||||
<SetNodeToDecorations />
|
<SetNodeToDecorations />
|
||||||
<Editable
|
<Editable
|
||||||
decorate={decorate}
|
decorate={decorate}
|
||||||
renderElement={renderElement}
|
renderElement={ElementWrapper}
|
||||||
renderLeaf={renderLeaf}
|
renderLeaf={renderLeaf}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
/>
|
/>
|
||||||
@@ -60,7 +60,7 @@ const CodeHighlightingExample = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderElement = (props: RenderElementProps) => {
|
const ElementWrapper = (props: RenderElementProps) => {
|
||||||
const { attributes, children, element } = props
|
const { attributes, children, element } = props
|
||||||
const editor = useSlateStatic()
|
const editor = useSlateStatic()
|
||||||
|
|
||||||
@@ -161,14 +161,17 @@ const renderLeaf = (props: RenderLeafProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const useDecorate = (editor: Editor) => {
|
const useDecorate = (editor: Editor) => {
|
||||||
return useCallback(([node, path]) => {
|
return useCallback(
|
||||||
|
([node, path]) => {
|
||||||
if (Element.isElement(node) && node.type === CodeLineType) {
|
if (Element.isElement(node) && node.type === CodeLineType) {
|
||||||
const ranges = editor.nodeToDecorations.get(node) || []
|
const ranges = editor.nodeToDecorations.get(node) || []
|
||||||
return ranges
|
return ranges
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
return []
|
||||||
}, [])
|
},
|
||||||
|
[editor.nodeToDecorations]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getChildNodeToDecorations = ([block, blockPath]: NodeEntry<
|
const getChildNodeToDecorations = ([block, blockPath]: NodeEntry<
|
||||||
@@ -220,7 +223,6 @@ const getChildNodeToDecorations = ([block, blockPath]: NodeEntry<
|
|||||||
const SetNodeToDecorations = () => {
|
const SetNodeToDecorations = () => {
|
||||||
const editor = useSlate()
|
const editor = useSlate()
|
||||||
|
|
||||||
useMemo(() => {
|
|
||||||
const blockEntries = Array.from(
|
const blockEntries = Array.from(
|
||||||
Editor.nodes(editor, {
|
Editor.nodes(editor, {
|
||||||
at: [],
|
at: [],
|
||||||
@@ -234,20 +236,22 @@ const SetNodeToDecorations = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
editor.nodeToDecorations = nodeToDecorations
|
editor.nodeToDecorations = nodeToDecorations
|
||||||
}, [editor.children])
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const useOnKeydown = (editor: Editor) => {
|
const useOnKeydown = (editor: Editor) => {
|
||||||
const onKeyDown: React.KeyboardEventHandler = useCallback(e => {
|
const onKeyDown: React.KeyboardEventHandler = useCallback(
|
||||||
|
e => {
|
||||||
if (isHotkey('tab', e)) {
|
if (isHotkey('tab', e)) {
|
||||||
// handle tab key, insert spaces
|
// handle tab key, insert spaces
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
Editor.insertText(editor, ' ')
|
Editor.insertText(editor, ' ')
|
||||||
}
|
}
|
||||||
}, [])
|
},
|
||||||
|
[editor]
|
||||||
|
)
|
||||||
|
|
||||||
return onKeyDown
|
return onKeyDown
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,8 @@ const MarkdownShortcutsExample = () => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleDOMBeforeInput = useCallback((e: InputEvent) => {
|
const handleDOMBeforeInput = useCallback(
|
||||||
|
(e: InputEvent) => {
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
const pendingDiffs = ReactEditor.androidPendingDiffs(editor)
|
const pendingDiffs = ReactEditor.androidPendingDiffs(editor)
|
||||||
|
|
||||||
@@ -64,7 +65,9 @@ const MarkdownShortcutsExample = () => {
|
|||||||
ReactEditor.androidScheduleFlush(editor)
|
ReactEditor.androidScheduleFlush(editor)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [])
|
},
|
||||||
|
[editor]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={initialValue}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
|
@@ -57,7 +57,7 @@ const MentionExample = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[index, search, target]
|
[chars, editor, index, target]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
10
yarn.lock
10
yarn.lock
@@ -6769,6 +6769,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"eslint-plugin-react-hooks@npm:^4.6.0":
|
||||||
|
version: 4.6.0
|
||||||
|
resolution: "eslint-plugin-react-hooks@npm:4.6.0"
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
|
||||||
|
checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"eslint-plugin-react@npm:^7.16.0":
|
"eslint-plugin-react@npm:^7.16.0":
|
||||||
version: 7.24.0
|
version: 7.24.0
|
||||||
resolution: "eslint-plugin-react@npm:7.24.0"
|
resolution: "eslint-plugin-react@npm:7.24.0"
|
||||||
@@ -13872,6 +13881,7 @@ resolve@^2.0.0-next.3:
|
|||||||
eslint-plugin-import: ^2.18.2
|
eslint-plugin-import: ^2.18.2
|
||||||
eslint-plugin-prettier: ^3.1.1
|
eslint-plugin-prettier: ^3.1.1
|
||||||
eslint-plugin-react: ^7.16.0
|
eslint-plugin-react: ^7.16.0
|
||||||
|
eslint-plugin-react-hooks: ^4.6.0
|
||||||
faker: ^4.1.0
|
faker: ^4.1.0
|
||||||
image-extensions: ^1.1.0
|
image-extensions: ^1.1.0
|
||||||
is-hotkey: ^0.1.6
|
is-hotkey: ^0.1.6
|
||||||
|
Reference in New Issue
Block a user