diff --git a/Example/android/build.gradle b/Example/android/build.gradle index eed9972..f96eb32 100644 --- a/Example/android/build.gradle +++ b/Example/android/build.gradle @@ -2,10 +2,11 @@ buildscript { repositories { - jcenter() + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath("com.android.tools.build:gradle:4.2.2") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,7 +16,7 @@ buildscript { allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" diff --git a/lib/Popover.js b/lib/Popover.js index b624755..3549639 100644 --- a/lib/Popover.js +++ b/lib/Popover.js @@ -1,107 +1,108 @@ import React, { PureComponent } from 'react'; -import { findNodeHandle, Text, ViewPropTypes } from 'react-native'; +import { findNodeHandle } from 'react-native'; import PropTypes from 'prop-types'; import { v4 as uuidv4 } from 'uuid'; class Popover extends PureComponent { static contextTypes = { - registerPopover: PropTypes.func, - unregisterPopover: PropTypes.func, + registerPopover: PropTypes.func, + unregisterPopover: PropTypes.func, }; static propTypes = { - children: PropTypes.node, - isVisible: PropTypes.bool, - arrowColor: PropTypes.string, - arrowWidth: PropTypes.number, - arrowHeight: PropTypes.number, - placement: PropTypes.oneOf(['left', 'right', 'top', 'bottom', 'auto']), - pointerEvents: PropTypes.string, - offset: PropTypes.shape({ - x: PropTypes.number.isRequired, - y: PropTypes.number.isRequired, - }), + children: PropTypes.node, + isVisible: PropTypes.bool, + arrowColor: PropTypes.string, + arrowWidth: PropTypes.number, + arrowHeight: PropTypes.number, + placement: PropTypes.oneOf(['left', 'right', 'top', 'bottom', 'auto']), + pointerEvents: PropTypes.string, + offset: PropTypes.shape({ + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired, + }), }; static defaultProps = { - children: null, - isVisible: true, - arrowColor: 'white', - arrowWidth: 15, - arrowHeight: 10, - placement: 'auto', - pointerEvents: 'box-none', - offset: { - x: 0, - y: 0, - }, + children: null, + isVisible: true, + arrowColor: 'white', + arrowWidth: 15, + arrowHeight: 10, + placement: 'auto', + pointerEvents: 'box-none', + offset: { + x: 0, + y: 0, + }, }; constructor(props) { - super(props); - this._id = uuidv4(); + super(props); + this._id = uuidv4(); } componentDidMount() { - if (!this.props.isVisible) { - return; - } - this.registerSelf(); + if (!this.props.isVisible) { + return; + } + this.registerSelf(); } componentDidUpdate(prevProps) { - if (prevProps.isVisible !== this.props.isVisible || prevProps.placement !== this.props.placement) { - if (this.props.isVisible) { - this.registerSelf(); - } else { - this.unregisterSelf(); + if (prevProps.isVisible !== this.props.isVisible || prevProps.placement !== this.props.placement) { + if (this.props.isVisible) { + this.registerSelf(); + } else { + this.unregisterSelf(); + } } - } } componentWillUnmount() { - this.unregisterSelf(); + this.unregisterSelf(); } - setElementRef = x => { - this._element = x; + setElementRef = (x) => { + this._element = x; }; registerSelf() { - // delay to the next tick to guarantee layout - setTimeout(() => { - if (this._element !== null) { - const { - arrowColor, - arrowWidth, - arrowHeight, - placement, - component, - pointerEvents, - offset, - } = this.props; - this.context.registerPopover(this._id, findNodeHandle(this._element), { - arrowColor, - arrowWidth, - arrowHeight, - placement, - component, - pointerEvents, - offset, - }); - } - }); + // delay to the next tick to guarantee layout + setTimeout(() => { + if (this._element !== null) { + const { + arrowColor, + arrowWidth, + arrowHeight, + placement, + component, + pointerEvents, + offset, + } = this.props; + this.context.registerPopover(this._id, findNodeHandle(this._element), { + arrowColor, + arrowWidth, + arrowHeight, + placement, + component, + pointerEvents, + offset, + }); + } + }); } unregisterSelf() { - this.context.unregisterPopover(this._id); + this.context.unregisterPopover(this._id); } render() { - const child = React.Children.only(this.props.children); - return React.cloneElement(child, { - ref: this.setElementRef, - }); + const child = React.Children.only(this.props.children); + return React.cloneElement(child, { + ref: this.setElementRef, + collapsable: false, // to avoid crashes on Android + }); } } diff --git a/lib/PopoverContainer.js b/lib/PopoverContainer.js index db1e930..7dbaa2f 100644 --- a/lib/PopoverContainer.js +++ b/lib/PopoverContainer.js @@ -1,95 +1,111 @@ import React, { Component } from 'react'; -import { PanResponder, findNodeHandle, UIManager, View } from 'react-native'; +import { UIManager, View } from 'react-native'; import PropTypes from 'prop-types'; import PopoverElement from './PopoverElement'; const addKey = (obj, key, value) => ({ ...obj, [key]: value }); const delKey = (obj, key) => { - const copy = Object.assign({}, obj); - delete copy[key]; - return copy; + const copy = Object.assign({}, obj); + delete copy[key]; + return copy; }; class PopoverContainer extends Component { static propTypes = { - children: PropTypes.node, - padding: PropTypes.number, + children: PropTypes.node, + padding: PropTypes.number, }; static defaultProps = { - children: null, - padding: 0, + children: null, + padding: 0, }; static childContextTypes = { - registerPopover: PropTypes.func, - unregisterPopover: PropTypes.func, + registerPopover: PropTypes.func, + unregisterPopover: PropTypes.func, }; state = { - registry: {}, - containerSize: null, + registry: {}, + containerSize: null, }; getChildContext() { - return { - registerPopover: this.registerPopover, - unregisterPopover: this.unregisterPopover, - }; + return { + registerPopover: this.registerPopover, + unregisterPopover: this.unregisterPopover, + }; } onRootLayout = ({ nativeEvent: { layout: { width, height } } }) => { - this.setState({ containerSize: { width, height } }); + this.setState({ containerSize: { width, height } }); }; registerPopover = (id, element, props) => { - if (this.state.containerSize === null) { - setTimeout(() => this.registerPopover(id, element, props)); - return; - } - UIManager.measureLayout( - element, - findNodeHandle(this._root), - err => { - console.error(err); - }, - (x, y, width, height) => { - this.setState({ - registry: addKey(this.state.registry, id, { - rect: { x, y, width, height }, - props, - }), - }); - }, - ); + if (this.state.containerSize === null) { + setTimeout(() => this.registerPopover(id, element, props)); + return; + } + UIManager.measureInWindow( + element, + (x, y, width, height) => { + this.setState({ + registry: addKey(this.state.registry, id, { + rect: { + x, y, width, height, + }, + props, + }), + }); + }, + ); + /* TODO: investigate why the code bellow doesn't work + UIManager.measureLayout( + element, + findNodeHandle(this._root), + (err) => { + console.error(err); + }, + (x, y, width, height) => { + this.setState({ + registry: addKey(this.state.registry, id, { + rect: { + x, y, width, height, + }, + props, + }), + }); + }, + ); + */ }; - unregisterPopover = id => { - this.setState({ registry: delKey(this.state.registry, id) }); + unregisterPopover = (id) => { + this.setState(state => ({ registry: delKey(state.registry, id) })); }; render() { - return ( - { - this._root = x; - }} - style={{ flex: 1 }} - onLayout={this.onRootLayout} - > - {this.props.children} - {Object.entries(this.state.registry).map(([id, { rect, props }]) => - , - )} - - ); + return ( + { + this._root = x; + }} + style={{ flex: 1 }} + onLayout={this.onRootLayout} + > + {this.props.children} + {Object.entries(this.state.registry).map(([id, { rect, props }]) => + ())} + + ); } } diff --git a/lib/PopoverElement.js b/lib/PopoverElement.js index 99d139c..e982493 100644 --- a/lib/PopoverElement.js +++ b/lib/PopoverElement.js @@ -1,9 +1,8 @@ import React, { Component } from 'react'; -import { StyleSheet, View, ViewPropTypes } from 'react-native'; +import { StyleSheet, View } from 'react-native'; import PropTypes from 'prop-types'; import computeGeometry from './computeGeometry'; import { - PLACEMENT_OPTIONS, capitalizeFirstLetter, findDirectionWithoutColor, } from './utils'; @@ -95,6 +94,9 @@ class PopoverElement extends Component { } measureLayout = ({ nativeEvent: { layout: { width, height } } }) => { + if (width === this.state.width && height === this.state.height) { + return; + } this.setState({ width, height }, () => this.computeStyles(this.props)); };