UNPKG

@shopify/polaris

Version:

Shopify’s product component library

77 lines (76 loc) 3.26 kB
import * as tslib_1 from "tslib"; import React from 'react'; import { createUniqueIDFactory } from '@shopify/javascript-utilities/other'; import { focusFirstFocusableNode, findFirstFocusableNode, } from '@shopify/javascript-utilities/focus'; import { Portal } from '../Portal'; import { CloseSource, Pane, PopoverOverlay, Section } from './components'; export { CloseSource }; const getUniqueID = createUniqueIDFactory('Popover'); export class Popover extends React.PureComponent { constructor() { super(...arguments); this.state = { activatorNode: null, }; this.activatorContainer = null; this.id = getUniqueID(); this.handleClose = (source) => { this.props.onClose(source); if (this.activatorContainer == null) { return; } if (source === CloseSource.FocusOut || source === CloseSource.EscapeKeypress) { focusFirstFocusableNode(this.activatorContainer, false); } }; this.setActivator = (node) => { if (node == null) { this.activatorContainer = null; this.setState({ activatorNode: null }); return; } this.setState({ activatorNode: node.firstElementChild }); this.activatorContainer = node; }; } componentDidMount() { this.setAccessibilityAttributes(); } componentDidUpdate() { if (this.activatorContainer && this.state.activatorNode && !this.activatorContainer.contains(this.state.activatorNode)) { this.setActivator(this.activatorContainer); } this.setAccessibilityAttributes(); } render() { const _a = this.props, { activatorWrapper: WrapperComponent = 'div', children, onClose, activator, active, fixed } = _a, rest = tslib_1.__rest(_a, ["activatorWrapper", "children", "onClose", "activator", "active", "fixed"]); const { activatorNode } = this.state; const portal = activatorNode ? (<Portal idPrefix="popover" testID="portal"> <PopoverOverlay testID="popoverOverlay" id={this.id} activator={activatorNode} onClose={this.handleClose} active={active} fixed={fixed} {...rest}> {children} </PopoverOverlay> </Portal>) : null; return (<WrapperComponent testID="wrapper-component" ref={this.setActivator}> {React.Children.only(this.props.activator)} {portal} </WrapperComponent>); } setAccessibilityAttributes() { const { id, activatorContainer } = this; if (activatorContainer == null) { return; } const firstFocusable = findFirstFocusableNode(activatorContainer); const focusableActivator = firstFocusable || activatorContainer; focusableActivator.tabIndex = focusableActivator.tabIndex || 0; focusableActivator.setAttribute('aria-controls', id); focusableActivator.setAttribute('aria-owns', id); focusableActivator.setAttribute('aria-haspopup', 'true'); focusableActivator.setAttribute('aria-expanded', String(this.props.active)); } } Popover.Pane = Pane; Popover.Section = Section;