react-native
Version:
A framework for building native apps using React
168 lines (144 loc) • 5.07 kB
JavaScript
/**
* 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 {NativeIntersectionObserverEntry} from './specs/NativeIntersectionObserver';
import DOMRectReadOnly from '../dom/geometry/DOMRectReadOnly';
/**
* 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;
// There are cases where this cannot be safely derived from the instance
// handle in the native entry (when the target is detached), so we need to
// keep a reference to it directly.
_target: ReactNativeElement;
constructor(
nativeEntry: NativeIntersectionObserverEntry,
target: ReactNativeElement,
) {
this._nativeEntry = nativeEntry;
this._target = target;
}
/**
* 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;
}
const ratio =
(intersectionRect.width * intersectionRect.height) /
(boundingClientRect.width * boundingClientRect.height);
// Prevent rounding errors from making this value greater than 1.
return Math.min(ratio, 1);
}
/**
* Returns the ratio of the `intersectionRect` to the `boundingRootRect`.
*/
get rnRootIntersectionRatio(): number {
const intersectionRect = this.intersectionRect;
const rootRect = this._nativeEntry.rootRect;
const boundingRootRect = new DOMRectReadOnly(
rootRect[0],
rootRect[1],
rootRect[2],
rootRect[3],
);
if (boundingRootRect.width === 0 || boundingRootRect.height === 0) {
return 0;
}
const ratio =
(intersectionRect.width * intersectionRect.height) /
(boundingRootRect.width * boundingRootRect.height);
// Prevent rounding errors from making this value greater than 1.
return Math.min(ratio, 1);
}
/**
* 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 {
return this._target;
}
/**
* 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,
target: ReactNativeElement,
): IntersectionObserverEntry {
return new IntersectionObserverEntry(entry, target);
}