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 bafdeb65e42..ea95a988d0e 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 e970cdc06a6..e758572882c 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 852f9da15d1..3a13fdd0666 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 0c9761a7078..658ec6b8b81 100644 --- a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm +++ b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm @@ -98,6 +98,8 @@ RCT_EXPORT_METHOD(showActionSheetWithOptions 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 @@ RCT_EXPORT_METHOD(showActionSheetWithOptions @"anchor" : anchor ?: @"(null)", @"tintColor" : tintColor ?: @"(null)", @"cancelButtonTintColor" : cancelButtonTintColor ?: @"(null)", + @"disabledButtonTintColor" : disabledButtonTintColor ?: @"(null)", @"disabledButtonIndices" : disabledButtonIndices ?: @"(null)", }); return; @@ -166,7 +169,11 @@ RCT_EXPORT_METHOD(showActionSheetWithOptions 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 37407bd01cf..2364a83c4fa 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 623067a4af0..c21161dfdca 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 {