UNPKG

@shopify/polaris

Version:

Shopify’s product component library

61 lines (60 loc) 2.25 kB
import React from 'react'; import { closest } from '@shopify/javascript-utilities/dom'; import { focusFirstFocusableNode, findFirstFocusableNode, focusLastFocusableNode, } from '@shopify/javascript-utilities/focus'; import { EventListener } from '../EventListener'; import { Focus } from '../Focus'; export class TrapFocus extends React.PureComponent { constructor() { super(...arguments); this.state = { shouldFocusSelf: undefined, }; this.setFocusTrapWrapper = (node) => { this.focusTrapWrapper = node; }; this.handleBlur = (event) => { const { relatedTarget } = event; const { focusTrapWrapper } = this; const { trapping = true } = this.props; if (relatedTarget == null || trapping === false) { return; } if (focusTrapWrapper && !focusTrapWrapper.contains(relatedTarget) && !closest(relatedTarget, '[data-polaris-overlay]')) { event.preventDefault(); if (event.srcElement === findFirstFocusableNode(focusTrapWrapper)) { return focusLastFocusableNode(focusTrapWrapper); } focusFirstFocusableNode(focusTrapWrapper); } }; } componentDidMount() { this.setState(this.handleTrappingChange()); } handleTrappingChange() { const { trapping = true } = this.props; if (this.focusTrapWrapper.contains(document.activeElement)) { return { shouldFocusSelf: false }; } return { shouldFocusSelf: trapping }; } render() { const { children } = this.props; return (<Focus disabled={this.shouldDisable} root={this.focusTrapWrapper}> <div ref={this.setFocusTrapWrapper}> <EventListener event="focusout" handler={this.handleBlur}/> {children} </div> </Focus>); } get shouldDisable() { const { trapping = true } = this.props; const { shouldFocusSelf } = this.state; if (shouldFocusSelf === undefined) { return true; } return shouldFocusSelf ? !trapping : !shouldFocusSelf; } }