import React from "react"; import { View, ViewStyle } from "react-native"; import { useTheme } from "@applicaster/zapp-react-native-utils/theme"; import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks"; import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils"; import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils"; interface IProps { targetScreenId?: string; children?: React.ReactNode; style?: ViewStyle; extraVerticalOffset: Option; } /** * The MarginTop is essentially a feature used for managing the visibility of components on your screen. * A more accurate term for this might be something like a 'component visibility threshold' or 'cut-off point'. * In practical terms, MarginTop determines a specific vertical position (given in the 'y' coordinate) * on your screen above which components aren't shown. * You might visualize this as a horizontal line across your screen, and any component crossing this line becomes invisible. * * Classic use case for this feature is making sure that component aren't displayed underneath the navigation bar. */ export const useMarginTop = (targetScreenId: string): number => { const theme = useTheme(); const screenData = useCurrentScreenData(targetScreenId); const isGeneralContentScreen = screenData?.plugin_type === "general_content"; const supportsUiComponents = screenData?.ui_components; /** * ScreenPicker is a component but should really be a screen. * We need to skip margin top for it as it's already applied to the target screen **/ // ignore margin on screenPicker if (isFirstComponentScreenPicker(screenData?.ui_components)) { return 0; } const isPlayer = screenData?.plugin_type === "player"; // ignore margin on inlinePlayer (remove if better way of identifying cases for plugins that don't have marginTop) if (isPlayer) { return 0; } // Empty string means that value is blank in the CMS. Fallback to theme if (String(screenData?.styles?.screen_margin_top) === "") { return toNumberWithDefault(0, theme.screen_margin_top); } /** * If value is undefined it means one of three things * 1. Screen is not a general content screen and it doesn't handle ui components (return 0) * 2. Screen is a general content screen but it doesn't have a margin top value (return theme value) * 3. Screen isn't general content screen but it handles the ui components (return theme value) */ if (screenData?.styles?.screen_margin_top === undefined) { if (isGeneralContentScreen || supportsUiComponents) { return toNumberWithDefault(0, theme.screen_margin_top); } return 0; } return toNumberWithDefault(0, screenData?.styles?.screen_margin_top); }; export const TopMarginApplicator: React.FC = ({ targetScreenId, style, children, extraVerticalOffset, }: IProps) => { const extraOffset = toNumberWithDefault(0, extraVerticalOffset); // HACK: Remove extraOffset when focusIssue with absolute elements is fixed on tvos const marginTop = useMarginTop(targetScreenId); return ( {children} ); };