From 089c87e22e9f431d0e7f35292dce2e36fa86d09a Mon Sep 17 00:00:00 2001 From: Henning Hall Date: Mon, 18 Nov 2024 05:26:38 -0800 Subject: [PATCH] feat: add `disabledButtonTintColor` prop in `ActionSheetIOS` (#46883) Summary: ### Problem Setting the `tintColor` prop in ActionSheetIOS also changes the tint of disabled entries. This could make them visually indistinguishable from enabled items. The degree to which they are indistinguishable depends on the tint color. ### Solution This new prop `disabledButtonTintColor` allows customization of disabled items' tint color. Related PR: https://github.com/facebook/react-native/pull/31972 ## Changelog: [IOS] [ADDED] - added `disabledButtonTintColor` prop to ActionSheetIOS Pull Request resolved: https://github.com/facebook/react-native/pull/46883 Test Plan: Tested in RNTester project.
Before After
Screenshot Before Screenshot After
Before After
Reviewed By: lunaleaps Differential Revision: D65757069 Pulled By: cipolleschi fbshipit-source-id: 1f51ed6927bfb4fe4e21018c541303dff44b2217 --- .../ActionSheetIOS/ActionSheetIOS.d.ts | 1 + .../ActionSheetIOS/ActionSheetIOS.js | 13 +++++ .../__snapshots__/public-api-test.js.snap | 1 + .../CoreModules/RCTActionSheetManager.mm | 9 +++- .../specs/modules/NativeActionSheetManager.js | 2 + .../ActionSheetIOS/ActionSheetIOSExample.js | 50 +++++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts b/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts index bafdeb65e42106..ea95a988d0e3c1 100644 --- a/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts +++ b/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts @@ -22,6 +22,7 @@ export interface ActionSheetIOSOptions { anchor?: number | undefined; tintColor?: ColorValue | ProcessedColorValue | undefined; cancelButtonTintColor?: ColorValue | ProcessedColorValue | undefined; + disabledButtonTintColor?: ColorValue | ProcessedColorValue | undefined; userInterfaceStyle?: 'light' | 'dark' | undefined; disabledButtonIndices?: number[] | undefined; } diff --git a/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.js b/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.js index e970cdc06a68a2..e758572882c64e 100644 --- a/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/packages/react-native/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -49,6 +49,7 @@ const ActionSheetIOS = { +anchor?: ?number, +tintColor?: ColorValue | ProcessedColorValue, +cancelButtonTintColor?: ColorValue | ProcessedColorValue, + +disabledButtonTintColor?: ColorValue | ProcessedColorValue, +userInterfaceStyle?: string, +disabledButtonIndices?: Array, |}, @@ -64,6 +65,7 @@ const ActionSheetIOS = { const { tintColor, cancelButtonTintColor, + disabledButtonTintColor, destructiveButtonIndex, ...remainingOptions } = options; @@ -77,6 +79,10 @@ const ActionSheetIOS = { const processedTintColor = processColor(tintColor); const processedCancelButtonTintColor = processColor(cancelButtonTintColor); + const processedDisabledButtonTintColor = processColor( + disabledButtonTintColor, + ); + invariant( processedTintColor == null || typeof processedTintColor === 'number', 'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions tintColor', @@ -86,6 +92,11 @@ const ActionSheetIOS = { typeof processedCancelButtonTintColor === 'number', 'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions cancelButtonTintColor', ); + invariant( + processedDisabledButtonTintColor == null || + typeof processedDisabledButtonTintColor === 'number', + 'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions disabledButtonTintColor', + ); RCTActionSheetManager.showActionSheetWithOptions( { ...remainingOptions, @@ -93,6 +104,8 @@ const ActionSheetIOS = { tintColor: processedTintColor, // $FlowFixMe[incompatible-call] cancelButtonTintColor: processedCancelButtonTintColor, + // $FlowFixMe[incompatible-call] + disabledButtonTintColor: processedDisabledButtonTintColor, destructiveButtonIndices, }, callback, diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 852f9da15d16c4..3a13fdd066611d 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -12,6 +12,7 @@ exports[`public API should not change unintentionally Libraries/ActionSheetIOS/A +anchor?: ?number, +tintColor?: ColorValue | ProcessedColorValue, +cancelButtonTintColor?: ColorValue | ProcessedColorValue, + +disabledButtonTintColor?: ColorValue | ProcessedColorValue, +userInterfaceStyle?: string, +disabledButtonIndices?: Array, |}, diff --git a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm index 0c9761a70781db..658ec6b8b81e18 100644 --- a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm +++ b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm @@ -98,6 +98,8 @@ - (void)presentViewController:(UIViewController *)alertController UIColor *tintColor = [RCTConvert UIColor:options.tintColor() ? @(*options.tintColor()) : nil]; UIColor *cancelButtonTintColor = [RCTConvert UIColor:options.cancelButtonTintColor() ? @(*options.cancelButtonTintColor()) : nil]; + UIColor *disabledButtonTintColor = + [RCTConvert UIColor:options.disabledButtonTintColor() ? @(*options.disabledButtonTintColor()) : nil]; NSString *userInterfaceStyle = [RCTConvert NSString:options.userInterfaceStyle()]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -114,6 +116,7 @@ - (void)presentViewController:(UIViewController *)alertController @"anchor" : anchor ?: @"(null)", @"tintColor" : tintColor ?: @"(null)", @"cancelButtonTintColor" : cancelButtonTintColor ?: @"(null)", + @"disabledButtonTintColor" : disabledButtonTintColor ?: @"(null)", @"disabledButtonIndices" : disabledButtonIndices ?: @"(null)", }); return; @@ -166,7 +169,11 @@ - (void)presentViewController:(UIViewController *)alertController if (disabledButtonIndices) { for (NSNumber *disabledButtonIndex in disabledButtonIndices) { if ([disabledButtonIndex integerValue] < buttons.count) { - [alertController.actions[[disabledButtonIndex integerValue]] setEnabled:false]; + UIAlertAction *action = alertController.actions[[disabledButtonIndex integerValue]]; + [action setEnabled:false]; + if (disabledButtonTintColor) { + [action setValue:disabledButtonTintColor forKey:@"titleTextColor"]; + } } else { RCTLogError( @"Index %@ from `disabledButtonIndices` is out of bounds. Maximum index value is %@.", diff --git a/packages/react-native/src/private/specs/modules/NativeActionSheetManager.js b/packages/react-native/src/private/specs/modules/NativeActionSheetManager.js index 37407bd01cf61d..2364a83c4faf49 100644 --- a/packages/react-native/src/private/specs/modules/NativeActionSheetManager.js +++ b/packages/react-native/src/private/specs/modules/NativeActionSheetManager.js @@ -24,6 +24,7 @@ export interface Spec extends TurboModule { +anchor?: ?number, +tintColor?: ?number, +cancelButtonTintColor?: ?number, + +disabledButtonTintColor?: ?number, +userInterfaceStyle?: ?string, +disabledButtonIndices?: Array, |}, @@ -37,6 +38,7 @@ export interface Spec extends TurboModule { +anchor?: ?number, +tintColor?: ?number, +cancelButtonTintColor?: ?number, + +disabledButtonTintColor?: ?number, +excludedActivityTypes?: ?Array, +userInterfaceStyle?: ?string, |}, diff --git a/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js b/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js index 623067a4af0738..c21161dfdcae92 100644 --- a/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js +++ b/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js @@ -155,6 +155,50 @@ class ActionSheetCancelButtonTintExample extends React.Component< }; } +class ActionSheetDisabledButtonTintExample extends React.Component< + $FlowFixMeProps, + $FlowFixMeState, +> { + state: any | {clicked: string} = { + clicked: 'none', + }; + + render(): React.Node { + return ( + + {theme => ( + + + Click to show the ActionSheet + + + Clicked button: {this.state.clicked} + + + )} + + ); + } + + showActionSheet = () => { + ActionSheetIOS.showActionSheetWithOptions( + { + options: BUTTONS, + cancelButtonIndex: CANCEL_INDEX, + destructiveButtonIndex: DESTRUCTIVE_INDEX, + disabledButtonIndices: DISABLED_BUTTON_INDICES, + tintColor: 'black', + disabledButtonTintColor: 'gray', + }, + buttonIndex => { + this.setState({clicked: BUTTONS[buttonIndex]}); + }, + ); + }; +} + class ActionSheetAnchorExample extends React.Component< $FlowFixMeProps, $FlowFixMeState, @@ -480,6 +524,12 @@ exports.examples = [ return ; }, }, + { + title: 'Show Action Sheet with disabled tinted button', + render(): React.MixedElement { + return ; + }, + }, { title: 'Show Action Sheet with anchor', render(): React.MixedElement {