react-native-toast-message 2.3.1 → 2.3.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/lib/src/Toast.js +4 -2
- package/lib/src/components/AnimatedContainer.js +15 -3
- package/lib/src/contexts/GestureContext.d.ts +12 -0
- package/lib/src/contexts/GestureContext.js +14 -0
- package/lib/src/contexts/index.d.ts +1 -0
- package/lib/src/contexts/index.js +1 -0
- package/lib/src/hooks/usePanResponder.d.ts +6 -2
- package/lib/src/hooks/usePanResponder.js +21 -11
- package/lib/src/useToast.js +11 -5
- package/package.json +1 -1
package/lib/src/Toast.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { LoggerProvider } from './contexts';
|
|
2
|
+
import { LoggerProvider, GestureProvider } from './contexts';
|
|
3
3
|
import { ToastUI } from './ToastUI';
|
|
4
4
|
import { useToast } from './useToast';
|
|
5
5
|
const ToastRoot = React.forwardRef((props, ref) => {
|
|
@@ -53,7 +53,9 @@ export function Toast(props) {
|
|
|
53
53
|
}
|
|
54
54
|
}, []);
|
|
55
55
|
return (<LoggerProvider enableLogs={false}>
|
|
56
|
-
<
|
|
56
|
+
<GestureProvider>
|
|
57
|
+
<ToastRoot ref={setRef} {...props}/>
|
|
58
|
+
</GestureProvider>
|
|
57
59
|
</LoggerProvider>);
|
|
58
60
|
}
|
|
59
61
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Animated, Dimensions } from 'react-native';
|
|
3
|
-
import { useLogger } from '../contexts';
|
|
3
|
+
import { useLogger, useGesture } from '../contexts';
|
|
4
4
|
import { usePanResponder, useSlideAnimation, useViewDimensions } from '../hooks';
|
|
5
5
|
import { noop } from '../utils/func';
|
|
6
6
|
import { bound } from '../utils/number';
|
|
@@ -39,6 +39,7 @@ export function animatedValueFor(gesture, position, damping) {
|
|
|
39
39
|
}
|
|
40
40
|
export function AnimatedContainer({ children, isVisible, position, topOffset, bottomOffset, keyboardOffset, avoidKeyboard, onHide, onRestorePosition = noop, swipeable }) {
|
|
41
41
|
const { log } = useLogger();
|
|
42
|
+
const { panning } = useGesture();
|
|
42
43
|
const { computeViewDimensions, height } = useViewDimensions();
|
|
43
44
|
const { animatedValue, animate, animationStyles } = useSlideAnimation({
|
|
44
45
|
position,
|
|
@@ -48,6 +49,15 @@ export function AnimatedContainer({ children, isVisible, position, topOffset, bo
|
|
|
48
49
|
keyboardOffset,
|
|
49
50
|
avoidKeyboard
|
|
50
51
|
});
|
|
52
|
+
const disable = !swipeable || !isVisible;
|
|
53
|
+
const onStart = React.useCallback(() => {
|
|
54
|
+
log('Swipe, pan start');
|
|
55
|
+
panning.current = true;
|
|
56
|
+
}, [log, panning]);
|
|
57
|
+
const onEnd = React.useCallback(() => {
|
|
58
|
+
log('Swipe, pan end');
|
|
59
|
+
panning.current = false;
|
|
60
|
+
}, [log, panning]);
|
|
51
61
|
const onDismiss = React.useCallback(() => {
|
|
52
62
|
log('Swipe, dismissing');
|
|
53
63
|
animate(0);
|
|
@@ -68,7 +78,9 @@ export function AnimatedContainer({ children, isVisible, position, topOffset, bo
|
|
|
68
78
|
computeNewAnimatedValueForGesture,
|
|
69
79
|
onDismiss,
|
|
70
80
|
onRestore,
|
|
71
|
-
|
|
81
|
+
onStart,
|
|
82
|
+
onEnd,
|
|
83
|
+
disable,
|
|
72
84
|
});
|
|
73
85
|
React.useLayoutEffect(() => {
|
|
74
86
|
const newAnimationValue = isVisible ? 1 : 0;
|
|
@@ -77,7 +89,7 @@ export function AnimatedContainer({ children, isVisible, position, topOffset, bo
|
|
|
77
89
|
return (<Animated.View testID={getTestId('AnimatedContainer')} onLayout={computeViewDimensions} style={[styles.base, styles[position], animationStyles]}
|
|
78
90
|
// This container View is never the target of touch events but its subviews can be.
|
|
79
91
|
// By doing this, tapping buttons behind the Toast is allowed
|
|
80
|
-
pointerEvents=
|
|
92
|
+
pointerEvents='box-none' {...panResponder.panHandlers}>
|
|
81
93
|
{children}
|
|
82
94
|
</Animated.View>);
|
|
83
95
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ReactChildren } from '../types';
|
|
3
|
+
export declare type GestureContextType = {
|
|
4
|
+
panning: React.MutableRefObject<boolean>;
|
|
5
|
+
};
|
|
6
|
+
export declare type GestureProviderProps = {
|
|
7
|
+
children: ReactChildren;
|
|
8
|
+
panning?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare function GestureProvider({ children, panning }: GestureProviderProps): JSX.Element;
|
|
11
|
+
declare function useGesture(): GestureContextType;
|
|
12
|
+
export { GestureProvider, useGesture };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
const GestureContext = React.createContext({
|
|
3
|
+
panning: { current: false }
|
|
4
|
+
});
|
|
5
|
+
function GestureProvider({ children, panning = false }) {
|
|
6
|
+
const panningRef = React.useRef(panning);
|
|
7
|
+
const value = { panning: panningRef };
|
|
8
|
+
return (<GestureContext.Provider value={value}>{children}</GestureContext.Provider>);
|
|
9
|
+
}
|
|
10
|
+
function useGesture() {
|
|
11
|
+
const ctx = React.useContext(GestureContext);
|
|
12
|
+
return ctx;
|
|
13
|
+
}
|
|
14
|
+
export { GestureProvider, useGesture };
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
2
|
import { Animated, GestureResponderEvent, PanResponderGestureState } from 'react-native';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function startShouldSetPanResponder(): boolean;
|
|
4
|
+
export declare function moveShouldSetPanResponder(_event: GestureResponderEvent, gesture: PanResponderGestureState): boolean;
|
|
4
5
|
export declare function shouldDismissView(newAnimatedValue: number, gesture: PanResponderGestureState): boolean;
|
|
5
6
|
export declare type UsePanResponderParams = {
|
|
6
7
|
animatedValue: RefObject<Animated.Value>;
|
|
7
8
|
computeNewAnimatedValueForGesture: (gesture: PanResponderGestureState) => number;
|
|
8
9
|
onDismiss: () => void;
|
|
9
10
|
onRestore: () => void;
|
|
11
|
+
onStart: () => void;
|
|
12
|
+
onEnd: () => void;
|
|
10
13
|
disable?: boolean;
|
|
11
14
|
};
|
|
12
|
-
export declare function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, disable }: UsePanResponderParams): {
|
|
15
|
+
export declare function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, onStart, onEnd, disable }: UsePanResponderParams): {
|
|
13
16
|
panResponder: import("react-native").PanResponderInstance;
|
|
17
|
+
onGrant: () => void;
|
|
14
18
|
onMove: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
15
19
|
onRelease: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
16
20
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { PanResponder } from 'react-native';
|
|
3
|
-
export function
|
|
3
|
+
export function startShouldSetPanResponder() {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
export function moveShouldSetPanResponder(_event, gesture) {
|
|
4
7
|
const { dx, dy } = gesture;
|
|
5
8
|
// Fixes onPress handler
|
|
6
9
|
// https://github.com/calintamas/react-native-toast-message/issues/113
|
|
@@ -13,35 +16,42 @@ export function shouldDismissView(newAnimatedValue, gesture) {
|
|
|
13
16
|
return (newAnimatedValue <= dismissThreshold ||
|
|
14
17
|
(Math.abs(vy) >= dismissThreshold && dy < 0));
|
|
15
18
|
}
|
|
16
|
-
export function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, disable }) {
|
|
19
|
+
export function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, onStart, onEnd, disable }) {
|
|
20
|
+
const onGrant = React.useCallback(() => {
|
|
21
|
+
if (disable)
|
|
22
|
+
return;
|
|
23
|
+
onStart();
|
|
24
|
+
}, [onStart, disable]);
|
|
17
25
|
const onMove = React.useCallback((_event, gesture) => {
|
|
18
|
-
if (disable)
|
|
26
|
+
if (disable)
|
|
19
27
|
return;
|
|
20
|
-
}
|
|
21
28
|
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
22
29
|
animatedValue.current?.setValue(newAnimatedValue);
|
|
23
30
|
}, [animatedValue, computeNewAnimatedValueForGesture, disable]);
|
|
24
31
|
const onRelease = React.useCallback((_event, gesture) => {
|
|
25
|
-
if (disable)
|
|
32
|
+
if (disable)
|
|
26
33
|
return;
|
|
27
|
-
}
|
|
28
34
|
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
35
|
+
onEnd();
|
|
29
36
|
if (shouldDismissView(newAnimatedValue, gesture)) {
|
|
30
37
|
onDismiss();
|
|
31
38
|
}
|
|
32
39
|
else {
|
|
33
40
|
onRestore();
|
|
34
41
|
}
|
|
35
|
-
}, [computeNewAnimatedValueForGesture, onDismiss, onRestore, disable]);
|
|
42
|
+
}, [computeNewAnimatedValueForGesture, onEnd, onDismiss, onRestore, disable]);
|
|
36
43
|
const panResponder = React.useMemo(() => PanResponder.create({
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
onStartShouldSetPanResponder: startShouldSetPanResponder,
|
|
45
|
+
onPanResponderGrant: onGrant,
|
|
46
|
+
onMoveShouldSetPanResponder: moveShouldSetPanResponder,
|
|
47
|
+
onMoveShouldSetPanResponderCapture: moveShouldSetPanResponder,
|
|
39
48
|
onPanResponderMove: onMove,
|
|
40
49
|
onPanResponderRelease: onRelease
|
|
41
|
-
}), [onMove, onRelease]);
|
|
50
|
+
}), [onMove, onRelease, onGrant]);
|
|
42
51
|
return {
|
|
43
52
|
panResponder,
|
|
53
|
+
onGrant,
|
|
44
54
|
onMove,
|
|
45
|
-
onRelease
|
|
55
|
+
onRelease,
|
|
46
56
|
};
|
|
47
57
|
}
|
package/lib/src/useToast.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { useLogger } from './contexts';
|
|
2
|
+
import { useLogger, useGesture } from './contexts';
|
|
3
3
|
import { useTimeout } from './hooks';
|
|
4
4
|
import { noop } from './utils/func';
|
|
5
5
|
import { mergeIfDefined } from './utils/obj';
|
|
@@ -26,15 +26,21 @@ export const DEFAULT_OPTIONS = {
|
|
|
26
26
|
};
|
|
27
27
|
export function useToast({ defaultOptions }) {
|
|
28
28
|
const { log } = useLogger();
|
|
29
|
+
const { panning } = useGesture();
|
|
29
30
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
30
31
|
const [data, setData] = React.useState(DEFAULT_DATA);
|
|
31
32
|
const initialOptions = mergeIfDefined(DEFAULT_OPTIONS, defaultOptions);
|
|
32
33
|
const [options, setOptions] = React.useState(initialOptions);
|
|
33
34
|
const onAutoHide = React.useCallback(() => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
if (panning.current) {
|
|
36
|
+
log('Auto hiding was blocked due to panning');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
log('Auto hiding');
|
|
40
|
+
setIsVisible(false);
|
|
41
|
+
options.onHide();
|
|
42
|
+
}
|
|
43
|
+
}, [log, options, panning]);
|
|
38
44
|
const { startTimer, clearTimer } = useTimeout(onAutoHide, options.visibilityTime);
|
|
39
45
|
const hide = React.useCallback(() => {
|
|
40
46
|
log('Hiding');
|