import React, { useCallback, useLayoutEffect, useRef } from 'react'; import type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native'; import { Modal, View, TouchableWithoutFeedback, StyleSheet, useWindowDimensions, } from 'react-native'; import type { Placement } from './StyledAppCue'; import { StyledContainer, StyledContent, StyledIconContainer, } from './StyledAppCue'; import Typography from '../Typography'; import Icon from '../Icon'; import { useTheme } from '../../theme'; import { calculatePosition, calulateContentMaxWidth } from './utils'; interface AppCueProps { /* * The content of the App Cue. */ content: string | React.ReactElement; /* * The target where the App Cue is relatively placed to. */ target: React.ReactElement<{ onPress?: () => void; children?: React.ReactNode; }>; /** * The Position of the App Cue. */ placement?: Placement; /** * Additional style. */ style?: StyleProp; /** * Testing ID of the component. */ testID?: string; } const AppCue = ({ target, content, placement = 'top', style, testID, }: AppCueProps) => { const targetContainerRef = useRef(null); const [visible, setVisible] = React.useState(false); const theme = useTheme(); const { offset } = theme.__hd__.appCue.space; const [position, setPosition] = React.useState({ pageX: 0, pageY: 0, width: 0, height: 0, }); const [contentSize, setContentSize] = React.useState({ width: 0, height: 0, }); const doMeasure = useCallback((cb?: () => void) => { targetContainerRef.current?.measure( (_, __, width, height, pageX, pageY) => { setPosition({ pageX, pageY, width, height }); cb?.(); } ); }, []); const handleOpen = () => { doMeasure(() => setVisible(true)); }; useLayoutEffect(() => { doMeasure(); }, [doMeasure]); const enhancedTarget = React.cloneElement( target, { onPress: () => { handleOpen(); target.props?.onPress?.(); }, }, target.props.children ); const measureContent = (event: LayoutChangeEvent) => { setContentSize({ width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height, }); }; const { width: windowWidth } = useWindowDimensions(); const pos = calculatePosition({ position, contentSize, placement, offset, windowWidth, }); const maxWidth = calulateContentMaxWidth({ position, offset, placement, windowWidth, }); const renderContent = () => { if (typeof content === 'string') { return {content}; } return content; }; return ( <> {enhancedTarget} setVisible(false)} transparent presentationStyle="overFullScreen" statusBarTranslucent > setVisible(false)} > {renderContent()} ); }; export default AppCue;