diff --git a/Popover.js b/Popover.js index a937b01..b2f1eb8 100644 --- a/Popover.js +++ b/Popover.js @@ -1,6 +1,6 @@ 'use strict'; -import React, { PropTypes } from 'react'; +import React from 'react'; import { StyleSheet, Dimensions, @@ -10,6 +10,7 @@ import { View, Easing } from 'react-native'; +import PropTypes from 'prop-types'; var noop = () => {}; @@ -33,13 +34,25 @@ function Rect(x, y, width, height) { this.height = height; } -var Popover = React.createClass({ - propTypes: { +export default class Popover extends React.Component { + + static propTypes = { isVisible: PropTypes.bool, onClose: PropTypes.func, - }, - getInitialState() { - return { + } + + static defaultProps = { + isVisible: false, + displayArea: new Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), + arrowSize: DEFAULT_ARROW_SIZE, + placement: 'auto', + onClose: noop, + } + + + constructor(props) { + super(props); + this.state = { contentSize: {}, anchorPoint: {}, popoverOrigin: {}, @@ -51,16 +64,8 @@ var Popover = React.createClass({ fade: new Animated.Value(0), }, }; - }, - getDefaultProps() { - return { - isVisible: false, - displayArea: new Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), - arrowSize: DEFAULT_ARROW_SIZE, - placement: 'auto', - onClose: noop, - }; - }, + } + measureContent(x) { var {width, height} = x.nativeEvent.layout; var contentSize = {width, height}; @@ -73,7 +78,8 @@ var Popover = React.createClass({ // from the state isAwaitingShow && this._startAnimation({show: true}); }); - }, + } + computeGeometry({contentSize, placement}) { placement = placement || this.props.placement; @@ -96,7 +102,8 @@ var Popover = React.createClass({ default: return this.computeAutoGeometry(options); } - }, + } + computeTopGeometry({displayArea, fromRect, contentSize, arrowSize}) { var popoverOrigin = new Point( Math.min(displayArea.x + displayArea.width - contentSize.width, @@ -109,7 +116,8 @@ var Popover = React.createClass({ anchorPoint, placement: 'top', } - }, + } + computeBottomGeometry({displayArea, fromRect, contentSize, arrowSize}) { var popoverOrigin = new Point( Math.min(displayArea.x + displayArea.width - contentSize.width, @@ -122,7 +130,8 @@ var Popover = React.createClass({ anchorPoint, placement: 'bottom', } - }, + } + computeLeftGeometry({displayArea, fromRect, contentSize, arrowSize}) { var popoverOrigin = new Point(fromRect.x - contentSize.width - arrowSize.width, Math.min(displayArea.y + displayArea.height - contentSize.height, @@ -134,7 +143,8 @@ var Popover = React.createClass({ anchorPoint, placement: 'left', } - }, + } + computeRightGeometry({displayArea, fromRect, contentSize, arrowSize}) { var popoverOrigin = new Point(fromRect.x + fromRect.width + arrowSize.width, Math.min(displayArea.y + displayArea.height - contentSize.height, @@ -146,7 +156,8 @@ var Popover = React.createClass({ anchorPoint, placement: 'right', } - }, + } + computeAutoGeometry({displayArea, contentSize}) { var placementsToTry = ['left', 'right', 'bottom', 'top']; @@ -164,7 +175,8 @@ var Popover = React.createClass({ } return geom; - }, + } + getArrowSize(placement) { var size = this.props.arrowSize; switch(placement) { @@ -174,10 +186,12 @@ var Popover = React.createClass({ default: return size; } - }, + } + getArrowColorStyle(color) { return { borderTopColor: color }; - }, + } + getArrowRotation(placement) { switch (placement) { case 'bottom': @@ -189,7 +203,8 @@ var Popover = React.createClass({ default: return '0deg'; } - }, + } + getArrowDynamicStyle() { var {anchorPoint, popoverOrigin} = this.state; var arrowSize = this.props.arrowSize; @@ -211,14 +226,16 @@ var Popover = React.createClass({ borderBottomWidth: height / 2, borderLeftWidth: width / 2, } - }, + } + getTranslateOrigin() { var {contentSize, popoverOrigin, anchorPoint} = this.state; var popoverCenter = new Point(popoverOrigin.x + contentSize.width / 2, popoverOrigin.y + contentSize.height / 2); return new Point(anchorPoint.x - popoverCenter.x, anchorPoint.y - popoverCenter.y); - }, - componentWillReceiveProps(nextProps:any) { + } + + componentWillReceiveProps(nextProps) { var willBeVisible = nextProps.isVisible; var { isVisible, @@ -233,12 +250,14 @@ var Popover = React.createClass({ this._startAnimation({show: false}); } } - }, + } + _startAnimation({show}) { - var handler = this.props.startCustomAnimation || this._startDefaultAnimation; + var handler = this.props.startCustomAnimation || this._startDefaultAnimation.bind(this); handler({show, doneCallback: () => this.setState({isTransitioning: false})}); this.setState({isTransitioning: true}); - }, + } + _startDefaultAnimation({show, doneCallback}) { var animDuration = 300; var values = this.state.defaultAnimatedValues; @@ -267,7 +286,8 @@ var Popover = React.createClass({ ...commonConfig, }) ]).start(doneCallback); - }, + } + _getDefaultAnimatedStyles() { // If there's a custom animation handler, // we don't return the default animated styles @@ -300,7 +320,8 @@ var Popover = React.createClass({ ], } }; - }, + } + _getExtendedStyles() { var background = []; var popover = []; @@ -322,7 +343,8 @@ var Popover = React.createClass({ arrow, content, } - }, + } + render() { if (!this.props.isVisible && !this.state.isTransitioning) { return null; @@ -344,14 +366,14 @@ var Popover = React.createClass({ return ( - + - + {this.props.children} @@ -359,7 +381,7 @@ var Popover = React.createClass({ ); } -}); +} var styles = StyleSheet.create({ @@ -403,6 +425,4 @@ var styles = StyleSheet.create({ borderBottomColor: 'transparent', borderLeftColor: 'transparent', }, -}); - -module.exports = Popover; +}) diff --git a/package.json b/package.json index 57f434b..41a4744 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "react": "^15.0.2", - "react-native": "^0.26.2" + "react-native": "^0.26.2", + "prop-types": "^15.5.10" } }