diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js index 076ab004a56eb3..9852791cdf67a7 100644 --- a/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -33,6 +33,7 @@ const ActionSheetIOS = { * - `destructiveButtonIndex` (int or array of ints) - index or indices of destructive buttons in `options` * - `title` (string) - a title to show above the action sheet * - `message` (string) - a message to show below the title + * - `disabledButtonIndices` (array of numbers) - a list of button indices which should be disabled * * The 'callback' function takes one parameter, the zero-based index * of the selected item. @@ -49,6 +50,7 @@ const ActionSheetIOS = { +anchor?: ?number, +tintColor?: ColorValue | ProcessedColorValue, +userInterfaceStyle?: string, + +disabledButtonIndices?: Array, |}, callback: (buttonIndex: number) => void, ) { diff --git a/Libraries/ActionSheetIOS/NativeActionSheetManager.js b/Libraries/ActionSheetIOS/NativeActionSheetManager.js index 063d9147e1d69b..6d86200d9accd6 100644 --- a/Libraries/ActionSheetIOS/NativeActionSheetManager.js +++ b/Libraries/ActionSheetIOS/NativeActionSheetManager.js @@ -25,6 +25,7 @@ export interface Spec extends TurboModule { +anchor?: ?number, +tintColor?: ?number, +userInterfaceStyle?: ?string, + +disabledButtonIndices?: Array, |}, callback: (buttonIndex: number) => void, ) => void; diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index 4323cd25040c21..56a2c6b9c16371 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -114,6 +114,7 @@ namespace JS { NSString *message() const; folly::Optional> options() const; folly::Optional> destructiveButtonIndices() const; + folly::Optional> disabledButtonIndices() const; folly::Optional cancelButtonIndex() const; folly::Optional anchor() const; folly::Optional tintColor() const; @@ -2922,6 +2923,11 @@ inline folly::Optional> JS::NativeActionShee id const p = _v[@"destructiveButtonIndices"]; return RCTBridgingToOptionalVec(p, ^double(id itemValue_0) { return RCTBridgingToDouble(itemValue_0); }); } +inline folly::Optional> JS::NativeActionSheetManager::SpecShowActionSheetWithOptionsOptions::disabledButtonIndices() const +{ + id const p = _v[@"disabledButtonIndices"]; + return RCTBridgingToOptionalVec(p, ^double(id itemValue_0) { return RCTBridgingToDouble(itemValue_0); }); +} inline folly::Optional JS::NativeActionSheetManager::SpecShowActionSheetWithOptionsOptions::cancelButtonIndex() const { id const p = _v[@"cancelButtonIndex"]; diff --git a/RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js b/RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js index c1130357829df5..a5ea2d79771d82 100644 --- a/RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js +++ b/RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js @@ -25,6 +25,7 @@ const ScreenshotManager = NativeModules.ScreenshotManager; const BUTTONS = ['Option 0', 'Option 1', 'Option 2', 'Delete', 'Cancel']; const DESTRUCTIVE_INDEX = 3; const CANCEL_INDEX = 4; +const DISABLED_BUTTON_INDICES = [1, 2]; type Props = $ReadOnly<{||}>; type State = {|clicked: string|}; @@ -138,6 +139,37 @@ class ActionSheetAnchorExample extends React.Component< }; } +class ActionSheetDisabledExample extends React.Component { + state = { + clicked: 'none', + }; + + render() { + return ( + + + 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, + }, + buttonIndex => { + this.setState({clicked: BUTTONS[buttonIndex]}); + }, + ); + }; +} + class ShareActionSheetExample extends React.Component< $FlowFixMeProps, $FlowFixMeState, @@ -315,6 +347,12 @@ exports.examples = [ return ; }, }, + { + title: 'Show Action Sheet with disabled buttons', + render(): React.Element { + return ; + }, + }, { title: 'Show Share Action Sheet', render(): React.Element { diff --git a/React/CoreModules/RCTActionSheetManager.mm b/React/CoreModules/RCTActionSheetManager.mm index 754e461157349d..62e38b29e1b13b 100644 --- a/React/CoreModules/RCTActionSheetManager.mm +++ b/React/CoreModules/RCTActionSheetManager.mm @@ -76,6 +76,9 @@ - (void)presentViewController:(UIViewController *)alertController NSInteger cancelButtonIndex = options.cancelButtonIndex() ? [RCTConvert NSInteger:@(*options.cancelButtonIndex())] : -1; NSArray *destructiveButtonIndices; + NSArray *disabledButtonIndices = RCTConvertVecToArray(*options.disabledButtonIndices(), ^id(double element) { + return @(element); + }); if (options.destructiveButtonIndices()) { destructiveButtonIndices = RCTConvertVecToArray(*options.destructiveButtonIndices(), ^id(double element) { return @(element); @@ -98,6 +101,7 @@ - (void)presentViewController:(UIViewController *)alertController @"destructiveButtonIndices" : destructiveButtonIndices, @"anchor" : anchor, @"tintColor" : tintColor, + @"disabledButtonIndices" : disabledButtonIndices, }); return; } @@ -132,6 +136,15 @@ - (void)presentViewController:(UIViewController *)alertController index++; } + for (NSNumber *disabledButtonIndex in disabledButtonIndices) { + if ([disabledButtonIndex integerValue] < buttons.count) { + [alertController.actions[[disabledButtonIndex integerValue]] setEnabled:false]; + } else { + RCTLogError(@"Index %@ from `disabledButtonIndices` is out of bounds. Maximum index value is %@.", @([disabledButtonIndex integerValue]), @(buttons.count - 1)); + return; + } + } + alertController.view.tintColor = tintColor; #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0