From 5a6a4dfc368c2dee1384ff08c7d773cbd42a013e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 16 Sep 2025 11:28:35 -0700 Subject: [PATCH 1/7] add host platform headers --- .../components/view/HostPlatformTouch.h | 16 ++++++++++++ .../view/HostPlatformViewEventEmitter.h | 26 +++++++++++++++++++ .../components/view/HostPlatformViewProps.h | 16 ++++++++++++ .../view/HostPlatformViewTraitsInitializer.h | 23 ++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h new file mode 100644 index 00000000000000..ef3b407272250e --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + // [macOS] + +#pragma once + +#include + +namespace facebook::react { +using HostPlatformTouch = BaseTouch; +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h new file mode 100644 index 00000000000000..a844eaeea37b07 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + // [macOS] + +#pragma once + +#include + +namespace facebook::react { +using HostPlatformViewEventEmitter = BaseViewEventEmitter; +} // namespace facebook::react + +#pragma mark - Focus Events + +void HostPlatformViewEventEmitter::onFocus() const { + dispatchEvent("focus"); +} + +void HostPlatformViewEventEmitter::onBlur() const { + dispatchEvent("blur"); +} \ No newline at end of file diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h new file mode 100644 index 00000000000000..636185775491cb --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + // [macOS] + +#pragma once + +#include + +namespace facebook::react { +using HostPlatformViewProps = BaseViewProps; +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h new file mode 100644 index 00000000000000..f40277e3b0356f --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook::react::HostPlatformViewTraitsInitializer { + +inline bool formsStackingContext(const ViewProps& props) { + return false; +} + +inline bool formsView(const ViewProps& props) { + return false; +} + +} // namespace facebook::react::HostPlatformViewTraitsInitializer From 19aa285c323f7ca604b5cf1df4e16f8d90f808e9 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 16 Sep 2025 11:53:28 -0700 Subject: [PATCH 2/7] Add focus props --- .../components/view/HostPlatformViewProps.h | 29 ++++++++- .../view/HostPlatformViewTraitsInitializer.h | 2 +- .../components/view/MacOSViewEvents.h | 60 +++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h index 636185775491cb..502ae1bc398d2b 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h @@ -6,11 +6,36 @@ */ // [macOS] - + #pragma once #include +#include +#include +#include namespace facebook::react { -using HostPlatformViewProps = BaseViewProps; + +class HostPlatformViewProps : public BaseViewProps { + public: + HostPlatformViewProps() = default; + HostPlatformViewProps( + const PropsParserContext& context, + const HostPlatformViewProps& sourceProps, + const RawProps& rawProps); + + void setProp( + const PropsParserContext& context, + RawPropsPropNameHash hash, + const char* propName, + const RawValue& value); + + MacOSViewEvents macOSViewEvents{}; + +#pragma mark - Props + + bool focusable{false}; + bool enableFocusRing{true}; + +}; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h index f40277e3b0356f..133994e1e9c10a 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h @@ -17,7 +17,7 @@ inline bool formsStackingContext(const ViewProps& props) { } inline bool formsView(const ViewProps& props) { - return false; + return props.focusable || props.enableFocusRing; } } // namespace facebook::react::HostPlatformViewTraitsInitializer diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h new file mode 100644 index 00000000000000..6956812fbb7a3a --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +namespace facebook::react { + +struct MacOSViewEvents { + std::bitset<8> bits{}; // TODO: Windows sets this to 32.. should we be higher? + + enum class Offset : uint8_t { // TODO: Windows sets this and others to std::size_t instead of uint8_t.. should we? + // Focus Events + Focus = 0, + Blur = 1, + }; + + constexpr bool operator[](const Offset offset) const { + return bits[static_cast(offset)]; + } + + std::bitset<8>::reference operator[](const Offset offset) { + return bits[static_cast(offset)]; + } +}; + +inline static bool operator==(MacOSViewEvents const &lhs, MacOSViewEvents const &rhs) { + return lhs.bits == rhs.bits; +} + +inline static bool operator!=(MacOSViewEvents const &lhs, MacOSViewEvents const &rhs) { + return lhs.bits != rhs.bits; +} + +static inline MacOSViewEvents convertRawProp( + const PropsParserContext &context, + const RawProps &rawProps, + const MacOSViewEvents &sourceValue, + const MacOSViewEvents &defaultValue) { + MacOSViewEvents result{}; + using Offset = MacOSViewEvents::Offset; + + // Focus Events + result[Offset::Focus] = + convertRawProp(context, rawProps, "onFocus", sourceValue[Offset::Focus], defaultValue[Offset::Focus]); + result[Offset::Blur] = + convertRawProp(context, rawProps, "onBlur", sourceValue[Offset::Blur], defaultValue[Offset::Blur]); + + return result; +} + +} // namespace facebook::react \ No newline at end of file From a58b40632908c4de00854eefd85303814832a5fd Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 16 Sep 2025 13:47:22 -0700 Subject: [PATCH 3/7] Add macOS props and events --- .../view/HostPlatformViewEventEmitter.cpp | 24 ++++++ .../view/HostPlatformViewEventEmitter.h | 16 ++-- .../components/view/HostPlatformViewProps.cpp | 86 +++++++++++++++++++ .../components/view/HostPlatformViewProps.h | 2 + .../components/view/MacOSViewEvents.h | 1 + 5 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp create mode 100644 packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp new file mode 100644 index 00000000000000..6ad5d85108777b --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + // [macOS] + +#include + +namespace facebook::react { + +#pragma mark - Focus Events + +void HostPlatformViewEventEmitter::onFocus() const { + dispatchEvent("focus"); +} + +void HostPlatformViewEventEmitter::onBlur() const { + dispatchEvent("blur"); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h index a844eaeea37b07..132f1563e5a8ea 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h @@ -12,15 +12,15 @@ #include namespace facebook::react { -using HostPlatformViewEventEmitter = BaseViewEventEmitter; -} // namespace facebook::react + +class HostPlatformViewEventEmitter : public BaseViewEventEmitter { + public: + using BaseViewEventEmitter::BaseViewEventEmitter; #pragma mark - Focus Events -void HostPlatformViewEventEmitter::onFocus() const { - dispatchEvent("focus"); -} + void onFocus() const; + void onBlur() const; +}; -void HostPlatformViewEventEmitter::onBlur() const { - dispatchEvent("blur"); -} \ No newline at end of file +} // namespace facebook::react \ No newline at end of file diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp new file mode 100644 index 00000000000000..ad224e03eb1c30 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp @@ -0,0 +1,86 @@ +/* + * 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 "HostPlatformViewProps.h" + +#include + +#include +#include +#include +#include +#include + +namespace facebook::react { + +HostPlatformViewProps::HostPlatformViewProps( + const PropsParserContext& context, + const HostPlatformViewProps& sourceProps, + const RawProps& rawProps) + : BaseViewProps(context, sourceProps, rawProps), + macOSViewEvents( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.macOSViewEvents + : convertRawProp( + context, + rawProps, + sourceProps.macOSViewEvents, + {})), + focusable( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.focusable + : convertRawProp( + context, + rawProps, + "focusable", + sourceProps.focusable, + {})), + enableFocusRing( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.enableFocusRing + : convertRawProp( + context, + rawProps, + "enableFocusRing", + sourceProps.enableFocusRing, + {})) {} + +#define MACOS_VIEW_EVENT_CASE(eventType) \ +case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \ + const auto offset = MacOSViewEvents::Offset::eventType; \ + MacOSViewEvents defaultViewEvents{}; \ + bool res = defaultViewEvents[offset]; \ + if (value.hasValue()) { \ + fromRawValue(context, value, res); \ + } \ + macOSViewEvents[offset] = res; \ + return; \ +} + +void HostPlatformViewProps::setProp( + const PropsParserContext& context, + RawPropsPropNameHash hash, + const char* propName, + const RawValue& value) { + // All Props structs setProp methods must always, unconditionally, + // call all super::setProp methods, since multiple structs may + // reuse the same values. + BaseViewProps::setProp(context, hash, propName, value); + + static auto defaults = HostPlatformViewProps{}; + + switch (hash) { + RAW_SET_PROP_SWITCH_CASE_BASIC(focusable); + RAW_SET_PROP_SWITCH_CASE_BASIC(enableFocusRing); + MACOS_VIEW_EVENT_CASE(Focus); + MACOS_VIEW_EVENT_CASE(Blur); + + } +} + + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h index 502ae1bc398d2b..b60a690aa5eb35 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h @@ -14,6 +14,8 @@ #include #include +#include "MacOSViewEvents.h" + namespace facebook::react { class HostPlatformViewProps : public BaseViewProps { diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h index 6956812fbb7a3a..24fade5cdff963 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h @@ -14,6 +14,7 @@ namespace facebook::react { +// TODO: Windows names this "WindowsEvents" and drops "View". Should we? struct MacOSViewEvents { std::bitset<8> bits{}; // TODO: Windows sets this to 32.. should we be higher? From 96691575f166c3acb76ae2ef35406c521c223d11 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 16 Sep 2025 13:47:31 -0700 Subject: [PATCH 4/7] fix casting issue --- .../ScrollView/RCTPullToRefreshViewComponentView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm index 486f0c1251fe18..e5cb16b6749a14 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm @@ -76,7 +76,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & { // Prop updates are ignored by _refreshControl until after the initial layout, so just store them in _props until then if (_isBeforeInitialLayout) { - _props = std::static_pointer_cast(props); + _props = std::static_pointer_cast(props); // [macOS] return; } From 1a0b81af4ec499f1110a02550cf7c09795b0baf4 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 16 Sep 2025 14:49:33 -0700 Subject: [PATCH 5/7] uint8_t --> std::size_t --- .../react/renderer/components/view/MacOSViewEvents.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h index 24fade5cdff963..d346e1a2db32a2 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h @@ -16,20 +16,20 @@ namespace facebook::react { // TODO: Windows names this "WindowsEvents" and drops "View". Should we? struct MacOSViewEvents { - std::bitset<8> bits{}; // TODO: Windows sets this to 32.. should we be higher? + std::bitset<64> bits{}; - enum class Offset : uint8_t { // TODO: Windows sets this and others to std::size_t instead of uint8_t.. should we? + enum class Offset : std::size_t { // Focus Events Focus = 0, Blur = 1, }; constexpr bool operator[](const Offset offset) const { - return bits[static_cast(offset)]; + return bits[static_cast(offset)]; } - std::bitset<8>::reference operator[](const Offset offset) { - return bits[static_cast(offset)]; + std::bitset<64>::reference operator[](const Offset offset) { + return bits[static_cast(offset)]; } }; @@ -58,4 +58,4 @@ static inline MacOSViewEvents convertRawProp( return result; } -} // namespace facebook::react \ No newline at end of file +} // namespace facebook::react From 0f76473ab8799d5a3f44f2113bca97f0ee143ba4 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 17 Sep 2025 10:56:21 -0700 Subject: [PATCH 6/7] PR feedback --- .../components/view/HostPlatformViewTraitsInitializer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h index 133994e1e9c10a..4f678feeb24c1f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h @@ -17,7 +17,7 @@ inline bool formsStackingContext(const ViewProps& props) { } inline bool formsView(const ViewProps& props) { - return props.focusable || props.enableFocusRing; + return props.focusable; } } // namespace facebook::react::HostPlatformViewTraitsInitializer From 7ca8960f6650e81b11f6653aab7a5748bfff930e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 17 Sep 2025 11:05:13 -0700 Subject: [PATCH 7/7] remove comment --- .../macos/react/renderer/components/view/MacOSViewEvents.h | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h index d346e1a2db32a2..8657de54c77ed6 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/MacOSViewEvents.h @@ -14,7 +14,6 @@ namespace facebook::react { -// TODO: Windows names this "WindowsEvents" and drops "View". Should we? struct MacOSViewEvents { std::bitset<64> bits{};