1- import React , { useState , useMemo , useRef , useEffect } from 'react' ;
1+ import React , { useState , useMemo , useRef , useEffect , useReducer } from 'react' ;
22import { Animated , StyleSheet , LayoutChangeEvent , Dimensions , ViewStyle } from 'react-native' ;
33import MaskLayer , { MaskLayerProps } from '../MaskLayer' ;
44import { Theme } from '../theme' ;
@@ -8,20 +8,35 @@ const MainWidth = Dimensions.get('window').width;
88const MainHeight = Dimensions . get ( 'window' ) . height ;
99
1010export interface ModalProps extends MaskLayerProps {
11- placement ?: 'top' | 'right' | 'bottom' | 'left' ;
11+ placement ?: 'top' | 'right' | 'bottom' | 'left' | 'middle' ;
1212 onClosed ?: ( ) => void ;
1313 containerStyle ?: ViewStyle ;
1414}
1515
16+ interface StoreType {
17+ layoutHeight : number ;
18+ layoutWidth : number ;
19+ }
20+
21+ export const reducer : React . Reducer < StoreType , Partial < StoreType > > = ( state , action ) => {
22+ return {
23+ ...state ,
24+ ...action ,
25+ } ;
26+ } ;
27+
1628const Modal = ( props : ModalProps = { } ) => {
1729 const { onClosed, visible, children, placement = 'bottom' , containerStyle, ...otherProps } = props ;
1830 const theme = useTheme < Theme > ( ) ;
1931 const AnimatedOpacity = useRef ( new Animated . Value ( 0 ) ) . current ;
20- const [ layoutHeight , setLayoutHeight ] = useState ( 0 ) ;
21- const [ layoutWidth , setLayoutWidth ] = useState ( 0 ) ;
32+ const [ { layoutHeight, layoutWidth } , dispatch ] = useReducer ( reducer , { layoutHeight : 0 , layoutWidth : 0 } ) ;
2233 const [ translateValue ] = useState ( new Animated . Value ( 0 ) ) ;
23- const isVertical = / ^ ( t o p | b o t t o m ) $ / . test ( placement ) ;
24- const isHorizontal = / ^ ( l e f t | r i g h t ) $ / . test ( placement ) ;
34+
35+ const { isVertical, isHorizontal } = useMemo ( ( ) => {
36+ const isVertical = / ^ ( t o p | b o t t o m ) $ / . test ( placement ) ;
37+ const isHorizontal = / ^ ( l e f t | r i g h t ) $ / . test ( placement ) ;
38+ return { isVertical, isHorizontal } ;
39+ } , [ placement ] ) ;
2540
2641 useEffect ( ( ) => {
2742 function getTransformSize ( ) {
@@ -37,6 +52,9 @@ const Modal = (props: ModalProps = {}) => {
3752 if ( placement === 'right' ) {
3853 return layoutWidth ;
3954 }
55+ if ( placement === 'middle' ) {
56+ return layoutWidth ;
57+ }
4058 return 0 ;
4159 }
4260 const result = getTransformSize ( ) ;
@@ -82,20 +100,30 @@ const Modal = (props: ModalProps = {}) => {
82100 if ( isHorizontal ) {
83101 translateStyle . translateX = translateValue ;
84102 }
103+ if ( placement === 'middle' ) {
104+ translateStyle . translateY = translateValue ;
105+ }
85106
86107 const child = useMemo (
87108 ( ) => (
88109 < Animated . View
89- style = { [ styles . content , placement && styles [ placement ] , { opacity : AnimatedOpacity } , containerStyle ] }
110+ style = { [
111+ styles . content ,
112+ placement && styles [ placement ] ,
113+ placement === 'middle' && styles . middle_warp ,
114+ { opacity : AnimatedOpacity } ,
115+ containerStyle ,
116+ ] }
90117 >
91118 < Animated . View
92119 onLayout = { ( event : LayoutChangeEvent ) => {
93120 const { height, width } = event . nativeEvent . layout ;
94- if ( ! layoutHeight && isVertical ) {
95- setLayoutHeight ( height ) ;
96- }
97- if ( ! layoutWidth && isHorizontal ) {
98- setLayoutWidth ( width ) ;
121+ if ( placement === 'middle' ) {
122+ dispatch ( { layoutHeight : height , layoutWidth : width } ) ;
123+ } else if ( ! layoutHeight && isVertical ) {
124+ dispatch ( { layoutHeight : height } ) ;
125+ } else if ( ! layoutWidth && isHorizontal ) {
126+ dispatch ( { layoutWidth : width } ) ;
99127 }
100128 } }
101129 style = { [
@@ -165,4 +193,13 @@ const styles = StyleSheet.create({
165193 height : MainHeight ,
166194 right : 0 ,
167195 } ,
196+ middle : { } ,
197+ middle_warp : {
198+ bottom : 0 ,
199+ top : 0 ,
200+ right : 0 ,
201+ left : 0 ,
202+ justifyContent : 'center' ,
203+ alignItems : 'center' ,
204+ } ,
168205} ) ;
0 commit comments