UNPKG

weex-nuke

Version:

基于 Rax 、Weex 的高性能组件体系 ~~

246 lines (236 loc) 6.74 kB
/** @jsx createElement */ import { createElement, findDOMNode, PropTypes, Component } from 'rax'; import { isWeb } from 'nuke-env'; import Mask from 'nuke-mask'; import Touchable from 'nuke-touchable'; import Transition from 'nuke-transition'; import Dimensions from 'nuke-dimensions'; import { connectStyle } from 'nuke-theme-provider'; import stylesProvider from './styles'; const deviceInfo = isWeb ? Dimensions.get('window') : Dimensions.get('screen'); class Slip extends Component { constructor(props) { super(props); this.onVisibleChanged = this.onVisibleChanged.bind(this); this.transition = this.transition.bind(this); this.show = this.show.bind(this); this.hide = this.hide.bind(this); this.onMaskShow = this.onMaskShow.bind(this); this.onMaskHide = this.onMaskHide.bind(this); this.onMaskPress = this.onMaskPress.bind(this); this.onPanePress = this.onPanePress.bind(this); this.state = { visible: props.defaultVisible || false, defaultVisible: props.defaultVisible || false, scrollPosition: 0, }; } onVisibleChanged(e) { this.setState({ visible: e.visible, }); } onMaskHide() { this.setState({ visible: false, }); const { onHide } = this.props; onHide && onHide(); } onPanePress(e) { if (isWeb) { e.stopPropagation(); } } onMaskShow() { const styles = this.calcTransitionStyle(false); const box = findDOMNode(this.refs.slipPane); setTimeout(() => { this.transition(box, styles, () => { this.setState({ visible: true }); const { onShow } = this.props; onShow && onShow(); }); }, 10); } onMaskPress() { const { maskClosable } = this.props; if (!maskClosable) { return; } this.hide(); } getWidthAndHeight() { const { direction } = this.props; let { width, height } = this.props; if (!height && (direction === 'left' || direction === 'right')) { height = parseInt(deviceInfo.height, 10); } if (!width && (direction === 'top' || direction === 'bottom')) { width = 750; } return { width, height, }; } calcTransitionStyle(contentDialogVisualState) { const visible = typeof contentDialogVisualState === 'undefined' ? this.state.visible : contentDialogVisualState; const { direction } = this.props; const { width, height } = this.getWidthAndHeight(); let transitionStyle = {}; switch (direction) { case 'left': transitionStyle = { transform: !visible ? `translateX(${width})` : 'translateX(0)', webkitTransform: !visible ? `translateX(${width})` : 'translateX(0)', }; break; case 'right': transitionStyle = { transform: !visible ? `translateX(${-width})` : 'translateX(0)', webkitTransform: !visible ? `translateX(${-width})` : 'translateX(0)', }; // right break; case 'top': transitionStyle = { transform: !visible ? `translateY(${height})` : 'translateX(0)', webkitTransform: !visible ? `translateY(${height})` : 'translateX(0)', }; break; default: transitionStyle = { transform: !visible ? `translateY(${-height})` : 'translateX(0)', webkitTransform: !visible ? `translateY(${-height})` : 'translateX(0)', }; break; } return transitionStyle; } calcInitStyle() { const { direction } = this.props; const { width, height } = this.getWidthAndHeight(); let positionObj = { position: 'absolute', width: `${width}rem`, height: `${height}rem`, }; switch (direction) { case 'left': positionObj = { ...positionObj, left: `${-width}rem`, top: 0, }; break; case 'right': positionObj = { ...positionObj, right: `${-width}rem`, }; // right break; case 'top': positionObj = { ...positionObj, top: `${-height}rem`, }; break; default: positionObj = { ...positionObj, bottom: `${-height}rem`, }; break; } return positionObj; } transition(box, styles, cb) { const { effect, duration } = this.props; Transition( box, styles, { timingFunction: effect, delay: 0, duration, }, function () { cb && cb.call(this); } ); } show() { // first show mask, // then in mask onShow callback, show dialogContent; this.refs.BaseSlipMask.show(); if (isWeb) { this.setState({ scrollPosition: window.scrollY }); document.body.style.position = 'fixed'; document.body.style.overflow = 'hidden'; } } hide() { // first hide dialogContent, then hideMask const styles = this.calcTransitionStyle(true); const box = findDOMNode(this.refs.slipPane); setTimeout(() => { this.transition(box, styles, () => { this.setState({ visible: !this.state.visible }); this.refs.BaseSlipMask.hide(); }); }, 10); if (isWeb) { document.body.style.position = 'initial'; document.body.style.overflow = 'initial'; window.scrollTo(0, this.state.scrollPosition); } } render() { const { children, contentStyle } = this.props; const styles = this.props.themeStyle; return ( <Mask defaultVisible={this.state.defaultVisible} animate={false} maskClosable={false} ref="BaseSlipMask" onVisibleChanged={this.onVisibleChanged} onShow={this.onMaskShow} onHide={this.onMaskHide} style={styles.mask} > <Touchable style={styles['fullscreen-body']} onPress={this.onMaskPress}> <Touchable ref="slipPane" style={[styles.pane, this.calcInitStyle(), contentStyle]} onPress={this.onPanePress} > {children} </Touchable> </Touchable> </Mask> ); } } Slip.propTypes = { direction: PropTypes.oneOf(['left', 'right', 'top', 'bottom']), maskClosable: PropTypes.boolean, effect: PropTypes.oneOf(['ease-in', 'ease-in-out', 'ease-out', 'linear', 'cubic-bezier']), width: PropTypes.number, height: PropTypes.number, contentStyle: PropTypes.any, duration: PropTypes.number, }; Slip.defaultProps = { direction: 'bottom', maskClosable: false, effect: 'ease-in-out', duration: 200, width: 750, contentStyle: {}, }; Slip.displayName = 'Slip'; const StyledSlip = connectStyle(stylesProvider)(Slip); export default StyledSlip;