2024-03-16 14:11:43 +08:00

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