import { debounce } from 'es-toolkit'; import { PropsWithChildren, ReactElement, ReactNode, useContext, useEffect, useMemo, useState } from 'react'; import { StyleProp, View, ViewStyle } from 'react-native'; import { InView, IOContext } from '../intersection-observer'; import { noop } from '../utils/noop'; import { usePreservedCallback } from '../utils/usePreservedCallback'; import { useVisibility } from '../visibility'; interface Props { onImpressionStart?: () => void; onImpressionEnd?: () => void; enabled?: boolean; UNSAFE__impressFallbackOnMount?: boolean; style?: StyleProp; areaThreshold?: number; timeThreshold?: number; children?: ReactNode; } /** * @public * @category 화면 제어 * @name ImpressionArea * @description * 특정 컴포넌트가 화면에 보이는지 여부를 감지해서 외부에 알려주는 컴포넌트예요. 이 컴포넌트를 사용해서 화면에 특정 컴포넌트가 보이면 로그를 수집하거나 애니메이션을 실행하는 구현을 쉽게 할 수 있어요. * 화면에 보이는지 여부는 `useVisibility`의 반환값과 뷰포트(Viewport) 내에 표시되었는 지 알려주는 `IOScrollView`와 `InView` 컴포넌트로 감지해요. React에서 `ScrollView`를 사용하면 뷰가 화면에 보이지 않더라도, `ImpressionArea`를 사용하면 해당 뷰가 실제로 화면에 보일때만 이벤트를 발생시킬 수 있어요. ::: info 유의하세요 `ImpressionArea`는 반드시 `IOScrollView` 안에서 사용해야 해요. 만약 `IOScrollView` 외부에서 사용해야 한다면, `UNSAFE__impressFallbackOnMount` 속성을 `true`로 설정해서 컴포넌트가 마운트될 때를 기준으로 감지할 수 있어요. 이 속성이 `false`로 설정된 상태에서 `IOScrollView` 외부에서 사용하면 `IOProviderMissingError`가 발생해요. ::: * * @param {() => void} [onImpressionStart] 자식 컴포넌트가 화면에 보일 때 실행되는 콜백함수예요. * @param {() => void} [onImpressionEnd] 자식 컴포넌트가 화면에 가려졌을 때 실행되는 콜백함수예요. * @param {boolean} [enabled=true] 화면에 보여졌다는 조건을 직접 제어하는 값이에요. 기본값은 `true` 에요. `false` 로 전달하면 화면에 보여져도 `onImpressionStart` 콜백 함수가 실행되지 않아요. * @param {number} [areaThreshold=0] 보여지는 영역의 비율을 설정하는 값이에요. 이 값보다 큰 비율로 컴포넌트가 화면에 나타나면 `onImpressionStart`를 호출해요. * 값은 0부터 1 사이의 숫자로 설정하며, 0으로 설정하면 컴포넌트의 1px이라도 보일 때 이벤트가 발생해요. 반대로, 1로 설정하면 컴포넌트가 100% 화면에 노출될 때만 이벤트가 호출돼요. * @param {number} [timeThreshold=0] 이 컴포넌트가 화면에 보인 후 `onImpressionStart` 호출될 때까지의 시간을 밀리초 단위로 설정해요.기본값은 `0`밀리초(0초)에요. * @param {ViewStyle} [style] `InView` 컴포넌트에 적용할 `style` 값이에요. 기본값은 `undefined`이고, `style`을 지정하고 싶을 때 사용해요. * @param {boolean} [UNSAFE__impressFallbackOnMount=false] 컴포넌트가 마운트될 때 즉시 화면에 나타난 것으로 간주할지 여부예요. 기본값은 `false`예요. * `IOScrollView`를 사용하지 않는 상황에서, 컴포넌트가 뷰포트(Viewport) 안에 있는지 판단할 수 없을 떼 유용해요. 예를 들어, `IOScrollView` 밖에 위치한 컴포넌트는 `true`로 설정하면 마운트 시점에 보여졌다고 판단해요. * * @returns {ReactElement} - 화면에 보이는 여부를 감지할 수 있는 컴포넌트가 반환돼요. * @example * * ### 기본 사용 예시 * * ```tsx * import { useState } from 'react'; * import { Button, Dimensions, Text, View } from 'react-native'; * import { ImpressionArea, IOScrollView } from 'react-native-bedrock'; * * export default function ImpressionAreaExample() { * const [isImpressionStart, setIsImpressionStart] = useState(false); * * return ( * <> * {isImpressionStart ? 'Impression Start' : 'Impression End'} * * * Scroll to here * * * setIsImpressionStart(true)} * onImpressionEnd={() => setIsImpressionStart(false)} * > *