Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-native-popover-view

Package Overview
Dependencies
Maintainers
1
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-popover-view

A component for react-native

  • 0.5.2
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

react-native-popover-view

npm version npm version npm licence

A well-tested, adaptable, lightweight <Popover> component for react-native. Great for use in Tablets; you can put entire views that you would normally show in a modal (on a smaller device) into a popover, optionally give it an anchor point, and have it float on top of all of the other views.

It is written entirely in JavaScript, but uses React Native's native driver for responsive animations, even when the JS thread is busy.

The <Popover> is able to handle dynamic content and adapt to screen size changes while showing, and will move out of the way for on-screen keyboards automatically.

A Note on Origins

This is a fork of react-native-popover, originally created by Jean Regisser but since abandoned.

I have rebuilt most of the library from the ground up for improved handling of changing screen sizes on tablets (split-screen mode), a redesigned automatic placement algorithm, and ES6 compatibility.

Similar forks exist on Github (such as react-native-modal-popover), but this is the first to be published on NPM as far as I know.

Demo

Table of Contents

Installation

npm i --save react-native-popover-view@latest

or

yarn add react-native-popover-view@latest

Standalone Usage

import Popover from 'react-native-popover-view'

...
  render (
    <Popover
      isVisible={this.state.isVisible} />
      <CustomElement />
    </Popover>
  )

Props

PropTypeOptionalDefaultDescription
isVisibleboolYesfalseShow/Hide the popover
fromRectrectYesnullRectangle at which to anchor the popover. If not provided, the popover will appear in the center of the screen.
displayArearectYesscreen rectArea where the popover is allowed to be displayed
placementstringYes'auto'How to position the popover - top | bottom | left | right | auto. When 'auto' is specified, it will determine the ideal placement so that the popover is fully visible within displayArea.
onClosefunctionYesCallback to be fired when the user taps the popover
doneClosingCallbackfunctionYesCallback to be fired when the popover is finished closing (after animation)
showInModalboolYestrueWhether the Popover should be encapsulated in the Modal view from RN, which allows it to show above all other content, or just be present in the view hierarchy like a normal view.
showArrowboolYestrueWhether the arrow that points to the rect (passing in as fromRect) is shown. If fromRect is null, the arrow will never be shown.
showBackgroundboolYestrueWhether the background behind the popover darkens when the popover is shown.

rect is an object with the following properties: {x: number, y: number, width: number, height: number}. You can create the object yourself, or import Popover, { Rect } from 'react-native-popover-view and create a rect by calling new Rect(x, y, width, height).

Full Example

import React, { Component } from 'react';
import Popover from 'react-native-popover-view';
import {
  AppRegistry,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
} from 'react-native';

class PopoverExample extends Component {
  this.state = {
    isVisible: false,
    buttonRect: {},
  }

  showPopover() {
    this.refs.button.measure((ox, oy, width, height, px, py) => {
      this.setState({
        isVisible: true,
        buttonRect: {x: px, y: py, width: width, height: height}
      });
    });
  },

  closePopover() {
    this.setState({isVisible: false});
  },

  render() {
    return (
      <View style={styles.container}>
        <TouchableHighlight ref='button' style={styles.button} onPress={this.showPopover}>
          <Text style={styles.buttonText}>Press me</Text>
        </TouchableHighlight>

        <Popover
          isVisible={this.state.isVisible}
          fromRect={this.state.buttonRect}
          onClose={this.closePopover}>
          <Text>I'm the content of this popover!</Text>
        </Popover>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgb(43, 186, 180)',
  },
  button: {
    borderRadius: 4,
    padding: 10,
    marginLeft: 10,
    marginRight: 10,
    backgroundColor: '#ccc',
    borderColor: '#333',
    borderWidth: 1,
  },
  buttonText: {
  }
});

AppRegistry.registerComponent('PopoverExample', () => PopoverExample);

Usage with React Navigation

This can also be integrated with react-navigation's StackNavigator, so that on tablets, views higher up in the stack show in a popover instead of a full-screen modal.

Basic Setup

1) Add HOC around Root Component

In your index file, add:

import { withPopoverNavigationRootWrapper } from 'react-native-popover-view'
...
AppRegistry.registerComponent('AppName', () => withPopoverNavigationRootWrapper(RootComponent));

This simply passes updates in the screen size to Popover components that are currently showing, so that if your app is moved into split screen while a Popover is showing, it can adapt to the new display area.

2) Define when Popover should be shown

You also need to provide a function that returns when a popover should be used instead of a full-screen modal (which is default for react-navigation). This is best done in the constructor of your root component or in global space. Here is an example that uses the isTablet function from react-native-device-info; however, you can provide a function that uses whatever you want to make a distinction.

import DeviceInfo from 'react-native-device-info'

PopoverNavigation.setShouldShowInPopover(() => DeviceInfo.isTablet())
3) Change StackNavigator to PopoverStackNavigator

PopoverStackNavigator is a drop-in replacement for react-navigation's StackNavigator. It assumes the first view in your RouteConfigs is the base view, and every other view should be shown in a Popover when the function you passed to setShouldShowInPopover returns true. You can pass a few per-screen options through your RouteConfigs:

OptionTypeDefaultDescription
placementPLACEMENT_OPTIONSPLACEMENT_OPTIONS.AUTOPassed through to Popover.
preferedWidthnumber380The width for the internal view that wraps the Popover. (Default 380)
preferedWidthnumbernull (allows view to fill display area vertically)The height for the internal view that wraps the Popover.
showInModalbooleantruePassed through to Popover. If you want to stack multiple Popover's, only the bottom one can be shown in a Modal on iOS.

