309 lines
11 KiB
JavaScript
309 lines
11 KiB
JavaScript
import React from 'react';
|
|
import { View, TouchableOpacity, StyleSheet, Animated } from 'react-native';
|
|
import { Modal } from '../Modal';
|
|
import { SlideAnimated } from '../../common/animations';
|
|
import variables from '../../common/styles/variables';
|
|
export const slideModalStyles = StyleSheet.create({
|
|
container: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0,
|
|
flexDirection: 'row',
|
|
alignItems: 'flex-start',
|
|
justifyContent: 'center',
|
|
overflow: 'hidden',
|
|
},
|
|
backdrop: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
right: 0,
|
|
backgroundColor: variables.mtdFillBackdrop
|
|
},
|
|
content: {
|
|
position: 'absolute',
|
|
overflow: 'hidden'
|
|
}
|
|
});
|
|
export class SlideModal extends Modal {
|
|
constructor(props) {
|
|
super(props);
|
|
this.handleLayout = (e) => {
|
|
const { directionType, direction } = this.state;
|
|
const { width, height } = e.nativeEvent.layout;
|
|
const ret = [];
|
|
directionType.forEach((directionTypeItem) => {
|
|
if (directionTypeItem === 'vertical') {
|
|
ret.push({
|
|
size: direction.indexOf('up') !== -1 ? height : -height,
|
|
directionTypeItem,
|
|
});
|
|
}
|
|
if (directionTypeItem === 'horizontal') {
|
|
ret.push({
|
|
size: direction.indexOf('right') !== -1 ? -width : width,
|
|
directionTypeItem
|
|
});
|
|
}
|
|
});
|
|
this.animated.reset(ret);
|
|
};
|
|
}
|
|
// 重写 Modal 父类 init 方法
|
|
init(props, syncTag) {
|
|
const directions = [
|
|
['up'],
|
|
['up', 'left'],
|
|
['up', 'right'],
|
|
['down'],
|
|
['down', 'left'],
|
|
['down', 'right'],
|
|
['left'],
|
|
['right']
|
|
];
|
|
const direction = typeof (props.direction) === 'string' ? [props.direction] : props.direction;
|
|
const propsDirectionValid = directions.some((directionItem) => {
|
|
const str1 = directionItem.join();
|
|
const str2 = directionItem.reverse().join();
|
|
const str3 = direction.join();
|
|
if (str3 === str1 || str3 === str2) {
|
|
return true;
|
|
}
|
|
});
|
|
if (!propsDirectionValid) {
|
|
throw new TypeError(`direction 参数 ${props.direction} 为无效值`);
|
|
}
|
|
const directionType = [];
|
|
if (direction.indexOf('up') !== -1 || direction.indexOf('down') !== -1) {
|
|
directionType.push('vertical');
|
|
}
|
|
if (direction.indexOf('left') !== -1 || direction.indexOf('right') !== -1) {
|
|
directionType.push('horizontal');
|
|
}
|
|
let align;
|
|
if (direction.length === 1) {
|
|
if (directionType.indexOf('vertical') !== -1) {
|
|
align = props.align === 'left' || props.align === 'right' ? props.align : 'right';
|
|
}
|
|
else {
|
|
align = props.align === 'up' || props.align === 'down' ? props.align : 'down';
|
|
}
|
|
}
|
|
let directionWithAlign = [];
|
|
if (direction.length === 2) {
|
|
directionWithAlign = direction;
|
|
}
|
|
else {
|
|
directionWithAlign = [
|
|
...direction,
|
|
align
|
|
];
|
|
}
|
|
const offsetY = typeof props.offsetY === 'number' ? props.offsetY : props.screenHeight;
|
|
const data = {
|
|
directionType,
|
|
direction,
|
|
align,
|
|
directionWithAlign,
|
|
offsetY
|
|
};
|
|
this.animated = new SlideAnimated({
|
|
// duration: 1000
|
|
directionType: data.directionType,
|
|
});
|
|
if (syncTag) {
|
|
this.state = {
|
|
...this.state,
|
|
...data,
|
|
};
|
|
}
|
|
else {
|
|
this.setState({
|
|
...this.state,
|
|
...data
|
|
});
|
|
}
|
|
}
|
|
componentWillReceiveProps(nextProps) {
|
|
if (nextProps.direction !== this.props.direction ||
|
|
nextProps.align !== this.props.align ||
|
|
nextProps.offsetX !== this.props.offsetX ||
|
|
nextProps.offsetY !== this.props.offsetY ||
|
|
nextProps.screenWidth !== this.props.screenWidth ||
|
|
nextProps.screenHeight !== this.props.screenHeight) {
|
|
this.init(nextProps, false);
|
|
}
|
|
}
|
|
open(c) {
|
|
return Modal.prototype.open.call(this, c);
|
|
}
|
|
getRects() {
|
|
const { offsetX, screenWidth, screenHeight } = this.props;
|
|
const { directionWithAlign, offsetY } = this.state;
|
|
const defaultRect = { top: null, bottom: null, left: null, right: null };
|
|
const contentContainerRect = { ...defaultRect };
|
|
const contentRect = { ...defaultRect };
|
|
const contentClockwise2Rect = {
|
|
backgroundColor: 'red',
|
|
...defaultRect
|
|
};
|
|
const contentClockwise1Rect = {
|
|
backgroundColor: 'blue',
|
|
...defaultRect
|
|
};
|
|
const contentClockwise3Rect = {
|
|
backgroundColor: 'green',
|
|
...defaultRect
|
|
};
|
|
if (directionWithAlign.indexOf('up') !== -1) {
|
|
contentContainerRect.top = 0;
|
|
contentContainerRect.bottom = screenHeight - offsetY;
|
|
contentClockwise2Rect.top = offsetY;
|
|
contentClockwise2Rect.bottom = 0;
|
|
contentClockwise1Rect.left = offsetX;
|
|
contentClockwise1Rect.right = 0;
|
|
contentClockwise3Rect.left = 0;
|
|
contentClockwise3Rect.right = screenWidth - offsetX;
|
|
contentRect.bottom = 0;
|
|
}
|
|
if (directionWithAlign.indexOf('down') !== -1) {
|
|
contentContainerRect.top = offsetY;
|
|
contentContainerRect.bottom = 0;
|
|
contentClockwise2Rect.top = 0;
|
|
contentClockwise2Rect.bottom = screenHeight - offsetY;
|
|
contentClockwise1Rect.left = 0;
|
|
contentClockwise1Rect.right = screenWidth - offsetX;
|
|
contentClockwise3Rect.left = offsetX;
|
|
contentClockwise3Rect.right = 0;
|
|
contentRect.top = 0;
|
|
}
|
|
if (directionWithAlign.indexOf('right') !== -1) {
|
|
contentContainerRect.left = offsetX;
|
|
contentContainerRect.right = 0;
|
|
contentClockwise2Rect.left = 0;
|
|
contentClockwise2Rect.right = screenWidth - offsetX;
|
|
contentClockwise1Rect.top = offsetY;
|
|
contentClockwise1Rect.bottom = 0;
|
|
contentClockwise3Rect.top = 0;
|
|
contentClockwise3Rect.bottom = screenHeight - offsetY;
|
|
contentRect.left = 0;
|
|
}
|
|
if (directionWithAlign.indexOf('left') !== -1) {
|
|
contentContainerRect.left = 0;
|
|
contentContainerRect.right = screenWidth - offsetX;
|
|
contentClockwise2Rect.left = offsetX;
|
|
contentClockwise2Rect.right = 0;
|
|
contentClockwise1Rect.top = 0;
|
|
contentClockwise1Rect.bottom = screenHeight - offsetY;
|
|
contentClockwise3Rect.top = offsetY;
|
|
contentClockwise3Rect.bottom = 0;
|
|
contentRect.right = 0;
|
|
}
|
|
return {
|
|
contentContainerRect,
|
|
contentRect,
|
|
contentClockwise1Rect,
|
|
contentClockwise2Rect,
|
|
contentClockwise3Rect
|
|
};
|
|
}
|
|
getFullScreenPatch() {
|
|
const { cancelable, backdropColor, fullScreenPatch } = this.props;
|
|
if (fullScreenPatch.length !== 3) {
|
|
throw new TypeError(`fullScreenPatch 参数 ${fullScreenPatch} 为无效值`);
|
|
}
|
|
const rects = this.getRects();
|
|
const tmp = fullScreenPatch.map((patchItem, patchIndex) => {
|
|
if (patchItem) {
|
|
return `contentClockwise${patchIndex + 1}Rect`;
|
|
}
|
|
else {
|
|
return '';
|
|
}
|
|
}).filter((tmpItem) => {
|
|
return tmpItem;
|
|
}).map((key) => {
|
|
return {
|
|
key,
|
|
cancelable,
|
|
closeFn: this.close.bind(this, 'backdrop'),
|
|
rect: {
|
|
...rects[key],
|
|
backgroundColor: backdropColor,
|
|
}
|
|
};
|
|
});
|
|
return tmp;
|
|
}
|
|
getContent(inner) {
|
|
const { screenWidth, screenHeight } = this.props;
|
|
const tmp = inner == null ? this.props.children : inner;
|
|
const { contentContainerRect, contentRect } = this.getRects();
|
|
const fullScreenPatch = this.getFullScreenPatch();
|
|
return (React.createElement(View, { style: [
|
|
{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: screenWidth,
|
|
height: screenHeight,
|
|
},
|
|
this.props.styles.root
|
|
], collapsable: false, pointerEvents: 'box-none' },
|
|
fullScreenPatch.map((patchItem, patchIndex) => {
|
|
return (React.createElement(TouchableOpacity, { key: patchIndex, activeOpacity: 1, style: {
|
|
position: 'absolute',
|
|
...patchItem.rect
|
|
}, onPress: () => {
|
|
if (patchItem.cancelable) {
|
|
patchItem.closeFn();
|
|
}
|
|
} }));
|
|
}),
|
|
React.createElement(View, { collapsable: false, style: [
|
|
slideModalStyles.container,
|
|
{
|
|
...contentContainerRect
|
|
},
|
|
this.props.styles.container
|
|
] },
|
|
React.createElement(TouchableOpacity, { testID: 'backdrop', style: [
|
|
slideModalStyles.backdrop,
|
|
{
|
|
backgroundColor: this.props.backdropColor
|
|
},
|
|
this.props.styles.backdrop
|
|
], activeOpacity: 1, onPress: () => {
|
|
this.handlePressBackdrop();
|
|
} }),
|
|
React.createElement(Animated.View, { style: [
|
|
slideModalStyles.content,
|
|
{
|
|
...contentRect
|
|
},
|
|
{
|
|
transform: [
|
|
{ translateY: this.animated.getState().translateY },
|
|
{ translateX: this.animated.getState().translateX }
|
|
],
|
|
opacity: this.animated.getState().opacity
|
|
},
|
|
this.props.styles.content
|
|
], onLayout: this.handleLayout }, tmp || null))));
|
|
}
|
|
}
|
|
SlideModal.defaultProps = {
|
|
...Modal.defaultProps,
|
|
styles: {},
|
|
cancelable: false,
|
|
offsetX: 0,
|
|
offsetY: undefined,
|
|
direction: 'up',
|
|
align: 'right',
|
|
fullScreenPatch: [false, false, false]
|
|
};
|
|
//# sourceMappingURL=index.js.map
|