From 578d08e560c55dfcd14359a8cc57a5a9a3578c70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Jul 2025 06:36:09 +0000 Subject: [PATCH 1/5] Initial plan From 639e4da81c733272b0e996e3ffbeb8b9776e2f28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Jul 2025 06:45:22 +0000 Subject: [PATCH 2/5] Initial commit - establish baseline and plan for tabIndex implementation Co-authored-by: protikbiswas100 <219775028+protikbiswas100@users.noreply.github.com> --- vnext/codegen/rnwcoreJSI-generated.cpp | 112 +-- vnext/codegen/rnwcoreJSI.h | 1034 ++++++++++++------------ 2 files changed, 573 insertions(+), 573 deletions(-) diff --git a/vnext/codegen/rnwcoreJSI-generated.cpp b/vnext/codegen/rnwcoreJSI-generated.cpp index a5375b6a74b..14c1d6bb123 100644 --- a/vnext/codegen/rnwcoreJSI-generated.cpp +++ b/vnext/codegen/rnwcoreJSI-generated.cpp @@ -940,41 +940,6 @@ NativeAnimatedTurboModuleCxxSpecJSI::NativeAnimatedTurboModuleCxxSpecJSI(std::sh methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAnimatedTurboModuleCxxSpecJSI_removeListeners}; methodMap_["queueAndExecuteBatchedOperations"] = MethodMetadata {1, __hostFunction_NativeAnimatedTurboModuleCxxSpecJSI_queueAndExecuteBatchedOperations}; } -static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - auto result = static_cast(&turboModule)->getColorScheme( - rt - ); - return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); -} -static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - static_cast(&turboModule)->setColorScheme( - rt, - count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) - ); - return jsi::Value::undefined(); -} -static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - static_cast(&turboModule)->addListener( - rt, - count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) - ); - return jsi::Value::undefined(); -} -static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - static_cast(&turboModule)->removeListeners( - rt, - count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() - ); - return jsi::Value::undefined(); -} - -NativeAppearanceCxxSpecJSI::NativeAppearanceCxxSpecJSI(std::shared_ptr jsInvoker) - : TurboModule("Appearance", jsInvoker) { - methodMap_["getColorScheme"] = MethodMetadata {0, __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme}; - methodMap_["setColorScheme"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme}; - methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_addListener}; - methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners}; -} static jsi::Value __hostFunction_NativeAppStateCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getConstants( rt @@ -1020,6 +985,41 @@ NativeAppThemeCxxSpecJSI::NativeAppThemeCxxSpecJSI(std::shared_ptr : TurboModule("AppTheme", jsInvoker) { methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeAppThemeCxxSpecJSI_getConstants}; } +static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getColorScheme( + rt + ); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setColorScheme( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->addListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->removeListeners( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() + ); + return jsi::Value::undefined(); +} + +NativeAppearanceCxxSpecJSI::NativeAppearanceCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("Appearance", jsInvoker) { + methodMap_["getColorScheme"] = MethodMetadata {0, __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme}; + methodMap_["setColorScheme"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme}; + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_addListener}; + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners}; +} static jsi::Value __hostFunction_NativeBlobModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getConstants( rt @@ -1123,27 +1123,6 @@ NativeClipboardCxxSpecJSI::NativeClipboardCxxSpecJSI(std::shared_ptr(&turboModule)->invokeDefaultBackPressHandler( - rt - ); - return jsi::Value::undefined(); -} - -NativeDeviceEventManagerCxxSpecJSI::NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr jsInvoker) - : TurboModule("DeviceEventManager", jsInvoker) { - methodMap_["invokeDefaultBackPressHandler"] = MethodMetadata {0, __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler}; -} -static jsi::Value __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - return static_cast(&turboModule)->getConstants( - rt - ); -} - -NativeDeviceInfoCxxSpecJSI::NativeDeviceInfoCxxSpecJSI(std::shared_ptr jsInvoker) - : TurboModule("DeviceInfo", jsInvoker) { - methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants}; -} static jsi::Value __hostFunction_NativeDevLoadingViewCxxSpecJSI_showMessage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->showMessage( rt, @@ -1287,6 +1266,27 @@ NativeDevSettingsCxxSpecJSI::NativeDevSettingsCxxSpecJSI(std::shared_ptr(&turboModule)->invokeDefaultBackPressHandler( + rt + ); + return jsi::Value::undefined(); +} + +NativeDeviceEventManagerCxxSpecJSI::NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("DeviceEventManager", jsInvoker) { + methodMap_["invokeDefaultBackPressHandler"] = MethodMetadata {0, __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler}; +} +static jsi::Value __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} + +NativeDeviceInfoCxxSpecJSI::NativeDeviceInfoCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("DeviceInfo", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants}; +} static jsi::Value __hostFunction_NativeDialogManagerAndroidCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getConstants( rt diff --git a/vnext/codegen/rnwcoreJSI.h b/vnext/codegen/rnwcoreJSI.h index f2d2d7f0451..3a336af1b17 100644 --- a/vnext/codegen/rnwcoreJSI.h +++ b/vnext/codegen/rnwcoreJSI.h @@ -1853,87 +1853,6 @@ class JSI_EXPORT NativeAnimatedTurboModuleCxxSpec : public TurboModule { }; - class JSI_EXPORT NativeAppearanceCxxSpecJSI : public TurboModule { -protected: - NativeAppearanceCxxSpecJSI(std::shared_ptr jsInvoker); - -public: - virtual std::optional getColorScheme(jsi::Runtime &rt) = 0; - virtual void setColorScheme(jsi::Runtime &rt, jsi::String colorScheme) = 0; - virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; - virtual void removeListeners(jsi::Runtime &rt, double count) = 0; - -}; - -template -class JSI_EXPORT NativeAppearanceCxxSpec : public TurboModule { -public: - jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { - return delegate_.create(rt, propName); - } - - std::vector getPropertyNames(jsi::Runtime& runtime) override { - return delegate_.getPropertyNames(runtime); - } - - static constexpr std::string_view kModuleName = "Appearance"; - -protected: - NativeAppearanceCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeAppearanceCxxSpec::kModuleName}, jsInvoker), - delegate_(reinterpret_cast(this), jsInvoker) {} - - -private: - class Delegate : public NativeAppearanceCxxSpecJSI { - public: - Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeAppearanceCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { - - } - - std::optional getColorScheme(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::getColorScheme) == 1, - "Expected getColorScheme(...) to have 1 parameters"); - - return bridging::callFromJs>( - rt, &T::getColorScheme, jsInvoker_, instance_); - } - void setColorScheme(jsi::Runtime &rt, jsi::String colorScheme) override { - static_assert( - bridging::getParameterCount(&T::setColorScheme) == 2, - "Expected setColorScheme(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::setColorScheme, jsInvoker_, instance_, std::move(colorScheme)); - } - void addListener(jsi::Runtime &rt, jsi::String eventName) override { - static_assert( - bridging::getParameterCount(&T::addListener) == 2, - "Expected addListener(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); - } - void removeListeners(jsi::Runtime &rt, double count) override { - static_assert( - bridging::getParameterCount(&T::removeListeners) == 2, - "Expected removeListeners(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); - } - - private: - friend class NativeAppearanceCxxSpec; - T *instance_; - }; - - Delegate delegate_; -}; - - #pragma mark - NativeAppStateAppState @@ -2287,6 +2206,87 @@ class JSI_EXPORT NativeAppThemeCxxSpec : public TurboModule { }; + class JSI_EXPORT NativeAppearanceCxxSpecJSI : public TurboModule { +protected: + NativeAppearanceCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual std::optional getColorScheme(jsi::Runtime &rt) = 0; + virtual void setColorScheme(jsi::Runtime &rt, jsi::String colorScheme) = 0; + virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void removeListeners(jsi::Runtime &rt, double count) = 0; + +}; + +template +class JSI_EXPORT NativeAppearanceCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "Appearance"; + +protected: + NativeAppearanceCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeAppearanceCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeAppearanceCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeAppearanceCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + std::optional getColorScheme(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getColorScheme) == 1, + "Expected getColorScheme(...) to have 1 parameters"); + + return bridging::callFromJs>( + rt, &T::getColorScheme, jsInvoker_, instance_); + } + void setColorScheme(jsi::Runtime &rt, jsi::String colorScheme) override { + static_assert( + bridging::getParameterCount(&T::setColorScheme) == 2, + "Expected setColorScheme(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setColorScheme, jsInvoker_, instance_, std::move(colorScheme)); + } + void addListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::addListener) == 2, + "Expected addListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); + } + void removeListeners(jsi::Runtime &rt, double count) override { + static_assert( + bridging::getParameterCount(&T::removeListeners) == 2, + "Expected removeListeners(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); + } + + private: + friend class NativeAppearanceCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + #pragma mark - NativeBlobModuleConstants @@ -2577,17 +2577,18 @@ class JSI_EXPORT NativeClipboardCxxSpec : public TurboModule { }; - class JSI_EXPORT NativeDeviceEventManagerCxxSpecJSI : public TurboModule { + class JSI_EXPORT NativeDevLoadingViewCxxSpecJSI : public TurboModule { protected: - NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr jsInvoker); + NativeDevLoadingViewCxxSpecJSI(std::shared_ptr jsInvoker); public: - virtual void invokeDefaultBackPressHandler(jsi::Runtime &rt) = 0; + virtual void showMessage(jsi::Runtime &rt, jsi::String message, std::optional withColor, std::optional withBackgroundColor) = 0; + virtual void hide(jsi::Runtime &rt) = 0; }; template -class JSI_EXPORT NativeDeviceEventManagerCxxSpec : public TurboModule { +class JSI_EXPORT NativeDevLoadingViewCxxSpec : public TurboModule { public: jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { return delegate_.create(rt, propName); @@ -2597,33 +2598,41 @@ class JSI_EXPORT NativeDeviceEventManagerCxxSpec : public TurboModule { return delegate_.getPropertyNames(runtime); } - static constexpr std::string_view kModuleName = "DeviceEventManager"; + static constexpr std::string_view kModuleName = "DevLoadingView"; protected: - NativeDeviceEventManagerCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeDeviceEventManagerCxxSpec::kModuleName}, jsInvoker), + NativeDevLoadingViewCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeDevLoadingViewCxxSpec::kModuleName}, jsInvoker), delegate_(reinterpret_cast(this), jsInvoker) {} private: - class Delegate : public NativeDeviceEventManagerCxxSpecJSI { + class Delegate : public NativeDevLoadingViewCxxSpecJSI { public: Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeDeviceEventManagerCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + NativeDevLoadingViewCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { } - void invokeDefaultBackPressHandler(jsi::Runtime &rt) override { + void showMessage(jsi::Runtime &rt, jsi::String message, std::optional withColor, std::optional withBackgroundColor) override { static_assert( - bridging::getParameterCount(&T::invokeDefaultBackPressHandler) == 1, - "Expected invokeDefaultBackPressHandler(...) to have 1 parameters"); + bridging::getParameterCount(&T::showMessage) == 4, + "Expected showMessage(...) to have 4 parameters"); return bridging::callFromJs( - rt, &T::invokeDefaultBackPressHandler, jsInvoker_, instance_); + rt, &T::showMessage, jsInvoker_, instance_, std::move(message), std::move(withColor), std::move(withBackgroundColor)); + } + void hide(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::hide) == 1, + "Expected hide(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::hide, jsInvoker_, instance_); } private: - friend class NativeDeviceEventManagerCxxSpec; + friend class NativeDevLoadingViewCxxSpec; T *instance_; }; @@ -2631,54 +2640,333 @@ class JSI_EXPORT NativeDeviceEventManagerCxxSpec : public TurboModule { }; - -#pragma mark - NativeDeviceInfoDeviceInfoConstants + class JSI_EXPORT NativeDevMenuCxxSpecJSI : public TurboModule { +protected: + NativeDevMenuCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void show(jsi::Runtime &rt) = 0; + virtual void reload(jsi::Runtime &rt) = 0; + virtual void setProfilingEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual void setHotLoadingEnabled(jsi::Runtime &rt, bool enabled) = 0; -template -struct NativeDeviceInfoDeviceInfoConstants { - P0 Dimensions; - P1 isIPhoneX_deprecated; - bool operator==(const NativeDeviceInfoDeviceInfoConstants &other) const { - return Dimensions == other.Dimensions && isIPhoneX_deprecated == other.isIPhoneX_deprecated; - } }; template -struct NativeDeviceInfoDeviceInfoConstantsBridging { - static T types; - - static T fromJs( - jsi::Runtime &rt, - const jsi::Object &value, - const std::shared_ptr &jsInvoker) { - T result{ - bridging::fromJs(rt, value.getProperty(rt, "Dimensions"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, "isIPhoneX_deprecated"), jsInvoker)}; - return result; - } - -#ifdef DEBUG - static jsi::Object DimensionsToJs(jsi::Runtime &rt, decltype(types.Dimensions) value) { - return bridging::toJs(rt, value); - } - - static bool isIPhoneX_deprecatedToJs(jsi::Runtime &rt, decltype(types.isIPhoneX_deprecated) value) { - return bridging::toJs(rt, value); +class JSI_EXPORT NativeDevMenuCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); } -#endif - static jsi::Object toJs( - jsi::Runtime &rt, - const T &value, - const std::shared_ptr &jsInvoker) { - auto result = facebook::jsi::Object(rt); - result.setProperty(rt, "Dimensions", bridging::toJs(rt, value.Dimensions, jsInvoker)); - if (value.isIPhoneX_deprecated) { - result.setProperty(rt, "isIPhoneX_deprecated", bridging::toJs(rt, value.isIPhoneX_deprecated.value(), jsInvoker)); - } - return result; + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); } -}; + + static constexpr std::string_view kModuleName = "DevMenu"; + +protected: + NativeDevMenuCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeDevMenuCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeDevMenuCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeDevMenuCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void show(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::show) == 1, + "Expected show(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::show, jsInvoker_, instance_); + } + void reload(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::reload) == 1, + "Expected reload(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::reload, jsInvoker_, instance_); + } + void setProfilingEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setProfilingEnabled) == 2, + "Expected setProfilingEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setProfilingEnabled, jsInvoker_, instance_, std::move(enabled)); + } + void setHotLoadingEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setHotLoadingEnabled) == 2, + "Expected setHotLoadingEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setHotLoadingEnabled, jsInvoker_, instance_, std::move(enabled)); + } + + private: + friend class NativeDevMenuCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + class JSI_EXPORT NativeDevSettingsCxxSpecJSI : public TurboModule { +protected: + NativeDevSettingsCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void reload(jsi::Runtime &rt) = 0; + virtual void reloadWithReason(jsi::Runtime &rt, jsi::String reason) = 0; + virtual void onFastRefresh(jsi::Runtime &rt) = 0; + virtual void setHotLoadingEnabled(jsi::Runtime &rt, bool isHotLoadingEnabled) = 0; + virtual void setProfilingEnabled(jsi::Runtime &rt, bool isProfilingEnabled) = 0; + virtual void toggleElementInspector(jsi::Runtime &rt) = 0; + virtual void addMenuItem(jsi::Runtime &rt, jsi::String title) = 0; + virtual void openDebugger(jsi::Runtime &rt) = 0; + virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void removeListeners(jsi::Runtime &rt, double count) = 0; + virtual void setIsShakeToShowDevMenuEnabled(jsi::Runtime &rt, bool enabled) = 0; + +}; + +template +class JSI_EXPORT NativeDevSettingsCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "DevSettings"; + +protected: + NativeDevSettingsCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeDevSettingsCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeDevSettingsCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeDevSettingsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void reload(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::reload) == 1, + "Expected reload(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::reload, jsInvoker_, instance_); + } + void reloadWithReason(jsi::Runtime &rt, jsi::String reason) override { + static_assert( + bridging::getParameterCount(&T::reloadWithReason) == 2, + "Expected reloadWithReason(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::reloadWithReason, jsInvoker_, instance_, std::move(reason)); + } + void onFastRefresh(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::onFastRefresh) == 1, + "Expected onFastRefresh(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::onFastRefresh, jsInvoker_, instance_); + } + void setHotLoadingEnabled(jsi::Runtime &rt, bool isHotLoadingEnabled) override { + static_assert( + bridging::getParameterCount(&T::setHotLoadingEnabled) == 2, + "Expected setHotLoadingEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setHotLoadingEnabled, jsInvoker_, instance_, std::move(isHotLoadingEnabled)); + } + void setProfilingEnabled(jsi::Runtime &rt, bool isProfilingEnabled) override { + static_assert( + bridging::getParameterCount(&T::setProfilingEnabled) == 2, + "Expected setProfilingEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setProfilingEnabled, jsInvoker_, instance_, std::move(isProfilingEnabled)); + } + void toggleElementInspector(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::toggleElementInspector) == 1, + "Expected toggleElementInspector(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::toggleElementInspector, jsInvoker_, instance_); + } + void addMenuItem(jsi::Runtime &rt, jsi::String title) override { + static_assert( + bridging::getParameterCount(&T::addMenuItem) == 2, + "Expected addMenuItem(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::addMenuItem, jsInvoker_, instance_, std::move(title)); + } + void openDebugger(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::openDebugger) == 1, + "Expected openDebugger(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::openDebugger, jsInvoker_, instance_); + } + void addListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::addListener) == 2, + "Expected addListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); + } + void removeListeners(jsi::Runtime &rt, double count) override { + static_assert( + bridging::getParameterCount(&T::removeListeners) == 2, + "Expected removeListeners(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); + } + void setIsShakeToShowDevMenuEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setIsShakeToShowDevMenuEnabled) == 2, + "Expected setIsShakeToShowDevMenuEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setIsShakeToShowDevMenuEnabled, jsInvoker_, instance_, std::move(enabled)); + } + + private: + friend class NativeDevSettingsCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + class JSI_EXPORT NativeDeviceEventManagerCxxSpecJSI : public TurboModule { +protected: + NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void invokeDefaultBackPressHandler(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeDeviceEventManagerCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "DeviceEventManager"; + +protected: + NativeDeviceEventManagerCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeDeviceEventManagerCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeDeviceEventManagerCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeDeviceEventManagerCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void invokeDefaultBackPressHandler(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::invokeDefaultBackPressHandler) == 1, + "Expected invokeDefaultBackPressHandler(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::invokeDefaultBackPressHandler, jsInvoker_, instance_); + } + + private: + friend class NativeDeviceEventManagerCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeDeviceInfoDeviceInfoConstants + +template +struct NativeDeviceInfoDeviceInfoConstants { + P0 Dimensions; + P1 isIPhoneX_deprecated; + bool operator==(const NativeDeviceInfoDeviceInfoConstants &other) const { + return Dimensions == other.Dimensions && isIPhoneX_deprecated == other.isIPhoneX_deprecated; + } +}; + +template +struct NativeDeviceInfoDeviceInfoConstantsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "Dimensions"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "isIPhoneX_deprecated"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object DimensionsToJs(jsi::Runtime &rt, decltype(types.Dimensions) value) { + return bridging::toJs(rt, value); + } + + static bool isIPhoneX_deprecatedToJs(jsi::Runtime &rt, decltype(types.isIPhoneX_deprecated) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "Dimensions", bridging::toJs(rt, value.Dimensions, jsInvoker)); + if (value.isIPhoneX_deprecated) { + result.setProperty(rt, "isIPhoneX_deprecated", bridging::toJs(rt, value.isIPhoneX_deprecated.value(), jsInvoker)); + } + return result; + } +}; @@ -2783,323 +3071,115 @@ struct NativeDeviceInfoDisplayMetricsBridging { #ifdef DEBUG static double widthToJs(jsi::Runtime &rt, decltype(types.width) value) { - return bridging::toJs(rt, value); - } - - static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) { - return bridging::toJs(rt, value); - } - - static double scaleToJs(jsi::Runtime &rt, decltype(types.scale) value) { - return bridging::toJs(rt, value); - } - - static double fontScaleToJs(jsi::Runtime &rt, decltype(types.fontScale) value) { - return bridging::toJs(rt, value); - } -#endif - - static jsi::Object toJs( - jsi::Runtime &rt, - const T &value, - const std::shared_ptr &jsInvoker) { - auto result = facebook::jsi::Object(rt); - result.setProperty(rt, "width", bridging::toJs(rt, value.width, jsInvoker)); - result.setProperty(rt, "height", bridging::toJs(rt, value.height, jsInvoker)); - result.setProperty(rt, "scale", bridging::toJs(rt, value.scale, jsInvoker)); - result.setProperty(rt, "fontScale", bridging::toJs(rt, value.fontScale, jsInvoker)); - return result; - } -}; - - - -#pragma mark - NativeDeviceInfoDisplayMetricsAndroid - -template -struct NativeDeviceInfoDisplayMetricsAndroid { - P0 width; - P1 height; - P2 scale; - P3 fontScale; - P4 densityDpi; - bool operator==(const NativeDeviceInfoDisplayMetricsAndroid &other) const { - return width == other.width && height == other.height && scale == other.scale && fontScale == other.fontScale && densityDpi == other.densityDpi; - } -}; - -template -struct NativeDeviceInfoDisplayMetricsAndroidBridging { - static T types; - - static T fromJs( - jsi::Runtime &rt, - const jsi::Object &value, - const std::shared_ptr &jsInvoker) { - T result{ - bridging::fromJs(rt, value.getProperty(rt, "width"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, "height"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, "scale"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, "fontScale"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, "densityDpi"), jsInvoker)}; - return result; - } - -#ifdef DEBUG - static double widthToJs(jsi::Runtime &rt, decltype(types.width) value) { - return bridging::toJs(rt, value); - } - - static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) { - return bridging::toJs(rt, value); - } - - static double scaleToJs(jsi::Runtime &rt, decltype(types.scale) value) { - return bridging::toJs(rt, value); - } - - static double fontScaleToJs(jsi::Runtime &rt, decltype(types.fontScale) value) { - return bridging::toJs(rt, value); - } - - static double densityDpiToJs(jsi::Runtime &rt, decltype(types.densityDpi) value) { - return bridging::toJs(rt, value); - } -#endif - - static jsi::Object toJs( - jsi::Runtime &rt, - const T &value, - const std::shared_ptr &jsInvoker) { - auto result = facebook::jsi::Object(rt); - result.setProperty(rt, "width", bridging::toJs(rt, value.width, jsInvoker)); - result.setProperty(rt, "height", bridging::toJs(rt, value.height, jsInvoker)); - result.setProperty(rt, "scale", bridging::toJs(rt, value.scale, jsInvoker)); - result.setProperty(rt, "fontScale", bridging::toJs(rt, value.fontScale, jsInvoker)); - result.setProperty(rt, "densityDpi", bridging::toJs(rt, value.densityDpi, jsInvoker)); - return result; - } -}; - -class JSI_EXPORT NativeDeviceInfoCxxSpecJSI : public TurboModule { -protected: - NativeDeviceInfoCxxSpecJSI(std::shared_ptr jsInvoker); - -public: - virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; - -}; - -template -class JSI_EXPORT NativeDeviceInfoCxxSpec : public TurboModule { -public: - jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { - return delegate_.create(rt, propName); - } - - std::vector getPropertyNames(jsi::Runtime& runtime) override { - return delegate_.getPropertyNames(runtime); - } - - static constexpr std::string_view kModuleName = "DeviceInfo"; - -protected: - NativeDeviceInfoCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeDeviceInfoCxxSpec::kModuleName}, jsInvoker), - delegate_(reinterpret_cast(this), jsInvoker) {} - - -private: - class Delegate : public NativeDeviceInfoCxxSpecJSI { - public: - Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeDeviceInfoCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { - - } - - jsi::Object getConstants(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::getConstants) == 1, - "Expected getConstants(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::getConstants, jsInvoker_, instance_); - } - - private: - friend class NativeDeviceInfoCxxSpec; - T *instance_; - }; - - Delegate delegate_; -}; - - - class JSI_EXPORT NativeDevLoadingViewCxxSpecJSI : public TurboModule { -protected: - NativeDevLoadingViewCxxSpecJSI(std::shared_ptr jsInvoker); - -public: - virtual void showMessage(jsi::Runtime &rt, jsi::String message, std::optional withColor, std::optional withBackgroundColor) = 0; - virtual void hide(jsi::Runtime &rt) = 0; - -}; - -template -class JSI_EXPORT NativeDevLoadingViewCxxSpec : public TurboModule { -public: - jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { - return delegate_.create(rt, propName); - } - - std::vector getPropertyNames(jsi::Runtime& runtime) override { - return delegate_.getPropertyNames(runtime); - } - - static constexpr std::string_view kModuleName = "DevLoadingView"; - -protected: - NativeDevLoadingViewCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeDevLoadingViewCxxSpec::kModuleName}, jsInvoker), - delegate_(reinterpret_cast(this), jsInvoker) {} - - -private: - class Delegate : public NativeDevLoadingViewCxxSpecJSI { - public: - Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeDevLoadingViewCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { - - } - - void showMessage(jsi::Runtime &rt, jsi::String message, std::optional withColor, std::optional withBackgroundColor) override { - static_assert( - bridging::getParameterCount(&T::showMessage) == 4, - "Expected showMessage(...) to have 4 parameters"); - - return bridging::callFromJs( - rt, &T::showMessage, jsInvoker_, instance_, std::move(message), std::move(withColor), std::move(withBackgroundColor)); - } - void hide(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::hide) == 1, - "Expected hide(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::hide, jsInvoker_, instance_); - } - - private: - friend class NativeDevLoadingViewCxxSpec; - T *instance_; - }; - - Delegate delegate_; -}; - - - class JSI_EXPORT NativeDevMenuCxxSpecJSI : public TurboModule { -protected: - NativeDevMenuCxxSpecJSI(std::shared_ptr jsInvoker); + return bridging::toJs(rt, value); + } -public: - virtual void show(jsi::Runtime &rt) = 0; - virtual void reload(jsi::Runtime &rt) = 0; - virtual void setProfilingEnabled(jsi::Runtime &rt, bool enabled) = 0; - virtual void setHotLoadingEnabled(jsi::Runtime &rt, bool enabled) = 0; + static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) { + return bridging::toJs(rt, value); + } -}; + static double scaleToJs(jsi::Runtime &rt, decltype(types.scale) value) { + return bridging::toJs(rt, value); + } -template -class JSI_EXPORT NativeDevMenuCxxSpec : public TurboModule { -public: - jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { - return delegate_.create(rt, propName); + static double fontScaleToJs(jsi::Runtime &rt, decltype(types.fontScale) value) { + return bridging::toJs(rt, value); } +#endif - std::vector getPropertyNames(jsi::Runtime& runtime) override { - return delegate_.getPropertyNames(runtime); + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "width", bridging::toJs(rt, value.width, jsInvoker)); + result.setProperty(rt, "height", bridging::toJs(rt, value.height, jsInvoker)); + result.setProperty(rt, "scale", bridging::toJs(rt, value.scale, jsInvoker)); + result.setProperty(rt, "fontScale", bridging::toJs(rt, value.fontScale, jsInvoker)); + return result; } +}; - static constexpr std::string_view kModuleName = "DevMenu"; -protected: - NativeDevMenuCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeDevMenuCxxSpec::kModuleName}, jsInvoker), - delegate_(reinterpret_cast(this), jsInvoker) {} +#pragma mark - NativeDeviceInfoDisplayMetricsAndroid -private: - class Delegate : public NativeDevMenuCxxSpecJSI { - public: - Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeDevMenuCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { +template +struct NativeDeviceInfoDisplayMetricsAndroid { + P0 width; + P1 height; + P2 scale; + P3 fontScale; + P4 densityDpi; + bool operator==(const NativeDeviceInfoDisplayMetricsAndroid &other) const { + return width == other.width && height == other.height && scale == other.scale && fontScale == other.fontScale && densityDpi == other.densityDpi; + } +}; - } +template +struct NativeDeviceInfoDisplayMetricsAndroidBridging { + static T types; - void show(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::show) == 1, - "Expected show(...) to have 1 parameters"); + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "width"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "height"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "scale"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "fontScale"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "densityDpi"), jsInvoker)}; + return result; + } - return bridging::callFromJs( - rt, &T::show, jsInvoker_, instance_); - } - void reload(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::reload) == 1, - "Expected reload(...) to have 1 parameters"); +#ifdef DEBUG + static double widthToJs(jsi::Runtime &rt, decltype(types.width) value) { + return bridging::toJs(rt, value); + } - return bridging::callFromJs( - rt, &T::reload, jsInvoker_, instance_); - } - void setProfilingEnabled(jsi::Runtime &rt, bool enabled) override { - static_assert( - bridging::getParameterCount(&T::setProfilingEnabled) == 2, - "Expected setProfilingEnabled(...) to have 2 parameters"); + static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) { + return bridging::toJs(rt, value); + } - return bridging::callFromJs( - rt, &T::setProfilingEnabled, jsInvoker_, instance_, std::move(enabled)); - } - void setHotLoadingEnabled(jsi::Runtime &rt, bool enabled) override { - static_assert( - bridging::getParameterCount(&T::setHotLoadingEnabled) == 2, - "Expected setHotLoadingEnabled(...) to have 2 parameters"); + static double scaleToJs(jsi::Runtime &rt, decltype(types.scale) value) { + return bridging::toJs(rt, value); + } - return bridging::callFromJs( - rt, &T::setHotLoadingEnabled, jsInvoker_, instance_, std::move(enabled)); - } + static double fontScaleToJs(jsi::Runtime &rt, decltype(types.fontScale) value) { + return bridging::toJs(rt, value); + } - private: - friend class NativeDevMenuCxxSpec; - T *instance_; - }; + static double densityDpiToJs(jsi::Runtime &rt, decltype(types.densityDpi) value) { + return bridging::toJs(rt, value); + } +#endif - Delegate delegate_; + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "width", bridging::toJs(rt, value.width, jsInvoker)); + result.setProperty(rt, "height", bridging::toJs(rt, value.height, jsInvoker)); + result.setProperty(rt, "scale", bridging::toJs(rt, value.scale, jsInvoker)); + result.setProperty(rt, "fontScale", bridging::toJs(rt, value.fontScale, jsInvoker)); + result.setProperty(rt, "densityDpi", bridging::toJs(rt, value.densityDpi, jsInvoker)); + return result; + } }; - - class JSI_EXPORT NativeDevSettingsCxxSpecJSI : public TurboModule { +class JSI_EXPORT NativeDeviceInfoCxxSpecJSI : public TurboModule { protected: - NativeDevSettingsCxxSpecJSI(std::shared_ptr jsInvoker); + NativeDeviceInfoCxxSpecJSI(std::shared_ptr jsInvoker); public: - virtual void reload(jsi::Runtime &rt) = 0; - virtual void reloadWithReason(jsi::Runtime &rt, jsi::String reason) = 0; - virtual void onFastRefresh(jsi::Runtime &rt) = 0; - virtual void setHotLoadingEnabled(jsi::Runtime &rt, bool isHotLoadingEnabled) = 0; - virtual void setProfilingEnabled(jsi::Runtime &rt, bool isProfilingEnabled) = 0; - virtual void toggleElementInspector(jsi::Runtime &rt) = 0; - virtual void addMenuItem(jsi::Runtime &rt, jsi::String title) = 0; - virtual void openDebugger(jsi::Runtime &rt) = 0; - virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; - virtual void removeListeners(jsi::Runtime &rt, double count) = 0; - virtual void setIsShakeToShowDevMenuEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; }; template -class JSI_EXPORT NativeDevSettingsCxxSpec : public TurboModule { +class JSI_EXPORT NativeDeviceInfoCxxSpec : public TurboModule { public: jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { return delegate_.create(rt, propName); @@ -3109,113 +3189,33 @@ class JSI_EXPORT NativeDevSettingsCxxSpec : public TurboModule { return delegate_.getPropertyNames(runtime); } - static constexpr std::string_view kModuleName = "DevSettings"; + static constexpr std::string_view kModuleName = "DeviceInfo"; protected: - NativeDevSettingsCxxSpec(std::shared_ptr jsInvoker) - : TurboModule(std::string{NativeDevSettingsCxxSpec::kModuleName}, jsInvoker), + NativeDeviceInfoCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeDeviceInfoCxxSpec::kModuleName}, jsInvoker), delegate_(reinterpret_cast(this), jsInvoker) {} private: - class Delegate : public NativeDevSettingsCxxSpecJSI { + class Delegate : public NativeDeviceInfoCxxSpecJSI { public: Delegate(T *instance, std::shared_ptr jsInvoker) : - NativeDevSettingsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { - - } - - void reload(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::reload) == 1, - "Expected reload(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::reload, jsInvoker_, instance_); - } - void reloadWithReason(jsi::Runtime &rt, jsi::String reason) override { - static_assert( - bridging::getParameterCount(&T::reloadWithReason) == 2, - "Expected reloadWithReason(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::reloadWithReason, jsInvoker_, instance_, std::move(reason)); - } - void onFastRefresh(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::onFastRefresh) == 1, - "Expected onFastRefresh(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::onFastRefresh, jsInvoker_, instance_); - } - void setHotLoadingEnabled(jsi::Runtime &rt, bool isHotLoadingEnabled) override { - static_assert( - bridging::getParameterCount(&T::setHotLoadingEnabled) == 2, - "Expected setHotLoadingEnabled(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::setHotLoadingEnabled, jsInvoker_, instance_, std::move(isHotLoadingEnabled)); - } - void setProfilingEnabled(jsi::Runtime &rt, bool isProfilingEnabled) override { - static_assert( - bridging::getParameterCount(&T::setProfilingEnabled) == 2, - "Expected setProfilingEnabled(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::setProfilingEnabled, jsInvoker_, instance_, std::move(isProfilingEnabled)); - } - void toggleElementInspector(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::toggleElementInspector) == 1, - "Expected toggleElementInspector(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::toggleElementInspector, jsInvoker_, instance_); - } - void addMenuItem(jsi::Runtime &rt, jsi::String title) override { - static_assert( - bridging::getParameterCount(&T::addMenuItem) == 2, - "Expected addMenuItem(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::addMenuItem, jsInvoker_, instance_, std::move(title)); - } - void openDebugger(jsi::Runtime &rt) override { - static_assert( - bridging::getParameterCount(&T::openDebugger) == 1, - "Expected openDebugger(...) to have 1 parameters"); - - return bridging::callFromJs( - rt, &T::openDebugger, jsInvoker_, instance_); - } - void addListener(jsi::Runtime &rt, jsi::String eventName) override { - static_assert( - bridging::getParameterCount(&T::addListener) == 2, - "Expected addListener(...) to have 2 parameters"); + NativeDeviceInfoCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { - return bridging::callFromJs( - rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); } - void removeListeners(jsi::Runtime &rt, double count) override { - static_assert( - bridging::getParameterCount(&T::removeListeners) == 2, - "Expected removeListeners(...) to have 2 parameters"); - return bridging::callFromJs( - rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); - } - void setIsShakeToShowDevMenuEnabled(jsi::Runtime &rt, bool enabled) override { + jsi::Object getConstants(jsi::Runtime &rt) override { static_assert( - bridging::getParameterCount(&T::setIsShakeToShowDevMenuEnabled) == 2, - "Expected setIsShakeToShowDevMenuEnabled(...) to have 2 parameters"); + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); - return bridging::callFromJs( - rt, &T::setIsShakeToShowDevMenuEnabled, jsInvoker_, instance_, std::move(enabled)); + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); } private: - friend class NativeDevSettingsCxxSpec; + friend class NativeDeviceInfoCxxSpec; T *instance_; }; From 6f3355220d448480812547bb170c8516f68b10ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Jul 2025 06:55:39 +0000 Subject: [PATCH 3/5] Implement tabIndex property for View in Fabric Co-authored-by: protikbiswas100 <219775028+protikbiswas100@users.noreply.github.com> --- .../js/examples/View/ViewExample.windows.js | 69 +++++++++++++++++++ .../test/ViewComponentTest.test.ts | 7 ++ .../Fabric/ComponentView.cpp | 5 ++ .../Fabric/ComponentView.h | 1 + .../CompositionViewComponentView.cpp | 11 +++ .../CompositionViewComponentView.h | 1 + .../Fabric/Composition/FocusManager.cpp | 20 ++++++ .../components/view/HostPlatformViewProps.cpp | 8 ++- .../components/view/HostPlatformViewProps.h | 2 + 9 files changed, 123 insertions(+), 1 deletion(-) diff --git a/packages/@react-native-windows/tester/src/js/examples/View/ViewExample.windows.js b/packages/@react-native-windows/tester/src/js/examples/View/ViewExample.windows.js index d9117c9f404..c329992b4a3 100644 --- a/packages/@react-native-windows/tester/src/js/examples/View/ViewExample.windows.js +++ b/packages/@react-native-windows/tester/src/js/examples/View/ViewExample.windows.js @@ -1429,6 +1429,75 @@ export default ({ ); }, + }, + { + title: 'Tab Index', + name: 'tab-index', + render(): React.Node { + return ( + + + Tab Index Example + + + These views should be focusable with tabIndex: + + + tabIndex: 1 + + + tabIndex: 3 + + + tabIndex: 2 + + + tabIndex: -1 (not in tab order) + + + ); + }, }, // ]TODO(macOS ISS#2323203) // Windows] ], diff --git a/packages/e2e-test-app-fabric/test/ViewComponentTest.test.ts b/packages/e2e-test-app-fabric/test/ViewComponentTest.test.ts index 4b6e7574fe6..90ca42c05b9 100644 --- a/packages/e2e-test-app-fabric/test/ViewComponentTest.test.ts +++ b/packages/e2e-test-app-fabric/test/ViewComponentTest.test.ts @@ -199,4 +199,11 @@ describe('View Tests', () => { const dump = await dumpVisualTree('nativeid'); expect(dump).toMatchSnapshot(); }); + test('Views can have tabIndex', async () => { + await searchBox('tab'); + const componentsTab = await app.findElementByTestID('view-test-tab-index'); + await componentsTab.waitForDisplayed({timeout: 5000}); + const dump = await dumpVisualTree('view-test-tab-index'); + expect(dump).toMatchSnapshot(); + }); }); diff --git a/vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp index b1d0593b3c9..3bb154f1350 100644 --- a/vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp @@ -5,6 +5,7 @@ #include "ComponentView.h" #include +#include #include "DynamicReader.h" #include "ComponentView.g.cpp" @@ -612,6 +613,10 @@ bool ComponentView::focusable() const noexcept { return false; } +int ComponentView::tabIndex() const noexcept { + return std::numeric_limits::max(); +} + facebook::react::SharedViewEventEmitter ComponentView::eventEmitterAtPoint(facebook::react::Point pt) noexcept { return nullptr; } diff --git a/vnext/Microsoft.ReactNative/Fabric/ComponentView.h b/vnext/Microsoft.ReactNative/Fabric/ComponentView.h index 66a1de581fd..cb7b0aca6dc 100644 --- a/vnext/Microsoft.ReactNative/Fabric/ComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/ComponentView.h @@ -200,6 +200,7 @@ struct ComponentView bool TryFocus() noexcept; virtual bool focusable() const noexcept; + virtual int tabIndex() const noexcept; virtual facebook::react::SharedViewEventEmitter eventEmitterAtPoint(facebook::react::Point pt) noexcept; virtual facebook::react::SharedViewEventEmitter eventEmitter() noexcept; virtual facebook::react::Tag Tag() const noexcept; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 2426128f1a3..c5d156d710a 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1323,9 +1323,20 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ViewComponentV } bool ViewComponentView::focusable() const noexcept { + // If tabIndex is set to a valid value (not max int), then it should be focusable + // This matches the behavior of the Paper implementation + if (m_props->tabIndex != std::numeric_limits::max()) { + return true; + } + + // Otherwise, use the focusable property return m_props->focusable; } +int ViewComponentView::tabIndex() const noexcept { + return m_props->tabIndex; +} + std::string ViewComponentView::DefaultControlType() const noexcept { return "group"; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h index 588af7ad463..486c9069517 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h @@ -189,6 +189,7 @@ struct ViewComponentView : public ViewComponentViewT< facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept override; void prepareForRecycle() noexcept override; bool focusable() const noexcept override; + int tabIndex() const noexcept; void OnKeyDown(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override; void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override; std::string DefaultControlType() const noexcept override; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp index b8e90650783..7bbcc2bb229 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp @@ -5,6 +5,7 @@ #include "FocusManager.h" #include "Composition.FocusManager.g.cpp" #include +#include namespace winrt::Microsoft::ReactNative::implementation { @@ -116,10 +117,20 @@ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelpe winrt::Microsoft::ReactNative::implementation::ComponentView &view, winrt::Microsoft::ReactNative::FocusNavigationReason reason) { if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First) { + // For First navigation, we need to consider tabIndex + auto tabIndex = view.tabIndex(); + + // If this view has a positive tabIndex, it should be focusable + if (tabIndex >= 0 && tabIndex != std::numeric_limits::max()) { + return &view; + } + + // Otherwise, check if it's naturally focusable if (view.focusable()) { return &view; } } + winrt::Microsoft::ReactNative::implementation::ComponentView *toFocus = nullptr; Mso::Functor fn = @@ -131,6 +142,15 @@ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelpe } if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::Last) { + // For Last navigation, we need to consider tabIndex + auto tabIndex = view.tabIndex(); + + // If this view has a positive tabIndex, it should be focusable + if (tabIndex >= 0 && tabIndex != std::numeric_limits::max()) { + return &view; + } + + // Otherwise, check if it's naturally focusable if (view.focusable()) { return &view; } diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp index ff5b778be44..b0e43fb4d2f 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace facebook::react { @@ -71,7 +72,11 @@ HostPlatformViewProps::HostPlatformViewProps( rawProps, "accessibilityLiveRegion", sourceProps.accessibilityLiveRegion, - "none")) {} + "none")), + tabIndex( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.tabIndex + : convertRawProp(context, rawProps, "tabIndex", sourceProps.tabIndex, std::numeric_limits::max())) {} #define WINDOWS_VIEW_EVENT_CASE(eventType) \ case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \ @@ -117,6 +122,7 @@ void HostPlatformViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(keyDownEvents); RAW_SET_PROP_SWITCH_CASE_BASIC(keyUpEvents); RAW_SET_PROP_SWITCH_CASE_BASIC(tooltip); + RAW_SET_PROP_SWITCH_CASE_BASIC(tabIndex); } } diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h index 3466a06dde6..95d8e89c27e 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h @@ -5,6 +5,7 @@ #include #include +#include #include "CompositionAccessibilityProps.h" #include "KeyEvent.h" #include "WindowsViewEvents.h" @@ -38,5 +39,6 @@ class HostPlatformViewProps : public BaseViewProps { std::optional tooltip{}; std::vector keyDownEvents{}; std::vector keyUpEvents{}; + int tabIndex{std::numeric_limits::max()}; }; } // namespace facebook::react From 576bde5ee4c9eac57c9989041dd5351b796db420 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 08:21:59 +0000 Subject: [PATCH 4/5] Update tabIndex implementation to use Windows.UI.Composition APIs Co-authored-by: protikbiswas100 <219775028+protikbiswas100@users.noreply.github.com> --- .../CompositionViewComponentView.cpp | 46 +++++++++++++++++-- .../Fabric/Composition/FocusManager.cpp | 26 ++--------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index c5d156d710a..75462166af0 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1115,6 +1115,23 @@ void ViewComponentView::updateProps( Visual().Comment(winrt::to_hstring(newViewProps.testId)); } + // Update tabIndex using Windows.UI.Composition Visual Properties + if (oldViewProps.tabIndex != newViewProps.tabIndex) { + auto visual = + winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); + if (newViewProps.tabIndex != std::numeric_limits::max()) { + // Store tabIndex in Visual's Properties collection + visual.Properties().InsertScalar(L"ReactNative.TabIndex", static_cast(newViewProps.tabIndex)); + // Also set IsHitTestVisible to make it participate in focus + visual.IsHitTestVisible(true); + } else { + // Remove tabIndex property when not set + if (visual.Properties().TryGetScalar(L"ReactNative.TabIndex")) { + visual.Properties().Remove(L"ReactNative.TabIndex"); + } + } + } + // update BaseComponentView props updateAccessibilityProps(oldViewProps, newViewProps); updateTransformProps(oldViewProps, newViewProps, Visual()); @@ -1323,17 +1340,36 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ViewComponentV } bool ViewComponentView::focusable() const noexcept { - // If tabIndex is set to a valid value (not max int), then it should be focusable - // This matches the behavior of the Paper implementation + // Check if tabIndex is explicitly set via Windows.UI.Composition Visual Properties + if (m_visual) { + auto visual = + winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); + if (auto tabIndexValue = visual.Properties().TryGetScalar(L"ReactNative.TabIndex")) { + auto tabIndex = static_cast(tabIndexValue.Value()); + // Elements with tabIndex >= 0 are focusable, negative tabIndex means focusable but not in tab order + return tabIndex >= -1; + } + } + + // Fallback to props-based logic if not set in Visual Properties if (m_props->tabIndex != std::numeric_limits::max()) { - return true; + return m_props->tabIndex >= -1; } - - // Otherwise, use the focusable property + + // Default focusable behavior from props return m_props->focusable; } int ViewComponentView::tabIndex() const noexcept { + // Read tabIndex from Windows.UI.Composition Visual Properties + if (m_visual) { + auto visual = + winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); + if (auto tabIndexValue = visual.Properties().TryGetScalar(L"ReactNative.TabIndex")) { + return static_cast(tabIndexValue.Value()); + } + } + // Fallback to props if not set in Visual Properties return m_props->tabIndex; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp index 7bbcc2bb229..f20b88f8dc1 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp @@ -5,7 +5,6 @@ #include "FocusManager.h" #include "Composition.FocusManager.g.cpp" #include -#include namespace winrt::Microsoft::ReactNative::implementation { @@ -117,40 +116,23 @@ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelpe winrt::Microsoft::ReactNative::implementation::ComponentView &view, winrt::Microsoft::ReactNative::FocusNavigationReason reason) { if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First) { - // For First navigation, we need to consider tabIndex - auto tabIndex = view.tabIndex(); - - // If this view has a positive tabIndex, it should be focusable - if (tabIndex >= 0 && tabIndex != std::numeric_limits::max()) { - return &view; - } - - // Otherwise, check if it's naturally focusable if (view.focusable()) { return &view; } } - + winrt::Microsoft::ReactNative::implementation::ComponentView *toFocus = nullptr; Mso::Functor fn = - [reason, &toFocus](::winrt::Microsoft::ReactNative::implementation::ComponentView &v) noexcept - -> bool { return (toFocus = NavigateFocusHelper(v, reason)); }; + [reason, &toFocus](::winrt::Microsoft::ReactNative::implementation::ComponentView &v) noexcept -> bool { + return (toFocus = NavigateFocusHelper(v, reason)); + }; if (view.runOnChildren(reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First, fn)) { return toFocus; } if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::Last) { - // For Last navigation, we need to consider tabIndex - auto tabIndex = view.tabIndex(); - - // If this view has a positive tabIndex, it should be focusable - if (tabIndex >= 0 && tabIndex != std::numeric_limits::max()) { - return &view; - } - - // Otherwise, check if it's naturally focusable if (view.focusable()) { return &view; } From c9d30921a101b35d8bcc20a1c6f2f42270dccf83 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 20:21:31 +0000 Subject: [PATCH 5/5] Update tabIndex implementation to use proper Windows.UI.Composition APIs with comprehensive focus logic comments Co-authored-by: protikbiswas100 <219775028+protikbiswas100@users.noreply.github.com> --- .../CompositionViewComponentView.cpp | 38 ++++++++++++++----- .../Fabric/Composition/FocusManager.cpp | 14 +++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 75462166af0..abb283b3cdc 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1115,20 +1115,31 @@ void ViewComponentView::updateProps( Visual().Comment(winrt::to_hstring(newViewProps.testId)); } - // Update tabIndex using Windows.UI.Composition Visual Properties + // Update tabIndex using Windows.UI.Composition APIs for focus management if (oldViewProps.tabIndex != newViewProps.tabIndex) { auto visual = winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); + if (newViewProps.tabIndex != std::numeric_limits::max()) { - // Store tabIndex in Visual's Properties collection + // Use Windows.UI.Composition Visual Properties API to store tabIndex for focus navigation visual.Properties().InsertScalar(L"ReactNative.TabIndex", static_cast(newViewProps.tabIndex)); - // Also set IsHitTestVisible to make it participate in focus + + // Enable Windows.UI.Composition focus participation by setting IsHitTestVisible + // This integrates with the native Windows focus system for proper tab order handling visual.IsHitTestVisible(true); + + // Set focus capability in Visual properties for Windows.UI.Composition focus system + visual.Properties().InsertBoolean(L"ReactNative.Focusable", true); } else { - // Remove tabIndex property when not set + // Remove Windows.UI.Composition focus properties when tabIndex is not set if (visual.Properties().TryGetScalar(L"ReactNative.TabIndex")) { visual.Properties().Remove(L"ReactNative.TabIndex"); } + if (visual.Properties().TryGetBoolean(L"ReactNative.Focusable")) { + visual.Properties().Remove(L"ReactNative.Focusable"); + } + // Reset hit test visibility when not focusable through tabIndex + visual.IsHitTestVisible(false); } } @@ -1340,28 +1351,35 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ViewComponentV } bool ViewComponentView::focusable() const noexcept { - // Check if tabIndex is explicitly set via Windows.UI.Composition Visual Properties + // Windows.UI.Composition focus logic - check Visual Properties for focus capability if (m_visual) { auto visual = winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); + + // Check if explicitly marked as focusable in Windows.UI.Composition Visual Properties + if (auto focusableValue = visual.Properties().TryGetBoolean(L"ReactNative.Focusable")) { + return focusableValue.Value(); + } + + // Check Windows.UI.Composition Visual Properties for tabIndex-based focus capability if (auto tabIndexValue = visual.Properties().TryGetScalar(L"ReactNative.TabIndex")) { auto tabIndex = static_cast(tabIndexValue.Value()); - // Elements with tabIndex >= 0 are focusable, negative tabIndex means focusable but not in tab order + // Elements with tabIndex >= -1 are focusable (negative means focusable but not in tab order) return tabIndex >= -1; } } - // Fallback to props-based logic if not set in Visual Properties + // Fallback to React Native props-based focus logic if not set in Windows.UI.Composition if (m_props->tabIndex != std::numeric_limits::max()) { return m_props->tabIndex >= -1; } - // Default focusable behavior from props + // Default React Native focusable behavior from props return m_props->focusable; } int ViewComponentView::tabIndex() const noexcept { - // Read tabIndex from Windows.UI.Composition Visual Properties + // Windows.UI.Composition focus logic - read tabIndex from Visual Properties if (m_visual) { auto visual = winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()); @@ -1369,7 +1387,7 @@ int ViewComponentView::tabIndex() const noexcept { return static_cast(tabIndexValue.Value()); } } - // Fallback to props if not set in Visual Properties + // Fallback to React Native props if not set in Windows.UI.Composition Visual Properties return m_props->tabIndex; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp index f20b88f8dc1..6590043d376 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp @@ -112,9 +112,14 @@ void GettingFocusEventArgs::TrySetNewFocusedComponent( namespace winrt::Microsoft::ReactNative::Composition::implementation { +// Windows.UI.Composition-aware focus navigation helper +// This function implements the core focus navigation logic using Windows.UI.Composition APIs +// and React Native component tree traversal for tab order management winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelper( winrt::Microsoft::ReactNative::implementation::ComponentView &view, winrt::Microsoft::ReactNative::FocusNavigationReason reason) { + + // Windows.UI.Composition focus logic: Check if this view is focusable first if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First) { if (view.focusable()) { return &view; @@ -123,15 +128,18 @@ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelpe winrt::Microsoft::ReactNative::implementation::ComponentView *toFocus = nullptr; + // Focus navigation through component tree with Windows.UI.Composition integration Mso::Functor fn = [reason, &toFocus](::winrt::Microsoft::ReactNative::implementation::ComponentView &v) noexcept -> bool { return (toFocus = NavigateFocusHelper(v, reason)); }; + // Traverse children using Windows.UI.Composition-aware focus logic if (view.runOnChildren(reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First, fn)) { return toFocus; } + // Windows.UI.Composition focus logic: Check if this view is focusable for last navigation if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::Last) { if (view.focusable()) { return &view; @@ -141,9 +149,12 @@ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelpe return nullptr; } +// Windows.UI.Composition focus API: Find the first focusable element in the component tree +// Uses Windows.UI.Composition Visual Properties to determine focus capability winrt::Microsoft::ReactNative::ComponentView FocusManager::FindFirstFocusableElement( const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept { auto selfSearchScope = winrt::get_self(searchScope); + // Use Windows.UI.Composition-aware navigation helper for focus search auto view = NavigateFocusHelper(*selfSearchScope, winrt::Microsoft::ReactNative::FocusNavigationReason::First); if (view) { winrt::Microsoft::ReactNative::ComponentView component{nullptr}; @@ -154,9 +165,12 @@ winrt::Microsoft::ReactNative::ComponentView FocusManager::FindFirstFocusableEle return nullptr; } +// Windows.UI.Composition focus API: Find the last focusable element in the component tree +// Uses Windows.UI.Composition Visual Properties to determine focus capability winrt::Microsoft::ReactNative::ComponentView FocusManager::FindLastFocusableElement( const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept { auto selfSearchScope = winrt::get_self(searchScope); + // Use Windows.UI.Composition-aware navigation helper for focus search auto view = NavigateFocusHelper(*selfSearchScope, winrt::Microsoft::ReactNative::FocusNavigationReason::Last); if (view) { winrt::Microsoft::ReactNative::ComponentView component{nullptr};