Skip to content

Commit 2d0d4d4

Browse files
committed
adding iOS functionalities from facebook#33468
for original commit history before applying squash see https://github.com/facebook/react-native/pull/33468/commits
1 parent 8ea1cba commit 2d0d4d4

File tree

19 files changed

+234
-2
lines changed

19 files changed

+234
-2
lines changed

Libraries/Components/TextInput/RCTTextInputViewConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ const RCTTextInputViewConfig = {
107107
allowFontScaling: true,
108108
fontStyle: true,
109109
textTransform: true,
110+
accessibilityErrorMessage: true,
111+
accessibilityInvalid: true,
110112
textAlign: true,
111113
fontFamily: true,
112114
lineHeight: true,

Libraries/Components/TextInput/TextInput.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,14 @@ export interface TextInputProps
521521
TextInputIOSProps,
522522
TextInputAndroidProps,
523523
AccessibilityProps {
524+
/**
525+
* String to be read by screenreaders to indicate an error state. The acceptable parameters
526+
* of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates
527+
* the error message. Setting accessibilityInvalid to false removes the error message.
528+
*/
529+
accessibilityErrorMessage?: string | undefined;
530+
accessibilityInvalid?: boolean | undefined;
531+
524532
/**
525533
* Specifies whether fonts should scale to respect Text Size accessibility settings.
526534
* The default is `true`.

Libraries/Components/TextInput/TextInput.flow.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,14 @@ export type Props = $ReadOnly<{|
523523
...IOSProps,
524524
...AndroidProps,
525525

526+
/**
527+
* String to be read by screenreaders to indicate an error state. The acceptable parameters
528+
* of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates
529+
* the error message. Setting accessibilityInvalid to false removes the error message.
530+
*/
531+
accessibilityErrorMessage?: ?Stringish,
532+
accessibilityInvalid?: ?boolean,
533+
526534
/**
527535
* Can tell `TextInput` to automatically capitalize certain characters.
528536
*

Libraries/Components/TextInput/TextInput.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,14 @@ export type Props = $ReadOnly<{|
561561
...IOSProps,
562562
...AndroidProps,
563563

564+
/**
565+
* String to be read by screenreaders to indicate an error state. The acceptable parameters
566+
* of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates
567+
* the error message. Setting accessibilityInvalid to false removes the error message.
568+
*/
569+
accessibilityErrorMessage?: ?Stringish,
570+
accessibilityInvalid?: ?boolean,
571+
564572
/**
565573
* Can tell `TextInput` to automatically capitalize certain characters.
566574
*
@@ -1365,6 +1373,12 @@ function InternalTextInput(props: Props): React.Node {
13651373
}
13661374

13671375
const accessible = props.accessible !== false;
1376+
1377+
const accessibilityErrorMessage =
1378+
props.accessibilityInvalid === true
1379+
? props.accessibilityErrorMessage
1380+
: null;
1381+
13681382
const focusable = props.focusable !== false;
13691383

13701384
const config = React.useMemo(
@@ -1439,6 +1453,7 @@ function InternalTextInput(props: Props): React.Node {
14391453
ref={ref}
14401454
{...otherProps}
14411455
{...eventHandlers}
1456+
accessibilityErrorMessage={accessibilityErrorMessage}
14421457
accessibilityState={_accessibilityState}
14431458
accessible={accessible}
14441459
submitBehavior={submitBehavior}
@@ -1490,6 +1505,7 @@ function InternalTextInput(props: Props): React.Node {
14901505
ref={ref}
14911506
{...otherProps}
14921507
{...eventHandlers}
1508+
accessibilityErrorMessage={accessibilityErrorMessage}
14931509
accessibilityState={_accessibilityState}
14941510
accessibilityLabelledBy={_accessibilityLabelledBy}
14951511
accessible={accessible}

Libraries/Components/TextInput/__tests__/TextInput-test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ describe('TextInput', () => {
186186

187187
expect(instance.toJSON()).toMatchInlineSnapshot(`
188188
<RCTSinglelineTextInputView
189+
accessibilityErrorMessage={null}
189190
accessible={true}
190191
allowFontScaling={true}
191192
focusable={true}
@@ -231,6 +232,7 @@ describe('TextInput compat with web', () => {
231232

232233
expect(instance.toJSON()).toMatchInlineSnapshot(`
233234
<RCTSinglelineTextInputView
235+
accessibilityErrorMessage={null}
234236
accessible={true}
235237
allowFontScaling={true}
236238
focusable={true}
@@ -315,6 +317,7 @@ describe('TextInput compat with web', () => {
315317

316318
expect(instance.toJSON()).toMatchInlineSnapshot(`
317319
<RCTSinglelineTextInputView
320+
accessibilityErrorMessage={null}
318321
accessibilityState={
319322
Object {
320323
"busy": true,
@@ -407,6 +410,7 @@ describe('TextInput compat with web', () => {
407410

408411
expect(instance.toJSON()).toMatchInlineSnapshot(`
409412
<RCTSinglelineTextInputView
413+
accessibilityErrorMessage={null}
410414
accessible={true}
411415
allowFontScaling={true}
412416
focusable={true}

Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
exports[`TextInput tests should render as expected: should deep render when mocked (please verify output manually) 1`] = `
44
<RCTSinglelineTextInputView
5+
accessibilityErrorMessage={null}
56
accessible={true}
67
allowFontScaling={true}
78
focusable={true}
@@ -31,6 +32,7 @@ exports[`TextInput tests should render as expected: should deep render when mock
3132

3233
exports[`TextInput tests should render as expected: should deep render when not mocked (please verify output manually) 1`] = `
3334
<RCTSinglelineTextInputView
35+
accessibilityErrorMessage={null}
3436
accessible={true}
3537
allowFontScaling={true}
3638
focusable={true}

Libraries/Text/TextInput/Multiline/RCTUITextView.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN
2222

2323
@property (nonatomic, weak) id<RCTBackedTextInputDelegate> textInputDelegate;
2424

25+
@property (nonatomic, assign, nullable) NSString *accessibilityErrorMessage;
26+
@property (nonatomic, readwrite, nullable) NSString *currentAccessibilityError;
27+
@property (nonatomic, readwrite, nullable) NSString *previousAccessibilityError;
2528
@property (nonatomic, assign) BOOL contextMenuHidden;
2629
@property (nonatomic, assign, readonly) BOOL textWasPasted;
2730
@property (nonatomic, copy, nullable) NSString *placeholder;

Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
1515
@protocol RCTBackedTextInputViewProtocol <UITextInput>
1616

1717
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
18+
@property (nonatomic, assign, nullable) NSString *accessibilityErrorMessage;
19+
@property (nonatomic, readwrite, nullable) NSString *currentAccessibilityError;
20+
@property (nonatomic, readwrite, nullable) NSString *previousAccessibilityError;
1821
@property (nonatomic, copy, nullable) NSString *placeholder;
1922
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
2023
@property (nonatomic, assign, readonly) BOOL textWasPasted;

Libraries/Text/TextInput/RCTBaseTextInputView.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,17 @@ - (void)setAttributedText:(NSAttributedString *)attributedText
148148

149149
textNeedsUpdate = ([self textOf:attributedTextCopy equals:backedTextInputViewTextCopy] == NO);
150150

151+
NSString *currentAccessibilityError = self.backedTextInputView.currentAccessibilityError;
152+
NSString *previousAccessibilityError = self.backedTextInputView.previousAccessibilityError;
153+
BOOL accessibilityErrorMessageWasRemoved = currentAccessibilityError == nil && ![currentAccessibilityError isEqualToString: previousAccessibilityError];
154+
if (accessibilityErrorMessageWasRemoved) {
155+
BOOL validString = attributedText && [attributedText.string length] != 0;
156+
NSString *lastChar = validString ? [attributedText.string substringFromIndex:[attributedText.string length] - 1] : @"";
157+
self.backedTextInputView.accessibilityValue = nil;
158+
// Triggering the announcement manually fixes screenreader announcement getting cut off
159+
// https://bit.ly/3w18QmV https://bit.ly/3AdVKW3 https://bit.ly/3QHm7c7 https://bit.ly/3BVnmAy
160+
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, lastChar);
161+
}
151162
if (eventLag == 0 && textNeedsUpdate) {
152163
UITextRange *selection = self.backedTextInputView.selectedTextRange;
153164
NSInteger oldTextLength = self.backedTextInputView.attributedText.string.length;

Libraries/Text/TextInput/RCTBaseTextInputViewManager.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ @implementation RCTBaseTextInputViewManager {
3636
RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType)
3737
RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)
3838
RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL)
39+
RCT_REMAP_VIEW_PROPERTY(accessibilityErrorMessage, backedTextInputView.accessibilityErrorMessage, NSString)
3940
RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL)
4041
RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance)
4142
RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)

0 commit comments

Comments
 (0)