react-native-toast-message 2.0.2 → 2.1.1
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 +22 -0
- package/README.md +6 -0
- package/lib/src/Toast.js +68 -6
- 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/types/index.d.ts +12 -8
- package/lib/src/useToast.js +11 -6
- package/package.json +10 -7
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,28 @@ Headers are one of:
|
|
|
9
9
|
|
|
10
10
|
- `Added`, `Changed`, `Removed`, `Fixed` or `Breaking`.
|
|
11
11
|
|
|
12
|
+
## [2.1.1]
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- 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))
|
|
17
|
+
|
|
18
|
+
## [2.1.0]
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- 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))
|
|
23
|
+
- 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))
|
|
24
|
+
|
|
25
|
+
Big thanks go to [jstheoriginal](https://github.com/jstheoriginal) for all the work on fixing the two issues above 🙌.
|
|
26
|
+
|
|
27
|
+
- Flexbox not working for setting Toast width or alignment ([3400f00](https://github.com/calintamas/react-native-toast-message/commit/3400f0074116f5acb37ca2eb696ea50b0c669ddc))
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `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)
|
|
32
|
+
- Peer deps no longer require a min version ([e91ed21](https://github.com/calintamas/react-native-toast-message/commit/e91ed21d277d7348b674834765147be752b6abfb))
|
|
33
|
+
|
|
12
34
|
## [2.0.2]
|
|
13
35
|
|
|
14
36
|
### Fixed
|
package/README.md
CHANGED
|
@@ -33,3 +33,9 @@ Animated toast message component for React Native.
|
|
|
33
33
|
## License
|
|
34
34
|
|
|
35
35
|
MIT
|
|
36
|
+
|
|
37
|
+
## Support
|
|
38
|
+
|
|
39
|
+
Not a requirement in any way, but if this package helped you (or your company) and you feel like supporting my future work:
|
|
40
|
+
|
|
41
|
+
<a href="https://buymeacoffee.com/calintamas"><img src="https://user-images.githubusercontent.com/9104454/143683074-69dc6a53-3e54-4a2c-8dcf-c1e27448a2f4.png" alt="Buy me a coffee" width="150px" /></a>
|
package/lib/src/Toast.js
CHANGED
|
@@ -7,21 +7,83 @@ 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
|
+
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
|
+
}
|
|
17
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={
|
|
56
|
+
<ToastRoot ref={setRef} {...props}/>
|
|
20
57
|
</LoggerProvider>);
|
|
21
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the active Toast instance `ref`, by priority.
|
|
61
|
+
* The "highest" Toast in the `View` hierarchy has the highest priority.
|
|
62
|
+
*
|
|
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
|
+
*
|
|
67
|
+
* ```js
|
|
68
|
+
* <>
|
|
69
|
+
* <Toast />
|
|
70
|
+
* <Modal>
|
|
71
|
+
* <Toast />
|
|
72
|
+
* </Modal>
|
|
73
|
+
* </>
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function getRef() {
|
|
77
|
+
const reversePriority = [...refs].reverse();
|
|
78
|
+
const activeRef = reversePriority.find((ref) => ref?.current !== null);
|
|
79
|
+
if (!activeRef) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return activeRef.current;
|
|
83
|
+
}
|
|
22
84
|
Toast.show = (params) => {
|
|
23
|
-
|
|
85
|
+
getRef()?.show(params);
|
|
24
86
|
};
|
|
25
87
|
Toast.hide = (params) => {
|
|
26
|
-
|
|
88
|
+
getRef()?.hide(params);
|
|
27
89
|
};
|
|
@@ -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
|
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
|
};
|
|
@@ -101,6 +101,10 @@ export declare type ToastConfigParams<Props> = {
|
|
|
101
101
|
export declare type ToastConfig = {
|
|
102
102
|
[key: string]: (params: ToastConfigParams<any>) => React.ReactNode;
|
|
103
103
|
};
|
|
104
|
+
export declare type ToastRef = {
|
|
105
|
+
show: (params: ToastShowParams) => void;
|
|
106
|
+
hide: (params: ToastHideParams) => void;
|
|
107
|
+
};
|
|
104
108
|
/**
|
|
105
109
|
* `props` that can be set on the Toast instance.
|
|
106
110
|
* They act as defaults for all Toasts that are shown.
|
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.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Toast message component for React Native",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"prettier": "./node_modules/.bin/prettier --write",
|
|
22
22
|
"lint": "./node_modules/.bin/eslint --fix",
|
|
23
23
|
"lint-staged": "./node_modules/.bin/lint-staged",
|
|
24
|
-
"test": "./node_modules/.bin/jest"
|
|
24
|
+
"test": "./node_modules/.bin/jest",
|
|
25
|
+
"yalc:push": "yarn build && yalc publish --push",
|
|
26
|
+
"quality": "yarn lint && tsc --noEmit"
|
|
25
27
|
},
|
|
26
28
|
"author": "Calin Tamas <calintamas2@gmail.com>",
|
|
27
29
|
"license": "MIT",
|
|
@@ -32,20 +34,21 @@
|
|
|
32
34
|
"@testing-library/react-native": "^8.0.0",
|
|
33
35
|
"@types/jest": "^27.0.1",
|
|
34
36
|
"@types/react-native": "^0.66.2",
|
|
35
|
-
"eslint-config-backpacker-react-ts": "^0.
|
|
37
|
+
"eslint-config-backpacker-react-ts": "^0.2.0",
|
|
36
38
|
"husky": "^7.0.2",
|
|
37
39
|
"import-sort-style-module": "^6.0.0",
|
|
38
40
|
"jest": "^27.1.1",
|
|
39
|
-
"lint-staged": "^
|
|
41
|
+
"lint-staged": "^12.1.2",
|
|
40
42
|
"metro-react-native-babel-preset": "^0.66.2",
|
|
41
43
|
"prettier": "^2.4.1",
|
|
42
44
|
"prettier-plugin-import-sort": "^0.0.7",
|
|
43
45
|
"react-test-renderer": "^17.0.2",
|
|
44
|
-
"typescript": "^4.4.3"
|
|
46
|
+
"typescript": "^4.4.3",
|
|
47
|
+
"yalc": "^1.0.0-pre.53"
|
|
45
48
|
},
|
|
46
49
|
"peerDependencies": {
|
|
47
|
-
"react": "
|
|
48
|
-
"react-native": "
|
|
50
|
+
"react": "*",
|
|
51
|
+
"react-native": "*"
|
|
49
52
|
},
|
|
50
53
|
"importSort": {
|
|
51
54
|
".js, .jsx, .ts, .tsx": {
|