"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var React = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactClientsideEffect = _interopRequireDefault(require("react-clientside-effect")); var _focusLock = _interopRequireWildcard(require("focus-lock")); var _util = require("./util"); var _medium = require("./medium"); /* eslint-disable no-mixed-operators */ var focusOnBody = function focusOnBody() { return document && document.activeElement === document.body; }; var isFreeFocus = function isFreeFocus() { return focusOnBody() || (0, _focusLock.focusIsHidden)(); }; var lastActiveTrap = null; var lastActiveFocus = null; var lastPortaledElement = null; var focusWasOutsideWindow = false; var defaultWhitelist = function defaultWhitelist() { return true; }; var focusWhitelisted = function focusWhitelisted(activeElement) { return (lastActiveTrap.whiteList || defaultWhitelist)(activeElement); }; var recordPortal = function recordPortal(observerNode, portaledElement) { lastPortaledElement = { observerNode: observerNode, portaledElement: portaledElement }; }; var focusIsPortaledPair = function focusIsPortaledPair(element) { return lastPortaledElement && lastPortaledElement.portaledElement === element; }; function autoGuard(startIndex, end, step, allNodes) { var lastGuard = null; var i = startIndex; do { var item = allNodes[i]; if (item.guard) { if (item.node.dataset.focusAutoGuard) { lastGuard = item; } } else if (item.lockItem) { if (i !== startIndex) { // we will tab to the next element return; } lastGuard = null; } else { break; } } while ((i += step) !== end); if (lastGuard) { lastGuard.node.tabIndex = 0; } } var extractRef = function extractRef(ref) { return ref && 'current' in ref ? ref.current : ref; }; var focusWasOutside = function focusWasOutside(crossFrameOption) { if (crossFrameOption) { // with cross frame return true for any value return Boolean(focusWasOutsideWindow); } // in other case return only of focus went a while aho return focusWasOutsideWindow === 'meanwhile'; }; var checkInHost = function checkInHost(check, el, boundary) { return el && ( // find host equal to active element and check nested active element el.host === check && (!el.activeElement || boundary.contains(el.activeElement)) // dive up || el.parentNode && checkInHost(check, el.parentNode, boundary)); }; var withinHost = function withinHost(activeElement, workingArea) { return workingArea.some(function (area) { return checkInHost(activeElement, area, area); }); }; var activateTrap = function activateTrap() { var result = false; if (lastActiveTrap) { var _lastActiveTrap = lastActiveTrap, observed = _lastActiveTrap.observed, persistentFocus = _lastActiveTrap.persistentFocus, autoFocus = _lastActiveTrap.autoFocus, shards = _lastActiveTrap.shards, crossFrame = _lastActiveTrap.crossFrame, focusOptions = _lastActiveTrap.focusOptions; var workingNode = observed || lastPortaledElement && lastPortaledElement.portaledElement; var activeElement = document && document.activeElement; if (workingNode) { var workingArea = [workingNode].concat((0, _toConsumableArray2["default"])(shards.map(extractRef).filter(Boolean))); if (!activeElement || focusWhitelisted(activeElement)) { if (persistentFocus || focusWasOutside(crossFrame) || !isFreeFocus() || !lastActiveFocus && autoFocus) { if (workingNode && !( // active element is "inside" working area (0, _focusLock.focusInside)(workingArea) || // check for shadow-dom contained elements activeElement && withinHost(activeElement, workingArea) || focusIsPortaledPair(activeElement, workingNode))) { if (document && !lastActiveFocus && activeElement && !autoFocus) { // Check if blur() exists, which is missing on certain elements on IE if (activeElement.blur) { activeElement.blur(); } document.body.focus(); } else { result = (0, _focusLock["default"])(workingArea, lastActiveFocus, { focusOptions: focusOptions }); lastPortaledElement = {}; } } focusWasOutsideWindow = false; lastActiveFocus = document && document.activeElement; } } if (document) { var newActiveElement = document && document.activeElement; var allNodes = (0, _focusLock.getFocusabledIn)(workingArea); var focusedIndex = allNodes.map(function (_ref) { var node = _ref.node; return node; }).indexOf(newActiveElement); if (focusedIndex > -1) { // remove old focus allNodes.filter(function (_ref2) { var guard = _ref2.guard, node = _ref2.node; return guard && node.dataset.focusAutoGuard; }).forEach(function (_ref3) { var node = _ref3.node; return node.removeAttribute('tabIndex'); }); autoGuard(focusedIndex, allNodes.length, +1, allNodes); autoGuard(focusedIndex, -1, -1, allNodes); } } } } return result; }; var onTrap = function onTrap(event) { if (activateTrap() && event) { // prevent scroll jump event.stopPropagation(); event.preventDefault(); } }; var onBlur = function onBlur() { return (0, _util.deferAction)(activateTrap); }; var onFocus = function onFocus(event) { // detect portal var source = event.target; var currentNode = event.currentTarget; if (!currentNode.contains(source)) { recordPortal(currentNode, source); } }; var FocusWatcher = function FocusWatcher() { return null; }; var FocusTrap = function FocusTrap(_ref4) { var children = _ref4.children; return /*#__PURE__*/React.createElement("div", { onBlur: onBlur, onFocus: onFocus }, children); }; FocusTrap.propTypes = process.env.NODE_ENV !== "production" ? { children: _propTypes["default"].node.isRequired } : {}; var onWindowBlur = function onWindowBlur() { focusWasOutsideWindow = 'just'; // using setTimeout to set this variable after React/sidecar reaction (0, _util.deferAction)(function () { focusWasOutsideWindow = 'meanwhile'; }); }; var attachHandler = function attachHandler() { document.addEventListener('focusin', onTrap); document.addEventListener('focusout', onBlur); window.addEventListener('blur', onWindowBlur); }; var detachHandler = function detachHandler() { document.removeEventListener('focusin', onTrap); document.removeEventListener('focusout', onBlur); window.removeEventListener('blur', onWindowBlur); }; function reducePropsToState(propsList) { return propsList.filter(function (_ref5) { var disabled = _ref5.disabled; return !disabled; }); } function handleStateChangeOnClient(traps) { var trap = traps.slice(-1)[0]; if (trap && !lastActiveTrap) { attachHandler(); } var lastTrap = lastActiveTrap; var sameTrap = lastTrap && trap && trap.id === lastTrap.id; lastActiveTrap = trap; if (lastTrap && !sameTrap) { lastTrap.onDeactivation(); // return focus only of last trap was removed if (!traps.filter(function (_ref6) { var id = _ref6.id; return id === lastTrap.id; }).length) { // allow defer is no other trap is awaiting restore lastTrap.returnFocus(!trap); } } if (trap) { lastActiveFocus = null; if (!sameTrap || lastTrap.observed !== trap.observed) { trap.onActivation(); } activateTrap(true); (0, _util.deferAction)(activateTrap); } else { detachHandler(); lastActiveFocus = null; } } // bind medium _medium.mediumFocus.assignSyncMedium(onFocus); _medium.mediumBlur.assignMedium(onBlur); _medium.mediumEffect.assignMedium(function (cb) { return cb({ moveFocusInside: _focusLock["default"], focusInside: _focusLock.focusInside }); }); var _default = (0, _reactClientsideEffect["default"])(reducePropsToState, handleStateChangeOnClient)(FocusWatcher); exports["default"] = _default;