You can also pass some global options in your StackNavigatorConfig, which are all passed through to each Popover in the stack: showArrow, showBackground, and arrowSize. See the Popover props above for details of these.

Example:

let stack = PopoverStackNavigator({
  BaseView: {
    screen: BaseView,
    navigationOptions: ({navigation}) => {{title: 'BaseView', ...otherOptions}}
  },
  ModalView: {
    screen: ModalView,
    navigationOptions: ({navigation}) => {{title: 'ModalView', ...otherOptions}},
    popoverOptions: {
      preferedWidth: 500
    }
  }
}, 
{
  mode: 'modal',
  popoverOptions: {
    showArrow: false
  }
});
4) (Optional) Update your navigate calls with fromRect Information

If you want certain popovers to show from a rect, you need to pass this in as params to the navigate() call. For Example:

import { Rect } from 'react-native-popover-view';
...
  this.props.navigation.navigate('NextView', {fromRect: new Rect(10, 10, 40, 20), ...otherParams});

If the rect uses variables that could change when the display area changes, you should instead use calculateRect, and pass in a function that will return the rect. For example, if your popover originates from a button that is always centered, regardless of screen size, you could use the following:

import { Rect } from 'react-native-popover-view';
...
  this.props.navigation.navigate('NextView`, {calculateRect: () => new Rect(this.state.width/2 - 20, 50, 40, 20), ...otherParams});

Now, if your app is put into split-screen mode while the popover is still showing, calculateRect will be called again, and the popover will shift to point to the new rect.

Advanced Usage

Custumize Display Area used by Popovers

If you use withPopoverNavigationRootWrapper, the Popovers use a display area of: {x: 10, y: Platform.OS === 'ios' ? 20 : 10, width: APP_WIDTH - 20, height: APP_HEIGHT - (Platform.OS === 'ios' ? 30 : 20)}. If you want to restrict the display area of each Popover to a different area, you can set it yourself. Instead of wrapping your root component with withPopoverNavigationRootWrapper, just wrap it instead with a View, and in the onLayout callback, pass a rect to PopoverNavigation.setDisplayArea. For example:

import { PopoverNavigation, Rect } from 'react-native-popover-view'
...
class RootComponent {
  ...
  render() {
    return (
      <View onLayout={event => PopoverNavigation.setDisplayArea(new Rect(event.nativeEvent.layout.width/2 - 50, ...))}>
        <RestOfViews />
      </View>
    )
  }
}

AppRegistry.registerComponent('AppName', () => RootComponent);

Full Example

import React, { Component } from 'react';
import { withPopoverNavigationRootWrapper, PopoverStackNavigator } from 'react-native-popover-view';
import { MoreHeaderView, ExtraInfoView, MoreOptionView } from './myOtherViews';
import { Colors } from './Colors';
import DeviceInfo from 'react-native-device-info';

// Note: storing the width globally like this is not a good practice,
//       and is only used for the sake of simplicity in this example
let width = 0;

function isTablet() {
  return DeviceInfo.isTablet() && width > 500;
}

// Note: This is not exhaustive
const headerHeight = Platform.OS === 'ios' ? 64 : 54;

PopoverNavigation.setShouldShowInPopover(isTablet);

class MoreView extends Component {
  buttonPressed(option) {
    let rect = new Rect(width / 2 - 50, this.buttonLocations[option.key] + headerHeight, 100, 40);
    this.props.navigate('MoreOptionView', {fromRect: rect, title: option.tite, option});
  }

  render() {
    let moreOptions = this.props.options;

    return (
      <View style={styles.viewStyle} onLayout={evt => width = evt.nativeEvent.layout.width}>
        <MoreHeaderView />
        <View>
          {moreOptions.map(option => (
            <TouchableHighlight style={styles.buttonStyle} onPress={() => this.buttonPressed(option)}>
              <Text>{option.title}</Text>
            </TouchableHighlight>
            ))}
        </View>
        <ExtraInfoView />
      </View>
    )
  }
}

let MoreStack = PopoverStackNavigator({
  MoreView: {
    screen: MoreView,
    navigationOptions: ({navigation}) => ({title: 'More'})
  },
  MoreOptionView: {
    screen: MoreOptionView,
    navigationOptions: ({navigation}) => Object.assign({}, {title: navigation.state.params.title}, isTablet() ? {header: null} : styles.headerStyle)
  }
}, {
  headerMode: 'screen'
});

// If this view is included in a larger application, you should put the wrapper as high up as possible
// It is included here because this is the highest place in this example
export default withPopoverNavigationRootWrapper(MoreStack);

let styles = {
  buttonStyle: {
    width: 100,
    height: 40
  },
  viewStyle: {
    alignItems: 'center'
  },
  headerStyle: {
    headerStyle: {
      backgroundColor: Colors.backgroundColor
    },
    headerTintColor: Colors.tintColor,
    headerTitleStyle: {
      color: Colors.headerTextColor
    }
  }
}

Credits

Original codebase created by Jean Regisser jean.regisser@gmail.com (https://github.com/jeanregisser) as react-native-popover, which has been abandoned

The code supporting animations was inspired and adapted from @brentvatne's Transition.js mixin.


MIT Licensed

Keywords

FAQs

Package last updated on 29 Dec 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc