react-native-toast-message 2.1.0-beta.2 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,34 @@ Headers are one of:
9
9
 
10
10
  - `Added`, `Changed`, `Removed`, `Fixed` or `Breaking`.
11
11
 
12
+ ## [2.1.2]
13
+
14
+ ### Fixed
15
+
16
+ - Fixes `useNativeDriver` warning on web by [jpaas](https://github.com/jpaas) in [#334](https://github.com/calintamas/react-native-toast-message/pull/334)
17
+
18
+ ## [2.1.1]
19
+
20
+ ### Fixed
21
+
22
+ - Tapping a View / Button behind the Toast is not possible ([b9d191e](https://github.com/calintamas/react-native-toast-message/commit/b9d191e1dcc4d331fd5159ca9aabd54d7d0ecb97)) (fixes [#282](https://github.com/calintamas/react-native-toast-message/issues/282))
23
+
24
+ ## [2.1.0]
25
+
26
+ ### Fixed
27
+
28
+ - After a Toast is shown within a Modal, the main instance outside of Modal doesn't work anymore ([#293](https://github.com/calintamas/react-native-toast-message/pull/293))
29
+ - A previously set timer is not cleared when `autoHide` changes from `true` to `false`. This can make a newly shown Toast auto hide (even if it was shown with `autoHide: false`) ([#294](https://github.com/calintamas/react-native-toast-message/pull/294))
30
+
31
+ Big thanks go to [jstheoriginal](https://github.com/jstheoriginal) for all the work on fixing the two issues above 🙌.
32
+
33
+ - Flexbox not working for setting Toast width or alignment ([3400f00](https://github.com/calintamas/react-native-toast-message/commit/3400f0074116f5acb37ca2eb696ea50b0c669ddc))
34
+
35
+ ### Changed
36
+
37
+ - `BaseToastProps` style types allows passing an array of styles now `style={[styles.one, styles.two]}` ([#243](https://github.com/calintamas/react-native-toast-message/pull/243) was ported to v2)
38
+ - Peer deps no longer require a min version ([e91ed21](https://github.com/calintamas/react-native-toast-message/commit/e91ed21d277d7348b674834765147be752b6abfb))
39
+
12
40
  ## [2.0.2]
13
41
 
14
42
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import { ToastProps, ToastShowParams } from './types';
3
- export declare function Toast({ nestingLevel, ...rest }: ToastProps): JSX.Element;
3
+ export declare function Toast(props: ToastProps): JSX.Element;
4
4
  export declare namespace Toast {
5
5
  var show: (params: ToastShowParams) => void;
6
6
  var hide: (params?: void | undefined) => void;
package/lib/src/Toast.js CHANGED
@@ -7,33 +7,68 @@ const ToastRoot = React.forwardRef((props, ref) => {
7
7
  const { show, hide, isVisible, options, data } = useToast({
8
8
  defaultOptions
9
9
  });
10
- React.useImperativeHandle(ref, () => ({
10
+ // This must use useCallback to ensure the ref doesn't get set to null and then a new ref every render.
11
+ React.useImperativeHandle(ref, React.useCallback(() => ({
11
12
  show,
12
13
  hide
13
- }));
14
+ }), [hide, show]));
14
15
  return (<ToastUI isVisible={isVisible} options={options} data={data} hide={hide} show={show} config={config}/>);
15
16
  });
16
- const refs = [];
17
- export function Toast({ nestingLevel = 0, ...rest }) {
17
+ let refs = [];
18
+ /**
19
+ * Adds a ref to the end of the array, which will be used to show the toasts until its ref becomes null.
20
+ *
21
+ * @param newRef the new ref, which must be stable for the life of the Toast instance.
22
+ */
23
+ function addNewRef(newRef) {
24
+ refs.push({
25
+ current: newRef
26
+ });
27
+ }
28
+ /**
29
+ * Removes the passed in ref from the file-level refs array using a strict equality check.
30
+ *
31
+ * @param oldRef the exact ref object to remove from the refs array.
32
+ */
33
+ function removeOldRef(oldRef) {
34
+ refs = refs.filter((r) => r.current !== oldRef);
35
+ }
36
+ export function Toast(props) {
37
+ const toastRef = React.useRef(null);
38
+ /*
39
+ This must use `useCallback` to ensure the ref doesn't get set to null and then a new ref every render.
40
+ Failure to do so will cause whichever Toast *renders or re-renders* last to be the instance that is used,
41
+ rather than being the Toast that was *mounted* last.
42
+ */
43
+ const setRef = React.useCallback((ref) => {
44
+ // Since we know there's a ref, we'll update `refs` to use it.
45
+ if (ref) {
46
+ // store the ref in this toast instance to be able to remove it from the array later when the ref becomes null.
47
+ toastRef.current = ref;
48
+ addNewRef(ref);
49
+ }
50
+ else {
51
+ // remove the this toast's ref, wherever it is in the array.
52
+ removeOldRef(toastRef.current);
53
+ }
54
+ }, []);
18
55
  return (<LoggerProvider enableLogs={false}>
19
- <ToastRoot ref={(ref) => {
20
- refs[nestingLevel] = {
21
- current: ref
22
- };
23
- }} {...rest}/>
56
+ <ToastRoot ref={setRef} {...props}/>
24
57
  </LoggerProvider>);
25
58
  }
26
59
  /**
27
60
  * Get the active Toast instance `ref`, by priority.
28
61
  * The "highest" Toast in the `View` hierarchy has the highest priority.
29
62
  *
30
- * For example, a Toast inside a `Modal`, would have a higher priority than a Toast inside App's Root
31
- * (which has a default `nestingLevel` of 0)
63
+ * For example, a Toast inside a `Modal`, would have had its ref set later than a Toast inside App's Root.
64
+ * Therefore, the library knows that it is currently visible on top of the App's Root
65
+ * and will thus use the `Modal`'s Toast when showing/hiding.
66
+ *
32
67
  * ```js
33
68
  * <>
34
- * <Toast nestingLevel={0} />
69
+ * <Toast />
35
70
  * <Modal>
36
- * <Toast nestingLevel={1} />
71
+ * <Toast />
37
72
  * </Modal>
38
73
  * </>
39
74
  * ```
@@ -72,7 +72,10 @@ export function AnimatedContainer({ children, isVisible, position, topOffset, bo
72
72
  const newAnimationValue = isVisible ? 1 : 0;
73
73
  animate(newAnimationValue);
74
74
  }, [animate, isVisible]);
75
- return (<Animated.View testID={getTestId('AnimatedContainer')} onLayout={computeViewDimensions} style={[styles.base, styles[position], animationStyles]} {...panResponder.panHandlers}>
75
+ return (<Animated.View testID={getTestId('AnimatedContainer')} onLayout={computeViewDimensions} style={[styles.base, styles[position], animationStyles]}
76
+ // This container View is never the target of touch events but its subviews can be.
77
+ // By doing this, tapping buttons behind the Toast is allowed
78
+ pointerEvents='box-none' {...panResponder.panHandlers}>
76
79
  {children}
77
80
  </Animated.View>);
78
81
  }
@@ -1,9 +1,10 @@
1
1
  export declare const styles: {
2
2
  base: {
3
3
  position: "absolute";
4
+ left: number;
5
+ right: number;
4
6
  alignItems: "center";
5
7
  justifyContent: "center";
6
- alignSelf: "center";
7
8
  };
8
9
  top: {
9
10
  top: number;
@@ -2,9 +2,10 @@ import { StyleSheet } from 'react-native';
2
2
  export const styles = StyleSheet.create({
3
3
  base: {
4
4
  position: 'absolute',
5
+ left: 0,
6
+ right: 0,
5
7
  alignItems: 'center',
6
- justifyContent: 'center',
7
- alignSelf: 'center'
8
+ justifyContent: 'center'
8
9
  },
9
10
  top: {
10
11
  top: 0
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Animated } from 'react-native';
2
+ import { Animated, Platform } from 'react-native';
3
3
  import { additiveInverseArray } from '../utils/array';
4
4
  import { useKeyboard } from './useKeyboard';
5
5
  export function translateYOutputRangeFor({ position, height, topOffset, bottomOffset, keyboardHeight, keyboardOffset }) {
@@ -9,13 +9,14 @@ export function translateYOutputRangeFor({ position, height, topOffset, bottomOf
9
9
  const outputRange = position === 'bottom' ? additiveInverseArray(range) : range;
10
10
  return outputRange;
11
11
  }
12
+ const useNativeDriver = Platform.select({ native: true, default: false });
12
13
  export function useSlideAnimation({ position, height, topOffset, bottomOffset, keyboardOffset }) {
13
14
  const animatedValue = React.useRef(new Animated.Value(0));
14
15
  const { keyboardHeight } = useKeyboard();
15
16
  const animate = React.useCallback((toValue) => {
16
17
  Animated.spring(animatedValue.current, {
17
18
  toValue,
18
- useNativeDriver: true,
19
+ useNativeDriver,
19
20
  friction: 8
20
21
  }).start();
21
22
  }, []);
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { TextStyle, TouchableOpacityProps, ViewStyle } from 'react-native';
2
+ import { StyleProp, TextProps, TextStyle, TouchableOpacityProps, ViewProps, ViewStyle } from 'react-native';
3
3
  export declare type ReactChildren = React.ReactNode;
4
4
  export declare type ToastType = string;
5
5
  export declare type ToastPosition = 'top' | 'bottom';
@@ -74,16 +74,16 @@ export declare type BaseToastProps = {
74
74
  text2?: string;
75
75
  onPress?: () => void;
76
76
  activeOpacity?: number;
77
- style?: ViewStyle;
77
+ style?: StyleProp<ViewStyle>;
78
78
  touchableContainerProps?: TouchableOpacityProps;
79
- contentContainerStyle?: ViewStyle;
80
- contentContainerProps?: ViewStyle;
81
- text1Style?: TextStyle;
79
+ contentContainerStyle?: StyleProp<ViewStyle>;
80
+ contentContainerProps?: ViewProps;
81
+ text1Style?: StyleProp<TextStyle>;
82
82
  text1NumberOfLines?: number;
83
- text1Props?: TextStyle;
84
- text2Style?: TextStyle;
83
+ text1Props?: TextProps;
84
+ text2Style?: StyleProp<TextStyle>;
85
85
  text2NumberOfLines?: number;
86
- text2Props?: TextStyle;
86
+ text2Props?: TextProps;
87
87
  renderLeadingIcon?: () => React.ReactNode;
88
88
  renderTrailingIcon?: () => React.ReactNode;
89
89
  };
@@ -110,40 +110,6 @@ export declare type ToastRef = {
110
110
  * They act as defaults for all Toasts that are shown.
111
111
  */
112
112
  export declare type ToastProps = {
113
- /**
114
- * Nesting level for the Toast instance.
115
- * The "higher" a Toast instance is in the `View` hierarchy, the bigger its nesting level value.
116
- * Default `nestingLevel = 0`.
117
- *
118
- * By setting this prop, you can show Toasts inside Modals, no matter how nested they would be.
119
- *
120
- * For example, a Toast inside a `Modal`, would have a bigger `nestingLevel`
121
- * than a Toast inside App's Root (which has the default `nestingLevel` of 0).
122
- *
123
- * ```js
124
- * <>
125
- * <Toast />
126
- * <Modal>
127
- * <Toast nestingLevel={1} />
128
- * </Modal>
129
- * </>
130
- * ```
131
- *
132
- * If you have nested Modals, the `nestingLevel` prop needs to be adjusted accordingly:
133
- *
134
- * ```js
135
- * <>
136
- * <Toast />
137
- * <Modal>
138
- * <Toast nestingLevel={1} />
139
- * <Modal>
140
- * <Toast nestingLevel={2} />
141
- * </Modal>
142
- * </Modal>
143
- * </>
144
- * ```
145
- */
146
- nestingLevel?: number;
147
113
  /**
148
114
  * Layout configuration for custom Toast types
149
115
  */
@@ -41,9 +41,6 @@ export function useToast({ defaultOptions }) {
41
41
  const show = React.useCallback((params) => {
42
42
  log(`Showing with params: ${JSON.stringify(params)}`);
43
43
  const { text1 = DEFAULT_DATA.text1, text2 = DEFAULT_DATA.text2, type = initialOptions.type, position = initialOptions.position, autoHide = initialOptions.autoHide, visibilityTime = initialOptions.visibilityTime, topOffset = initialOptions.topOffset, bottomOffset = initialOptions.bottomOffset, keyboardOffset = initialOptions.keyboardOffset, onShow = initialOptions.onShow, onHide = initialOptions.onHide, onPress = initialOptions.onPress, props = initialOptions.props } = params;
44
- // TODO: validate input
45
- // TODO: use a queue when Toast is already visible
46
- setIsVisible(true);
47
44
  setData({
48
45
  text1,
49
46
  text2
@@ -61,14 +58,22 @@ export function useToast({ defaultOptions }) {
61
58
  onPress,
62
59
  props
63
60
  }));
61
+ // TODO: validate input
62
+ // TODO: use a queue when Toast is already visible
63
+ setIsVisible(true);
64
64
  onShow();
65
65
  }, [initialOptions, log]);
66
66
  React.useEffect(() => {
67
67
  const { autoHide } = options;
68
- if (isVisible && autoHide) {
69
- startTimer();
68
+ if (isVisible) {
69
+ if (autoHide) {
70
+ startTimer();
71
+ }
72
+ else {
73
+ clearTimer();
74
+ }
70
75
  }
71
- }, [isVisible, options, startTimer]);
76
+ }, [isVisible, options, startTimer, clearTimer]);
72
77
  return {
73
78
  isVisible,
74
79
  data,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-toast-message",
3
- "version": "2.1.0-beta.2",
3
+ "version": "2.1.2",
4
4
  "description": "Toast message component for React Native",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -22,7 +22,8 @@
22
22
  "lint": "./node_modules/.bin/eslint --fix",
23
23
  "lint-staged": "./node_modules/.bin/lint-staged",
24
24
  "test": "./node_modules/.bin/jest",
25
- "yalc:push": "yarn build && yalc publish --push"
25
+ "yalc:push": "yarn build && yalc publish --push",
26
+ "quality": "yarn lint && tsc --noEmit"
26
27
  },
27
28
  "author": "Calin Tamas <calintamas2@gmail.com>",
28
29
  "license": "MIT",
@@ -30,15 +31,15 @@
30
31
  "@babel/core": "^7.15.8",
31
32
  "@testing-library/jest-native": "^4.0.4",
32
33
  "@testing-library/react-hooks": "^7.0.2",
33
- "@testing-library/react-native": "^8.0.0",
34
+ "@testing-library/react-native": "^9.0.0",
34
35
  "@types/jest": "^27.0.1",
35
36
  "@types/react-native": "^0.66.2",
36
- "eslint-config-backpacker-react-ts": "^0.1.0",
37
+ "eslint-config-backpacker-react-ts": "^0.3.0",
37
38
  "husky": "^7.0.2",
38
39
  "import-sort-style-module": "^6.0.0",
39
40
  "jest": "^27.1.1",
40
- "lint-staged": "^11.1.2",
41
- "metro-react-native-babel-preset": "^0.66.2",
41
+ "lint-staged": "^12.1.2",
42
+ "metro-react-native-babel-preset": "^0.67.0",
42
43
  "prettier": "^2.4.1",
43
44
  "prettier-plugin-import-sort": "^0.0.7",
44
45
  "react-test-renderer": "^17.0.2",
@@ -46,8 +47,8 @@
46
47
  "yalc": "^1.0.0-pre.53"
47
48
  },
48
49
  "peerDependencies": {
49
- "react": ">=17.0.2",
50
- "react-native": ">=0.64.2"
50
+ "react": "*",
51
+ "react-native": "*"
51
52
  },
52
53
  "importSort": {
53
54
  ".js, .jsx, .ts, .tsx": {