Version

Popup

Displays a popup.

Example
body {
  overflow: hidden;
}

:global(.button) {
  position: absolute;
  left: 50px;
  bottom: 50px;
}

:global(.anchor) {
  position: absolute;
  width: 10px;
  height: 10px;
}

:global(.topLeft) {
  left: 0;
  top: 0;
  background-color: red;
}

:global(.topRight) {
  right: 0;
  top: 0;
  background-color: blue;
}

:global(.bottomLeft) {
  left: 0;
  bottom: 0;
  background-color: green;
}

:global(.bottomRight) {
  right: 0;
  bottom: 0;
  background-color: orange;
}
<div id="example"></div>
import React, {Component} from 'react';
import {render} from 'react-dom';
import classNames from 'classnames';

import Popup from '@jetbrains/ring-ui/components/popup/popup';

const {Directions} = Popup.PopupProps;

const directionMap = {
  topLeft: Directions.BOTTOM_RIGHT,
  topRight: Directions.BOTTOM_LEFT,
  bottomLeft: Directions.TOP_RIGHT,
  bottomRight: Directions.TOP_LEFT
}

const directionKeys = Object.keys(directionMap);
const initialState = directionKeys.reduce((acc, key) => {
  acc[key] = true;
  return acc;
}, {});

class PopupExample extends Component {
  state = initialState;

  renderPopup = key => (
    <div className={classNames("anchor", key)} key={key}>
      <Popup
        hidden={!this.state[key]}
        onCloseAttempt={() => this.setState({[key]: false})}
        directions={[directionMap[key]]}
      >
        <span>Hello, world!</span>
      </Popup>
    </div>
  );

  showAgain = () => setTimeout(() => {
    this.setState({bottomLeft: true});
  });

  render() {
    return (
      <div>
        {directionKeys.map(this.renderPopup)}
        <button
          className="button"
          onClick={this.showAgain}
        >Show again</button>
      </div>
    );
  }
}

render(<PopupExample />, document.getElementById('example'));

Auto-positioning a popup

Example
:global(.message) {
  position: absolute;

  top: 50%;
  left: 300px;
}

:global(.vert) {
  top: 20%;
  width: 150px;
}

:global(.anchor) {
  position: absolute;
}

:global(.left) {
  left: 0;
  top: 50px;
}

:global(.right) {
  right: 0;
  top: 50px;
}

:global(.bottom) {
  left: 150px;
  bottom: 0;
}

:global(.top) {
  right: 150px;
  top: 0;
}
<div id="example"></div>
import React from 'react';
import {render} from 'react-dom';

import Popup from '@jetbrains/ring-ui/components/popup/popup';

const Directions = Popup.PopupProps.Directions;

const content = <span className="popup">This is a popup</span>;
const example = (
  <div>
    <div className="message">Popup should
      change open direction when reaching window borders
      <Popup
        directions={[Directions.TOP_CENTER]}
      >{content}</Popup>
    </div>
    <div className="message vert">Popup should
      change open direction when reaching window borders
      <Popup
        directions={[Directions.RIGHT_CENTER]}
      >{content}</Popup>
    </div>
    <div className="anchor left">Left side open
      popup
      <Popup
        directions={[Directions.LEFT_BOTTOM, Directions.RIGHT_BOTTOM]}
      >{content}</Popup>
    </div>
    <div className="anchor right">Right side
      open popup
      <Popup
        directions={[Directions.RIGHT_BOTTOM, Directions.LEFT_BOTTOM]}
      >{content}</Popup>
    </div>
    <div className="anchor bottom">Downside open
      popup
      <Popup
        directions={[Directions.BOTTOM_RIGHT, Directions.TOP_LEFT]}
      >{content}</Popup>
    </div>
    <div className="anchor top">
      Upside open popup
      <Popup
        directions={[Directions.TOP_LEFT, Directions.BOTTOM_RIGHT]}
      >{content}</Popup>
    </div>
  </div>
);

render(example, document.getElementById('example'));

Popup in a popup

Example
:global(.parent-popup) {
  width: 100px;
  height: 100px;
  text-align: center;
}

:global(.child-popup) {
  background-color: red;
  text-align: center;
  margin: 8px;
}
<div id="example"></div>
import React, {Component} from 'react';
import {render} from 'react-dom';

import Popup from '@jetbrains/ring-ui/components/popup/popup';

class PopupBox extends Component {
  state = {hidden: false};

  render() {
    return (
      <Popup
        {...this.state}
        onCloseAttempt={() => this.setState({hidden: true})}
      >{this.props.children}</Popup>
    );
  }
}

const example = (
  <div>
    Parent popup anchor
    <PopupBox>
      <div className="parent-popup">
        This is a parent popup
        <PopupBox>
          <div className="child-popup">
            This is a child popup
          </div>
        </PopupBox>
      </div>
    </PopupBox>
  </div>
);

render(example, document.getElementById('example'));

Popup inside a scrollable container

Example
body {
  margin: 0;
}

:global(.container) {
  height: 100vh;
  overflow: auto;
}

:global(.example) {
  height: 200vh;
  display: inline-block;
}

.anchor{
  display: inline-block;
}
<div id="example"></div>
import React from 'react';
import {render} from 'react-dom';

import Popup from '@jetbrains/ring-ui/components/popup/popup';

const example = (
  <div className="container">
    <div className="example">
      <div className="anchor">
        Popup anchor
        <Popup>Popup content</Popup>
      </div>
    </div>
  </div>
);

render(example, document.getElementById('example'));

Popup fits screen

Example
body {
  margin: 0;
}

:global(html),
:global(body) {
  height: 100%;
}
:global(.popupContent) {
  height: 1300px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

:global(.anchorBottom) {
  position: absolute;
  bottom: 20px;
}
<div id="example"></div>
import React from 'react';
import {render} from 'react-dom';

import Popup from '@jetbrains/ring-ui/components/popup/popup';

const example = (
  <div className="anchorBottom">
    Popup anchor on bottom
    <Popup maxHeight={1380}>
      <div className="popupContent">
        <div>Popup top</div>
        <div>popup bottom</div>
      </div>
    </Popup>
  </div>
);

render(example, document.getElementById('example'));