Skip to content

Instantly share code, notes, and snippets.

@Krisztiaan
Created August 5, 2020 13:20
Show Gist options
  • Save Krisztiaan/d8cd7418eaf605f3908823cf307d6473 to your computer and use it in GitHub Desktop.
Save Krisztiaan/d8cd7418eaf605f3908823cf307d6473 to your computer and use it in GitHub Desktop.
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