/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict-local * @format */ // flowlint unsafe-getters-setters:off import type ReactNativeElement from '../DOM/Nodes/ReactNativeElement'; import type {InternalInstanceHandle} from '../Renderer/shims/ReactNativeTypes'; import type {NativeIntersectionObserverEntry} from './NativeIntersectionObserver'; import DOMRectReadOnly from '../DOM/Geometry/DOMRectReadOnly'; import {getPublicInstanceFromInternalInstanceHandle} from '../DOM/Nodes/ReadOnlyNode'; /** * The [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) * interface of the Intersection Observer API describes the intersection between * the target element and its root container at a specific moment of transition. * * An array of `IntersectionObserverEntry` is delivered to * `IntersectionObserver` callbacks as the first argument. */ export default class IntersectionObserverEntry { // We lazily compute all the properties from the raw entry provided by the // native module, so we avoid unnecessary work. _nativeEntry: NativeIntersectionObserverEntry; constructor(nativeEntry: NativeIntersectionObserverEntry) { this._nativeEntry = nativeEntry; } /** * Returns the bounds rectangle of the target element as a `DOMRectReadOnly`. * The bounds are computed as described in the documentation for * [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). */ get boundingClientRect(): DOMRectReadOnly { const targetRect = this._nativeEntry.targetRect; return new DOMRectReadOnly( targetRect[0], targetRect[1], targetRect[2], targetRect[3], ); } /** * Returns the ratio of the `intersectionRect` to the `boundingClientRect`. */ get intersectionRatio(): number { const intersectionRect = this.intersectionRect; const boundingClientRect = this.boundingClientRect; if (boundingClientRect.width === 0 || boundingClientRect.height === 0) { return 0; } return ( (intersectionRect.width * intersectionRect.height) / (boundingClientRect.width * boundingClientRect.height) ); } /** * Returns a `DOMRectReadOnly` representing the target's visible area. */ get intersectionRect(): DOMRectReadOnly { const intersectionRect = this._nativeEntry.intersectionRect; if (intersectionRect == null) { return new DOMRectReadOnly(); } return new DOMRectReadOnly( intersectionRect[0], intersectionRect[1], intersectionRect[2], intersectionRect[3], ); } /** * A `Boolean` value which is `true` if the target element intersects with the * intersection observer's root. * * If this is `true`, then, the `IntersectionObserverEntry` describes a * transition into a state of intersection. * * If it's `false`, then you know the transition is from intersecting to * not-intersecting. */ get isIntersecting(): boolean { return this._nativeEntry.isIntersectingAboveThresholds; } /** * Returns a `DOMRectReadOnly` for the intersection observer's root. */ get rootBounds(): DOMRectReadOnly { const rootRect = this._nativeEntry.rootRect; return new DOMRectReadOnly( rootRect[0], rootRect[1], rootRect[2], rootRect[3], ); } /** * The `ReactNativeElement` whose intersection with the root changed. */ get target(): ReactNativeElement { const targetInstanceHandle: InternalInstanceHandle = // $FlowExpectedError[incompatible-type] native modules don't support using InternalInstanceHandle as a type this._nativeEntry.targetInstanceHandle; const targetElement = getPublicInstanceFromInternalInstanceHandle(targetInstanceHandle); // $FlowExpectedError[incompatible-cast] we know targetElement is a ReactNativeElement, not just a ReadOnlyNode return (targetElement: ReactNativeElement); } /** * A `DOMHighResTimeStamp` indicating the time at which the intersection was * recorded, relative to the `IntersectionObserver`'s time origin. */ get time(): DOMHighResTimeStamp { return this._nativeEntry.time; } } export function createIntersectionObserverEntry( entry: NativeIntersectionObserverEntry, ): IntersectionObserverEntry { return new IntersectionObserverEntry(entry); }