From d8242a41e37f24070f6b6f4b3a4405b081fdc37f Mon Sep 17 00:00:00 2001 From: Abhijeet Jha <74712637+iamAbhi-916@users.noreply.github.com> Date: Mon, 19 Jan 2026 10:18:23 +0530 Subject: [PATCH] Implements selectionColor for (#15553) * implements selectionColor * Change files --- ...-28d68603-5db6-40f6-9d44-4a5b489813d4.json | 7 + packages/playground/Samples/text.tsx | 41 ++++- .../Composition/ParagraphComponentView.cpp | 13 +- .../components/text/BaseParagraphProps.cpp | 174 ++++++++++++++++++ .../components/text/BaseParagraphProps.h | 69 +++++++ vnext/overrides.json | 14 ++ 6 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 change/react-native-windows-28d68603-5db6-40f6-9d44-4a5b489813d4.json create mode 100644 vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp create mode 100644 vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h diff --git a/change/react-native-windows-28d68603-5db6-40f6-9d44-4a5b489813d4.json b/change/react-native-windows-28d68603-5db6-40f6-9d44-4a5b489813d4.json new file mode 100644 index 00000000000..e9f5b2f70ae --- /dev/null +++ b/change/react-native-windows-28d68603-5db6-40f6-9d44-4a5b489813d4.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "implements selectionColor", + "packageName": "react-native-windows", + "email": "74712637+iamAbhi-916@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/playground/Samples/text.tsx b/packages/playground/Samples/text.tsx index e5ce13a5090..a3143746077 100644 --- a/packages/playground/Samples/text.tsx +++ b/packages/playground/Samples/text.tsx @@ -37,10 +37,42 @@ export default class Bootstrap extends React.Component { + + Selection Color Test + + Red selection color - Select this text to see red highlight! + + + Green selection color (#00FF00) - Select this text! + + + Orange with 50% opacity - Select this text! + + + Blue selection color - Select this text! + + + Default selection color (no selectionColor prop) - Uses theme + default. + + + selectionBrush; - const D2D1_COLOR_F selectionColor = theme()->D2DPlatformColor("Highlight@40"); + D2D1_COLOR_F selectionColor; + const auto &props = paragraphProps(); + if (props.selectionColor) { + selectionColor = theme()->D2DColor(**props.selectionColor); + } else { + selectionColor = theme()->D2DPlatformColor("Highlight@40"); + } hr = renderTarget.CreateSolidColorBrush(selectionColor, selectionBrush.put()); if (FAILED(hr)) { diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp new file mode 100644 index 00000000000..e2f3091a321 --- /dev/null +++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp @@ -0,0 +1,174 @@ +/* + * 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 "BaseParagraphProps.h" + +#include +#include +#include +#include +#include + +#include + +namespace facebook::react { + +BaseParagraphProps::BaseParagraphProps( + const PropsParserContext& context, + const BaseParagraphProps& sourceProps, + const RawProps& rawProps) + : ViewProps(context, sourceProps, rawProps), + BaseTextProps(context, sourceProps, rawProps), + paragraphAttributes( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.paragraphAttributes + : convertRawProp( + context, + rawProps, + sourceProps.paragraphAttributes, + {})), + isSelectable( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.isSelectable + : convertRawProp( + context, + rawProps, + "selectable", + sourceProps.isSelectable, + false)), + onTextLayout( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.onTextLayout + : convertRawProp( + context, + rawProps, + "onTextLayout", + sourceProps.onTextLayout, + {})), + // [Windows] + selectionColor( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.selectionColor + : convertRawProp( + context, + rawProps, + "selectionColor", + sourceProps.selectionColor, + {})) { + /* + * These props are applied to `View`, therefore they must not be a part of + * base text attributes. + */ + textAttributes.opacity = std::numeric_limits::quiet_NaN(); + textAttributes.backgroundColor = {}; +}; + +void BaseParagraphProps::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. + ViewProps::setProp(context, hash, propName, value); + BaseTextProps::setProp(context, hash, propName, value); + + static auto defaults = BaseParagraphProps{}; + + // ParagraphAttributes has its own switch statement - to keep all + // of these fields together, and because there are some collisions between + // propnames parsed here and outside of ParagraphAttributes. + // This code is also duplicated in AndroidTextInput. + static auto paDefaults = ParagraphAttributes{}; + switch (hash) { + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + maximumNumberOfLines, + "numberOfLines"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, value, paragraphAttributes, ellipsizeMode, "ellipsizeMode"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + textBreakStrategy, + "textBreakStrategy"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + adjustsFontSizeToFit, + "adjustsFontSizeToFit"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + minimumFontScale, + "minimumFontScale"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + minimumFontSize, + "minimumFontSize"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + maximumFontSize, + "maximumFontSize"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + includeFontPadding, + "includeFontPadding"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + android_hyphenationFrequency, + "android_hyphenationFrequency"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, + value, + paragraphAttributes, + textAlignVertical, + "textAlignVertical"); + } + + switch (hash) { + RAW_SET_PROP_SWITCH_CASE(isSelectable, "selectable"); + RAW_SET_PROP_SWITCH_CASE_BASIC(onTextLayout); + // [Windows] + RAW_SET_PROP_SWITCH_CASE_BASIC(selectionColor); + } + + /* + * These props are applied to `View`, therefore they must not be a part of + * base text attributes. + */ + textAttributes.opacity = std::numeric_limits::quiet_NaN(); + textAttributes.backgroundColor = {}; +} + +#pragma mark - DebugStringConvertible + +#if RN_DEBUG_STRING_CONVERTIBLE +SharedDebugStringConvertibleList BaseParagraphProps::getDebugProps() const { + return ViewProps::getDebugProps() + BaseTextProps::getDebugProps() + + paragraphAttributes.getDebugProps() + + SharedDebugStringConvertibleList{ + debugStringConvertibleItem("selectable", isSelectable), + // [Windows] + debugStringConvertibleItem("selectionColor", selectionColor)}; +} +#endif +} // namespace facebook::react diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h new file mode 100644 index 00000000000..b2ac7275c17 --- /dev/null +++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h @@ -0,0 +1,69 @@ +/* + * 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 +// [Windows] +#include + +#include +#include +#include +#include +#include +// [Windows] +#include + +namespace facebook::react { + +/* + * Props of component. + * Most of the props are directly stored in composed `ParagraphAttributes` + * object. + */ +class BaseParagraphProps : public ViewProps, public BaseTextProps { + public: + BaseParagraphProps() = default; + BaseParagraphProps( + const PropsParserContext &context, + const BaseParagraphProps &sourceProps, + const RawProps &rawProps); + + void + setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, const RawValue &value); + +#pragma mark - Props + + /* + * Contains all prop values that affect visual representation of the + * paragraph. + */ + ParagraphAttributes paragraphAttributes{}; + + /* + * Defines can the text be selected (and copied) or not. + */ + bool isSelectable{}; + + bool onTextLayout{}; + + /* + * Defines the color of the selection highlight. + * [Windows] + */ + std::optional selectionColor{}; + +#pragma mark - DebugStringConvertible + +#if RN_DEBUG_STRING_CONVERTIBLE + SharedDebugStringConvertibleList getDebugProps() const override; +#endif +}; + +} // namespace facebook::react diff --git a/vnext/overrides.json b/vnext/overrides.json index b116ceb1b22..63418e0e52c 100644 --- a/vnext/overrides.json +++ b/vnext/overrides.json @@ -159,6 +159,20 @@ "baseHash": "7fdf1967fa9c3421b11e841afcf207624df18706", "issue": 15379 }, + { + "type": "derived", + "file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp", + "baseFile": "packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp", + "baseHash": "1aaf0a003c83195882c512a664409e429de4f892", + "issue": 15552 + }, + { + "type": "derived", + "file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h", + "baseFile": "packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.h", + "baseHash": "7661ba5c8392034cbda48f5d4b721a1ff30fe68d", + "issue": 15552 + }, { "type": "patch", "file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/ParagraphShadowNode.cpp",