diff --git a/README.md b/README.md index 8eb27e9..26d973a 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,53 @@ The old keys will continue to work for now but are deprecated and may be removed Dismisses any existing Snackbars. +## Advanced usage + +### Snackbar events +You can have information on snackbar visibility. + +```js + componentDidMount() { + const SnackbarEventEmitter = new NativeEventEmitter( + NativeModules.RNSnackbar, + ); + this.eventListener = SnackbarEventEmitter.addListener('onSnackbarVisibility', (event) => { + console.log(event.event); + }); + } + + componentWillUnmount() { + this.eventListener.remove(); + } +``` + +Or, with functional components: + +```js + useEffect(() => { + const subscription = new NativeEventEmitter( + NativeModules.RNSnackbar, + ).addListener('onSnackbarVisibility', event => { + console.log(event.event); + }); + return () => { + subscription.remove(); + }; + }, []); +``` + +Where event is one of the following options : + +| Key | Data type | Value | Description | +|-----|-----------|----------------|-------------| +| `Snackbar.DISMISS_EVENT_SWIPE` | `number` | 0 | Indicates that the Snackbar was dismissed via a swipe. | +| `Snackbar.DISMISS_EVENT_ACTION` | `number` | 1 | Indicates that the Snackbar was dismissed via an action click. | +| `Snackbar.DISMISS_EVENT_TIMEOUT` | `number` | 2 | Indicates that the Snackbar was dismissed via a timeout. | +| `Snackbar.DISMISS_EVENT_MANUAL` | `number` | 3 | Indicates that the Snackbar was dismissed via Snackbar.dismiss() call. | +| `Snackbar.DISMISS_EVENT_CONSECUTIVE` | `number` | 4 | Indicates that the Snackbar was dismissed from a new Snackbar being shown. | +| `Snackbar.SHOW_EVENT` | `number` | 5 | Indicates that Snackbar appears | + + ## Troubleshooting #### Snackbar not appearing [Android] diff --git a/android/build.gradle b/android/build.gradle index 8b05ea4..57a263b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -48,6 +48,7 @@ repositories { dependencies { implementation "com.facebook.react:react-native:${_reactNativeVersion}" + implementation "androidx.appcompat:appcompat:1.3.1" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "com.google.android.material:material:${_materialVersion}" } diff --git a/android/src/main/java/com/azendoo/reactnativesnackbar/SnackbarModule.java b/android/src/main/java/com/azendoo/reactnativesnackbar/SnackbarModule.java index bdb6fb2..a2f08c8 100644 --- a/android/src/main/java/com/azendoo/reactnativesnackbar/SnackbarModule.java +++ b/android/src/main/java/com/azendoo/reactnativesnackbar/SnackbarModule.java @@ -2,10 +2,6 @@ import android.graphics.Color; import android.graphics.Typeface; - -import com.google.android.material.snackbar.BaseTransientBottomBar; -import com.google.android.material.snackbar.Snackbar; - import android.os.Build; import android.content.Context; import android.util.DisplayMetrics; @@ -14,28 +10,42 @@ import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.google.android.material.snackbar.BaseTransientBottomBar; +import com.google.android.material.snackbar.Snackbar; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Collections; public class SnackbarModule extends ReactContextBaseJavaModule { private static final String REACT_NAME = "RNSnackbar"; - private List mActiveSnackbars = new ArrayList<>(); + + private static final String ON_SNACKBAR_VISIBILITY_EVENT = "onSnackbarVisibility"; + private static final int SHOW_EVENT = 5; + + private final List mActiveSnackbars = new ArrayList<>(); public SnackbarModule(ReactApplicationContext reactContext) { super(reactContext); } + @NonNull @Override public String getName() { return REACT_NAME; @@ -48,6 +58,12 @@ public Map getConstants() { constants.put("LENGTH_LONG", Snackbar.LENGTH_LONG); constants.put("LENGTH_SHORT", Snackbar.LENGTH_SHORT); constants.put("LENGTH_INDEFINITE", Snackbar.LENGTH_INDEFINITE); + constants.put("DISMISS_EVENT_SWIPE", Snackbar.Callback.DISMISS_EVENT_SWIPE); + constants.put("DISMISS_EVENT_ACTION", Snackbar.Callback.DISMISS_EVENT_ACTION); + constants.put("DISMISS_EVENT_TIMEOUT", Snackbar.Callback.DISMISS_EVENT_TIMEOUT); + constants.put("DISMISS_EVENT_MANUAL", Snackbar.Callback.DISMISS_EVENT_MANUAL); + constants.put("DISMISS_EVENT_CONSECUTIVE", Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE); + constants.put("SHOW_EVENT", SHOW_EVENT); return constants; } @@ -107,6 +123,16 @@ public void dismiss() { mActiveSnackbars.clear(); } + @ReactMethod + public void addListener(String eventName) { + // Keep: Required for RN built in Event Emitter Calls. + } + + @ReactMethod + public void removeListeners(Integer count) { + // Keep: Required for RN built in Event Emitter Calls. + } + private void displaySnackbar(View view, ReadableMap options, final Callback callback) { String text = getOptionValue(options, "text", ""); int duration = getOptionValue(options, "duration", Snackbar.LENGTH_SHORT); @@ -191,6 +217,18 @@ public void onClick(View v) { } } + snackbar.addCallback(new BaseTransientBottomBar.BaseCallback() { + @Override + public void onDismissed(Snackbar transientBottomBar, int event) { + sendSnackbarVisibilityEvent(event); + } + + @Override + public void onShown(Snackbar transientBottomBar) { + sendSnackbarVisibilityEvent(SHOW_EVENT); + } + }); + snackbar.show(); } @@ -217,6 +255,20 @@ private ArrayList recursiveLoopChildren(ViewGroup view, ArrayList mo return modals; } + private void sendSnackbarVisibilityEvent(int event) { + WritableMap params = Arguments.createMap(); + params.putInt("event", event); + sendEvent(getReactApplicationContext(), ON_SNACKBAR_VISIBILITY_EVENT, params); + } + + private void sendEvent(ReactContext reactContext, + String eventName, + @Nullable WritableMap params) { + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); + } + private String getOptionValue(ReadableMap options, String key, String fallback) { return options.hasKey(key) ? options.getString(key) : fallback; } diff --git a/example/ios/Podfile b/example/ios/Podfile index 59954b6..19d3296 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -35,6 +35,14 @@ target 'SnackbarExample' do # Pods for testing end use_native_modules! + + post_install do |installer| + ## Fix for XCode 12.5 + find_and_replace("../node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm", + "_initializeModules:(NSArray> *)modules", "_initializeModules:(NSArray *)modules") + find_and_replace("../node_modules/react-native/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm", + "RCTBridgeModuleNameForClass(module))", "RCTBridgeModuleNameForClass(Class(module)))") + end end target 'SnackbarExample-tvOS' do # Pods for SnackbarExample-tvOS @@ -43,3 +51,16 @@ target 'SnackbarExample-tvOS' do # Pods for testing end end + +def find_and_replace(dir, findstr, replacestr) + Dir[dir].each do |name| + text = File.read(name) + replace = text.gsub(findstr,replacestr) + if text != replace + puts "Fix: " + name + File.open(name, "w") { |file| file.puts replace } + STDOUT.flush + end + end + Dir[dir + '*/'].each(&method(:find_and_replace)) +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index dab13f7..a5ca2c0 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -217,7 +217,7 @@ PODS: - React-cxxreact (= 0.61.2) - React-jsi (= 0.61.2) - ReactCommon/jscallinvoker (= 0.61.2) - - RNSnackbar (2.2.4): + - RNSnackbar (2.4.0): - React-Core - Yoga (1.14.0) @@ -253,7 +253,7 @@ DEPENDENCIES: - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: - https://github.com/CocoaPods/Specs.git: + trunk: - boost-for-react-native EXTERNAL SOURCES: @@ -336,9 +336,9 @@ SPEC CHECKSUMS: React-RCTText: e3ef6191cdb627855ff7fe8fa0c1e14094967fb8 React-RCTVibration: fb54c732fd20405a76598e431aa2f8c2bf527de9 ReactCommon: 5848032ed2f274fcb40f6b9ec24067787c42d479 - RNSnackbar: 86092381dba7a0ed9fbd7acdb82ebbd5bfd26372 + RNSnackbar: be3333a21a453ccc272f41a8add5a71f7d44dfcd Yoga: 14927e37bd25376d216b150ab2a561773d57911f -PODFILE CHECKSUM: 4ec39b585cf6ab1637af9ccf9756b2ea164b2d94 +PODFILE CHECKSUM: fb6c1683e9500b74f4151c37cfa77a763e247845 -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.1 diff --git a/example/src/App.js b/example/src/App.js index c1c9478..a6da610 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -1,11 +1,24 @@ import React, { Component } from 'react'; -import { Text, View, TouchableOpacity } from 'react-native'; +import { Text, View, TouchableOpacity, NativeEventEmitter, NativeModules } from 'react-native'; import Snackbar from 'react-native-snackbar'; import styles from '../styles'; // eslint-disable-next-line react/prefer-stateless-function class Example extends Component { + componentDidMount() { + const SnackbarEventEmitter = new NativeEventEmitter( + NativeModules.RNSnackbar, + ); + this.eventListener = SnackbarEventEmitter.addListener('onSnackbarVisibility', (event) => { + console.log(event.event); + }); + } + + componentWillUnmount() { + this.eventListener.remove(); + } + render() { return ( diff --git a/example/src/__tests__/index.test.js b/example/src/__tests__/index.test.js index 05cc8f9..69579b5 100644 --- a/example/src/__tests__/index.test.js +++ b/example/src/__tests__/index.test.js @@ -6,6 +6,10 @@ import renderer from 'react-test-renderer'; import App from '../App'; +jest.mock( + '../../node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter', +); + describe('Snackbar example app', () => { it('renders without crashing', () => { renderer.create(); diff --git a/example/sync.sh b/example/sync.sh index 40b5270..64228ca 100755 --- a/example/sync.sh +++ b/example/sync.sh @@ -2,5 +2,5 @@ # # Saved as its own file so that Travis uses the correct shell to run it. -mkdir node_modules/react-native-snackbar +mkdir -p node_modules/react-native-snackbar cp -R ../{package.json,android,ios,lib} node_modules/react-native-snackbar/ diff --git a/ios/RNSnackBarView.h b/ios/RNSnackBarView.h index 738307b..4e15189 100644 --- a/ios/RNSnackBarView.h +++ b/ios/RNSnackBarView.h @@ -4,10 +4,11 @@ // #import +#import "RNSnackbar.h" @interface RNSnackBarView : UIView -+ (void)showWithOptions:(NSDictionary *)options andCallback:(void (^)())callback; ++ (void)showWithOptions:(NSDictionary *)options andCallback:(void (^)())callback rnSnackbar:(RNSnackbar *)rnSnackbar; + (void)dismiss; @end diff --git a/ios/RNSnackBarView.m b/ios/RNSnackBarView.m index ddcdfc9..9a1c68c 100644 --- a/ios/RNSnackBarView.m +++ b/ios/RNSnackBarView.m @@ -7,10 +7,11 @@ #import typedef NS_ENUM(NSInteger, RNSnackBarViewState) { + // Put RNSnackBarViewStateDismissed on the top to set it as a default value + RNSnackBarViewStateDismissed, RNSnackBarViewStateDisplayed, RNSnackBarViewStatePresenting, - RNSnackBarViewStateDismissing, - RNSnackBarViewStateDismissed + RNSnackBarViewStateDismissing }; static NSDictionary *DEFAULT_DURATIONS; @@ -25,6 +26,7 @@ @interface RNSnackBarView () { @property(nonatomic) RNSnackBarViewState state; @property(nonatomic, strong) NSDictionary *pendingOptions; +@property(nonatomic, strong) RNSnackbar *rnSnackbar; @property(nonatomic, strong) NSString *text; @property(nonatomic, strong) UIColor *textColor; @property(nonatomic, strong) NSString *actionText; @@ -39,7 +41,7 @@ @interface RNSnackBarView () { @implementation RNSnackBarView + (void)initialize { - DEFAULT_DURATIONS = @{@"-1" : @1500, @"-2" : @2750, @"0" : @INT_MAX}; + DEFAULT_DURATIONS = @{@"-1" : @1500, @"0" : @2750, @"-2" : @INT_MAX}; } + (id)sharedSnackBar { @@ -51,16 +53,21 @@ + (id)sharedSnackBar { return sharedSnackBar; } -+ (void)showWithOptions:(NSDictionary *)options andCallback:(void (^)())callback { ++ (void)showWithOptions:(NSDictionary *)options andCallback:(void (^)())callback rnSnackbar:(RNSnackbar *)rnSnackbar { RNSnackBarView *snackBar = [RNSnackBarView sharedSnackBar]; snackBar.pendingOptions = options; snackBar.pendingCallback = callback; + snackBar.rnSnackbar = rnSnackbar; [snackBar show]; + NSNumber *showEvent = [rnSnackbar constantsToExport][@"SHOW_EVENT"]; + [rnSnackbar sendSnackbarVisibilityEvent:showEvent]; } + (void)dismiss { RNSnackBarView *snackBar = [RNSnackBarView sharedSnackBar]; [snackBar dismiss]; + NSNumber *dismissEventManual = [snackBar->_rnSnackbar constantsToExport][@"DISMISS_EVENT_MANUAL"]; + [snackBar->_rnSnackbar sendSnackbarVisibilityEvent:dismissEventManual]; } - (instancetype)init { @@ -161,6 +168,8 @@ - (void)setActionTextColor:(UIColor *)actionTextColor { - (void)actionPressed:(UIButton *)sender { [self dismiss]; + NSNumber *dismissEventAction = [self->_rnSnackbar constantsToExport][@"DISMISS_EVENT_ACTION"]; + [self->_rnSnackbar sendSnackbarVisibilityEvent:dismissEventAction]; self.callback(); } @@ -204,8 +213,8 @@ - (void)presentWithDuration:(NSNumber *)duration { // Snackbar will slide up from bottom, unless a bottom margin is set in which case we use a fade animation self.transform = CGAffineTransformMakeTranslation(0, [self.marginBottom integerValue] == 0 ? self.bounds.size.height : 0); - textLabel.alpha = 0; - actionButton.alpha = 0; + self.textLabel.alpha = 0; + self.actionButton.alpha = 0; if ([self.marginBottom integerValue] == 0) { self.alpha = 0; } @@ -213,8 +222,8 @@ - (void)presentWithDuration:(NSNumber *)duration { [UIView animateWithDuration:ANIMATION_DURATION animations:^{ self.transform = CGAffineTransformIdentity; - textLabel.alpha = 1; - actionButton.alpha = 1; + self.textLabel.alpha = 1; + self.actionButton.alpha = 1; self.alpha = 1; } completion:^(BOOL finished) { @@ -226,14 +235,20 @@ - (void)presentWithDuration:(NSNumber *)duration { } else { interval = [duration doubleValue] / 1000; } - dismissTimer = [NSTimer scheduledTimerWithTimeInterval:interval + self->dismissTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self - selector:@selector(dismiss) + selector:@selector(dismissWithTimeout) userInfo:nil repeats:FALSE]; }]; } +- (void)dismissWithTimeout { + NSNumber *dismissEventTimeout = [self->_rnSnackbar constantsToExport][@"DISMISS_EVENT_TIMEOUT"]; + [self->_rnSnackbar sendSnackbarVisibilityEvent:dismissEventTimeout]; + [self dismiss]; +} + - (void)dismiss { [self.layer removeAllAnimations]; [dismissTimer invalidate]; @@ -246,7 +261,7 @@ - (void)dismiss { completion:^(BOOL finished) { self.state = RNSnackBarViewStateDismissed; [self removeFromSuperview]; - if (_pendingOptions) { + if (self->_pendingOptions) { [self show]; } }]; @@ -254,6 +269,8 @@ - (void)dismiss { - (void)show { if (self.state == RNSnackBarViewStateDisplayed || self.state == RNSnackBarViewStatePresenting) { + NSNumber *dismissEventConsecutive = [self->_rnSnackbar constantsToExport][@"DISMISS_EVENT_CONSECUTIVE"]; + [self->_rnSnackbar sendSnackbarVisibilityEvent:dismissEventConsecutive]; [self dismiss]; return; } diff --git a/ios/RNSnackbar.h b/ios/RNSnackbar.h index 14f3a34..9b1cec6 100644 --- a/ios/RNSnackbar.h +++ b/ios/RNSnackbar.h @@ -5,7 +5,11 @@ #import #import +#import -@interface RNSnackbar : NSObject +@interface RNSnackbar : RCTEventEmitter + +- (void)sendSnackbarVisibilityEvent:(NSNumber *)event; +- (NSDictionary *)constantsToExport; @end diff --git a/ios/RNSnackbar.m b/ios/RNSnackbar.m index a601b8c..d8fe018 100644 --- a/ios/RNSnackbar.m +++ b/ios/RNSnackbar.m @@ -6,16 +6,18 @@ #import "RNSnackBarView.h" #import "RNSnackbar.h" -@implementation RNSnackbar +@implementation RNSnackbar { + bool hasListeners; +} RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(show : (NSDictionary *)options callback : (RCTResponseSenderBlock)callback) { dispatch_async(dispatch_get_main_queue(), ^{ - [RNSnackBarView showWithOptions:options + [RNSnackBarView showWithOptions:options andCallback:^{ callback(@[ [NSNull null], [NSNull null] ]); - }]; + } rnSnackbar:self]; }); } @@ -25,6 +27,29 @@ @implementation RNSnackbar }); } +// Will be called when this module's first listener is added. +-(void)startObserving { + hasListeners = YES; + // Set up any upstream listeners or background tasks as necessary +} + +// Will be called when this module's last listener is removed, or on dealloc. +-(void)stopObserving { + hasListeners = NO; + // Remove upstream listeners, stop unnecessary background tasks +} + +- (NSArray *)supportedEvents { + return @[@"onSnackbarVisibility"]; +} + +- (void)sendSnackbarVisibilityEvent:(NSNumber *)event { + // Only send events if anyone is listening + if (hasListeners) { + [self sendEventWithName:@"onSnackbarVisibility" body:@{@"event": event}]; + } +} + + (BOOL)requiresMainQueueSetup { return YES; } @@ -32,8 +57,14 @@ + (BOOL)requiresMainQueueSetup { - (NSDictionary *)constantsToExport { return @{ @"LENGTH_SHORT" : @-1, - @"LENGTH_LONG" : @-2, - @"LENGTH_INDEFINITE" : @0, + @"LENGTH_LONG" : @0, + @"LENGTH_INDEFINITE" : @-2, + @"DISMISS_EVENT_SWIPE" : @0, + @"DISMISS_EVENT_ACTION" : @1, + @"DISMISS_EVENT_TIMEOUT" : @2, + @"DISMISS_EVENT_MANUAL" : @3, + @"DISMISS_EVENT_CONSECUTIVE" : @4, + @"SHOW_EVENT" : @5, }; } diff --git a/ios/RNSnackbar.xcodeproj/project.pbxproj b/ios/RNSnackbar.xcodeproj/project.pbxproj index bc501eb..de0f020 100644 --- a/ios/RNSnackbar.xcodeproj/project.pbxproj +++ b/ios/RNSnackbar.xcodeproj/project.pbxproj @@ -108,6 +108,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = 4114DC431C187C3A003CD988; @@ -169,7 +170,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -206,7 +207,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/src/index.d.ts b/src/index.d.ts index c360ec4..a54b7fc 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,5 +1,4 @@ // TypeScript typings. - /** * An optional, actionable button on the Snackbar. */ @@ -99,6 +98,36 @@ export interface SnackbarStatic { */ LENGTH_INDEFINITE: number; + /** + * Indicates that the Snackbar was dismissed via a swipe. + */ + DISMISS_EVENT_SWIPE: number; + + /** + * Indicates that the Snackbar was dismissed via an action click. + */ + DISMISS_EVENT_ACTION: number; + + /** + * Indicates that the Snackbar was dismissed via a timeout. + */ + DISMISS_EVENT_TIMEOUT: number; + + /** + * Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}. + */ + DISMISS_EVENT_MANUAL: number; + + /** + * Indicates that the Snackbar was dismissed from a new Snackbar being shown. + */ + DISMISS_EVENT_CONSECUTIVE: number; + + /** + * Indicates that Snackbar appears. + */ + SHOW_EVENT: number; + /** * Shows a native Snackbar component. */ diff --git a/src/index.js b/src/index.js index 7f0dde7..04a21c9 100644 --- a/src/index.js +++ b/src/index.js @@ -91,6 +91,36 @@ type ISnackBar = { */ LENGTH_INDEFINITE: number, + /** + * Indicates that the Snackbar was dismissed via a swipe. + */ + DISMISS_EVENT_SWIPE: number, + + /** + * Indicates that the Snackbar was dismissed via an action click. + */ + DISMISS_EVENT_ACTION: number, + + /** + * Indicates that the Snackbar was dismissed via a timeout. + */ + DISMISS_EVENT_TIMEOUT: number, + + /** + * Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}. + */ + DISMISS_EVENT_MANUAL: number, + + /** + * Indicates that the Snackbar was dismissed from a new Snackbar being shown. + */ + DISMISS_EVENT_CONSECUTIVE: number, + + /** + * Indicates that Snackbar appears. + */ + SHOW_EVENT: number, + /** * Shows a native Snackbar component. */ @@ -106,6 +136,12 @@ const SnackBar: ISnackBar = { LENGTH_LONG: NativeModules.RNSnackbar.LENGTH_LONG, LENGTH_SHORT: NativeModules.RNSnackbar.LENGTH_SHORT, LENGTH_INDEFINITE: NativeModules.RNSnackbar.LENGTH_INDEFINITE, + DISMISS_EVENT_SWIPE: NativeModules.RNSnackbar.DISMISS_EVENT_SWIPE, + DISMISS_EVENT_ACTION: NativeModules.RNSnackbar.DISMISS_EVENT_ACTION, + DISMISS_EVENT_TIMEOUT: NativeModules.RNSnackbar.DISMISS_EVENT_TIMEOUT, + DISMISS_EVENT_MANUAL: NativeModules.RNSnackbar.DISMISS_EVENT_MANUAL, + DISMISS_EVENT_CONSECUTIVE: NativeModules.RNSnackbar.DISMISS_EVENT_CONSECUTIVE, + SHOW_EVENT: NativeModules.RNSnackbar.SHOW_EVENT, show(options: SnackBarOptions) { warnDeprecation(options, 'title', 'text');