react-native-toast-message 2.2.0-beta.2 → 3.0.0-beta.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/README.md +3 -3
- package/ios/SafeAreaModule.h +5 -0
- package/ios/SafeAreaModule.mm +27 -0
- package/lib/src/Toast.d.ts +1 -1
- package/lib/src/Toast.js +3 -5
- package/lib/src/ToastUI.js +6 -4
- package/lib/src/components/AnimatedContainer.d.ts +2 -1
- package/lib/src/components/AnimatedContainer.js +6 -5
- package/lib/src/contexts/index.d.ts +1 -4
- package/lib/src/contexts/index.js +1 -2
- package/lib/src/hooks/index.d.ts +1 -0
- package/lib/src/hooks/index.js +1 -0
- package/lib/src/hooks/usePanResponder.d.ts +2 -1
- package/lib/src/hooks/usePanResponder.js +9 -3
- package/lib/src/hooks/useSafeArea.d.ts +10 -0
- package/lib/src/hooks/useSafeArea.js +25 -0
- package/lib/src/hooks/useSlideAnimation.d.ts +2 -6
- package/lib/src/hooks/useSlideAnimation.js +10 -35
- package/lib/src/types/index.d.ts +18 -12
- package/lib/src/useToast.js +11 -2
- package/lib/src/utils/array.d.ts +2 -0
- package/lib/src/utils/array.js +4 -0
- package/lib/src/utils/dimension.d.ts +2 -0
- package/lib/src/utils/dimension.js +3 -0
- package/package.json +12 -20
- package/react-native-toast-message.podspec +41 -0
- package/lib/src/contexts/EnvironmentContext.d.ts +0 -8
- package/lib/src/contexts/EnvironmentContext.js +0 -22
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-native-toast-message)
|
|
4
4
|
[](https://www.npmjs.com/package/react-native-toast-message)
|
|
5
|
-
[](https://coveralls.io/github/calintamas/react-native-toast-message?branch=
|
|
5
|
+
[](https://github.com/calintamas/react-native-toast-message/actions/workflows/publish.yml?query=workflow%3Abuild)
|
|
6
|
+
[](https://coveralls.io/github/calintamas/react-native-toast-message?branch=main)
|
|
7
7
|
[](https://github.com/prettier/prettier)
|
|
8
8
|
|
|
9
9
|
Animated toast message component for React Native.
|
|
@@ -20,7 +20,7 @@ Animated toast message component for React Native.
|
|
|
20
20
|
|
|
21
21
|
## Documentation
|
|
22
22
|
|
|
23
|
-
> This is the documentation for `react-native-toast-message@v2`, which has a similar API to v1, but contains a few important changes. [Read the complete changelog](
|
|
23
|
+
> This is the documentation for `react-native-toast-message@v2`, which has a similar API to v1, but contains a few important changes. [Read the complete changelog](https://github.com/calintamas/react-native-toast-message/releases/tag/v2.0.0).
|
|
24
24
|
|
|
25
25
|
- [Quick start](./docs/quick-start.md)
|
|
26
26
|
- [API](./docs/api.md)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
@interface SafeAreaModule : NSObject <RCTBridgeModule>
|
|
4
|
+
@end
|
|
5
|
+
|
|
6
|
+
@implementation SafeAreaModule
|
|
7
|
+
RCT_EXPORT_MODULE();
|
|
8
|
+
|
|
9
|
+
RCT_EXPORT_METHOD(getSafeAreaInsets:(RCTResponseSenderBlock)callback) {
|
|
10
|
+
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
|
|
11
|
+
UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
|
|
12
|
+
|
|
13
|
+
if (@available(iOS 11.0, *)) {
|
|
14
|
+
safeAreaInsets = rootViewController.view.safeAreaInsets;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
NSDictionary *result = @{
|
|
18
|
+
@"top": @(safeAreaInsets.top),
|
|
19
|
+
@"bottom": @(safeAreaInsets.bottom),
|
|
20
|
+
@"left": @(safeAreaInsets.left),
|
|
21
|
+
@"right": @(safeAreaInsets.right)
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
callback(@[[NSNull null], result]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@end
|
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { LoggerProvider } from './contexts';
|
|
3
3
|
import { ToastUI } from './ToastUI';
|
|
4
4
|
import { useToast } from './useToast';
|
|
5
5
|
const ToastRoot = React.forwardRef((props, ref) => {
|
|
@@ -33,7 +33,7 @@ function addNewRef(newRef) {
|
|
|
33
33
|
function removeOldRef(oldRef) {
|
|
34
34
|
refs = refs.filter((r) => r.current !== oldRef);
|
|
35
35
|
}
|
|
36
|
-
export function Toast(
|
|
36
|
+
export function Toast(props) {
|
|
37
37
|
const toastRef = React.useRef(null);
|
|
38
38
|
/*
|
|
39
39
|
This must use `useCallback` to ensure the ref doesn't get set to null and then a new ref every render.
|
|
@@ -53,9 +53,7 @@ export function Toast({ useNativeDriver, ...props }) {
|
|
|
53
53
|
}
|
|
54
54
|
}, []);
|
|
55
55
|
return (<LoggerProvider enableLogs={false}>
|
|
56
|
-
<
|
|
57
|
-
<ToastRoot ref={setRef} {...props}/>
|
|
58
|
-
</EnvironmentProvider>
|
|
56
|
+
<ToastRoot ref={setRef} {...props}/>
|
|
59
57
|
</LoggerProvider>);
|
|
60
58
|
}
|
|
61
59
|
/**
|
package/lib/src/ToastUI.js
CHANGED
|
@@ -10,14 +10,14 @@ const defaultToastConfig = {
|
|
|
10
10
|
};
|
|
11
11
|
function renderComponent({ data, options, config, isVisible, show, hide }) {
|
|
12
12
|
const { text1, text2 } = data;
|
|
13
|
-
const { type, onPress, position, props } = options;
|
|
13
|
+
const { type, onPress, text1Style, text2Style, position, props } = options;
|
|
14
14
|
const toastConfig = {
|
|
15
15
|
...defaultToastConfig,
|
|
16
16
|
...config
|
|
17
17
|
};
|
|
18
18
|
const ToastComponent = toastConfig[type];
|
|
19
19
|
if (!ToastComponent) {
|
|
20
|
-
throw new Error(`Toast type: '${type}' does not exist. You can add it via the 'config' prop on the Toast instance. Learn more: https://github.com/calintamas/react-native-toast-message/blob/
|
|
20
|
+
throw new Error(`Toast type: '${type}' does not exist. You can add it via the 'config' prop on the Toast instance. Learn more: https://github.com/calintamas/react-native-toast-message/blob/master/README.md`);
|
|
21
21
|
}
|
|
22
22
|
return ToastComponent({
|
|
23
23
|
position,
|
|
@@ -25,6 +25,8 @@ function renderComponent({ data, options, config, isVisible, show, hide }) {
|
|
|
25
25
|
isVisible,
|
|
26
26
|
text1,
|
|
27
27
|
text2,
|
|
28
|
+
text1Style,
|
|
29
|
+
text2Style,
|
|
28
30
|
show,
|
|
29
31
|
hide,
|
|
30
32
|
onPress,
|
|
@@ -33,8 +35,8 @@ function renderComponent({ data, options, config, isVisible, show, hide }) {
|
|
|
33
35
|
}
|
|
34
36
|
export function ToastUI(props) {
|
|
35
37
|
const { isVisible, options, hide } = props;
|
|
36
|
-
const { position, topOffset, bottomOffset, keyboardOffset } = options;
|
|
37
|
-
return (<AnimatedContainer isVisible={isVisible} position={position} topOffset={topOffset} bottomOffset={bottomOffset} keyboardOffset={keyboardOffset} onHide={hide}>
|
|
38
|
+
const { position, topOffset, bottomOffset, keyboardOffset, swipeable } = options;
|
|
39
|
+
return (<AnimatedContainer isVisible={isVisible} position={position} topOffset={topOffset} bottomOffset={bottomOffset} keyboardOffset={keyboardOffset} swipeable={swipeable} onHide={hide}>
|
|
38
40
|
{renderComponent(props)}
|
|
39
41
|
</AnimatedContainer>);
|
|
40
42
|
}
|
|
@@ -6,6 +6,7 @@ export declare type AnimatedContainerProps = {
|
|
|
6
6
|
isVisible: boolean;
|
|
7
7
|
position: ToastPosition;
|
|
8
8
|
topOffset: number;
|
|
9
|
+
swipeable: boolean;
|
|
9
10
|
bottomOffset: number;
|
|
10
11
|
keyboardOffset: number;
|
|
11
12
|
onHide: () => void;
|
|
@@ -19,4 +20,4 @@ export declare type AnimatedContainerProps = {
|
|
|
19
20
|
*/
|
|
20
21
|
export declare function dampingFor(gesture: PanResponderGestureState, position: ToastPosition): number;
|
|
21
22
|
export declare function animatedValueFor(gesture: PanResponderGestureState, position: ToastPosition, damping: number): number;
|
|
22
|
-
export declare function AnimatedContainer({ children, isVisible, position, topOffset, bottomOffset, keyboardOffset, onHide, onRestorePosition }: AnimatedContainerProps): JSX.Element;
|
|
23
|
+
export declare function AnimatedContainer({ children, isVisible, position, topOffset, bottomOffset, keyboardOffset, onHide, onRestorePosition, swipeable }: AnimatedContainerProps): JSX.Element;
|
|
@@ -37,10 +37,10 @@ export function animatedValueFor(gesture, position, damping) {
|
|
|
37
37
|
throw new Error(`Toast position: ${position} not implemented`);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
export function AnimatedContainer({ children, isVisible, position, topOffset, bottomOffset, keyboardOffset, onHide, onRestorePosition = noop }) {
|
|
40
|
+
export function AnimatedContainer({ children, isVisible, position, topOffset, bottomOffset, keyboardOffset, onHide, onRestorePosition = noop, swipeable }) {
|
|
41
41
|
const { log } = useLogger();
|
|
42
42
|
const { computeViewDimensions, height } = useViewDimensions();
|
|
43
|
-
const { animatedValue, animate,
|
|
43
|
+
const { animatedValue, animate, animationStyles } = useSlideAnimation({
|
|
44
44
|
position,
|
|
45
45
|
height,
|
|
46
46
|
topOffset,
|
|
@@ -66,16 +66,17 @@ export function AnimatedContainer({ children, isVisible, position, topOffset, bo
|
|
|
66
66
|
animatedValue,
|
|
67
67
|
computeNewAnimatedValueForGesture,
|
|
68
68
|
onDismiss,
|
|
69
|
-
onRestore
|
|
69
|
+
onRestore,
|
|
70
|
+
disable: !swipeable
|
|
70
71
|
});
|
|
71
72
|
React.useLayoutEffect(() => {
|
|
72
73
|
const newAnimationValue = isVisible ? 1 : 0;
|
|
73
74
|
animate(newAnimationValue);
|
|
74
75
|
}, [animate, isVisible]);
|
|
75
|
-
return (<Animated.View testID={getTestId('AnimatedContainer')} onLayout={computeViewDimensions} style={[styles.base, styles[position],
|
|
76
|
+
return (<Animated.View testID={getTestId('AnimatedContainer')} onLayout={computeViewDimensions} style={[styles.base, styles[position], animationStyles]}
|
|
76
77
|
// This container View is never the target of touch events but its subviews can be.
|
|
77
78
|
// By doing this, tapping buttons behind the Toast is allowed
|
|
78
|
-
pointerEvents='box-none' {...panResponder.panHandlers}>
|
|
79
|
+
pointerEvents={isVisible ? 'box-none' : 'none'} {...panResponder.panHandlers}>
|
|
79
80
|
{children}
|
|
80
81
|
</Animated.View>);
|
|
81
82
|
}
|
|
@@ -1,4 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export type { LoggerContextType } from './LoggerContext';
|
|
3
|
-
export { EnvironmentProvider, useEnvironmentContext } from './EnvironmentContext';
|
|
4
|
-
export type { EnvironmentContextType } from './EnvironmentContext';
|
|
1
|
+
export * from './LoggerContext';
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { EnvironmentProvider, useEnvironmentContext } from './EnvironmentContext';
|
|
1
|
+
export * from './LoggerContext';
|
package/lib/src/hooks/index.d.ts
CHANGED
package/lib/src/hooks/index.js
CHANGED
|
@@ -7,8 +7,9 @@ export declare type UsePanResponderParams = {
|
|
|
7
7
|
computeNewAnimatedValueForGesture: (gesture: PanResponderGestureState) => number;
|
|
8
8
|
onDismiss: () => void;
|
|
9
9
|
onRestore: () => void;
|
|
10
|
+
disable?: boolean;
|
|
10
11
|
};
|
|
11
|
-
export declare function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore }: UsePanResponderParams): {
|
|
12
|
+
export declare function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, disable }: UsePanResponderParams): {
|
|
12
13
|
panResponder: import("react-native").PanResponderInstance;
|
|
13
14
|
onMove: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
14
15
|
onRelease: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
@@ -13,12 +13,18 @@ export function shouldDismissView(newAnimatedValue, gesture) {
|
|
|
13
13
|
return (newAnimatedValue <= dismissThreshold ||
|
|
14
14
|
(Math.abs(vy) >= dismissThreshold && dy < 0));
|
|
15
15
|
}
|
|
16
|
-
export function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore }) {
|
|
16
|
+
export function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore, disable }) {
|
|
17
17
|
const onMove = React.useCallback((_event, gesture) => {
|
|
18
|
+
if (disable) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
18
21
|
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
19
22
|
animatedValue.current?.setValue(newAnimatedValue);
|
|
20
|
-
}, [animatedValue, computeNewAnimatedValueForGesture]);
|
|
23
|
+
}, [animatedValue, computeNewAnimatedValueForGesture, disable]);
|
|
21
24
|
const onRelease = React.useCallback((_event, gesture) => {
|
|
25
|
+
if (disable) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
22
28
|
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
23
29
|
if (shouldDismissView(newAnimatedValue, gesture)) {
|
|
24
30
|
onDismiss();
|
|
@@ -26,7 +32,7 @@ export function usePanResponder({ animatedValue, computeNewAnimatedValueForGestu
|
|
|
26
32
|
else {
|
|
27
33
|
onRestore();
|
|
28
34
|
}
|
|
29
|
-
}, [computeNewAnimatedValueForGesture, onDismiss, onRestore]);
|
|
35
|
+
}, [computeNewAnimatedValueForGesture, onDismiss, onRestore, disable]);
|
|
30
36
|
const panResponder = React.useMemo(() => PanResponder.create({
|
|
31
37
|
onMoveShouldSetPanResponder: shouldSetPanResponder,
|
|
32
38
|
onMoveShouldSetPanResponderCapture: shouldSetPanResponder,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { NativeModules, StatusBar } from 'react-native';
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { isIOS } from "../utils/platform";
|
|
4
|
+
import { SCREEN_HEIGHT, WINDOW_HEIGHT } from "../utils/dimension";
|
|
5
|
+
export const useSafeArea = () => {
|
|
6
|
+
const [safeAreaInsets, setSafeAreaInsets] = useState(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (isIOS()) {
|
|
9
|
+
NativeModules?.SafeAreaModule?.getSafeAreaInsets((error, result) => {
|
|
10
|
+
if (error) {
|
|
11
|
+
console.error(error);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
setSafeAreaInsets(result);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const statusBarHeight = StatusBar.currentHeight ?? 0;
|
|
20
|
+
const bottomInset = SCREEN_HEIGHT - WINDOW_HEIGHT - statusBarHeight;
|
|
21
|
+
setSafeAreaInsets({ top: statusBarHeight, bottom: bottomInset, left: 0, right: 0 });
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
24
|
+
return { safeAreaInsets };
|
|
25
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Animated } from 'react-native';
|
|
3
3
|
import { ToastPosition } from '../types';
|
|
4
|
-
|
|
4
|
+
declare type UseSlideAnimationParams = {
|
|
5
5
|
position: ToastPosition;
|
|
6
6
|
height: number;
|
|
7
7
|
topOffset: number;
|
|
@@ -14,11 +14,6 @@ export declare function translateYOutputRangeFor({ position, height, topOffset,
|
|
|
14
14
|
export declare function useSlideAnimation({ position, height, topOffset, bottomOffset, keyboardOffset }: UseSlideAnimationParams): {
|
|
15
15
|
animatedValue: React.MutableRefObject<Animated.Value>;
|
|
16
16
|
animate: (toValue: number) => void;
|
|
17
|
-
defaultStyles: {
|
|
18
|
-
transform: {
|
|
19
|
-
translateY: number;
|
|
20
|
-
}[];
|
|
21
|
-
};
|
|
22
17
|
animationStyles: {
|
|
23
18
|
opacity: Animated.AnimatedInterpolation;
|
|
24
19
|
transform: {
|
|
@@ -26,3 +21,4 @@ export declare function useSlideAnimation({ position, height, topOffset, bottomO
|
|
|
26
21
|
}[];
|
|
27
22
|
};
|
|
28
23
|
};
|
|
24
|
+
export {};
|
|
@@ -1,42 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Animated } from 'react-native';
|
|
3
|
-
import {
|
|
2
|
+
import { Animated, Platform } from 'react-native';
|
|
3
|
+
import { additiveInverseArray } from '../utils/array';
|
|
4
4
|
import { useKeyboard } from './useKeyboard';
|
|
5
|
-
const startPointFor = (position, height) => {
|
|
6
|
-
const value = height * 2;
|
|
7
|
-
if (position === 'top') {
|
|
8
|
-
return -value;
|
|
9
|
-
}
|
|
10
|
-
return value;
|
|
11
|
-
};
|
|
12
5
|
export function translateYOutputRangeFor({ position, height, topOffset, bottomOffset, keyboardHeight, keyboardOffset }) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return range;
|
|
19
|
-
}
|
|
20
|
-
case 'top': {
|
|
21
|
-
const keyboardAwareOffset = 0;
|
|
22
|
-
const range = [startPoint, Math.max(topOffset, keyboardAwareOffset)];
|
|
23
|
-
return range;
|
|
24
|
-
}
|
|
25
|
-
default:
|
|
26
|
-
throw new Error(`Position '${position}' not supported`);
|
|
27
|
-
}
|
|
6
|
+
const offset = position === 'bottom' ? bottomOffset : topOffset;
|
|
7
|
+
const keyboardAwareOffset = position === 'bottom' ? keyboardHeight + keyboardOffset : 0;
|
|
8
|
+
const range = [-(height * 2), Math.max(offset, keyboardAwareOffset)];
|
|
9
|
+
const outputRange = position === 'bottom' ? additiveInverseArray(range) : range;
|
|
10
|
+
return outputRange;
|
|
28
11
|
}
|
|
12
|
+
const useNativeDriver = Platform.select({ native: true, default: false });
|
|
29
13
|
export function useSlideAnimation({ position, height, topOffset, bottomOffset, keyboardOffset }) {
|
|
30
|
-
const { useNativeDriver } = useEnvironmentContext();
|
|
31
14
|
const animatedValue = React.useRef(new Animated.Value(0));
|
|
32
15
|
const { keyboardHeight } = useKeyboard();
|
|
33
16
|
const animate = React.useCallback((toValue) => {
|
|
34
17
|
Animated.spring(animatedValue.current, {
|
|
35
18
|
toValue,
|
|
36
|
-
useNativeDriver
|
|
19
|
+
useNativeDriver,
|
|
37
20
|
friction: 8
|
|
38
21
|
}).start();
|
|
39
|
-
}, [
|
|
22
|
+
}, []);
|
|
40
23
|
const translateY = React.useMemo(() => animatedValue.current.interpolate({
|
|
41
24
|
inputRange: [0, 1],
|
|
42
25
|
outputRange: translateYOutputRangeFor({
|
|
@@ -52,17 +35,9 @@ export function useSlideAnimation({ position, height, topOffset, bottomOffset, k
|
|
|
52
35
|
inputRange: [0, 0.7, 1],
|
|
53
36
|
outputRange: [0, 1, 1]
|
|
54
37
|
});
|
|
55
|
-
const defaultStyles = {
|
|
56
|
-
transform: [
|
|
57
|
-
{
|
|
58
|
-
translateY: startPointFor(position, height)
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
|
-
};
|
|
62
38
|
return {
|
|
63
39
|
animatedValue,
|
|
64
40
|
animate,
|
|
65
|
-
defaultStyles,
|
|
66
41
|
animationStyles: {
|
|
67
42
|
opacity,
|
|
68
43
|
transform: [
|
package/lib/src/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { StyleProp, TextProps, TextStyle, TouchableOpacityProps, ViewProps, ViewStyle } from 'react-native';
|
|
3
3
|
export declare type ReactChildren = React.ReactNode;
|
|
4
|
-
export declare type ToastType = string;
|
|
4
|
+
export declare type ToastType = 'success' | 'error' | 'info' | (string & {});
|
|
5
5
|
export declare type ToastPosition = 'top' | 'bottom';
|
|
6
6
|
export declare type ToastOptions = {
|
|
7
7
|
/**
|
|
@@ -9,23 +9,36 @@ export declare type ToastOptions = {
|
|
|
9
9
|
* Default value: `success`
|
|
10
10
|
*/
|
|
11
11
|
type?: ToastType;
|
|
12
|
+
/**
|
|
13
|
+
* Style for the header text in the Toast (text1).
|
|
14
|
+
*/
|
|
15
|
+
text1Style?: StyleProp<TextStyle>;
|
|
16
|
+
/**
|
|
17
|
+
* Style for the inner message text in the Toast (text2).
|
|
18
|
+
*/
|
|
19
|
+
text2Style?: StyleProp<TextStyle>;
|
|
12
20
|
/**
|
|
13
21
|
* Toast position.
|
|
14
22
|
* Default value: `top`
|
|
15
23
|
*/
|
|
16
24
|
position?: ToastPosition;
|
|
17
25
|
/**
|
|
18
|
-
* When `true`, the visible Toast automatically hides after a certain number of
|
|
26
|
+
* When `true`, the visible Toast automatically hides after a certain number of milliseconds,
|
|
19
27
|
* specified by the `visibilityTime` prop.
|
|
20
28
|
* Default value: `true`
|
|
21
29
|
*/
|
|
22
30
|
autoHide?: boolean;
|
|
23
31
|
/**
|
|
24
|
-
* Number of
|
|
32
|
+
* Number of milliseconds after which Toast automatically hides.
|
|
25
33
|
* Has effect only in conjunction with `autoHide` prop set to `true`.
|
|
26
34
|
* Default value: `4000`
|
|
27
35
|
*/
|
|
28
36
|
visibilityTime?: number;
|
|
37
|
+
/**
|
|
38
|
+
* When `true`, the Toast can be dismissed by a swipe gesture, specified by the `swipeable` prop.
|
|
39
|
+
* Default value: `true`
|
|
40
|
+
*/
|
|
41
|
+
swipeable?: boolean;
|
|
29
42
|
/**
|
|
30
43
|
* Offset from the top of the screen (in px).
|
|
31
44
|
* Has effect only when `position` is `top`
|
|
@@ -93,6 +106,8 @@ export declare type ToastConfigParams<Props> = {
|
|
|
93
106
|
isVisible: boolean;
|
|
94
107
|
text1?: string;
|
|
95
108
|
text2?: string;
|
|
109
|
+
text1Style?: StyleProp<TextStyle>;
|
|
110
|
+
text2Style?: StyleProp<TextStyle>;
|
|
96
111
|
show: (params: ToastShowParams) => void;
|
|
97
112
|
hide: (params: ToastHideParams) => void;
|
|
98
113
|
onPress: () => void;
|
|
@@ -154,15 +169,6 @@ export declare type ToastProps = {
|
|
|
154
169
|
* Default value: `10`
|
|
155
170
|
*/
|
|
156
171
|
keyboardOffset?: number;
|
|
157
|
-
/**
|
|
158
|
-
* Enable / disable native driver for the slide animation.
|
|
159
|
-
*
|
|
160
|
-
* Default:
|
|
161
|
-
* - `true` on iOS
|
|
162
|
-
* - `false` on Android (fixes [issue #300](https://github.com/calintamas/react-native-toast-message/issues/300))
|
|
163
|
-
* - `false` on Web (fixes [issue #311](https://github.com/calintamas/react-native-toast-message/issues/311))
|
|
164
|
-
*/
|
|
165
|
-
useNativeDriver?: boolean;
|
|
166
172
|
/**
|
|
167
173
|
* Called when any Toast is shown
|
|
168
174
|
*/
|
package/lib/src/useToast.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useLogger } from './contexts';
|
|
3
|
-
import { useTimeout } from './hooks';
|
|
3
|
+
import { useSafeArea, useTimeout } from './hooks';
|
|
4
4
|
import { noop } from './utils/func';
|
|
5
5
|
import { mergeIfDefined } from './utils/obj';
|
|
6
6
|
export const DEFAULT_DATA = {
|
|
@@ -9,8 +9,11 @@ export const DEFAULT_DATA = {
|
|
|
9
9
|
};
|
|
10
10
|
export const DEFAULT_OPTIONS = {
|
|
11
11
|
type: 'success',
|
|
12
|
+
text1Style: null,
|
|
13
|
+
text2Style: null,
|
|
12
14
|
position: 'top',
|
|
13
15
|
autoHide: true,
|
|
16
|
+
swipeable: true,
|
|
14
17
|
visibilityTime: 4000,
|
|
15
18
|
topOffset: 40,
|
|
16
19
|
bottomOffset: 40,
|
|
@@ -24,6 +27,7 @@ export function useToast({ defaultOptions }) {
|
|
|
24
27
|
const { log } = useLogger();
|
|
25
28
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
26
29
|
const [data, setData] = React.useState(DEFAULT_DATA);
|
|
30
|
+
const { safeAreaInsets } = useSafeArea();
|
|
27
31
|
const initialOptions = mergeIfDefined(DEFAULT_OPTIONS, defaultOptions);
|
|
28
32
|
const [options, setOptions] = React.useState(initialOptions);
|
|
29
33
|
const onAutoHide = React.useCallback(() => {
|
|
@@ -40,13 +44,17 @@ export function useToast({ defaultOptions }) {
|
|
|
40
44
|
}, [clearTimer, log, options]);
|
|
41
45
|
const show = React.useCallback((params) => {
|
|
42
46
|
log(`Showing with params: ${JSON.stringify(params)}`);
|
|
43
|
-
const
|
|
47
|
+
const topOffset = safeAreaInsets && safeAreaInsets.top > 0 ? safeAreaInsets.top : initialOptions.topOffset;
|
|
48
|
+
const bottomOffset = safeAreaInsets && safeAreaInsets.bottom > 0 ? safeAreaInsets.bottom : initialOptions.bottomOffset;
|
|
49
|
+
const { text1 = DEFAULT_DATA.text1, text2 = DEFAULT_DATA.text2, type = initialOptions.type, text1Style = initialOptions.text1Style, text2Style = initialOptions.text2Style, position = initialOptions.position, autoHide = initialOptions.autoHide, visibilityTime = initialOptions.visibilityTime, keyboardOffset = initialOptions.keyboardOffset, onShow = initialOptions.onShow, onHide = initialOptions.onHide, onPress = initialOptions.onPress, swipeable = initialOptions.swipeable, props = initialOptions.props } = params;
|
|
44
50
|
setData({
|
|
45
51
|
text1,
|
|
46
52
|
text2
|
|
47
53
|
});
|
|
48
54
|
setOptions(mergeIfDefined(initialOptions, {
|
|
49
55
|
type,
|
|
56
|
+
text1Style,
|
|
57
|
+
text2Style,
|
|
50
58
|
position,
|
|
51
59
|
autoHide,
|
|
52
60
|
visibilityTime,
|
|
@@ -56,6 +64,7 @@ export function useToast({ defaultOptions }) {
|
|
|
56
64
|
onShow,
|
|
57
65
|
onHide,
|
|
58
66
|
onPress,
|
|
67
|
+
swipeable,
|
|
59
68
|
props
|
|
60
69
|
}));
|
|
61
70
|
// TODO: validate input
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-toast-message",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-beta.1",
|
|
4
4
|
"description": "Toast message component for React Native",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
|
-
"/lib"
|
|
8
|
+
"/lib",
|
|
9
|
+
"ios",
|
|
10
|
+
"*.podspec"
|
|
9
11
|
],
|
|
10
12
|
"repository": {
|
|
11
13
|
"type": "git",
|
|
@@ -22,8 +24,8 @@
|
|
|
22
24
|
"lint": "./node_modules/.bin/eslint --fix",
|
|
23
25
|
"lint-staged": "./node_modules/.bin/lint-staged",
|
|
24
26
|
"test": "./node_modules/.bin/jest",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
+
"yalc:push": "yarn build && yalc publish --push",
|
|
28
|
+
"quality": "yarn lint && tsc --noEmit"
|
|
27
29
|
},
|
|
28
30
|
"author": "Calin Tamas <calintamas2@gmail.com>",
|
|
29
31
|
"license": "MIT",
|
|
@@ -32,22 +34,17 @@
|
|
|
32
34
|
"@testing-library/jest-native": "^4.0.4",
|
|
33
35
|
"@testing-library/react-hooks": "^8.0.0",
|
|
34
36
|
"@testing-library/react-native": "^9.0.0",
|
|
35
|
-
"@types/jest": "^
|
|
36
|
-
"@types/react-native": "^0.67.
|
|
37
|
-
"@types/react-test-renderer": "^18.0.0",
|
|
38
|
-
"babel-plugin-module-resolver": "^4.1.0",
|
|
37
|
+
"@types/jest": "^28.1.0",
|
|
38
|
+
"@types/react-native": "^0.67.3",
|
|
39
39
|
"eslint-config-backpacker-react-ts": "^0.3.0",
|
|
40
40
|
"husky": "^8.0.1",
|
|
41
|
-
"import-sort-style-module
|
|
42
|
-
"jest": "^
|
|
41
|
+
"import-sort-style-module": "^6.0.0",
|
|
42
|
+
"jest": "^28.1.0",
|
|
43
43
|
"lint-staged": "^13.0.0",
|
|
44
44
|
"metro-react-native-babel-preset": "^0.71.0",
|
|
45
45
|
"prettier": "^2.4.1",
|
|
46
46
|
"prettier-plugin-import-sort": "^0.0.7",
|
|
47
|
-
"react": "17.0.2",
|
|
48
|
-
"react-native": "0.68.2",
|
|
49
47
|
"react-test-renderer": "^17.0.2",
|
|
50
|
-
"tsc-watch": "^5.0.3",
|
|
51
48
|
"typescript": "^4.4.3",
|
|
52
49
|
"yalc": "^1.0.0-pre.53"
|
|
53
50
|
},
|
|
@@ -57,13 +54,8 @@
|
|
|
57
54
|
},
|
|
58
55
|
"importSort": {
|
|
59
56
|
".js, .jsx, .ts, .tsx": {
|
|
60
|
-
"style": "module
|
|
61
|
-
"parser": "typescript"
|
|
62
|
-
"options": {
|
|
63
|
-
"alias": [
|
|
64
|
-
"~"
|
|
65
|
-
]
|
|
66
|
-
}
|
|
57
|
+
"style": "module",
|
|
58
|
+
"parser": "typescript"
|
|
67
59
|
}
|
|
68
60
|
},
|
|
69
61
|
"lint-staged": {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
5
|
+
|
|
6
|
+
Pod::Spec.new do |s|
|
|
7
|
+
s.name = "react-native-toast-message"
|
|
8
|
+
s.version = package["version"]
|
|
9
|
+
s.summary = package["description"]
|
|
10
|
+
s.homepage = "https://github.com/calintamas/react-native-toast-message"
|
|
11
|
+
s.license = package["license"]
|
|
12
|
+
s.authors = package["author"]
|
|
13
|
+
|
|
14
|
+
s.platforms = { :ios => "9.0" }
|
|
15
|
+
s.source = { :git => "https://github.com/calintamas/react-native-toast-message.git", :tag => "#{s.version}" }
|
|
16
|
+
|
|
17
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
18
|
+
|
|
19
|
+
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
20
|
+
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
21
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
22
|
+
install_modules_dependencies(s)
|
|
23
|
+
else
|
|
24
|
+
s.dependency "React-Core"
|
|
25
|
+
|
|
26
|
+
# Don't install the dependencies when we run `pod install` in the old architecture.
|
|
27
|
+
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
|
28
|
+
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
|
29
|
+
s.pod_target_xcconfig = {
|
|
30
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
|
|
31
|
+
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
|
|
32
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
|
33
|
+
}
|
|
34
|
+
s.dependency "React-Codegen"
|
|
35
|
+
s.dependency "RCT-Folly"
|
|
36
|
+
s.dependency "RCTRequired"
|
|
37
|
+
s.dependency "RCTTypeSafety"
|
|
38
|
+
s.dependency "ReactCommon/turbomodule/core"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ToastProps } from '~/types';
|
|
3
|
-
export declare type EnvironmentContextType = {
|
|
4
|
-
useNativeDriver?: ToastProps['useNativeDriver'];
|
|
5
|
-
};
|
|
6
|
-
declare const EnvironmentProvider: React.FC<EnvironmentContextType>;
|
|
7
|
-
declare function useEnvironmentContext(): EnvironmentContextType;
|
|
8
|
-
export { EnvironmentProvider, useEnvironmentContext };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Platform } from 'react-native';
|
|
3
|
-
const EnvironmentContext = React.createContext(null);
|
|
4
|
-
const EnvironmentProvider = ({ children, useNativeDriver = Platform.select({
|
|
5
|
-
default: true,
|
|
6
|
-
web: false
|
|
7
|
-
}) }) => {
|
|
8
|
-
const value = {
|
|
9
|
-
useNativeDriver
|
|
10
|
-
};
|
|
11
|
-
return (<EnvironmentContext.Provider value={value}>
|
|
12
|
-
{children}
|
|
13
|
-
</EnvironmentContext.Provider>);
|
|
14
|
-
};
|
|
15
|
-
function useEnvironmentContext() {
|
|
16
|
-
const ctx = React.useContext(EnvironmentContext);
|
|
17
|
-
if (!ctx) {
|
|
18
|
-
throw new Error(`useEnvironment() must be called within EnvironmentProvider context`);
|
|
19
|
-
}
|
|
20
|
-
return ctx;
|
|
21
|
-
}
|
|
22
|
-
export { EnvironmentProvider, useEnvironmentContext };
|