react-native-toast-message 1.6.0 → 2.0.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 +86 -2
- package/README.md +19 -252
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/src/Toast.d.ts +7 -0
- package/lib/src/Toast.js +27 -0
- package/lib/src/ToastUI.d.ts +11 -0
- package/lib/src/ToastUI.js +40 -0
- package/lib/src/components/AnimatedContainer.d.ts +16 -0
- package/lib/src/components/AnimatedContainer.js +72 -0
- package/lib/src/components/AnimatedContainer.styles.d.ts +14 -0
- package/lib/src/components/AnimatedContainer.styles.js +15 -0
- package/lib/src/components/BaseToast.d.ts +3 -0
- package/lib/src/components/BaseToast.js +19 -0
- package/lib/src/components/BaseToast.styles.d.ts +41 -0
- package/lib/src/components/BaseToast.styles.js +39 -0
- package/lib/src/components/ErrorToast.d.ts +3 -0
- package/lib/src/components/ErrorToast.js +5 -0
- package/lib/src/components/InfoToast.d.ts +3 -0
- package/lib/src/components/InfoToast.js +5 -0
- package/lib/src/components/SuccessToast.d.ts +3 -0
- package/lib/src/components/SuccessToast.js +5 -0
- package/lib/src/components/Touchable.d.ts +8 -0
- package/lib/src/components/Touchable.js +7 -0
- package/lib/src/contexts/LoggerContext.d.ts +12 -0
- package/lib/src/contexts/LoggerContext.js +22 -0
- package/lib/src/contexts/index.d.ts +1 -0
- package/lib/src/contexts/index.js +1 -0
- package/lib/src/hooks/index.d.ts +5 -0
- package/lib/src/hooks/index.js +5 -0
- package/lib/src/hooks/useKeyboard.d.ts +4 -0
- package/lib/src/hooks/useKeyboard.js +31 -0
- package/lib/src/hooks/usePanResponder.d.ts +15 -0
- package/lib/src/hooks/usePanResponder.js +41 -0
- package/lib/src/hooks/useSlideAnimation.d.ts +24 -0
- package/lib/src/hooks/useSlideAnimation.js +49 -0
- package/lib/src/hooks/useTimeout.d.ts +6 -0
- package/lib/src/hooks/useTimeout.js +29 -0
- package/lib/src/hooks/useViewDimensions.d.ts +13 -0
- package/lib/src/hooks/useViewDimensions.js +20 -0
- package/lib/src/types/index.d.ts +165 -0
- package/lib/src/types/index.js +1 -0
- package/lib/src/useToast.d.ts +13 -0
- package/lib/src/useToast.js +79 -0
- package/lib/src/utils/array.d.ts +2 -0
- package/lib/src/utils/array.js +4 -0
- package/lib/src/utils/func.d.ts +1 -0
- package/lib/src/utils/func.js +1 -0
- package/lib/src/utils/number.d.ts +3 -0
- package/lib/src/utils/number.js +9 -0
- package/lib/src/utils/obj.d.ts +3 -0
- package/lib/src/utils/obj.js +11 -0
- package/lib/src/utils/platform.d.ts +1 -0
- package/lib/src/utils/platform.js +4 -0
- package/lib/src/utils/test-id.d.ts +1 -0
- package/lib/src/utils/test-id.js +3 -0
- package/package.json +46 -35
- package/.github/dependabot.yml +0 -17
- package/.github/workflows/publish.yml +0 -22
- package/.github/workflows/tag.yml +0 -16
- package/.github/workflows/tests.yml +0 -44
- package/babel.config.js +0 -3
- package/index.d.ts +0 -72
- package/index.js +0 -7
- package/jest.config.js +0 -5
- package/jest.setup.js +0 -1
- package/src/assets/icons/close.png +0 -0
- package/src/assets/icons/close@2x.png +0 -0
- package/src/assets/icons/close@3x.png +0 -0
- package/src/assets/icons/error.png +0 -0
- package/src/assets/icons/error@2x.png +0 -0
- package/src/assets/icons/error@3x.png +0 -0
- package/src/assets/icons/info.png +0 -0
- package/src/assets/icons/info@2x.png +0 -0
- package/src/assets/icons/info@3x.png +0 -0
- package/src/assets/icons/success.png +0 -0
- package/src/assets/icons/success@2x.png +0 -0
- package/src/assets/icons/success@3x.png +0 -0
- package/src/assets/index.js +0 -15
- package/src/colors/index.js +0 -10
- package/src/components/base/index.js +0 -134
- package/src/components/base/styles.js +0 -54
- package/src/components/error.js +0 -19
- package/src/components/icon/index.js +0 -40
- package/src/components/icon/styles.js +0 -8
- package/src/components/info.js +0 -19
- package/src/components/success.js +0 -19
- package/src/index.js +0 -420
- package/src/styles.js +0 -17
- package/src/utils/arr.js +0 -3
- package/src/utils/obj.js +0 -9
- package/src/utils/platform.js +0 -5
- package/src/utils/prop-types.js +0 -5
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
export const HEIGHT = 60;
|
|
3
|
+
export const WIDTH = 340;
|
|
4
|
+
export const BORDER_RADIUS = 6;
|
|
5
|
+
export const styles = StyleSheet.create({
|
|
6
|
+
base: {
|
|
7
|
+
flexDirection: 'row',
|
|
8
|
+
height: HEIGHT,
|
|
9
|
+
width: WIDTH,
|
|
10
|
+
borderRadius: BORDER_RADIUS,
|
|
11
|
+
shadowOffset: { width: 0, height: 0 },
|
|
12
|
+
shadowOpacity: 0.1,
|
|
13
|
+
shadowRadius: BORDER_RADIUS,
|
|
14
|
+
elevation: 2,
|
|
15
|
+
backgroundColor: '#FFF'
|
|
16
|
+
},
|
|
17
|
+
leadingBorder: {
|
|
18
|
+
borderLeftWidth: 5,
|
|
19
|
+
borderLeftColor: '#D8D8D8'
|
|
20
|
+
},
|
|
21
|
+
contentContainer: {
|
|
22
|
+
paddingHorizontal: 25,
|
|
23
|
+
flex: 1,
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
alignItems: 'flex-start' // In case of RTL, the text will start from the right
|
|
26
|
+
},
|
|
27
|
+
text1: {
|
|
28
|
+
fontSize: 12,
|
|
29
|
+
fontWeight: 'bold',
|
|
30
|
+
marginBottom: 2,
|
|
31
|
+
color: '#000',
|
|
32
|
+
width: '100%' // Fixes: https://github.com/calintamas/react-native-toast-message/issues/130
|
|
33
|
+
},
|
|
34
|
+
text2: {
|
|
35
|
+
fontSize: 10,
|
|
36
|
+
color: '#979797',
|
|
37
|
+
width: '100%' // Fixes: https://github.com/calintamas/react-native-toast-message/issues/130
|
|
38
|
+
}
|
|
39
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { TouchableOpacityProps } from 'react-native';
|
|
3
|
+
import { ReactChildren } from '../types';
|
|
4
|
+
declare type TouchableProps = {
|
|
5
|
+
children: ReactChildren;
|
|
6
|
+
} & TouchableOpacityProps;
|
|
7
|
+
export declare function Touchable({ children, activeOpacity, ...rest }: TouchableProps): JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { ReactChildren } from '../types';
|
|
3
|
+
export declare type LoggerContextType = {
|
|
4
|
+
log: (...args: unknown[]) => void;
|
|
5
|
+
};
|
|
6
|
+
export declare type LoggerProviderProps = {
|
|
7
|
+
children: ReactChildren;
|
|
8
|
+
enableLogs?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare function LoggerProvider({ children, enableLogs }: LoggerProviderProps): JSX.Element;
|
|
11
|
+
declare function useLogger(): LoggerContextType;
|
|
12
|
+
export { LoggerProvider, useLogger };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { noop } from '../utils/func';
|
|
3
|
+
const LoggerContext = React.createContext({
|
|
4
|
+
log: noop
|
|
5
|
+
});
|
|
6
|
+
function LoggerProvider({ children, enableLogs = false }) {
|
|
7
|
+
const log = React.useCallback((...args) => {
|
|
8
|
+
if (enableLogs) {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
10
|
+
console.log('Toast:', ...args);
|
|
11
|
+
}
|
|
12
|
+
}, [enableLogs]);
|
|
13
|
+
const value = {
|
|
14
|
+
log
|
|
15
|
+
};
|
|
16
|
+
return (<LoggerContext.Provider value={value}>{children}</LoggerContext.Provider>);
|
|
17
|
+
}
|
|
18
|
+
function useLogger() {
|
|
19
|
+
const ctx = React.useContext(LoggerContext);
|
|
20
|
+
return ctx;
|
|
21
|
+
}
|
|
22
|
+
export { LoggerProvider, useLogger };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LoggerContext';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LoggerContext';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Keyboard } from 'react-native';
|
|
3
|
+
import { isIOS } from '../utils/platform';
|
|
4
|
+
export function useKeyboard() {
|
|
5
|
+
const [keyboardHeight, setKeyboardHeight] = React.useState(0);
|
|
6
|
+
const [isKeyboardVisible, setIsKeyboardVisible] = React.useState(false);
|
|
7
|
+
const onShow = React.useCallback((event) => {
|
|
8
|
+
const { height } = event.endCoordinates;
|
|
9
|
+
setKeyboardHeight(height);
|
|
10
|
+
setIsKeyboardVisible(true);
|
|
11
|
+
}, []);
|
|
12
|
+
const onHide = React.useCallback(() => {
|
|
13
|
+
setKeyboardHeight(0);
|
|
14
|
+
setIsKeyboardVisible(false);
|
|
15
|
+
}, []);
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (!isIOS()) {
|
|
18
|
+
return () => { };
|
|
19
|
+
}
|
|
20
|
+
const didShowListener = Keyboard.addListener('keyboardDidShow', onShow);
|
|
21
|
+
const didHideListener = Keyboard.addListener('keyboardDidHide', onHide);
|
|
22
|
+
return () => {
|
|
23
|
+
didShowListener.remove();
|
|
24
|
+
didHideListener.remove();
|
|
25
|
+
};
|
|
26
|
+
}, [onHide, onShow]);
|
|
27
|
+
return {
|
|
28
|
+
keyboardHeight,
|
|
29
|
+
isKeyboardVisible
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { Animated, GestureResponderEvent, PanResponderGestureState } from 'react-native';
|
|
3
|
+
export declare function shouldSetPanResponder(_event: GestureResponderEvent, gesture: PanResponderGestureState): boolean;
|
|
4
|
+
export declare function shouldDismissView(newAnimatedValue: number, gesture: PanResponderGestureState): boolean;
|
|
5
|
+
export declare type UsePanResponderParams = {
|
|
6
|
+
animatedValue: RefObject<Animated.Value>;
|
|
7
|
+
computeNewAnimatedValueForGesture: (gesture: PanResponderGestureState) => number;
|
|
8
|
+
onDismiss: () => void;
|
|
9
|
+
onRestore: () => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore }: UsePanResponderParams): {
|
|
12
|
+
panResponder: import("react-native").PanResponderInstance;
|
|
13
|
+
onMove: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
14
|
+
onRelease: (_event: GestureResponderEvent, gesture: PanResponderGestureState) => void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { PanResponder } from 'react-native';
|
|
3
|
+
export function shouldSetPanResponder(_event, gesture) {
|
|
4
|
+
const { dx, dy } = gesture;
|
|
5
|
+
// Fixes onPress handler
|
|
6
|
+
// https://github.com/calintamas/react-native-toast-message/issues/113
|
|
7
|
+
const offset = 2;
|
|
8
|
+
return Math.abs(dx) > offset || Math.abs(dy) > offset;
|
|
9
|
+
}
|
|
10
|
+
export function shouldDismissView(newAnimatedValue, gesture) {
|
|
11
|
+
const dismissThreshold = 0.65;
|
|
12
|
+
const { vy, dy } = gesture;
|
|
13
|
+
return (newAnimatedValue <= dismissThreshold ||
|
|
14
|
+
(Math.abs(vy) >= dismissThreshold && dy < 0));
|
|
15
|
+
}
|
|
16
|
+
export function usePanResponder({ animatedValue, computeNewAnimatedValueForGesture, onDismiss, onRestore }) {
|
|
17
|
+
const onMove = React.useCallback((_event, gesture) => {
|
|
18
|
+
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
19
|
+
animatedValue.current?.setValue(newAnimatedValue);
|
|
20
|
+
}, [animatedValue, computeNewAnimatedValueForGesture]);
|
|
21
|
+
const onRelease = React.useCallback((_event, gesture) => {
|
|
22
|
+
const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
|
|
23
|
+
if (shouldDismissView(newAnimatedValue, gesture)) {
|
|
24
|
+
onDismiss();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
onRestore();
|
|
28
|
+
}
|
|
29
|
+
}, [computeNewAnimatedValueForGesture, onDismiss, onRestore]);
|
|
30
|
+
const panResponder = React.useMemo(() => PanResponder.create({
|
|
31
|
+
onMoveShouldSetPanResponder: shouldSetPanResponder,
|
|
32
|
+
onMoveShouldSetPanResponderCapture: shouldSetPanResponder,
|
|
33
|
+
onPanResponderMove: onMove,
|
|
34
|
+
onPanResponderRelease: onRelease
|
|
35
|
+
}), [onMove, onRelease]);
|
|
36
|
+
return {
|
|
37
|
+
panResponder,
|
|
38
|
+
onMove,
|
|
39
|
+
onRelease
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Animated } from 'react-native';
|
|
3
|
+
import { ToastPosition } from '../types';
|
|
4
|
+
declare type UseSlideAnimationParams = {
|
|
5
|
+
position: ToastPosition;
|
|
6
|
+
height: number;
|
|
7
|
+
topOffset: number;
|
|
8
|
+
bottomOffset: number;
|
|
9
|
+
keyboardOffset: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function translateYOutputRangeFor({ position, height, topOffset, bottomOffset, keyboardHeight, keyboardOffset }: UseSlideAnimationParams & {
|
|
12
|
+
keyboardHeight: number;
|
|
13
|
+
}): number[];
|
|
14
|
+
export declare function useSlideAnimation({ position, height, topOffset, bottomOffset, keyboardOffset }: UseSlideAnimationParams): {
|
|
15
|
+
animatedValue: React.MutableRefObject<Animated.Value>;
|
|
16
|
+
animate: (toValue: number) => void;
|
|
17
|
+
animationStyles: {
|
|
18
|
+
opacity: Animated.AnimatedInterpolation;
|
|
19
|
+
transform: {
|
|
20
|
+
translateY: Animated.AnimatedInterpolation;
|
|
21
|
+
}[];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Animated } from 'react-native';
|
|
3
|
+
import { additiveInverseArray } from '../utils/array';
|
|
4
|
+
import { useKeyboard } from './useKeyboard';
|
|
5
|
+
export function translateYOutputRangeFor({ position, height, topOffset, bottomOffset, keyboardHeight, keyboardOffset }) {
|
|
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;
|
|
11
|
+
}
|
|
12
|
+
export function useSlideAnimation({ position, height, topOffset, bottomOffset, keyboardOffset }) {
|
|
13
|
+
const animatedValue = React.useRef(new Animated.Value(0));
|
|
14
|
+
const { keyboardHeight } = useKeyboard();
|
|
15
|
+
const animate = React.useCallback((toValue) => {
|
|
16
|
+
Animated.spring(animatedValue.current, {
|
|
17
|
+
toValue,
|
|
18
|
+
useNativeDriver: true,
|
|
19
|
+
friction: 8
|
|
20
|
+
}).start();
|
|
21
|
+
}, []);
|
|
22
|
+
const translateY = animatedValue.current.interpolate({
|
|
23
|
+
inputRange: [0, 1],
|
|
24
|
+
outputRange: translateYOutputRangeFor({
|
|
25
|
+
position,
|
|
26
|
+
height,
|
|
27
|
+
topOffset,
|
|
28
|
+
bottomOffset,
|
|
29
|
+
keyboardHeight,
|
|
30
|
+
keyboardOffset
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
const opacity = animatedValue.current.interpolate({
|
|
34
|
+
inputRange: [0, 0.7, 1],
|
|
35
|
+
outputRange: [0, 1, 1]
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
animatedValue,
|
|
39
|
+
animate,
|
|
40
|
+
animationStyles: {
|
|
41
|
+
opacity,
|
|
42
|
+
transform: [
|
|
43
|
+
{
|
|
44
|
+
translateY
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useLogger } from '../contexts';
|
|
3
|
+
function useTimeout(cb, delayMs = 0) {
|
|
4
|
+
const { log } = useLogger();
|
|
5
|
+
const ref = React.useRef();
|
|
6
|
+
const clearTimer = React.useCallback(() => {
|
|
7
|
+
if (ref.current) {
|
|
8
|
+
log('Clearing timer', ref.current);
|
|
9
|
+
clearTimeout(ref.current);
|
|
10
|
+
ref.current = undefined;
|
|
11
|
+
}
|
|
12
|
+
}, [log]);
|
|
13
|
+
const startTimer = React.useCallback(() => {
|
|
14
|
+
clearTimer();
|
|
15
|
+
ref.current = setTimeout(() => {
|
|
16
|
+
cb();
|
|
17
|
+
log('Running timer', ref.current);
|
|
18
|
+
ref.current = undefined;
|
|
19
|
+
}, delayMs);
|
|
20
|
+
log('Starting timer', ref.current);
|
|
21
|
+
}, [clearTimer, delayMs, log, cb]);
|
|
22
|
+
React.useEffect(() => () => clearTimer(), [clearTimer]);
|
|
23
|
+
return {
|
|
24
|
+
startTimer,
|
|
25
|
+
clearTimer,
|
|
26
|
+
isActive: ref.current !== undefined
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export { useTimeout };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { LayoutChangeEvent } from 'react-native';
|
|
2
|
+
export declare type UseViewDimensionsParams = {
|
|
3
|
+
heightOffset?: number;
|
|
4
|
+
widthOffset?: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Retrieves View dimensions (height, width) from a LayoutChangeEvent and sets them on state
|
|
8
|
+
*/
|
|
9
|
+
export declare function useViewDimensions({ heightOffset, widthOffset }?: UseViewDimensionsParams): {
|
|
10
|
+
computeViewDimensions: (event: LayoutChangeEvent) => void;
|
|
11
|
+
height: number;
|
|
12
|
+
width: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
const getLayoutValue = (key) => (event) => event?.nativeEvent?.layout?.[key] ?? 0;
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves View dimensions (height, width) from a LayoutChangeEvent and sets them on state
|
|
5
|
+
*/
|
|
6
|
+
export function useViewDimensions({ heightOffset = 0, widthOffset = 0 } = {}) {
|
|
7
|
+
const [height, setHeight] = React.useState(0);
|
|
8
|
+
const [width, setWidth] = React.useState(0);
|
|
9
|
+
const computeViewDimensions = React.useCallback((event) => {
|
|
10
|
+
const h = getLayoutValue('height')(event);
|
|
11
|
+
const w = getLayoutValue('width')(event);
|
|
12
|
+
setHeight(h + heightOffset);
|
|
13
|
+
setWidth(w + widthOffset);
|
|
14
|
+
}, [heightOffset, widthOffset]);
|
|
15
|
+
return {
|
|
16
|
+
computeViewDimensions,
|
|
17
|
+
height,
|
|
18
|
+
width
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TextStyle, TouchableOpacityProps, ViewStyle } from 'react-native';
|
|
3
|
+
export declare type ReactChildren = React.ReactNode;
|
|
4
|
+
export declare type ToastType = string;
|
|
5
|
+
export declare type ToastPosition = 'top' | 'bottom';
|
|
6
|
+
export declare type ToastOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Toast type.
|
|
9
|
+
* Default value: `success`
|
|
10
|
+
*/
|
|
11
|
+
type?: ToastType;
|
|
12
|
+
/**
|
|
13
|
+
* Toast position.
|
|
14
|
+
* Default value: `top`
|
|
15
|
+
*/
|
|
16
|
+
position?: ToastPosition;
|
|
17
|
+
/**
|
|
18
|
+
* When `true`, the visible Toast automatically hides after a certain number of seconds,
|
|
19
|
+
* specified by the `visibilityTime` prop.
|
|
20
|
+
* Default value: `true`
|
|
21
|
+
*/
|
|
22
|
+
autoHide?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Number of seconds after which Toast automatically hides.
|
|
25
|
+
* Has effect only in conjunction with `autoHide` prop set to `true`.
|
|
26
|
+
* Default value: `4000`
|
|
27
|
+
*/
|
|
28
|
+
visibilityTime?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Offset from the top of the screen (in px).
|
|
31
|
+
* Has effect only when `position` is `top`
|
|
32
|
+
* Default value: `40`
|
|
33
|
+
*/
|
|
34
|
+
topOffset?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Offset from the bottom of the screen (in px)
|
|
37
|
+
* Has effect only when `position` is `bottom`
|
|
38
|
+
* Default value: `40`
|
|
39
|
+
*/
|
|
40
|
+
bottomOffset?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Offset from the Keyboard (in px)
|
|
43
|
+
* Has effect only when `position` is `bottom` and Keyboard is visible
|
|
44
|
+
* Default value: `10`
|
|
45
|
+
*/
|
|
46
|
+
keyboardOffset?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Called when Toast is shown
|
|
49
|
+
*/
|
|
50
|
+
onShow?: () => void;
|
|
51
|
+
/**
|
|
52
|
+
* Called when Toast hides
|
|
53
|
+
*/
|
|
54
|
+
onHide?: () => void;
|
|
55
|
+
/**
|
|
56
|
+
* Called on Toast press
|
|
57
|
+
*/
|
|
58
|
+
onPress?: () => void;
|
|
59
|
+
/**
|
|
60
|
+
* Any custom props passed to the specified Toast type.
|
|
61
|
+
* Has effect only when there is a custom Toast type (configured via the `config` prop
|
|
62
|
+
* on the Toast instance) that uses the `props` parameter
|
|
63
|
+
*/
|
|
64
|
+
props?: any;
|
|
65
|
+
};
|
|
66
|
+
export declare type ToastData = {
|
|
67
|
+
text1?: string;
|
|
68
|
+
text2?: string;
|
|
69
|
+
};
|
|
70
|
+
export declare type ToastShowParams = ToastData & ToastOptions;
|
|
71
|
+
export declare type ToastHideParams = void;
|
|
72
|
+
export declare type BaseToastProps = {
|
|
73
|
+
text1?: string;
|
|
74
|
+
text2?: string;
|
|
75
|
+
onPress?: () => void;
|
|
76
|
+
activeOpacity?: number;
|
|
77
|
+
style?: ViewStyle;
|
|
78
|
+
touchableContainerProps?: TouchableOpacityProps;
|
|
79
|
+
contentContainerStyle?: ViewStyle;
|
|
80
|
+
contentContainerProps?: ViewStyle;
|
|
81
|
+
text1Style?: TextStyle;
|
|
82
|
+
text1NumberOfLines?: number;
|
|
83
|
+
text1Props?: TextStyle;
|
|
84
|
+
text2Style?: TextStyle;
|
|
85
|
+
text2NumberOfLines?: number;
|
|
86
|
+
text2Props?: TextStyle;
|
|
87
|
+
renderLeadingIcon?: () => React.ReactNode;
|
|
88
|
+
renderTrailingIcon?: () => React.ReactNode;
|
|
89
|
+
};
|
|
90
|
+
export declare type ToastConfigParams<Props> = {
|
|
91
|
+
position: ToastPosition;
|
|
92
|
+
type: ToastType;
|
|
93
|
+
isVisible: boolean;
|
|
94
|
+
text1?: string;
|
|
95
|
+
text2?: string;
|
|
96
|
+
show: (params: ToastShowParams) => void;
|
|
97
|
+
hide: (params: ToastHideParams) => void;
|
|
98
|
+
onPress: () => void;
|
|
99
|
+
props: Props;
|
|
100
|
+
};
|
|
101
|
+
export declare type ToastConfig = {
|
|
102
|
+
[key: string]: (params: ToastConfigParams<any>) => React.ReactNode;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* `props` that can be set on the Toast instance.
|
|
106
|
+
* They act as defaults for all Toasts that are shown.
|
|
107
|
+
*/
|
|
108
|
+
export declare type ToastProps = {
|
|
109
|
+
/**
|
|
110
|
+
* Layout configuration for custom Toast types
|
|
111
|
+
*/
|
|
112
|
+
config?: ToastConfig;
|
|
113
|
+
/**
|
|
114
|
+
* Toast type.
|
|
115
|
+
* Default value: `success`
|
|
116
|
+
*/
|
|
117
|
+
type?: ToastType;
|
|
118
|
+
/**
|
|
119
|
+
* Toast position.
|
|
120
|
+
* Default value: `top`
|
|
121
|
+
*/
|
|
122
|
+
position?: ToastPosition;
|
|
123
|
+
/**
|
|
124
|
+
* Number of milliseconds after which Toast automatically hides.
|
|
125
|
+
* Has effect only in conjunction with `autoHide` prop set to `true`.
|
|
126
|
+
* Default value: `4000`
|
|
127
|
+
*/
|
|
128
|
+
visibilityTime?: number;
|
|
129
|
+
/**
|
|
130
|
+
* When `true`, the visible Toast automatically hides after a certain number of milliseconds,
|
|
131
|
+
* specified by the `visibilityTime` prop.
|
|
132
|
+
* Default value: `true`
|
|
133
|
+
*/
|
|
134
|
+
autoHide?: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Offset from the top of the screen (in px).
|
|
137
|
+
* Has effect only when `position` is `top`
|
|
138
|
+
* Default value: `40`
|
|
139
|
+
*/
|
|
140
|
+
topOffset?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Offset from the bottom of the screen (in px)
|
|
143
|
+
* Has effect only when `position` is `bottom`
|
|
144
|
+
* Default value: `40`
|
|
145
|
+
*/
|
|
146
|
+
bottomOffset?: number;
|
|
147
|
+
/**
|
|
148
|
+
* Offset from the Keyboard (in px)
|
|
149
|
+
* Has effect only when `position` is `bottom` and Keyboard is visible (iOS only)
|
|
150
|
+
* Default value: `10`
|
|
151
|
+
*/
|
|
152
|
+
keyboardOffset?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Called when any Toast is shown
|
|
155
|
+
*/
|
|
156
|
+
onShow?: () => void;
|
|
157
|
+
/**
|
|
158
|
+
* Called when any Toast hides
|
|
159
|
+
*/
|
|
160
|
+
onHide?: () => void;
|
|
161
|
+
/**
|
|
162
|
+
* Called on any Toast press
|
|
163
|
+
*/
|
|
164
|
+
onPress?: () => void;
|
|
165
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ToastData, ToastOptions, ToastProps, ToastShowParams } from './types';
|
|
2
|
+
export declare const DEFAULT_DATA: ToastData;
|
|
3
|
+
export declare const DEFAULT_OPTIONS: Required<ToastOptions>;
|
|
4
|
+
export declare type UseToastParams = {
|
|
5
|
+
defaultOptions: Omit<ToastProps, 'config'>;
|
|
6
|
+
};
|
|
7
|
+
export declare function useToast({ defaultOptions }: UseToastParams): {
|
|
8
|
+
isVisible: boolean;
|
|
9
|
+
data: ToastData;
|
|
10
|
+
options: Required<ToastOptions>;
|
|
11
|
+
show: (params: ToastShowParams) => void;
|
|
12
|
+
hide: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useLogger } from './contexts';
|
|
3
|
+
import { useTimeout } from './hooks';
|
|
4
|
+
import { noop } from './utils/func';
|
|
5
|
+
import { mergeIfDefined } from './utils/obj';
|
|
6
|
+
export const DEFAULT_DATA = {
|
|
7
|
+
text1: undefined,
|
|
8
|
+
text2: undefined
|
|
9
|
+
};
|
|
10
|
+
export const DEFAULT_OPTIONS = {
|
|
11
|
+
type: 'success',
|
|
12
|
+
position: 'top',
|
|
13
|
+
autoHide: true,
|
|
14
|
+
visibilityTime: 4000,
|
|
15
|
+
topOffset: 40,
|
|
16
|
+
bottomOffset: 40,
|
|
17
|
+
keyboardOffset: 10,
|
|
18
|
+
onShow: noop,
|
|
19
|
+
onHide: noop,
|
|
20
|
+
onPress: noop,
|
|
21
|
+
props: {}
|
|
22
|
+
};
|
|
23
|
+
export function useToast({ defaultOptions }) {
|
|
24
|
+
const { log } = useLogger();
|
|
25
|
+
const [isVisible, setIsVisible] = React.useState(false);
|
|
26
|
+
const [data, setData] = React.useState(DEFAULT_DATA);
|
|
27
|
+
const initialOptions = mergeIfDefined(DEFAULT_OPTIONS, defaultOptions);
|
|
28
|
+
const [options, setOptions] = React.useState(initialOptions);
|
|
29
|
+
const onAutoHide = React.useCallback(() => {
|
|
30
|
+
log('Auto hiding');
|
|
31
|
+
setIsVisible(false);
|
|
32
|
+
options.onHide();
|
|
33
|
+
}, [log, options]);
|
|
34
|
+
const { startTimer, clearTimer } = useTimeout(onAutoHide, options.visibilityTime);
|
|
35
|
+
const hide = React.useCallback(() => {
|
|
36
|
+
log('Hiding');
|
|
37
|
+
setIsVisible(false);
|
|
38
|
+
clearTimer();
|
|
39
|
+
options.onHide();
|
|
40
|
+
}, [clearTimer, log, options]);
|
|
41
|
+
const show = React.useCallback((params) => {
|
|
42
|
+
log(`Showing with params: ${JSON.stringify(params)}`);
|
|
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
|
+
setData({
|
|
48
|
+
text1,
|
|
49
|
+
text2
|
|
50
|
+
});
|
|
51
|
+
setOptions(mergeIfDefined(initialOptions, {
|
|
52
|
+
type,
|
|
53
|
+
position,
|
|
54
|
+
autoHide,
|
|
55
|
+
visibilityTime,
|
|
56
|
+
topOffset,
|
|
57
|
+
bottomOffset,
|
|
58
|
+
keyboardOffset,
|
|
59
|
+
onShow,
|
|
60
|
+
onHide,
|
|
61
|
+
onPress,
|
|
62
|
+
props
|
|
63
|
+
}));
|
|
64
|
+
onShow();
|
|
65
|
+
}, [initialOptions, log]);
|
|
66
|
+
React.useEffect(() => {
|
|
67
|
+
const { autoHide } = options;
|
|
68
|
+
if (isVisible && autoHide) {
|
|
69
|
+
startTimer();
|
|
70
|
+
}
|
|
71
|
+
}, [isVisible, options, startTimer]);
|
|
72
|
+
return {
|
|
73
|
+
isVisible,
|
|
74
|
+
data,
|
|
75
|
+
options,
|
|
76
|
+
show,
|
|
77
|
+
hide
|
|
78
|
+
};
|
|
79
|
+
}
|