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 +28 -0
- package/lib/src/Toast.d.ts +1 -1
- package/lib/src/Toast.js +48 -13
- package/lib/src/components/AnimatedContainer.js +4 -1
- package/lib/src/components/AnimatedContainer.styles.d.ts +2 -1
- package/lib/src/components/AnimatedContainer.styles.js +3 -2
- package/lib/src/hooks/useSlideAnimation.js +3 -2
- package/lib/src/types/index.d.ts +8 -42
- package/lib/src/useToast.js +11 -6
- package/package.json +9 -8
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
|
package/lib/src/Toast.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { ToastProps, ToastShowParams } from './types';
|
|
3
|
-
export declare function Toast(
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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={
|
|
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
|
|
31
|
-
*
|
|
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
|
|
69
|
+
* <Toast />
|
|
35
70
|
* <Modal>
|
|
36
|
-
* <Toast
|
|
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]}
|
|
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
|
}
|
|
@@ -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
|
|
19
|
+
useNativeDriver,
|
|
19
20
|
friction: 8
|
|
20
21
|
}).start();
|
|
21
22
|
}, []);
|
package/lib/src/types/index.d.ts
CHANGED
|
@@ -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?:
|
|
81
|
-
text1Style?: TextStyle
|
|
79
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
80
|
+
contentContainerProps?: ViewProps;
|
|
81
|
+
text1Style?: StyleProp<TextStyle>;
|
|
82
82
|
text1NumberOfLines?: number;
|
|
83
|
-
text1Props?:
|
|
84
|
-
text2Style?: TextStyle
|
|
83
|
+
text1Props?: TextProps;
|
|
84
|
+
text2Style?: StyleProp<TextStyle>;
|
|
85
85
|
text2NumberOfLines?: number;
|
|
86
|
-
text2Props?:
|
|
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
|
*/
|
package/lib/src/useToast.js
CHANGED
|
@@ -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
|
|
69
|
-
|
|
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.
|
|
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": "^
|
|
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.
|
|
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": "^
|
|
41
|
-
"metro-react-native-babel-preset": "^0.
|
|
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": "
|
|
50
|
-
"react-native": "
|
|
50
|
+
"react": "*",
|
|
51
|
+
"react-native": "*"
|
|
51
52
|
},
|
|
52
53
|
"importSort": {
|
|
53
54
|
".js, .jsx, .ts, .tsx": {
|