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.

<table>
  <tr>
    <td align="center">
      <strong>Before</strong>
    </td>
    <td align="center">
      <strong>After</strong>
    </td>
  </tr>
  <tr>
    <td>
      <img src="https://github.com/user-attachments/assets/5ab251d9-3128-45e0-bb1f-907376422df0" alt="Screenshot Before" width="300"/>
    </td>
    <td>
      <img src="https://github.com/user-attachments/assets/96f76a08-bb8d-497a-9c89-dca0e0bdbcbb" alt="Screenshot After" width="300"/>
    </td>
  </tr>
  <tr>
    <td align="center">
      <strong>Before</strong>
    </td>
    <td align="center">
      <strong>After</strong>
    </td>
  </tr>
</table>

Reviewed By: lunaleaps

Differential Revision: D65757069

Pulled By: cipolleschi

fbshipit-source-id: 1f51ed6927bfb4fe4e21018c541303dff44b2217
This commit is contained in:
Henning Hall
2024-11-18 05:26:38 -08:00
committed by Facebook GitHub Bot
parent 7be98c99bd
commit 089c87e22e
6 changed files with 75 additions and 1 deletions
@@ -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;
}
@@ -49,6 +49,7 @@ const ActionSheetIOS = {
+anchor?: ?number,
+tintColor?: ColorValue | ProcessedColorValue,
+cancelButtonTintColor?: ColorValue | ProcessedColorValue,
+disabledButtonTintColor?: ColorValue | ProcessedColorValue,
+userInterfaceStyle?: string,
+disabledButtonIndices?: Array<number>,
|},
@@ -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,
@@ -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<number>,
|},
@@ -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 %@.",
@@ -24,6 +24,7 @@ export interface Spec extends TurboModule {
+anchor?: ?number,
+tintColor?: ?number,
+cancelButtonTintColor?: ?number,
+disabledButtonTintColor?: ?number,
+userInterfaceStyle?: ?string,
+disabledButtonIndices?: Array<number>,
|},
@@ -37,6 +38,7 @@ export interface Spec extends TurboModule {
+anchor?: ?number,
+tintColor?: ?number,
+cancelButtonTintColor?: ?number,
+disabledButtonTintColor?: ?number,
+excludedActivityTypes?: ?Array<string>,
+userInterfaceStyle?: ?string,
|},
@@ -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 (
<RNTesterThemeContext.Consumer>
{theme => (
<View>
<Text
onPress={this.showActionSheet}
style={[style.button, {color: theme.SecondaryLabelColor}]}>
Click to show the ActionSheet
</Text>
<Text style={{color: theme.SecondaryLabelColor}}>
Clicked button: {this.state.clicked}
</Text>
</View>
)}
</RNTesterThemeContext.Consumer>
);
}
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 <ActionSheetCancelButtonTintExample />;
},
},
{
title: 'Show Action Sheet with disabled tinted button',
render(): React.MixedElement {
return <ActionSheetDisabledButtonTintExample />;
},
},
{
title: 'Show Action Sheet with anchor',
render(): React.MixedElement {