Created
August 5, 2020 13:20
-
-
Save Krisztiaan/d8cd7418eaf605f3908823cf307d6473 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useContext, useEffect, useState, useCallback } from 'react'; | |
import { TouchableWithoutFeedbackProps } from 'react-native'; | |
import useDelayedState from './useDelayedState'; | |
const FocusChangeContext = React.createContext<(isFocused: boolean, instant?: boolean) => void>( | |
() => undefined | |
); | |
const HasFocusContext = React.createContext<boolean>(false); | |
const FOCUS_BLUR_DELAY = 100; | |
export function FocusableTree( | |
props: React.PropsWithChildren<{ onFocusChange: (isFocused: boolean) => void }> | |
) { | |
const setHasFocusParent = useContext(FocusChangeContext); | |
const { onFocusChange, ...rest } = props; | |
const [hasFocus, setHasFocus] = useDelayedState(false, FOCUS_BLUR_DELAY); | |
useEffect(() => { | |
onFocusChange(hasFocus); | |
setHasFocusParent(hasFocus, true); | |
}, [hasFocus, onFocusChange, setHasFocusParent]); | |
return ( | |
<HasFocusContext.Provider value={hasFocus}> | |
<FocusChangeContext.Provider value={setHasFocus} {...rest} /> | |
</HasFocusContext.Provider> | |
); | |
} | |
export function useTreeHasFocus() { | |
return useContext(HasFocusContext); | |
} | |
type FocusBlurProps = Required<Pick<TouchableWithoutFeedbackProps, 'onFocus' | 'onBlur'>>; | |
export default function useFocusableChild<T extends Partial<FocusBlurProps> | undefined>( | |
originalProps: T | |
//todo: TS4 label this touple | |
): [T | FocusBlurProps, boolean] { | |
const setHasFocus = useContext(FocusChangeContext); | |
const [isFocused, setIsFocused] = useState(false); | |
useEffect(() => setHasFocus(isFocused), [isFocused, setHasFocus]); | |
const onFocus = useCallback<FocusBlurProps['onFocus']>( | |
(e) => { | |
setIsFocused(true); | |
originalProps?.onFocus?.(e); | |
}, | |
[setIsFocused, originalProps?.onFocus] | |
); | |
const onBlur = useCallback<FocusBlurProps['onBlur']>( | |
(e) => { | |
setIsFocused(false); | |
originalProps?.onBlur?.(e); | |
}, | |
[setIsFocused, originalProps?.onBlur] | |
); | |
return [{ ...originalProps, onFocus, onBlur }, isFocused]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment