mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
feat(accessibility): support large content viewer on iOS (#45903)
Summary: Referring to the [iOS Large Content Viewer](https://developer.apple.com/videos/play/wwdc2019/261/): iOS Tab Bars can't grow with dynamic text, but the Large Content Viewer helps them to be seen by people with low vision. Currently on React Native we don't expose the properties that can help implementing iOS [UILargeContentViewerItem](https://developer.apple.com/documentation/uikit/uilargecontentvieweritem) protocol. The goal of this PR is to expose the necessary props. In this PR, I'm exposing 2 props: - `accessibilityShowsLargeContentViewer`: to enable the large content viewer - `accessibilityLargeContentTitle`: to define the large content viewer title I plan to use this to open a PR on react-navigation so that bottom tabbars can implement largeContentViewer. Should fix https://github.com/facebook/react-native/issues/30892 ## Changelog: [IOS] [ADDED] - Support LargeContentViewer on iOS for better accessibility Pull Request resolved: https://github.com/facebook/react-native/pull/45903 Test Plan: <img width="300" src="https://github.com/user-attachments/assets/d8f1dc46-66e7-4945-bc3b-f1d29044441b" /> Reviewed By: cipolleschi Differential Revision: D61148361 Pulled By: joevilches fbshipit-source-id: 86dd92f4f79534a58e6e015febdaf217ea291eb4
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d69dbd6f15
commit
6cc44d765a
@@ -22,6 +22,8 @@ const UIView = {
|
||||
accessibilityValue: true,
|
||||
accessibilityHint: true,
|
||||
accessibilityLanguage: true,
|
||||
accessibilityShowsLargeContentViewer: true,
|
||||
accessibilityLargeContentTitle: true,
|
||||
importantForAccessibility: true,
|
||||
nativeID: true,
|
||||
testID: true,
|
||||
|
||||
@@ -319,6 +319,21 @@ export interface AccessibilityPropsIOS {
|
||||
* @platform ios
|
||||
*/
|
||||
accessibilityLanguage?: string | undefined;
|
||||
|
||||
/**
|
||||
* A Boolean value that indicates whether or not to show the item in the large content viewer.
|
||||
* Available on iOS 13.0+
|
||||
* https://reactnative.dev/docs/accessibility#accessibilityshowslargecontentviewer
|
||||
* @platform ios
|
||||
*/
|
||||
accessibilityShowsLargeContentViewer?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* When `accessibilityShowsLargeContentViewer` is set, this string will be used as title for the large content viewer.
|
||||
* https://reactnative.dev/docs/accessibility#accessibilitylargecontenttitle
|
||||
* @platform ios
|
||||
*/
|
||||
accessibilityLargeContentTitle?: string | undefined;
|
||||
}
|
||||
|
||||
export type Role =
|
||||
|
||||
@@ -415,6 +415,20 @@ type IOSViewProps = $ReadOnly<{|
|
||||
*/
|
||||
accessibilityViewIsModal?: ?boolean,
|
||||
|
||||
/**
|
||||
* @platform ios
|
||||
*
|
||||
* See https://reactnative.dev/docs/view#accessibilityshowslargecontentviewer
|
||||
*/
|
||||
accessibilityShowsLargeContentViewer?: ?boolean,
|
||||
|
||||
/**
|
||||
* @platform ios
|
||||
*
|
||||
* See https://reactnative.dev/docs/view#accessibilitylargecontenttitle
|
||||
*/
|
||||
accessibilityLargeContentTitle?: ?string,
|
||||
|
||||
/**
|
||||
* The aria-modal attribute indicates content contained within a modal with aria-modal="true"
|
||||
* should be accessible to the user.
|
||||
|
||||
@@ -193,6 +193,8 @@ const validAttributesForNonEventProps = {
|
||||
accessibilityViewIsModal: true,
|
||||
accessibilityElementsHidden: true,
|
||||
accessibilityIgnoresInvertColors: true,
|
||||
accessibilityShowsLargeContentViewer: true,
|
||||
accessibilityLargeContentTitle: true,
|
||||
testID: true,
|
||||
backgroundColor: {process: require('../StyleSheet/processColor').default},
|
||||
backfaceVisibility: true,
|
||||
|
||||
@@ -3891,6 +3891,8 @@ exports[`public API should not change unintentionally Libraries/Components/View/
|
||||
accessibilityValue: true,
|
||||
accessibilityHint: true,
|
||||
accessibilityLanguage: true,
|
||||
accessibilityShowsLargeContentViewer: true,
|
||||
accessibilityLargeContentTitle: true,
|
||||
importantForAccessibility: true,
|
||||
nativeID: true,
|
||||
testID: true,
|
||||
@@ -4177,6 +4179,8 @@ type AndroidViewProps = $ReadOnly<{|
|
||||
type IOSViewProps = $ReadOnly<{|
|
||||
accessibilityIgnoresInvertColors?: ?boolean,
|
||||
accessibilityViewIsModal?: ?boolean,
|
||||
accessibilityShowsLargeContentViewer?: ?boolean,
|
||||
accessibilityLargeContentTitle?: ?string,
|
||||
\\"aria-modal\\"?: ?boolean,
|
||||
accessibilityElementsHidden?: ?boolean,
|
||||
accessibilityLanguage?: ?Stringish,
|
||||
|
||||
+20
@@ -347,6 +347,26 @@ using namespace facebook::react;
|
||||
self.accessibilityElement.accessibilityElementsHidden = newViewProps.accessibilityElementsHidden;
|
||||
}
|
||||
|
||||
// `accessibilityShowsLargeContentViewer`
|
||||
if (oldViewProps.accessibilityShowsLargeContentViewer != newViewProps.accessibilityShowsLargeContentViewer) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if (newViewProps.accessibilityShowsLargeContentViewer) {
|
||||
self.showsLargeContentViewer = YES;
|
||||
UILargeContentViewerInteraction *interaction = [[UILargeContentViewerInteraction alloc] init];
|
||||
[self addInteraction:interaction];
|
||||
} else {
|
||||
self.showsLargeContentViewer = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `accessibilityLargeContentTitle`
|
||||
if (oldViewProps.accessibilityLargeContentTitle != newViewProps.accessibilityLargeContentTitle) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
self.largeContentTitle = RCTNSStringFromStringNilIfEmpty(newViewProps.accessibilityLargeContentTitle);
|
||||
}
|
||||
}
|
||||
|
||||
// `accessibilityTraits`
|
||||
if (oldViewProps.accessibilityTraits != newViewProps.accessibilityTraits) {
|
||||
self.accessibilityElement.accessibilityTraits =
|
||||
|
||||
@@ -295,6 +295,28 @@ RCT_CUSTOM_VIEW_PROPERTY(accessibilityState, NSDictionary, RCTView)
|
||||
}
|
||||
}
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(accessibilityShowsLargeContentViewer, BOOL, RCTView)
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
BOOL showsLargeContentViewer = json ? [RCTConvert BOOL:json] : defaultView.showsLargeContentViewer;
|
||||
|
||||
if (showsLargeContentViewer) {
|
||||
view.showsLargeContentViewer = YES;
|
||||
UILargeContentViewerInteraction *interaction = [[UILargeContentViewerInteraction alloc] init];
|
||||
[view addInteraction:interaction];
|
||||
} else {
|
||||
view.showsLargeContentViewer = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(accessibilityLargeContentTitle, NSString, RCTView)
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
view.largeContentTitle = json ? [RCTConvert NSString:json] : defaultView.largeContentTitle;
|
||||
}
|
||||
}
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(nativeID, NSString *, RCTView)
|
||||
{
|
||||
view.nativeID = json ? [RCTConvert NSString:json] : defaultView.nativeID;
|
||||
|
||||
+20
@@ -81,6 +81,15 @@ AccessibilityProps::AccessibilityProps(
|
||||
"accessibilityLanguage",
|
||||
sourceProps.accessibilityLanguage,
|
||||
"")),
|
||||
accessibilityLargeContentTitle(
|
||||
CoreFeatures::enablePropIteratorSetter
|
||||
? sourceProps.accessibilityLargeContentTitle
|
||||
: convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"accessibilityLargeContentTitle",
|
||||
sourceProps.accessibilityLargeContentTitle,
|
||||
"")),
|
||||
accessibilityValue(
|
||||
CoreFeatures::enablePropIteratorSetter
|
||||
? sourceProps.accessibilityValue
|
||||
@@ -99,6 +108,15 @@ AccessibilityProps::AccessibilityProps(
|
||||
"accessibilityActions",
|
||||
sourceProps.accessibilityActions,
|
||||
{})),
|
||||
accessibilityShowsLargeContentViewer(
|
||||
CoreFeatures::enablePropIteratorSetter
|
||||
? sourceProps.accessibilityShowsLargeContentViewer
|
||||
: convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"accessibilityShowsLargeContentViewer",
|
||||
sourceProps.accessibilityShowsLargeContentViewer,
|
||||
false)),
|
||||
accessibilityViewIsModal(
|
||||
CoreFeatures::enablePropIteratorSetter
|
||||
? sourceProps.accessibilityViewIsModal
|
||||
@@ -229,6 +247,8 @@ void AccessibilityProps::setProp(
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabelledBy);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityHint);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLanguage);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityShowsLargeContentViewer);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLargeContentTitle);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityValue);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityActions);
|
||||
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityViewIsModal);
|
||||
|
||||
@@ -41,8 +41,10 @@ class AccessibilityProps {
|
||||
std::string accessibilityRole{""};
|
||||
std::string accessibilityHint{""};
|
||||
std::string accessibilityLanguage{""};
|
||||
std::string accessibilityLargeContentTitle{""};
|
||||
AccessibilityValue accessibilityValue;
|
||||
std::vector<AccessibilityAction> accessibilityActions{};
|
||||
bool accessibilityShowsLargeContentViewer{false};
|
||||
bool accessibilityViewIsModal{false};
|
||||
bool accessibilityElementsHidden{false};
|
||||
bool accessibilityIgnoresInvertColors{false};
|
||||
|
||||
Reference in New Issue
Block a user