UNPKG

react-focus-trap

Version:

Traps focus for accessible dropdowns and modal content.

170 lines (130 loc) 4.36 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = _interopDefault(require('react')); /** * FocalPoint * The container that will maintain focus */ var timer = null; var isDOM = typeof document !== 'undefined'; var defaultProps$1 = { element: 'div' }; var FocalPoint = (function (superclass) { function FocalPoint(props, context) { superclass.call(this, props, context); this.anchor = null; this.focus = this.focus.bind(this); this._onBlur = this._onBlur.bind(this); this._setRoot = this._setRoot.bind(this); } if ( superclass ) FocalPoint.__proto__ = superclass; FocalPoint.prototype = Object.create( superclass && superclass.prototype ); FocalPoint.prototype.constructor = FocalPoint; FocalPoint.prototype.contains = function contains (element) { return this.root.contains(element) }; FocalPoint.prototype.focus = function focus () { if (this.contains(document.activeElement) === false) { this.root.focus(); } }; FocalPoint.prototype.trapFocus = function trapFocus (e) { clearTimeout(timer); timer = setTimeout(this.focus, 10); }; FocalPoint.prototype.returnFocus = function returnFocus () { // When transitioning between pages using hash route state, // this anchor is some times lost. Do not attempt to focus // on a non-existent anchor. if ( this.anchor && typeof this.anchor === 'object' && typeof this.anchor.focus === 'function' ) { this.anchor.focus(); } }; FocalPoint.prototype.componentWillMount = function componentWillMount () { if (isDOM) { this.anchor = document.activeElement; } }; FocalPoint.prototype.componentDidMount = function componentDidMount () { this.trapFocus(); document.addEventListener('focus', this._onBlur, true); }; FocalPoint.prototype.componentWillUnmount = function componentWillUnmount () { document.removeEventListener('focus', this._onBlur, true); clearTimeout(timer); this.returnFocus(); this.anchor = null; }; FocalPoint.prototype.render = function render () { var ref = this.props; var children = ref.children; var element = ref.element; var className = ref.className; return React.createElement(element, { ref: this._setRoot, tabIndex: 0, className: className, children: children }) }; // Private -------------------------------------------------- // FocalPoint.prototype._setRoot = function _setRoot (el) { this.root = el; }; FocalPoint.prototype._onBlur = function _onBlur (event) { var current = this.anchor; if (current && current.contains(event.target) === false) { event.preventDefault(); this.trapFocus(); } }; return FocalPoint; }(React.Component)); FocalPoint.defaultProps = defaultProps$1; var defaultProps = { active: true, className: 'focus-trap', onExit: function () {} }; var FocusTrap = (function (superclass) { function FocusTrap(props, context) { superclass.call(this, props, context); this._onKeyUp = this._onKeyUp.bind(this); } if ( superclass ) FocusTrap.__proto__ = superclass; FocusTrap.prototype = Object.create( superclass && superclass.prototype ); FocusTrap.prototype.constructor = FocusTrap; FocusTrap.prototype.render = function render () { var ref = this.props; var active = ref.active; var className = ref.className; var children = ref.children; var element = ref.element; var onExit = ref.onExit; if (!active) { return null } return ( React.createElement( 'div', { className: (className + "-wrapper"), onKeyUp: this._onKeyUp }, React.createElement( 'div', { 'aria-hidden': "true", className: (className + "-backdrop"), onClick: onExit }), React.createElement( FocalPoint, { className: className, element: element }, children ) ) ) }; // Private -------------------------------------------------- // FocusTrap.prototype._onKeyUp = function _onKeyUp (event) { if (event.key === 'Escape') { this.props.onExit(); } }; return FocusTrap; }(React.Component)); FocusTrap.defaultProps = defaultProps; module.exports = FocusTrap; //# sourceMappingURL=index.js.map