Skip to content

Commit

Permalink
improve iOS solution based on facebook#35432
Browse files Browse the repository at this point in the history
  • Loading branch information
fabOnReact committed Dec 14, 2022
1 parent 1f9c10e commit 7dc0108
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 66 deletions.
3 changes: 0 additions & 3 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign, readonly) BOOL textWasPasted;
@property (nonatomic, copy, nullable) NSString *placeholder;
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
@property (nonatomic, assign, nullable) NSString *accessibilityErrorMessage;
@property (nonatomic, readwrite, nullable) NSString *currentAccessibilityError;
@property (nonatomic, readwrite, nullable) NSString *previousAccessibilityError;

@property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;

Expand Down
18 changes: 0 additions & 18 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,6 @@ - (void)setDefaultTextAttributes:(NSDictionary<NSAttributedStringKey, id> *)defa
[self _updatePlaceholder];
}

- (void)setAccessibilityErrorMessage:(NSString *)accessibilityErrorMessage
{
self.previousAccessibilityError = [self.currentAccessibilityError mutableCopy];
self.currentAccessibilityError = accessibilityErrorMessage;
NSString *text = self.attributedText == nil ? @"" : self.attributedText.string;
NSString *lastChar = [text length] == 0 ? @"" : [text substringFromIndex:[text length] - 1];
if (accessibilityErrorMessage != nil) {
NSString *errorWithLastCharacter = [NSString stringWithFormat: @"%@ %@", lastChar, accessibilityErrorMessage];
NSString *errorWithText = [NSString stringWithFormat: @"%@ %@", text, accessibilityErrorMessage];
self.accessibilityValue = errorWithText;
// onChangeText announce only the last typed/deleted character
// more info at https://bit.ly/3zOHsda
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, errorWithLastCharacter);
} else {
self.accessibilityValue = nil;
}
}

- (NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
{
return _defaultTextAttributes;
Expand Down
3 changes: 0 additions & 3 deletions Libraries/Text/TextInput/Singleline/RCTUITextField.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
@property (nonatomic, assign, getter=isEditable) BOOL editable;
@property (nonatomic, assign, nullable) NSString *accessibilityErrorMessage;
@property (nonatomic, readwrite, nullable) NSString *currentAccessibilityError;
@property (nonatomic, readwrite, nullable) NSString *previousAccessibilityError;
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
@property (nonatomic, assign, readonly) CGFloat zoomScale;
Expand Down
18 changes: 0 additions & 18 deletions Libraries/Text/TextInput/Singleline/RCTUITextField.m
Original file line number Diff line number Diff line change
Expand Up @@ -99,24 +99,6 @@ - (void)setEditable:(BOOL)editable
self.enabled = editable;
}

- (void)setAccessibilityErrorMessage:(NSString *)accessibilityErrorMessage
{
self.previousAccessibilityError = [self.currentAccessibilityError mutableCopy];
self.currentAccessibilityError = accessibilityErrorMessage;
NSString *text = self.attributedText == nil ? @"" : self.attributedText.string;
NSString *lastChar = [text length] == 0 ? @"" : [text substringFromIndex:[text length] - 1];
if (accessibilityErrorMessage != nil) {
NSString *errorWithLastCharacter = [NSString stringWithFormat: @"%@ %@", lastChar, accessibilityErrorMessage];
NSString *errorWithText = [NSString stringWithFormat: @"%@ %@", text, accessibilityErrorMessage];
self.accessibilityValue = errorWithText;
// onChangeText announce only the last typed/deleted character
// more info at https://bit.ly/3zOHsda
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, errorWithLastCharacter);
} else {
self.accessibilityValue = nil;
}
}

- (void)setSecureTextEntry:(BOOL)secureTextEntry
{
if (self.secureTextEntry == secureTextEntry) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,22 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
_backedTextInputView.editable = newTextInputProps.traits.editable;
}

if (newTextInputProps.accessibilityErrorMessage != oldTextInputProps.accessibilityErrorMessage || newTextInputProps.text != oldTextInputProps.text) {
if (newTextInputProps.text != oldTextInputProps.text) {
NSString *text = RCTNSStringFromString(newTextInputProps.text);
_backedTextInputView.accessibilityValue = text;
self.accessibilityElement.accessibilityValue = text;
}

if (newTextInputProps.accessibilityErrorMessage != oldTextInputProps.accessibilityErrorMessage) {
NSString *text = RCTNSStringFromString(newTextInputProps.text);
NSString *error = RCTNSStringFromString(newTextInputProps.accessibilityErrorMessage);
NSString *lastChar = [text length] == 0 ? @"" : [text substringFromIndex:[text length] - 1];
if ([error length] != 0) {
NSString *errorWithLastCharacter = [NSString stringWithFormat: @"%@ %@", lastChar, error];
self.triggerAccessibilityAnnouncement = YES;
NSString *errorWithText = [NSString stringWithFormat: @"%@ %@", text, error];
self.accessibilityElement.accessibilityValue = errorWithText;
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, errorWithLastCharacter);
self->_errorMessageRemoved = NO;
} else {
self.accessibilityElement.accessibilityValue = text;
self->_errorMessageRemoved = YES;
self.triggerAccessibilityAnnouncement = NO;
}
}

Expand Down Expand Up @@ -261,6 +264,15 @@ - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &
}
}

- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
{
[super finalizeUpdates:updateMask];
if (self.triggerAccessibilityAnnouncement) {
[self announceForAccessibilityWithOptions:self.accessibilityElement.accessibilityValue];
self.triggerAccessibilityAnnouncement = NO;
}
}

- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics
oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics
{
Expand Down Expand Up @@ -614,12 +626,15 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
UITextRange *selectedRange = _backedTextInputView.selectedTextRange;
NSInteger oldTextLength = _backedTextInputView.attributedText.string.length;
_backedTextInputView.attributedText = attributedString;
if (self->_errorMessageRemoved) {
_backedTextInputView.accessibilityValue = attributedString.string;
self.accessibilityElement.accessibilityValue = attributedString.string;

// check that current error is not empty
if (self.triggerAccessibilityAnnouncement) {
[self announceForAccessibilityWithOptions:self.accessibilityElement.accessibilityValue];
self.triggerAccessibilityAnnouncement = NO;
} else {
NSString *lastChar = [attributedString.string substringFromIndex:[attributedString.string length] - 1];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, lastChar);
self->_errorMessageRemoved = NO;
self.triggerAccessibilityAnnouncement = NO;
}
if (selectedRange.empty) {
// Maintaining a cursor position relative to the end of the old text.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
* Defaults to `self`.
*/
@property (nonatomic, strong, nullable, readonly) NSObject *accessibilityElement;

@property (nonatomic, readwrite) BOOL triggerAccessibilityAnnouncement;
/**
* Insets used when hit testing inside this view.
*/
Expand All @@ -85,6 +85,7 @@ NS_ASSUME_NONNULL_BEGIN
* This is a fragment of temporary workaround that we need only temporary and will get rid of soon.
*/
- (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN;
- (void)announceForAccessibilityWithOptions:(NSString *)announcement;

@end

Expand Down
11 changes: 11 additions & 0 deletions React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,17 @@ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
[self invalidateLayer];
}

- (void)announceForAccessibilityWithOptions:(NSString*)announcement
{
if (@available(iOS 11.0, *)) {
BOOL accessibilityAnnouncementNotEmpty = [announcement length] != 0;
if (accessibilityAnnouncementNotEmpty) {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, announcement);
self.triggerAccessibilityAnnouncement = NO;
}
}
}

- (void)prepareForRecycle
{
[super prepareForRecycle];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1592,7 +1592,8 @@ function AccessibilityErrorWithButtons(): React.Node {
if (newText === 'Error') {
setError('the newText is: ' + newText);
setAccessibilityInvalid(true);
} else if (newText === 'null') {
} else {
setError(null);
setAccessibilityInvalid(false);
}
}}
Expand Down Expand Up @@ -1711,6 +1712,18 @@ exports.title = 'Accessibility';
exports.documentationURL = 'https://reactnative.dev/docs/accessibilityinfo';
exports.description = 'Examples of using Accessibility APIs.';
exports.examples = [
{
title: 'accessibilityErrorMessage onChangeText or Button onPress',
render: function (): React.Node {
return <AccessibilityErrorWithButtons />;
},
},
{
title: 'accessibilityErrorMessage does not clear with text change',
render: function (): React.Node {
return <AccessibilityErrorDoesNotClear />;
},
},
{
title: 'Accessibility expanded',
render(): React.Element<typeof AccessibilityExpandedExample> {
Expand Down Expand Up @@ -1804,18 +1817,6 @@ exports.examples = [
);
},
},
{
title: 'accessibilityErrorMessage onChangeText or Button onPress',
render: function (): React.Node {
return <AccessibilityErrorWithButtons />;
},
},
{
title: 'accessibilityErrorMessage does not clear with text change',
render: function (): React.Node {
return <AccessibilityErrorDoesNotClear />;
},
},
{
title: 'TextInput with aria-labelledby attribute"',
render(): React.Element<typeof View> {
Expand Down

0 comments on commit 7dc0108

Please sign in to comment.