Skip to content

Commit 4bb47d0

Browse files
authored
Implements selectionColor for <Text> (#15553) (#15556)
* implements selectionColor * Change files
1 parent 8fc409b commit 4bb47d0

File tree

6 files changed

+315
-3
lines changed

6 files changed

+315
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "implements selectionColor",
4+
"packageName": "react-native-windows",
5+
"email": "74712637+iamAbhi-916@users.noreply.github.com",
6+
"dependentChangeType": "patch"
7+
}

packages/playground/Samples/text.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,42 @@ export default class Bootstrap extends React.Component {
3737
</Text>
3838
</View>
3939

40+
<View style={styles.selectionColorTestContainer}>
41+
<Text style={styles.sectionTitle}>Selection Color Test</Text>
42+
<Text
43+
selectable={true}
44+
selectionColor="red"
45+
style={styles.selectableText}>
46+
Red selection color - Select this text to see red highlight!
47+
</Text>
48+
<Text
49+
selectable={true}
50+
selectionColor="#00FF00"
51+
style={styles.selectableText}>
52+
Green selection color (#00FF00) - Select this text!
53+
</Text>
54+
<Text
55+
selectable={true}
56+
selectionColor="rgba(255, 165, 0, 0.5)"
57+
style={styles.selectableText}>
58+
Orange with 50% opacity - Select this text!
59+
</Text>
60+
<Text
61+
selectable={true}
62+
selectionColor="blue"
63+
style={styles.selectableText}>
64+
Blue selection color - Select this text!
65+
</Text>
66+
<Text selectable={true} style={styles.selectableText}>
67+
Default selection color (no selectionColor prop) - Uses theme
68+
default.
69+
</Text>
70+
</View>
71+
4072
<View
4173
style={styles.container2}
4274
accessible={true}
43-
accessibilityLabel="Annotation Checkc"
75+
accessibilityLabel="Annotation Check"
4476
accessibilityAnnotation={{
4577
typeID: 'Comment',
4678
typeName: 'Check Comment',
@@ -88,6 +120,13 @@ const styles = StyleSheet.create({
88120
borderRadius: 8,
89121
width: 400,
90122
},
123+
selectionColorTestContainer: {
124+
backgroundColor: '#fff0f5',
125+
padding: 15,
126+
marginVertical: 10,
127+
borderRadius: 8,
128+
width: 400,
129+
},
91130
sectionTitle: {
92131
fontSize: 18,
93132
fontWeight: 'bold',

vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ void ParagraphComponentView::updateProps(
107107
m_requireRedraw = true;
108108
}
109109

110+
if (oldViewProps.selectionColor != newViewProps.selectionColor) {
111+
m_requireRedraw = true;
112+
}
113+
110114
Super::updateProps(props, oldProps);
111115
}
112116

@@ -454,9 +458,14 @@ void ParagraphComponentView::DrawSelectionHighlight(
454458
return;
455459
}
456460

457-
// TODO: use prop selectionColor if provided
458461
winrt::com_ptr<ID2D1SolidColorBrush> selectionBrush;
459-
const D2D1_COLOR_F selectionColor = theme()->D2DPlatformColor("Highlight@40");
462+
D2D1_COLOR_F selectionColor;
463+
const auto &props = paragraphProps();
464+
if (props.selectionColor) {
465+
selectionColor = theme()->D2DColor(**props.selectionColor);
466+
} else {
467+
selectionColor = theme()->D2DPlatformColor("Highlight@40");
468+
}
460469
hr = renderTarget.CreateSolidColorBrush(selectionColor, selectionBrush.put());
461470

462471
if (FAILED(hr)) {
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "BaseParagraphProps.h"
9+
10+
#include <react/featureflags/ReactNativeFeatureFlags.h>
11+
#include <react/renderer/attributedstring/conversions.h>
12+
#include <react/renderer/attributedstring/primitives.h>
13+
#include <react/renderer/core/propsConversions.h>
14+
#include <react/renderer/debug/debugStringConvertibleUtils.h>
15+
16+
#include <glog/logging.h>
17+
18+
namespace facebook::react {
19+
20+
BaseParagraphProps::BaseParagraphProps(
21+
const PropsParserContext& context,
22+
const BaseParagraphProps& sourceProps,
23+
const RawProps& rawProps)
24+
: ViewProps(context, sourceProps, rawProps),
25+
BaseTextProps(context, sourceProps, rawProps),
26+
paragraphAttributes(
27+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
28+
? sourceProps.paragraphAttributes
29+
: convertRawProp(
30+
context,
31+
rawProps,
32+
sourceProps.paragraphAttributes,
33+
{})),
34+
isSelectable(
35+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
36+
? sourceProps.isSelectable
37+
: convertRawProp(
38+
context,
39+
rawProps,
40+
"selectable",
41+
sourceProps.isSelectable,
42+
false)),
43+
onTextLayout(
44+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
45+
? sourceProps.onTextLayout
46+
: convertRawProp(
47+
context,
48+
rawProps,
49+
"onTextLayout",
50+
sourceProps.onTextLayout,
51+
{})),
52+
// [Windows]
53+
selectionColor(
54+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
55+
? sourceProps.selectionColor
56+
: convertRawProp(
57+
context,
58+
rawProps,
59+
"selectionColor",
60+
sourceProps.selectionColor,
61+
{})) {
62+
/*
63+
* These props are applied to `View`, therefore they must not be a part of
64+
* base text attributes.
65+
*/
66+
textAttributes.opacity = std::numeric_limits<Float>::quiet_NaN();
67+
textAttributes.backgroundColor = {};
68+
};
69+
70+
void BaseParagraphProps::setProp(
71+
const PropsParserContext& context,
72+
RawPropsPropNameHash hash,
73+
const char* propName,
74+
const RawValue& value) {
75+
// All Props structs setProp methods must always, unconditionally,
76+
// call all super::setProp methods, since multiple structs may
77+
// reuse the same values.
78+
ViewProps::setProp(context, hash, propName, value);
79+
BaseTextProps::setProp(context, hash, propName, value);
80+
81+
static auto defaults = BaseParagraphProps{};
82+
83+
// ParagraphAttributes has its own switch statement - to keep all
84+
// of these fields together, and because there are some collisions between
85+
// propnames parsed here and outside of ParagraphAttributes.
86+
// This code is also duplicated in AndroidTextInput.
87+
static auto paDefaults = ParagraphAttributes{};
88+
switch (hash) {
89+
REBUILD_FIELD_SWITCH_CASE(
90+
paDefaults,
91+
value,
92+
paragraphAttributes,
93+
maximumNumberOfLines,
94+
"numberOfLines");
95+
REBUILD_FIELD_SWITCH_CASE(
96+
paDefaults, value, paragraphAttributes, ellipsizeMode, "ellipsizeMode");
97+
REBUILD_FIELD_SWITCH_CASE(
98+
paDefaults,
99+
value,
100+
paragraphAttributes,
101+
textBreakStrategy,
102+
"textBreakStrategy");
103+
REBUILD_FIELD_SWITCH_CASE(
104+
paDefaults,
105+
value,
106+
paragraphAttributes,
107+
adjustsFontSizeToFit,
108+
"adjustsFontSizeToFit");
109+
REBUILD_FIELD_SWITCH_CASE(
110+
paDefaults,
111+
value,
112+
paragraphAttributes,
113+
minimumFontScale,
114+
"minimumFontScale");
115+
REBUILD_FIELD_SWITCH_CASE(
116+
paDefaults,
117+
value,
118+
paragraphAttributes,
119+
minimumFontSize,
120+
"minimumFontSize");
121+
REBUILD_FIELD_SWITCH_CASE(
122+
paDefaults,
123+
value,
124+
paragraphAttributes,
125+
maximumFontSize,
126+
"maximumFontSize");
127+
REBUILD_FIELD_SWITCH_CASE(
128+
paDefaults,
129+
value,
130+
paragraphAttributes,
131+
includeFontPadding,
132+
"includeFontPadding");
133+
REBUILD_FIELD_SWITCH_CASE(
134+
paDefaults,
135+
value,
136+
paragraphAttributes,
137+
android_hyphenationFrequency,
138+
"android_hyphenationFrequency");
139+
REBUILD_FIELD_SWITCH_CASE(
140+
paDefaults,
141+
value,
142+
paragraphAttributes,
143+
textAlignVertical,
144+
"textAlignVertical");
145+
}
146+
147+
switch (hash) {
148+
RAW_SET_PROP_SWITCH_CASE(isSelectable, "selectable");
149+
RAW_SET_PROP_SWITCH_CASE_BASIC(onTextLayout);
150+
// [Windows]
151+
RAW_SET_PROP_SWITCH_CASE_BASIC(selectionColor);
152+
}
153+
154+
/*
155+
* These props are applied to `View`, therefore they must not be a part of
156+
* base text attributes.
157+
*/
158+
textAttributes.opacity = std::numeric_limits<Float>::quiet_NaN();
159+
textAttributes.backgroundColor = {};
160+
}
161+
162+
#pragma mark - DebugStringConvertible
163+
164+
#if RN_DEBUG_STRING_CONVERTIBLE
165+
SharedDebugStringConvertibleList BaseParagraphProps::getDebugProps() const {
166+
return ViewProps::getDebugProps() + BaseTextProps::getDebugProps() +
167+
paragraphAttributes.getDebugProps() +
168+
SharedDebugStringConvertibleList{
169+
debugStringConvertibleItem("selectable", isSelectable),
170+
// [Windows]
171+
debugStringConvertibleItem("selectionColor", selectionColor)};
172+
}
173+
#endif
174+
} // namespace facebook::react
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <limits>
11+
#include <memory>
12+
// [Windows]
13+
#include <optional>
14+
15+
#include <react/renderer/attributedstring/ParagraphAttributes.h>
16+
#include <react/renderer/components/text/BaseTextProps.h>
17+
#include <react/renderer/components/view/ViewProps.h>
18+
#include <react/renderer/core/Props.h>
19+
#include <react/renderer/core/PropsParserContext.h>
20+
// [Windows]
21+
#include <react/renderer/graphics/Color.h>
22+
23+
namespace facebook::react {
24+
25+
/*
26+
* Props of <Paragraph> component.
27+
* Most of the props are directly stored in composed `ParagraphAttributes`
28+
* object.
29+
*/
30+
class BaseParagraphProps : public ViewProps, public BaseTextProps {
31+
public:
32+
BaseParagraphProps() = default;
33+
BaseParagraphProps(
34+
const PropsParserContext &context,
35+
const BaseParagraphProps &sourceProps,
36+
const RawProps &rawProps);
37+
38+
void
39+
setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, const RawValue &value);
40+
41+
#pragma mark - Props
42+
43+
/*
44+
* Contains all prop values that affect visual representation of the
45+
* paragraph.
46+
*/
47+
ParagraphAttributes paragraphAttributes{};
48+
49+
/*
50+
* Defines can the text be selected (and copied) or not.
51+
*/
52+
bool isSelectable{};
53+
54+
bool onTextLayout{};
55+
56+
/*
57+
* Defines the color of the selection highlight.
58+
* [Windows]
59+
*/
60+
std::optional<SharedColor> selectionColor{};
61+
62+
#pragma mark - DebugStringConvertible
63+
64+
#if RN_DEBUG_STRING_CONVERTIBLE
65+
SharedDebugStringConvertibleList getDebugProps() const override;
66+
#endif
67+
};
68+
69+
} // namespace facebook::react

vnext/overrides.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,20 @@
159159
"baseHash": "7fdf1967fa9c3421b11e841afcf207624df18706",
160160
"issue": 15379
161161
},
162+
{
163+
"type": "derived",
164+
"file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp",
165+
"baseFile": "packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp",
166+
"baseHash": "1aaf0a003c83195882c512a664409e429de4f892",
167+
"issue": 15552
168+
},
169+
{
170+
"type": "derived",
171+
"file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h",
172+
"baseFile": "packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.h",
173+
"baseHash": "7661ba5c8392034cbda48f5d4b721a1ff30fe68d",
174+
"issue": 15552
175+
},
162176
{
163177
"type": "patch",
164178
"file": "ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/ParagraphShadowNode.cpp",

0 commit comments

Comments
 (0)