From bfacafe5dce78b54365958c301de102ca3c15571 Mon Sep 17 00:00:00 2001 From: Henry Hobbs Date: Sat, 20 Jul 2024 19:39:30 -0400 Subject: [PATCH 1/4] added stickyCancel option --- README.md | 1 + example/App.tsx | 7 ++++ example/ShowActionSheetButton.tsx | 26 +++++++++++++-- src/ActionSheet/ActionGroup.tsx | 48 ++++++++++++++++++++++++--- src/ActionSheet/CustomActionSheet.tsx | 2 ++ src/types.ts | 1 + 6 files changed, 79 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2506494..1110085 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ The below props allow modification of the Android ActionSheet. They have no effe | `separatorStyle` | ViewStyle | Modify the look of the separators rather than use the default look. | | `useModal` | boolean | Defaults to `false` (`true` if autoFocus is also `true`) Wraps the ActionSheet with a Modal, in order to show in front of other Modals that were already opened ([issue reference](https://github.com/expo/react-native-action-sheet/issues/164)). | | `destructiveColor` | string | Modify color for text of destructive option. Defaults to `#d32f2f`. | +| `stickyCancel` | boolean | Moves the option specified by `cancelButtonIndex` top the bottom of the action sheet and outside of the underlying `ScrollView`. Defaults to `false`. | ## ActionSheetProvider Props diff --git a/example/App.tsx b/example/App.tsx index 51bb77d..f0575d3 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -207,6 +207,13 @@ class App extends React.Component { onSelection={this._updateSelectionText} showActionSheetWithOptions={showActionSheetWithOptions} /> + {this._renderSectionHeader('Special Cases')} Open Modal diff --git a/example/ShowActionSheetButton.tsx b/example/ShowActionSheetButton.tsx index d4e0fd5..a691e8f 100644 --- a/example/ShowActionSheetButton.tsx +++ b/example/ShowActionSheetButton.tsx @@ -21,7 +21,9 @@ interface Props { withCustomStyles?: boolean; withCancelButtonTintColor?: boolean; withAnchor?: boolean; + withExtendedOptions?: boolean; useModal?: boolean; + stickyCancel?: boolean; } // A custom button that shows examples of different share sheet configurations @@ -34,8 +36,10 @@ export default class ShowActionSheetButton extends React.PureComponent { withCustomStyles: false, withAnchor: false, withCancelButtonTintColor: false, + withExtendedOptions: false, onSelection: null, useModal: false, + stickyCancel: false, }; _anchorRef = React.createRef(); @@ -52,10 +56,26 @@ export default class ShowActionSheetButton extends React.PureComponent { onSelection, showActionSheetWithOptions, useModal, + stickyCancel, + withExtendedOptions, } = this.props; - + console.log('stickyCancel', stickyCancel); // Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html const options = ['Delete', 'Disabled', 'Save', 'Cancel']; + const extendedOptions = [ + 'Option 1', + 'Option 2', + 'Option 3', + 'Option 4', + 'Option 5', + 'Option 6', + 'Option 7', + 'Option 8', + 'Option 9', + 'Option 10', + 'Option 11', + 'Option 12', + ]; const icons = withIcons ? [icon('delete'), icon('save'), icon('share'), icon('cancel')] : undefined; @@ -99,7 +119,7 @@ export default class ShowActionSheetButton extends React.PureComponent { showActionSheetWithOptions( { - options, + options: withExtendedOptions ? [...options, ...extendedOptions] : options, cancelButtonIndex, cancelButtonTintColor: withCancelButtonTintColor ? '#D93F0B' : undefined, destructiveButtonIndex, @@ -123,6 +143,8 @@ export default class ShowActionSheetButton extends React.PureComponent { containerStyle, // Android only, useModal, + // Android only + stickyCancel, }, (buttonIndex?: number) => { // Do something here depending on the button index selected diff --git a/src/ActionSheet/ActionGroup.tsx b/src/ActionSheet/ActionGroup.tsx index 5f93b0c..781d570 100644 --- a/src/ActionSheet/ActionGroup.tsx +++ b/src/ActionSheet/ActionGroup.tsx @@ -24,6 +24,7 @@ type Props = ActionSheetOptions & { const BLACK_54PC_TRANSPARENT = '#0000008a'; const BLACK_87PC_TRANSPARENT = '#000000de'; const DESTRUCTIVE_COLOR = '#d32f2f'; +const RIPPLE_COLOR = 'rgba(180, 180, 180, 1)'; /** * Can be used as a React ref for a component to auto-focus for accessibility on render. @@ -66,6 +67,7 @@ export default class ActionGroup extends React.Component { showSeparators: false, tintIcons: true, textStyle: {}, + stickyCancel: false, }; render() { @@ -73,6 +75,7 @@ export default class ActionGroup extends React.Component { {this._renderTitleContent()} {this._renderOptionViews()} + {this._renderCancelButton()} ); } @@ -131,12 +134,10 @@ export default class ActionGroup extends React.Component { tintColor, autoFocus, showSeparators, + stickyCancel, } = this.props; const optionViews: React.ReactNode[] = []; - const nativeFeedbackBackground = TouchableNativeFeedbackSafe.Ripple( - 'rgba(180, 180, 180, 1)', - false - ); + const nativeFeedbackBackground = TouchableNativeFeedbackSafe.Ripple(RIPPLE_COLOR, false); for (let i = startIndex; i < startIndex + length; i++) { const defaultColor = tintColor @@ -144,6 +145,9 @@ export default class ActionGroup extends React.Component { : (textStyle || {}).color || BLACK_87PC_TRANSPARENT; const disabled = isIndexDisabled(i, disabledButtonIndices); const isCancelButton = i === cancelButtonIndex; + if (isCancelButton && stickyCancel) { + continue; + } const color = isIndexDestructive(i, destructiveButtonIndex) ? destructiveColor : isCancelButton @@ -174,6 +178,42 @@ export default class ActionGroup extends React.Component { return optionViews; }; + + _renderCancelButton = () => { + if (!this.props.stickyCancel || this.props.cancelButtonIndex === undefined) { + return null; + } + const { + options, + icons, + cancelButtonIndex, + cancelButtonTintColor, + disabledButtonIndices, + onSelect, + textStyle, + tintColor, + } = this.props; + const disabled = isIndexDisabled(cancelButtonIndex, disabledButtonIndices); + const defaultColor = tintColor ? tintColor : (textStyle || {}).color || BLACK_87PC_TRANSPARENT; + const color = cancelButtonTintColor || defaultColor; + const nativeFeedbackBackground = TouchableNativeFeedbackSafe.Ripple(RIPPLE_COLOR, false); + const iconSource = icons != null ? icons[cancelButtonIndex] : null; + const cancelOption = options[cancelButtonIndex]; + + return ( + onSelect(cancelButtonIndex)} + style={[styles.button, disabled && styles.disabledButton]} + accessibilityRole="button" + accessibilityLabel={cancelOption}> + {this._renderIconElement(iconSource, color)} + {cancelOption} + + ); + }; } const styles = StyleSheet.create({ diff --git a/src/ActionSheet/CustomActionSheet.tsx b/src/ActionSheet/CustomActionSheet.tsx index e88906c..f1790d8 100644 --- a/src/ActionSheet/CustomActionSheet.tsx +++ b/src/ActionSheet/CustomActionSheet.tsx @@ -140,6 +140,7 @@ export default class CustomActionSheet extends React.Component { separatorStyle, cancelButtonIndex, cancelButtonTintColor, + stickyCancel, } = options; return ( @@ -182,6 +183,7 @@ export default class CustomActionSheet extends React.Component { showSeparators={showSeparators} containerStyle={containerStyle} separatorStyle={separatorStyle} + stickyCancel={stickyCancel} /> diff --git a/src/types.ts b/src/types.ts index 44ad7ca..814b84d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,4 +42,5 @@ export interface ActionSheetOptions extends ActionSheetIOSOptions { separatorStyle?: ViewStyle; useModal?: boolean; destructiveColor?: string; + stickyCancel?: boolean; } From 2a7649a17ef4f68b8717d5aefe17760920e8b82f Mon Sep 17 00:00:00 2001 From: Henry Hobbs Date: Sun, 21 Jul 2024 19:16:08 -0400 Subject: [PATCH 2/4] fixed separator not rendering for sticky cancel --- example/App.tsx | 1 + example/ShowActionSheetButton.tsx | 13 ++++++++++++- src/ActionSheet/ActionGroup.tsx | 26 +++++++++++++++----------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/example/App.tsx b/example/App.tsx index f0575d3..66161ac 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -213,6 +213,7 @@ class App extends React.Component { stickyCancel onSelection={this._updateSelectionText} showActionSheetWithOptions={showActionSheetWithOptions} + withSeparators /> {this._renderSectionHeader('Special Cases')} diff --git a/example/ShowActionSheetButton.tsx b/example/ShowActionSheetButton.tsx index a691e8f..4399013 100644 --- a/example/ShowActionSheetButton.tsx +++ b/example/ShowActionSheetButton.tsx @@ -75,6 +75,14 @@ export default class ShowActionSheetButton extends React.PureComponent { 'Option 10', 'Option 11', 'Option 12', + 'Option 13', + 'Option 14', + 'Option 15', + 'Option 16', + 'Option 17', + 'Option 18', + 'Option 19', + 'Option 20', ]; const icons = withIcons ? [icon('delete'), icon('save'), icon('share'), icon('cancel')] @@ -112,7 +120,10 @@ export default class ShowActionSheetButton extends React.PureComponent { ? { backgroundColor: 'lightgrey', } - : undefined; + : {}; + if (withExtendedOptions) { + containerStyle.maxHeight = 500; + } const anchor: number | null = this._anchorRef.current ? findNodeHandle(this._anchorRef.current) : null; diff --git a/src/ActionSheet/ActionGroup.tsx b/src/ActionSheet/ActionGroup.tsx index 781d570..49e79c7 100644 --- a/src/ActionSheet/ActionGroup.tsx +++ b/src/ActionSheet/ActionGroup.tsx @@ -192,6 +192,7 @@ export default class ActionGroup extends React.Component { onSelect, textStyle, tintColor, + showSeparators, } = this.props; const disabled = isIndexDisabled(cancelButtonIndex, disabledButtonIndices); const defaultColor = tintColor ? tintColor : (textStyle || {}).color || BLACK_87PC_TRANSPARENT; @@ -201,17 +202,20 @@ export default class ActionGroup extends React.Component { const cancelOption = options[cancelButtonIndex]; return ( - onSelect(cancelButtonIndex)} - style={[styles.button, disabled && styles.disabledButton]} - accessibilityRole="button" - accessibilityLabel={cancelOption}> - {this._renderIconElement(iconSource, color)} - {cancelOption} - + <> + {showSeparators && this._renderRowSeparator('cancel')} + onSelect(cancelButtonIndex)} + style={[styles.button, disabled && styles.disabledButton]} + accessibilityRole="button" + accessibilityLabel={cancelOption}> + {this._renderIconElement(iconSource, color)} + {cancelOption} + + ); }; } From 113403ad6fdb4287e86582023cc204b85cde072e Mon Sep 17 00:00:00 2001 From: Henry Hobbs Date: Sun, 21 Jul 2024 19:18:56 -0400 Subject: [PATCH 3/4] fix readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1110085..b057d31 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ The below props allow modification of the Android ActionSheet. They have no effe | `separatorStyle` | ViewStyle | Modify the look of the separators rather than use the default look. | | `useModal` | boolean | Defaults to `false` (`true` if autoFocus is also `true`) Wraps the ActionSheet with a Modal, in order to show in front of other Modals that were already opened ([issue reference](https://github.com/expo/react-native-action-sheet/issues/164)). | | `destructiveColor` | string | Modify color for text of destructive option. Defaults to `#d32f2f`. | -| `stickyCancel` | boolean | Moves the option specified by `cancelButtonIndex` top the bottom of the action sheet and outside of the underlying `ScrollView`. Defaults to `false`. | +| `stickyCancel` | boolean | Moves the option specified by `cancelButtonIndex` to the bottom of the action sheet and outside of the underlying `ScrollView`. Defaults to `false`. | ## ActionSheetProvider Props From e91ce0f3d04565391bb8f9edf61ca7b7e662fec2 Mon Sep 17 00:00:00 2001 From: Henry Hobbs Date: Sun, 21 Jul 2024 19:34:48 -0400 Subject: [PATCH 4/4] remove console.log --- example/ShowActionSheetButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/example/ShowActionSheetButton.tsx b/example/ShowActionSheetButton.tsx index 4399013..a1aee27 100644 --- a/example/ShowActionSheetButton.tsx +++ b/example/ShowActionSheetButton.tsx @@ -59,7 +59,6 @@ export default class ShowActionSheetButton extends React.PureComponent { stickyCancel, withExtendedOptions, } = this.props; - console.log('stickyCancel', stickyCancel); // Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html const options = ['Delete', 'Disabled', 'Save', 'Cancel']; const extendedOptions = [