Skip to content

Commit 4cf06e3

Browse files
committed
fix(text): support start and end text alignment
1 parent 9ac12ce commit 4cf06e3

18 files changed

Lines changed: 189 additions & 27 deletions

File tree

packages/react-native/Libraries/Components/TextInput/TextInput.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,9 +972,9 @@ export interface TextInputProps
972972
style?: StyleProp<TextStyle> | undefined;
973973

974974
/**
975-
* Align the input text to the left, center, or right sides of the input field.
975+
* Align the input text to the left, center, right, start, or end side of the input field.
976976
*/
977-
textAlign?: 'left' | 'center' | 'right' | undefined;
977+
textAlign?: 'left' | 'center' | 'right' | 'start' | 'end' | undefined;
978978

979979
/**
980980
* Used to locate this view in end-to-end tests

packages/react-native/Libraries/Components/TextInput/TextInput.flow.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,9 +1051,9 @@ type TextInputBaseProps = Readonly<{
10511051
value?: ?Stringish,
10521052

10531053
/**
1054-
* Align the input text to the left, center, or right sides of the input field.
1054+
* Align the input text to the left, center, right, start, or end side of the input field.
10551055
*/
1056-
textAlign?: ?('left' | 'center' | 'right'),
1056+
textAlign?: ?('left' | 'center' | 'right' | 'start' | 'end'),
10571057
}>;
10581058

10591059
/** @build-types emit-as-interface Uniwind compatibility */

packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,15 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle {
627627
| undefined;
628628
letterSpacing?: number | undefined;
629629
lineHeight?: number | undefined;
630-
textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify' | undefined;
630+
textAlign?:
631+
| 'auto'
632+
| 'left'
633+
| 'right'
634+
| 'center'
635+
| 'justify'
636+
| 'start'
637+
| 'end'
638+
| undefined;
631639
textDecorationLine?:
632640
| 'none'
633641
| 'underline'

packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,14 @@ type ____TextStyle_InternalBase = Readonly<{
10101010
textShadowColor?: ____ColorValue_Internal,
10111011
letterSpacing?: number,
10121012
lineHeight?: number,
1013-
textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify',
1013+
textAlign?:
1014+
| 'auto'
1015+
| 'left'
1016+
| 'right'
1017+
| 'center'
1018+
| 'justify'
1019+
| 'start'
1020+
| 'end',
10141021
textAlignVertical?: 'auto' | 'top' | 'bottom' | 'center',
10151022
includeFontPadding?: boolean,
10161023
textDecorationLine?:

packages/react-native/React/Base/RCTConvert.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ + (NSLocale *)NSLocale:(id)json
316316
NSTextAlignment,
317317
(@{
318318
@"auto" : @(NSTextAlignmentNatural),
319+
@"start" : @(NSTextAlignmentLeft),
320+
@"end" : @(NSTextAlignmentRight),
319321
@"left" : @(NSTextAlignmentLeft),
320322
@"center" : @(NSTextAlignmentCenter),
321323
@"right" : @(NSTextAlignmentRight),

packages/react-native/React/Tests/Text/RCTAttributedTextUtilsTest.mm

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
#import <react/renderer/textlayoutmanager/RCTAttributedTextUtils.h>
1212

13+
#include <react/renderer/attributedstring/conversions.h>
14+
#include <react/renderer/core/RawValue.h>
15+
1316
using namespace facebook::react;
1417

1518
@interface RCTAttributedTextUtilsTest : XCTestCase
@@ -18,6 +21,40 @@ @interface RCTAttributedTextUtilsTest : XCTestCase
1821

1922
@implementation RCTAttributedTextUtilsTest
2023

24+
static NSTextAlignment NSTextAlignmentFromTextAlign(
25+
NSString *textAlign,
26+
LayoutDirection layoutDirection)
27+
{
28+
ContextContainer contextContainer{};
29+
PropsParserContext parserContext{-1, contextContainer};
30+
TextAlignment textAlignment = TextAlignment::Natural;
31+
fromRawValue(parserContext, RawValue{folly::dynamic{textAlign.UTF8String}}, textAlignment);
32+
33+
TextAttributes textAttributes;
34+
textAttributes.alignment = textAlignment;
35+
textAttributes.layoutDirection = layoutDirection;
36+
37+
NSDictionary<NSAttributedStringKey, id> *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes);
38+
NSParagraphStyle *paragraphStyle = attributes[NSParagraphStyleAttributeName];
39+
return paragraphStyle.alignment;
40+
}
41+
42+
- (void)testTextAlignmentStartAndEndResolveWithLayoutDirection
43+
{
44+
XCTAssertEqual(
45+
NSTextAlignmentFromTextAlign(@"start", LayoutDirection::LeftToRight),
46+
NSTextAlignmentLeft);
47+
XCTAssertEqual(
48+
NSTextAlignmentFromTextAlign(@"start", LayoutDirection::RightToLeft),
49+
NSTextAlignmentRight);
50+
XCTAssertEqual(
51+
NSTextAlignmentFromTextAlign(@"end", LayoutDirection::LeftToRight),
52+
NSTextAlignmentRight);
53+
XCTAssertEqual(
54+
NSTextAlignmentFromTextAlign(@"end", LayoutDirection::RightToLeft),
55+
NSTextAlignmentLeft);
56+
}
57+
2158
- (void)testSamenessOfEmptyAttributedStrings
2259
{
2360
NSAttributedString *attributedString1 = [[NSAttributedString alloc] initWithString:@""];

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ public class TextAttributeProps private constructor() {
507507
"justify" -> Gravity.LEFT
508508
null,
509509
"auto" -> Gravity.NO_GRAVITY
510+
"start" -> if (isRTL) Gravity.RIGHT else Gravity.LEFT
511+
"end" -> if (isRTL) Gravity.LEFT else Gravity.RIGHT
510512
"left" -> if (isRTL) Gravity.RIGHT else Gravity.LEFT
511513
"right" -> if (isRTL) Gravity.LEFT else Gravity.RIGHT
512514
"center" -> Gravity.CENTER_HORIZONTAL

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ internal object TextLayoutManager {
210210

211211
if (alignmentAttr == "center") {
212212
alignment = Layout.Alignment.ALIGN_CENTER
213-
} else if (alignmentAttr == "right") {
213+
} else if (alignmentAttr == "right" || alignmentAttr == "end") {
214214
alignment =
215215
if (swapNormalAndOpposite) Layout.Alignment.ALIGN_NORMAL
216216
else Layout.Alignment.ALIGN_OPPOSITE

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ public open class ReactTextInputManager public constructor() :
557557
when (textAlign) {
558558
null,
559559
"auto" -> view.gravityHorizontal = Gravity.NO_GRAVITY
560+
"start" -> view.gravityHorizontal = Gravity.START
561+
"end" -> view.gravityHorizontal = Gravity.END
560562
"left" -> view.gravityHorizontal = Gravity.LEFT
561563
"right" -> view.gravityHorizontal = Gravity.RIGHT
562564
"center" -> view.gravityHorizontal = Gravity.CENTER_HORIZONTAL
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
package com.facebook.react.views.text
9+
10+
import android.view.Gravity
11+
import com.facebook.react.bridge.JavaOnlyMap
12+
import com.facebook.react.uimanager.ReactStylesDiffMap
13+
import org.assertj.core.api.Assertions.assertThat
14+
import org.junit.Test
15+
16+
class TextAttributePropsTest {
17+
18+
@Test
19+
fun textAlignStartUsesStartSide() {
20+
assertThat(textAlignment("start", isRTL = false)).isEqualTo(Gravity.LEFT)
21+
assertThat(textAlignment("start", isRTL = true)).isEqualTo(Gravity.RIGHT)
22+
}
23+
24+
@Test
25+
fun textAlignEndUsesEndSide() {
26+
assertThat(textAlignment("end", isRTL = false)).isEqualTo(Gravity.RIGHT)
27+
assertThat(textAlignment("end", isRTL = true)).isEqualTo(Gravity.LEFT)
28+
}
29+
30+
private fun textAlignment(textAlign: String, isRTL: Boolean): Int {
31+
return TextAttributeProps.getTextAlignment(
32+
ReactStylesDiffMap(JavaOnlyMap.of("textAlign", textAlign)),
33+
isRTL,
34+
Gravity.CENTER_HORIZONTAL,
35+
)
36+
}
37+
}

0 commit comments

Comments
 (0)