/* eslint-disable unused-imports/no-unused-vars */ import * as React from "react"; import * as R from "ramda"; import { FocusableItemNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables"; import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable/index.ios"; import { focusManager, forceFocusableFocus, } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios"; import { findNodeHandle, ViewStyle } from "react-native"; function noop() {} type Props = { id: string; groupId: string; onPress?: (nativeEvent: any) => void; onFocus?: (nativeEvent: any) => void; onBlur?: (nativeEvent: any) => void; children: ((focused?: boolean) => React.ReactNode) | React.ReactNode; isParallaxDisabled: boolean; preferredFocus?: boolean; selected?: boolean; isFocusable?: boolean; nextFocusDown?: import("react").RefObject; nextFocusUp?: import("react").RefObject; nextFocusLeft?: import("react").RefObject; nextFocusRight?: import("react").RefObject; nextTvosFocusLeft?: import("react").RefObject; nextTvosFocusRight?: import("react").RefObject; nextTvosFocusUp?: import("react").RefObject; nextTvosFocusDown?: import("react").RefObject; forceFocus?: boolean; initialFocus?: boolean; onLayout?: (e: any) => void; willReceiveFocus: () => void; hasReceivedFocus: () => void; offsetUpdater: (arg1: string, arg2: number) => number; style: ViewStyle; }; export class Focusable extends BaseFocusable { private nextFocusableReactTags: Record; constructor(props) { super(props); this.isGroup = false; this.onPress = this.onPress.bind(this); this.onFocus = this.onFocus.bind(this); this.onBlur = this.onBlur.bind(this); this.nextFocusableReactTags = {}; this.preferredFocus = this.preferredFocus.bind(this); this.measureView = this.measureView.bind(this); } /** * indicates whether the underlying component should claim preferred focus * when navigating into the group of this item * @returns {boolean} */ isPreferredFocus() { return this.preferredFocus(); } preferredFocus() { return this.props.preferredFocus || false; } onPress({ nativeEvent }) { const { onPress = noop } = this.props; onPress(nativeEvent); } onFocus({ nativeEvent }) { const { onFocus = noop } = this.props; this.setState({ focused: true }); const currentFocusGroupId = focusManager.getCurrentGroup()?.props?.groupId; if (!nativeEvent?.itemID?.includes(currentFocusGroupId)) { focusManager.setFocus(nativeEvent?.itemID, undefined, { groupFocusedChanged: true, }); } onFocus(nativeEvent); } onBlur({ nativeEvent }) { const { onBlur = noop } = this.props; this.setState({ focused: false }); onBlur(nativeEvent); } setFocus(_direction, callback) { const focusMethods = [ { method: this.willReceiveFocus }, { method: this.focus, args: [callback] }, { method: this.hasReceivedFocus }, ]; const self = this; return R.reduce( (sequence, { method, args = [] }) => { return sequence .then(() => { return method.apply(self, args); }) .catch((e) => { throw e; }); }, Promise.resolve(), focusMethods ); } focus(callback) { const { groupId, id } = this.props; forceFocusableFocus(groupId, id, callback); } blur() {} focusableTags({ nextTvosFocusLeft, nextTvosFocusRight, nextTvosFocusUp, nextTvosFocusDown, }) { const retVal: Record = {}; const addFocusNodeIfNeeded = (ref, type) => { const current = ref?.current; if (current) { const node = findNodeHandle(current); if (node) { retVal[type] = node; } } }; addFocusNodeIfNeeded(nextTvosFocusDown, "nextTvosFocusDown"); addFocusNodeIfNeeded(nextTvosFocusUp, "nextTvosFocusUp"); addFocusNodeIfNeeded(nextTvosFocusLeft, "nextTvosFocusLeft"); addFocusNodeIfNeeded(nextTvosFocusRight, "nextTvosFocusRight"); return retVal; } componentDidUpdate() { const { nextTvosFocusLeft, nextTvosFocusRight, nextTvosFocusUp, nextTvosFocusDown, } = this.props; this.nextFocusableReactTags = this.focusableTags({ nextTvosFocusLeft, nextTvosFocusRight, nextTvosFocusUp, nextTvosFocusDown, }); } render() { const { children, groupId, id, isParallaxDisabled, isFocusable, // This done not to pass this props to native component, because it is not supported nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight, nextTvosFocusLeft, nextTvosFocusRight, nextTvosFocusUp, nextTvosFocusDown, ...otherProps } = this.props; const { focused } = this.state; return ( this.measureView()} focusable={isFocusable} {...this.nextFocusableReactTags} {...otherProps} > {typeof children === "function" ? children(focused) : children} ); } }