/* * 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. */ #include "NativeIntersectionObserver.h" #include #include #include #include #ifdef RN_DISABLE_OSS_PLUGIN_HEADER #include "Plugins.h" #endif std::shared_ptr NativeIntersectionObserverModuleProvider( std::shared_ptr jsInvoker) { return std::make_shared( std::move(jsInvoker)); } namespace facebook::react { namespace { jsi::Object tokenFromShadowNodeFamily( jsi::Runtime& runtime, ShadowNodeFamily::Shared shadowNodeFamily) { jsi::Object obj(runtime); // Need to const_cast since JSI only allows non-const pointees obj.setNativeState( runtime, std::const_pointer_cast(std::move(shadowNodeFamily))); return obj; } ShadowNodeFamily::Shared shadowNodeFamilyFromToken( jsi::Runtime& runtime, jsi::Object token) { return token.getNativeState(runtime); } } // namespace NativeIntersectionObserver::NativeIntersectionObserver( std::shared_ptr jsInvoker) : NativeIntersectionObserverCxxSpec(std::move(jsInvoker)) {} void NativeIntersectionObserver::observe( jsi::Runtime& runtime, NativeIntersectionObserverObserveOptions options) { observeV2(runtime, std::move(options)); } void NativeIntersectionObserver::unobserve( jsi::Runtime& runtime, IntersectionObserverObserverId intersectionObserverId, std::shared_ptr targetShadowNode) { auto token = tokenFromShadowNodeFamily(runtime, targetShadowNode->getFamilyShared()); unobserveV2(runtime, intersectionObserverId, std::move(token)); } jsi::Object NativeIntersectionObserver::observeV2( jsi::Runtime& runtime, NativeIntersectionObserverObserveOptions options) { auto intersectionObserverId = options.intersectionObserverId; auto shadowNode = options.targetShadowNode; auto shadowNodeFamily = shadowNode->getFamilyShared(); std::optional observationRootShadowNodeFamily; if (options.rootShadowNode.has_value()) { observationRootShadowNodeFamily = options.rootShadowNode.value()->getFamilyShared(); } auto thresholds = options.thresholds; auto rootThresholds = options.rootThresholds; auto& uiManager = getUIManagerFromRuntime(runtime); intersectionObserverManager_.observe( intersectionObserverId, observationRootShadowNodeFamily, shadowNodeFamily, thresholds, rootThresholds, uiManager); return tokenFromShadowNodeFamily(runtime, shadowNodeFamily); } void NativeIntersectionObserver::unobserveV2( jsi::Runtime& runtime, IntersectionObserverObserverId intersectionObserverId, jsi::Object targetToken) { auto shadowNodeFamily = shadowNodeFamilyFromToken(runtime, std::move(targetToken)); intersectionObserverManager_.unobserve( intersectionObserverId, shadowNodeFamily); } void NativeIntersectionObserver::connect( jsi::Runtime& runtime, AsyncCallback<> notifyIntersectionObserversCallback) { auto& uiManager = getUIManagerFromRuntime(runtime); intersectionObserverManager_.connect( *RuntimeSchedulerBinding::getBinding(runtime)->getRuntimeScheduler(), uiManager, std::move(notifyIntersectionObserversCallback)); } void NativeIntersectionObserver::disconnect(jsi::Runtime& runtime) { auto& uiManager = getUIManagerFromRuntime(runtime); intersectionObserverManager_.disconnect( *RuntimeSchedulerBinding::getBinding(runtime)->getRuntimeScheduler(), uiManager); } std::vector NativeIntersectionObserver::takeRecords(jsi::Runtime& runtime) { auto entries = intersectionObserverManager_.takeRecords(); std::vector nativeModuleEntries; nativeModuleEntries.reserve(entries.size()); for (const auto& entry : entries) { nativeModuleEntries.emplace_back( convertToNativeModuleEntry(entry, runtime)); } return nativeModuleEntries; } NativeIntersectionObserverEntry NativeIntersectionObserver::convertToNativeModuleEntry( const IntersectionObserverEntry& entry, jsi::Runtime& runtime) { RectAsTuple targetRect = { entry.targetRect.origin.x, entry.targetRect.origin.y, entry.targetRect.size.width, entry.targetRect.size.height}; RectAsTuple rootRect = { entry.rootRect.origin.x, entry.rootRect.origin.y, entry.rootRect.size.width, entry.rootRect.size.height}; RectAsTuple intersectionRect = { entry.intersectionRect.origin.x, entry.intersectionRect.origin.y, entry.intersectionRect.size.width, entry.intersectionRect.size.height}; NativeIntersectionObserverEntry nativeModuleEntry = { entry.intersectionObserverId, (*entry.shadowNodeFamily).getInstanceHandle(runtime), targetRect, rootRect, intersectionRect, entry.isIntersectingAboveThresholds, entry.time, }; return nativeModuleEntry; } UIManager& NativeIntersectionObserver::getUIManagerFromRuntime( jsi::Runtime& runtime) { return UIManagerBinding::getBinding(runtime)->getUIManager(); } } // namespace facebook::react