UNPKG

@applicaster/zapp-react-native-utils

Version:

Applicaster Zapp React Native utilities package

116 lines (94 loc) 3.05 kB
import * as React from "react"; import * as R from "ramda"; import { focusManager } from "./FocusManager"; import { NON_FOCUSABLE_COMPONENTS } from "./const"; import { useFocusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/index.android"; import { toBooleanWithDefaultTrue } from "../booleanUtils"; import { isNilOrEmpty } from "../reactUtils/helpers"; import { isAndroidTVPlatform } from "../reactUtils"; import { noop } from "../functionUtils"; export function useFocusManager() { return focusManager; } export function useInitialFocus( focused: boolean, initialRef?: FocusManager.TouchableReactRef | string, options: { refsList?: Array<FocusManager.TouchableReactRef> | Array<string>; withStateMemory?: boolean; initialFocusDirection?: FocusManager.Android.FocusNavigationDirections; initialScrollIndex?: number; } = {} ): ((index: number) => void) | (() => void) { const { withStateMemory, refsList } = options; const currentlyFocusedIndex = React.useRef<number>( options?.initialScrollIndex || 0 ); const setCurrentlyFocusedIndex = React.useCallback( (index: number) => (currentlyFocusedIndex.current = index), [] ); const focusManager = useFocusManager(); const nextFocus = (withStateMemory && refsList?.[currentlyFocusedIndex.current]) || initialRef; React.useEffect(() => { if (focused && nextFocus) { focusManager.setFocus(nextFocus, { initialFocusDirection: options?.initialFocusDirection, }); } }, [focused, initialRef]); if (withStateMemory) { return setCurrentlyFocusedIndex; } return noop; } export function useFocusRefs() { const { current } = React.useRef([]); return current; } export function useFocusEffect(onFocus, focusWatcher) { const [focused] = focusWatcher; React.useLayoutEffect(() => { let onBlur = () => null; if (focused) { onBlur = onFocus?.(); } else { onBlur?.(); } }, focusWatcher); } export const isFocusable = (component: ZappEntry | ZappUIComponent | any) => R.tryCatch( R.compose( R.not, R.includes(R.__, NON_FOCUSABLE_COMPONENTS), R.prop("component_type") ), R.T )(component); type Props = { component: ZappUIComponent; zappPipesData?: ZappPipesData; } & Record<string, any>; export const useIsFocusable = (props: Props): void => { const { component, zappPipesData } = props; const { setIsFocusable } = useFocusable(); const componentCellsFocusable = toBooleanWithDefaultTrue( component?.rules?.component_cells_focusable ); const hideIfDataEmpty = toBooleanWithDefaultTrue( component.rules.hide_component_if_data_is_empty ); const hasNoData = isNilOrEmpty(zappPipesData?.data) || isNilOrEmpty(zappPipesData?.data?.entry); React.useEffect(() => { if (isAndroidTVPlatform()) { setIsFocusable( componentCellsFocusable && (!hasNoData || !hideIfDataEmpty) ); } }, [setIsFocusable, componentCellsFocusable, hasNoData]); };