@haroldtran/react-native-modals 0.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.
@@ -0,0 +1,31 @@
1
+ // @flow
2
+
3
+ import React from 'react';
4
+ import { View, StyleSheet } from 'react-native';
5
+ import ModalContext from './ModalContext';
6
+ import type { ModalContentProps } from '../type';
7
+
8
+ const styles = StyleSheet.create({
9
+ content: {
10
+ paddingVertical: 24,
11
+ paddingHorizontal: 18,
12
+ },
13
+ noPaddingTop: {
14
+ paddingTop: 0,
15
+ },
16
+ });
17
+
18
+ const ModalContent = ({
19
+ style,
20
+ children,
21
+ }: ModalContentProps) => (
22
+ <ModalContext.Consumer>
23
+ {({ hasTitle }) => (
24
+ <View style={[styles.content, hasTitle && styles.noPaddingTop, style]}>
25
+ {children}
26
+ </View>
27
+ )}
28
+ </ModalContext.Consumer>
29
+ );
30
+
31
+ export default ModalContent;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ const ModalContext = React.createContext({
4
+ hasTitle: false,
5
+ hasFooter: false,
6
+ });
7
+
8
+ export default ModalContext;
@@ -0,0 +1,48 @@
1
+ // @flow
2
+
3
+ import React, { Children, cloneElement } from 'react';
4
+ import { View, StyleSheet, PixelRatio } from 'react-native';
5
+ import type { ModalFooterProps } from '../type';
6
+
7
+ const styles = StyleSheet.create({
8
+ border: {
9
+ borderColor: '#CCD0D5',
10
+ borderTopWidth: 1 / PixelRatio.get(),
11
+ },
12
+ actionsVertical: {
13
+ height: 200,
14
+ flexDirection: 'column',
15
+ },
16
+ actionsHorizontal: {
17
+ flexDirection: 'row',
18
+ },
19
+ });
20
+
21
+ const ModalActionList = ({
22
+ style,
23
+ children,
24
+ bordered = true,
25
+ }: ModalFooterProps) => {
26
+ const containerStyle = children.length > 2
27
+ ? styles.actionsVertical
28
+ : styles.actionsHorizontal;
29
+
30
+ const border = bordered
31
+ ? styles.border
32
+ : null;
33
+
34
+ // apply horizontal border if actions legnth is 2 & bordered is true
35
+ const content = children.length === 2
36
+ ? Children.map(children, ((child, index) => cloneElement(child, {
37
+ bordered: (1 % index === 0 && bordered),
38
+ })))
39
+ : children;
40
+
41
+ return (
42
+ <View style={[containerStyle, border, style]}>
43
+ {content}
44
+ </View>
45
+ );
46
+ };
47
+
48
+ export default ModalActionList;
@@ -0,0 +1,47 @@
1
+ // @flow
2
+
3
+ import React from "react";
4
+ import { PixelRatio, Platform, StyleSheet, Text, View } from "react-native";
5
+ import { Positions } from "../constants/Constants";
6
+ import type { ModalTitleProps } from "../type";
7
+
8
+ const isAndroid = Platform.OS === "android";
9
+
10
+ const styles = StyleSheet.create({
11
+ title: {
12
+ padding: 14,
13
+ paddingHorizontal: 18,
14
+ borderTopLeftRadius: 8,
15
+ borderTopRightRadius: 8,
16
+ },
17
+ titleBar: {
18
+ borderBottomWidth: 1 / PixelRatio.get(),
19
+ backgroundColor: "#F9F9FB",
20
+ borderColor: "#DAD9DC",
21
+ },
22
+ text: {
23
+ fontWeight: isAndroid ? "400" : "500",
24
+ fontFamily: isAndroid ? "sans-serif-medium" : "System",
25
+ fontSize: isAndroid ? 19 : 15,
26
+ color: "#151822",
27
+ },
28
+ });
29
+
30
+ const ModalTitle = ({
31
+ title,
32
+ style,
33
+ textStyle,
34
+ hasTitleBar = true,
35
+ align = "center",
36
+ }: ModalTitleProps) => {
37
+ const titleBar = hasTitleBar ? styles.titleBar : null;
38
+ const titleAlign = { alignItems: Positions[align as keyof typeof Positions] };
39
+
40
+ return (
41
+ <View style={[styles.title, titleAlign, titleBar, style]}>
42
+ <Text style={[styles.text, textStyle]}>{title}</Text>
43
+ </View>
44
+ );
45
+ };
46
+
47
+ export default ModalTitle;
@@ -0,0 +1,91 @@
1
+ // @flow
2
+
3
+ import { Animated, Dimensions } from "react-native";
4
+ import Animation, { AnimationConfig } from "../animations/Animation";
5
+
6
+ const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("window");
7
+
8
+ type SlideFrom = "top" | "bottom" | "left" | "right";
9
+ type SlideAnimationConfig = AnimationConfig & {
10
+ slideFrom?: SlideFrom;
11
+ };
12
+
13
+ export default class SlideAnimation extends Animation {
14
+ slideFrom: SlideFrom;
15
+
16
+ static SLIDE_FROM_TOP: SlideFrom = "top";
17
+ static SLIDE_FROM_BOTTOM: SlideFrom = "bottom";
18
+ static SLIDE_FROM_LEFT: SlideFrom = "left";
19
+ static SLIDE_FROM_RIGHT: SlideFrom = "right";
20
+
21
+ constructor({
22
+ initialValue = 0,
23
+ useNativeDriver = true,
24
+ slideFrom = SlideAnimation.SLIDE_FROM_BOTTOM,
25
+ }: SlideAnimationConfig = {}) {
26
+ super({ initialValue, useNativeDriver });
27
+ this.slideFrom = slideFrom;
28
+ }
29
+
30
+ in(onFinished: Animated.EndCallback = () => {}, options: any = {}): void {
31
+ Animated.spring(this.animate, {
32
+ toValue: 1,
33
+ velocity: 0,
34
+ tension: 65,
35
+ friction: 11,
36
+ useNativeDriver: this.useNativeDriver,
37
+ ...options,
38
+ }).start(onFinished);
39
+ }
40
+
41
+ out(onFinished: Animated.EndCallback = () => {}, options: any = {}): void {
42
+ Animated.spring(this.animate, {
43
+ toValue: 0,
44
+ velocity: 0,
45
+ tension: 65,
46
+ friction: 11,
47
+ useNativeDriver: this.useNativeDriver,
48
+ ...options,
49
+ }).start(onFinished);
50
+ }
51
+
52
+ getAnimations(): any {
53
+ const transform: any[] = [];
54
+ if (this.slideFrom === SlideAnimation.SLIDE_FROM_TOP) {
55
+ transform.push({
56
+ translateY: this.animate.interpolate({
57
+ inputRange: [0, 1],
58
+ outputRange: [-SCREEN_HEIGHT, 0],
59
+ }),
60
+ });
61
+ } else if (this.slideFrom === SlideAnimation.SLIDE_FROM_BOTTOM) {
62
+ transform.push({
63
+ translateY: this.animate.interpolate({
64
+ inputRange: [0, 1],
65
+ outputRange: [SCREEN_HEIGHT, 0],
66
+ }),
67
+ });
68
+ } else if (this.slideFrom === SlideAnimation.SLIDE_FROM_LEFT) {
69
+ transform.push({
70
+ translateX: this.animate.interpolate({
71
+ inputRange: [0, 1],
72
+ outputRange: [-SCREEN_WIDTH, 0],
73
+ }),
74
+ });
75
+ } else if (this.slideFrom === SlideAnimation.SLIDE_FROM_RIGHT) {
76
+ transform.push({
77
+ translateX: this.animate.interpolate({
78
+ inputRange: [0, 1],
79
+ outputRange: [SCREEN_WIDTH, 0],
80
+ }),
81
+ });
82
+ } else {
83
+ throw new Error(`
84
+ slideFrom: ${this.slideFrom} not supported. 'slideFrom' must be 'top' | 'bottom' | 'left' | 'right'
85
+ `);
86
+ }
87
+ return {
88
+ transform,
89
+ };
90
+ }
91
+ }
@@ -0,0 +1,5 @@
1
+ export const Positions = {
2
+ left: 'flex-start',
3
+ right: 'flex-end',
4
+ center: 'center',
5
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,32 @@
1
+ import Animation from "./animations/Animation";
2
+ import FadeAnimation from "./animations/FadeAnimation";
3
+ import ScaleAnimation from "./animations/ScaleAnimation";
4
+ import SlideAnimation from "./animations/SlideAnimation";
5
+ import BottomModal from "./BottomModal";
6
+ import Backdrop from "./components/Backdrop";
7
+ import DraggableView from "./components/DraggableView";
8
+ import ModalButton from "./components/ModalButton";
9
+ import ModalContent from "./components/ModalContent";
10
+ import ModalFooter from "./components/ModalFooter";
11
+ import ModalTitle from "./components/ModalTitle";
12
+ import Modal from "./Modal";
13
+ import ModalPortal from "./ModalPortal";
14
+ export * from "./type";
15
+
16
+ export {
17
+ Animation,
18
+ Backdrop,
19
+ BottomModal,
20
+ DraggableView,
21
+ FadeAnimation,
22
+ Modal,
23
+ ModalButton,
24
+ ModalContent,
25
+ ModalFooter,
26
+ ModalPortal,
27
+ ModalTitle,
28
+ ScaleAnimation,
29
+ SlideAnimation,
30
+ };
31
+
32
+ export default Modal;
package/src/type.ts ADDED
@@ -0,0 +1,90 @@
1
+ // TypeScript types for the library
2
+
3
+ import { ReactNode } from "react";
4
+ import Animation from "./animations/Animation";
5
+
6
+ export type SwipeDirection = "up" | "down" | "left" | "right";
7
+
8
+ export type DragEvent = {
9
+ axis: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ layout: {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ } | null;
19
+ swipeDirection: string | null;
20
+ };
21
+
22
+ export type ModalProps = {
23
+ visible?: boolean;
24
+ children?: any;
25
+ width?: number;
26
+ height?: number;
27
+ rounded?: boolean;
28
+ hasOverlay?: boolean;
29
+ overlayPointerEvents?: "auto" | "none";
30
+ overlayBackgroundColor?: string;
31
+ overlayOpacity?: number;
32
+ modalTitle?: any;
33
+ modalAnimation?: Animation;
34
+ modalStyle?: any;
35
+ style?: any;
36
+ animationDuration?: number;
37
+ onTouchOutside?: () => void;
38
+ onHardwareBackPress?: () => boolean;
39
+ onShow?: () => void;
40
+ onDismiss?: () => void;
41
+ footer?: ReactNode;
42
+ onMove?: (event: DragEvent) => void;
43
+ onSwiping?: (event: DragEvent) => void;
44
+ onSwipeRelease?: (event: DragEvent) => void;
45
+ onSwipingOut?: (event: DragEvent) => void;
46
+ onSwipeOut?: (event: DragEvent) => void;
47
+ swipeDirection?: SwipeDirection | Array<SwipeDirection>;
48
+ swipeThreshold?: number;
49
+ useNativeDriver?: boolean;
50
+ };
51
+
52
+ export type ModalFooterProps = {
53
+ children?: any;
54
+ style?: any;
55
+ bordered?: boolean;
56
+ };
57
+
58
+ export type ModalButtonProps = {
59
+ text: string;
60
+ onPress?: () => void;
61
+ align?: "left" | "right" | "center" | string;
62
+ style?: any;
63
+ textStyle?: any;
64
+ disabled?: boolean;
65
+ activeOpacity?: number;
66
+ bordered?: boolean;
67
+ };
68
+
69
+ export type ModalTitleProps = {
70
+ title: any;
71
+ style?: any;
72
+ textStyle?: any;
73
+ align?: "left" | "right" | "center" | string;
74
+ hasTitleBar?: boolean;
75
+ };
76
+
77
+ export type ModalContentProps = {
78
+ children: any;
79
+ style?: any;
80
+ };
81
+
82
+ export type BackdropProps = {
83
+ visible: boolean;
84
+ opacity: number;
85
+ onPress?: () => void;
86
+ backgroundColor?: string;
87
+ animationDuration?: number;
88
+ pointerEvents?: "auto" | "none" | "box-none" | "box-only";
89
+ useNativeDriver?: boolean;
90
+ };