UNPKG

vue-focus-lock

Version:
1,228 lines (1,061 loc) 71 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("vue-demi")); else if(typeof define === 'function' && define.amd) define("vue-focus-lock", ["vue-demi"], factory); else if(typeof exports === 'object') exports["vue-focus-lock"] = factory(require("vue-demi")); else root["vue-focus-lock"] = factory(root["vue-demi"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_29__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 15); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* unused harmony export filterFocusable */ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return filterAutoFocusable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return getTabbableNodes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getFocusableNodes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return parentAutofocusables; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return contains; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__array__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__is__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__tabOrder__ = __webpack_require__(11); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__tabUtils__ = __webpack_require__(12); /** * given list of focusable elements keeps the ones user can interact with * @param nodes * @param visibilityCache */ var filterFocusable = function (nodes, visibilityCache) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__array__["b" /* toArray */])(nodes) .filter(function (node) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__is__["a" /* isVisibleCached */])(visibilityCache, node); }) .filter(function (node) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__is__["b" /* notHiddenInput */])(node); }); }; var filterAutoFocusable = function (nodes, cache) { if (cache === void 0) { cache = new Map(); } return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__array__["b" /* toArray */])(nodes).filter(function (node) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__is__["c" /* isAutoFocusAllowedCached */])(cache, node); }); }; /** * !__WARNING__! Low level API. * @returns all tabbable nodes * * @see {@link getFocusableNodes} to get any focusable element * * @param topNodes - array of top level HTMLElements to search inside * @param visibilityCache - an cache to store intermediate measurements. Expected to be a fresh `new Map` on every call */ var getTabbableNodes = function (topNodes, visibilityCache, withGuards) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__tabOrder__["a" /* orderByTabIndex */])(filterFocusable(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__tabUtils__["a" /* getFocusables */])(topNodes, withGuards), visibilityCache), true, withGuards); }; /** * !__WARNING__! Low level API. * * @returns anything "focusable", not only tabbable. The difference is in `tabIndex=-1` * (without guards, as long as they are not expected to be ever focused) * * @see {@link getTabbableNodes} to get only tabble nodes element * * @param topNodes - array of top level HTMLElements to search inside * @param visibilityCache - an cache to store intermediate measurements. Expected to be a fresh `new Map` on every call */ var getFocusableNodes = function (topNodes, visibilityCache) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__tabOrder__["a" /* orderByTabIndex */])(filterFocusable(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__tabUtils__["a" /* getFocusables */])(topNodes), visibilityCache), false); }; /** * return list of nodes which are expected to be auto-focused * @param topNode * @param visibilityCache */ var parentAutofocusables = function (topNode, visibilityCache) { return filterFocusable(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__tabUtils__["b" /* getParentAutofocusables */])(topNode), visibilityCache); }; /* * Determines if element is contained in scope, including nested shadow DOMs */ var contains = function (scope, element) { if (scope.shadowRoot) { return contains(scope.shadowRoot, element); } else { if (Object.getPrototypeOf(scope).contains !== undefined && Object.getPrototypeOf(scope).contains.call(scope, element)) { return true; } return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__array__["b" /* toArray */])(scope.children).some(function (child) { var _a; if (child instanceof HTMLIFrameElement) { var iframeBody = (_a = child.contentDocument) === null || _a === void 0 ? void 0 : _a.body; if (iframeBody) { return contains(iframeBody, element); } return false; } return contains(child, element); }); } }; /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return toArray; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return asArray; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return getFirst; }); /* IE11 support */ var toArray = function (a) { var ret = Array(a.length); for (var i = 0; i < a.length; ++i) { ret[i] = a[i]; } return ret; }; var asArray = function (a) { return (Array.isArray(a) ? a : [a]); }; var getFirst = function (a) { return (Array.isArray(a) ? a[0] : a); }; /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return isVisibleCached; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return isAutoFocusAllowedCached; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "g", function() { return getDataset; }); /* unused harmony export isHTMLButtonElement */ /* unused harmony export isHTMLInputElement */ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "h", function() { return isRadioElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return notHiddenInput; }); /* unused harmony export isAutoFocusAllowed */ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return isGuard; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return isNotAGuard; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "f", function() { return isDefined; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(3); var isElementHidden = function (node) { // we can measure only "elements" // consider others as "visible" if (node.nodeType !== Node.ELEMENT_NODE) { return false; } var computedStyle = window.getComputedStyle(node, null); if (!computedStyle || !computedStyle.getPropertyValue) { return false; } return (computedStyle.getPropertyValue('display') === 'none' || computedStyle.getPropertyValue('visibility') === 'hidden'); }; var getParentNode = function (node) { // DOCUMENT_FRAGMENT_NODE can also point on ShadowRoot. In this case .host will point on the next node return node.parentNode && node.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE ? // eslint-disable-next-line @typescript-eslint/no-explicit-any node.parentNode.host : node.parentNode; }; var isTopNode = function (node) { // @ts-ignore return node === document || (node && node.nodeType === Node.DOCUMENT_NODE); }; var isInert = function (node) { return node.hasAttribute('inert'); }; /** * @see https://github.com/testing-library/jest-dom/blob/main/src/to-be-visible.js */ var isVisibleUncached = function (node, checkParent) { return !node || isTopNode(node) || (!isElementHidden(node) && !isInert(node) && checkParent(getParentNode(node))); }; var isVisibleCached = function (visibilityCache, node) { var cached = visibilityCache.get(node); if (cached !== undefined) { return cached; } var result = isVisibleUncached(node, isVisibleCached.bind(undefined, visibilityCache)); visibilityCache.set(node, result); return result; }; var isAutoFocusAllowedUncached = function (node, checkParent) { return node && !isTopNode(node) ? (isAutoFocusAllowed(node) ? checkParent(getParentNode(node)) : false) : true; }; var isAutoFocusAllowedCached = function (cache, node) { var cached = cache.get(node); if (cached !== undefined) { return cached; } var result = isAutoFocusAllowedUncached(node, isAutoFocusAllowedCached.bind(undefined, cache)); cache.set(node, result); return result; }; var getDataset = function (node) { // @ts-ignore return node.dataset; }; var isHTMLButtonElement = function (node) { return node.tagName === 'BUTTON'; }; var isHTMLInputElement = function (node) { return node.tagName === 'INPUT'; }; var isRadioElement = function (node) { return isHTMLInputElement(node) && node.type === 'radio'; }; var notHiddenInput = function (node) { return !((isHTMLInputElement(node) || isHTMLButtonElement(node)) && (node.type === 'hidden' || node.disabled)); }; var isAutoFocusAllowed = function (node) { var attribute = node.getAttribute(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_NO_AUTOFOCUS"]); return ![true, 'true', ''].includes(attribute); }; var isGuard = function (node) { var _a; return Boolean(node && ((_a = getDataset(node)) === null || _a === void 0 ? void 0 : _a.focusGuard)); }; var isNotAGuard = function (node) { return !isGuard(node); }; var isDefined = function (x) { return Boolean(x); }; /***/ }), /* 3 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOCUS_GROUP", function() { return FOCUS_GROUP; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOCUS_DISABLED", function() { return FOCUS_DISABLED; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOCUS_ALLOW", function() { return FOCUS_ALLOW; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOCUS_AUTO", function() { return FOCUS_AUTO; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOCUS_NO_AUTOFOCUS", function() { return FOCUS_NO_AUTOFOCUS; }); /** * defines a focus group */ var FOCUS_GROUP = 'data-focus-lock'; /** * disables element discovery inside a group marked by key */ var FOCUS_DISABLED = 'data-focus-lock-disabled'; /** * allows uncontrolled focus within the marked area, effectively disabling focus lock for it's content */ var FOCUS_ALLOW = 'data-no-focus-lock'; /** * instructs autofocus engine to pick default autofocus inside a given node * can be set on the element or container */ var FOCUS_AUTO = 'data-autofocus-inside'; /** * instructs autofocus to ignore elements within a given node * can be set on the element or container */ var FOCUS_NO_AUTOFOCUS = 'data-no-autofocus'; /***/ }), /* 4 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getAllAffectedNodes; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__array__ = __webpack_require__(1); /** * in case of multiple nodes nested inside each other * keeps only top ones * this is O(nlogn) * @param nodes * @returns {*} */ var filterNested = function (nodes) { var contained = new Set(); var l = nodes.length; for (var i = 0; i < l; i += 1) { for (var j = i + 1; j < l; j += 1) { var position = nodes[i].compareDocumentPosition(nodes[j]); /* eslint-disable no-bitwise */ if ((position & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0) { contained.add(j); } if ((position & Node.DOCUMENT_POSITION_CONTAINS) > 0) { contained.add(i); } /* eslint-enable */ } } return nodes.filter(function (_, index) { return !contained.has(index); }); }; /** * finds top most parent for a node * @param node * @returns {*} */ var getTopParent = function (node) { return node.parentNode ? getTopParent(node.parentNode) : node; }; /** * returns all "focus containers" inside a given node * @param node - node or nodes to look inside * @returns Element[] */ var getAllAffectedNodes = function (node) { var nodes = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["a" /* asArray */])(node); return nodes.filter(Boolean).reduce(function (acc, currentNode) { var group = currentNode.getAttribute(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_GROUP"]); acc.push.apply(acc, (group ? filterNested(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["b" /* toArray */])(getTopParent(currentNode).querySelectorAll("[".concat(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_GROUP"], "=\"").concat(group, "\"]:not([").concat(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_DISABLED"], "=\"disabled\"])")))) : [currentNode])); return acc; }, []); }; /***/ }), /* 5 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getActiveElement; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__safe__ = __webpack_require__(25); /** * returns active element from document or from nested shadowdoms */ /** * returns current active element. If the active element is a "container" itself(shadowRoot or iframe) returns active element inside it * @param [inDocument] */ var getActiveElement = function (inDocument) { if (inDocument === void 0) { inDocument = document; } if (!inDocument || !inDocument.activeElement) { return undefined; } var activeElement = inDocument.activeElement; return (activeElement.shadowRoot ? getActiveElement(activeElement.shadowRoot) : activeElement instanceof HTMLIFrameElement && __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__safe__["a" /* safeProbe */])(function () { return activeElement.contentWindow.document; }) ? getActiveElement(activeElement.contentWindow.document) : activeElement); }; /***/ }), /* 6 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return focusOn; }); var focusOn = function (target, focusOptions) { if (!target) { // not clear how, but is possible https://github.com/theKashey/focus-lock/issues/53 return; } if ('focus' in target) { target.focus(focusOptions); } if ('contentWindow' in target && target.contentWindow) { target.contentWindow.focus(); } }; /***/ }), /* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return focusSolver; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__solver__ = __webpack_require__(23); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_DOMutils__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_all_affected__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_array__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__utils_auto_focus__ = __webpack_require__(24); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__utils_getActiveElement__ = __webpack_require__(5); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__utils_is__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__utils_parenting__ = __webpack_require__(10); var reorderNodes = function (srcNodes, dstNodes) { var remap = new Map(); // no Set(dstNodes) for IE11 :( dstNodes.forEach(function (entity) { return remap.set(entity.node, entity); }); // remap to dstNodes return srcNodes.map(function (node) { return remap.get(node); }).filter(__WEBPACK_IMPORTED_MODULE_6__utils_is__["f" /* isDefined */]); }; /** * contains the main logic of the `focus-lock` package. * * ! you probably dont need this function ! * * given top node(s) and the last active element returns the element to be focused next * @returns element which should be focused to move focus inside * @param topNode * @param lastNode */ var focusSolver = function (topNode, lastNode) { var activeElement = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_5__utils_getActiveElement__["a" /* getActiveElement */])(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__utils_array__["a" /* asArray */])(topNode).length > 0 ? document : __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__utils_array__["c" /* getFirst */])(topNode).ownerDocument); var entries = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__utils_all_affected__["a" /* getAllAffectedNodes */])(topNode).filter(__WEBPACK_IMPORTED_MODULE_6__utils_is__["d" /* isNotAGuard */]); var commonParent = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_7__utils_parenting__["a" /* getTopCommonParent */])(activeElement || topNode, topNode, entries); var visibilityCache = new Map(); var anyFocusable = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__utils_DOMutils__["a" /* getFocusableNodes */])(entries, visibilityCache); var innerElements = anyFocusable.filter(function (_a) { var node = _a.node; return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__utils_is__["d" /* isNotAGuard */])(node); }); if (!innerElements[0]) { return undefined; } var outerNodes = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__utils_DOMutils__["a" /* getFocusableNodes */])([commonParent], visibilityCache).map(function (_a) { var node = _a.node; return node; }); var orderedInnerElements = reorderNodes(outerNodes, innerElements); // collect inner focusable and separately tabbables var innerFocusables = orderedInnerElements.map(function (_a) { var node = _a.node; return node; }); var innerTabbable = orderedInnerElements.filter(function (_a) { var tabIndex = _a.tabIndex; return tabIndex >= 0; }).map(function (_a) { var node = _a.node; return node; }); var newId = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__solver__["a" /* newFocus */])(innerFocusables, innerTabbable, outerNodes, activeElement, lastNode); if (newId === __WEBPACK_IMPORTED_MODULE_0__solver__["b" /* NEW_FOCUS */]) { var focusNode = // first try only tabbable, and the fallback to all focusable, as long as at least one element should be picked for focus __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__utils_auto_focus__["a" /* pickAutofocus */])(anyFocusable, innerTabbable, __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_7__utils_parenting__["b" /* allParentAutofocusables */])(entries, visibilityCache)) || __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__utils_auto_focus__["a" /* pickAutofocus */])(anyFocusable, innerFocusables, __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_7__utils_parenting__["b" /* allParentAutofocusables */])(entries, visibilityCache)); if (focusNode) { return { node: focusNode }; } else { console.warn('focus-lock: cannot find any node to move focus into'); return undefined; } } if (newId === undefined) { return newId; } return orderedInnerElements[newId]; }; /***/ }), /* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return correctNode; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return correctNodes; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__is__ = __webpack_require__(2); var findSelectedRadio = function (node, nodes) { return nodes .filter(__WEBPACK_IMPORTED_MODULE_0__is__["h" /* isRadioElement */]) .filter(function (el) { return el.name === node.name; }) .filter(function (el) { return el.checked; })[0] || node; }; var correctNode = function (node, nodes) { if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__is__["h" /* isRadioElement */])(node) && node.name) { return findSelectedRadio(node, nodes); } return node; }; /** * giving a set of radio inputs keeps only selected (tabbable) ones * @param nodes */ var correctNodes = function (nodes) { // IE11 has no Set(array) constructor var resultSet = new Set(); nodes.forEach(function (node) { return resultSet.add(correctNode(node, nodes)); }); // using filter to support IE11 return nodes.filter(function (node) { return resultSet.has(node); }); }; /***/ }), /* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return pickFirstFocus; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return pickFocusable; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__correctFocus__ = __webpack_require__(8); var pickFirstFocus = function (nodes) { if (nodes[0] && nodes.length > 1) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__correctFocus__["a" /* correctNode */])(nodes[0], nodes); } return nodes[0]; }; var pickFocusable = function (nodes, node) { return nodes.indexOf(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__correctFocus__["a" /* correctNode */])(node, nodes)); }; /***/ }), /* 10 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* unused harmony export getCommonParent */ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getTopCommonParent; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return allParentAutofocusables; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DOMutils__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__array__ = __webpack_require__(1); var getParents = function (node, parents) { if (parents === void 0) { parents = []; } parents.push(node); if (node.parentNode) { getParents(node.parentNode.host || node.parentNode, parents); } return parents; }; /** * finds a parent for both nodeA and nodeB * @param nodeA * @param nodeB * @returns {boolean|*} */ var getCommonParent = function (nodeA, nodeB) { var parentsA = getParents(nodeA); var parentsB = getParents(nodeB); // tslint:disable-next-line:prefer-for-of for (var i = 0; i < parentsA.length; i += 1) { var currentParent = parentsA[i]; if (parentsB.indexOf(currentParent) >= 0) { return currentParent; } } return false; }; var getTopCommonParent = function (baseActiveElement, leftEntry, rightEntries) { var activeElements = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["a" /* asArray */])(baseActiveElement); var leftEntries = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["a" /* asArray */])(leftEntry); var activeElement = activeElements[0]; var topCommon = false; leftEntries.filter(Boolean).forEach(function (entry) { topCommon = getCommonParent(topCommon || entry, entry) || topCommon; rightEntries.filter(Boolean).forEach(function (subEntry) { var common = getCommonParent(activeElement, subEntry); if (common) { if (!topCommon || __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__DOMutils__["c" /* contains */])(common, topCommon)) { topCommon = common; } else { topCommon = getCommonParent(common, topCommon); } } }); }); // TODO: add assert here? return topCommon; }; /** * return list of nodes which are expected to be autofocused inside a given top nodes * @param entries * @param visibilityCache */ var allParentAutofocusables = function (entries, visibilityCache) { return entries.reduce(function (acc, node) { return acc.concat(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__DOMutils__["d" /* parentAutofocusables */])(node, visibilityCache)); }, []); }; /***/ }), /* 11 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* unused harmony export tabSort */ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return orderByTabIndex; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__array__ = __webpack_require__(1); var tabSort = function (a, b) { var aTab = Math.max(0, a.tabIndex); var bTab = Math.max(0, b.tabIndex); var tabDiff = aTab - bTab; var indexDiff = a.index - b.index; if (tabDiff) { if (!aTab) { return 1; } if (!bTab) { return -1; } } return tabDiff || indexDiff; }; var getTabIndex = function (node) { if (node.tabIndex < 0) { // all "focusable" elements are already preselected // but some might have implicit negative tabIndex // return 0 for <audio without tabIndex attribute - it is "tabbable" if (!node.hasAttribute('tabindex')) { return 0; } } return node.tabIndex; }; var orderByTabIndex = function (nodes, filterNegative, keepGuards) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__array__["b" /* toArray */])(nodes) .map(function (node, index) { var tabIndex = getTabIndex(node); return { node: node, index: index, tabIndex: keepGuards && tabIndex === -1 ? ((node.dataset || {}).focusGuard ? 0 : -1) : tabIndex, }; }) .filter(function (data) { return !filterNegative || data.tabIndex >= 0; }) .sort(tabSort); }; /***/ }), /* 12 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getFocusables; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return getParentAutofocusables; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__array__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__tabbables__ = __webpack_require__(26); var queryTabbables = __WEBPACK_IMPORTED_MODULE_2__tabbables__["a" /* tabbables */].join(','); var queryGuardTabbables = "".concat(queryTabbables, ", [data-focus-guard]"); var getFocusablesWithShadowDom = function (parent, withGuards) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["b" /* toArray */])((parent.shadowRoot || parent).children).reduce(function (acc, child) { return acc.concat(child.matches(withGuards ? queryGuardTabbables : queryTabbables) ? [child] : [], getFocusablesWithShadowDom(child)); }, []); }; var getFocusablesWithIFrame = function (parent, withGuards) { var _a; // contentDocument of iframe will be null if current origin cannot access it if (parent instanceof HTMLIFrameElement && ((_a = parent.contentDocument) === null || _a === void 0 ? void 0 : _a.body)) { return getFocusables([parent.contentDocument.body], withGuards); } return [parent]; }; var getFocusables = function (parents, withGuards) { return parents.reduce(function (acc, parent) { var _a; var focusableWithShadowDom = getFocusablesWithShadowDom(parent, withGuards); var focusableWithIframes = (_a = []).concat.apply(_a, focusableWithShadowDom.map(function (node) { return getFocusablesWithIFrame(node, withGuards); })); return acc.concat( // add all tabbables inside and within shadow DOMs in DOM order focusableWithIframes, // add if node is tabbable itself parent.parentNode ? __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["b" /* toArray */])(parent.parentNode.querySelectorAll(queryTabbables)).filter(function (node) { return node === parent; }) : []); }, []); }; /** * return a list of focusable nodes within an area marked as "auto-focusable" * @param parent */ var getParentAutofocusables = function (parent) { var parentFocus = parent.querySelectorAll("[".concat(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_AUTO"], "]")); return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__array__["b" /* toArray */])(parentFocus) .map(function (node) { return getFocusables([node]); }) .reduce(function (acc, nodes) { return acc.concat(nodes); }, []); }; /***/ }), /* 13 */ /***/ (function(module, exports, __webpack_require__) { var Component = __webpack_require__(27)( /* script */ __webpack_require__(14), /* template */ __webpack_require__(28), /* scopeId */ null, /* cssModules */ null ) Component.options.__file = "/Users/akorzunov/dev/github/focus/vue-focus-lock/src/Lock.vue" if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key !== "__esModule"})) {console.error("named exports are not supported in *.vue files.")} if (Component.options.functional) {console.error("[vue-loader] Lock.vue: functional components are not supported with templates, they should use render functions.")} /* hot reload */ if (false) {(function () { var hotAPI = require("vue-hot-reload-api") hotAPI.install(require("vue"), false) if (!hotAPI.compatible) return module.hot.accept() if (!module.hot.data) { hotAPI.createRecord("data-v-0d4029e0", Component.options) } else { hotAPI.reload("data-v-0d4029e0", Component.options) } })()} module.exports = Component.exports /***/ }), /* 14 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _vueDemi = __webpack_require__(29); var _focusLock = __webpack_require__(19); var _focusLock2 = _interopRequireDefault(_focusLock); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } // // // // // // // // // // // // // // // // // // // // // // // // // // // // function deferAction(action) { var setImmediate = window.setImmediate; if (typeof setImmediate !== 'undefined') { setImmediate(action); } else { setTimeout(action, 1); } } var lastActiveTrap = 0; var lastActiveFocus = null; var focusWasOutsideWindow = false; var focusOnBody = function focusOnBody() { return document && document.activeElement === document.body; }; var isFreeFocus = function isFreeFocus() { return focusOnBody() || (0, _focusLock.focusIsHidden)(); }; var activateTrap = function activateTrap() { var result = false; if (lastActiveTrap) { var _lastActiveTrap = lastActiveTrap, observed = _lastActiveTrap.observed, onActivation = _lastActiveTrap.onActivation; if (focusWasOutsideWindow || !isFreeFocus() || !lastActiveFocus) { if (observed && !(0, _focusLock.focusInside)(observed)) { onActivation(); result = (0, _focusLock2.default)(observed, lastActiveFocus); } focusWasOutsideWindow = false; lastActiveFocus = document && document.activeElement; } } return result; }; var reducePropsToState = function reducePropsToState(propsList) { return propsList.filter(function (_ref) { var disabled = _ref.disabled; return !disabled; }).slice(-1)[0]; }; var handleStateChangeOnClient = function handleStateChangeOnClient(trap) { if (lastActiveTrap !== trap) { lastActiveTrap = null; } lastActiveTrap = trap; if (trap) { activateTrap(); deferAction(activateTrap); } }; var instances = []; var emitChange = function emitChange() { handleStateChangeOnClient(reducePropsToState(instances)); }; var onTrap = function onTrap(event) { if (activateTrap() && event) { // prevent scroll jump event.stopPropagation(); event.preventDefault(); } }; var onBlur = function onBlur() { deferAction(activateTrap); }; var onWindowBlur = function onWindowBlur() { focusWasOutsideWindow = true; }; var attachHandler = function attachHandler() { document.addEventListener('focusin', onTrap, true); document.addEventListener('focusout', onBlur); window.addEventListener('blur', onWindowBlur); }; var detachHandler = function detachHandler() { document.removeEventListener('focusin', onTrap, true); document.removeEventListener('focusout', onBlur); window.removeEventListener('blur', onWindowBlur); }; exports.default = { name: 'Lock', props: { returnFocus: { type: Boolean }, disabled: { type: Boolean }, noFocusGuards: { type: [Boolean, String], default: false }, group: { type: String } }, setup: function setup(props) { var _toRefs = (0, _vueDemi.toRefs)(props), returnFocus = _toRefs.returnFocus, disabled = _toRefs.disabled, noFocusGuards = _toRefs.noFocusGuards, group = _toRefs.group; var rootEl = (0, _vueDemi.ref)(null); var data = (0, _vueDemi.ref)({}); var hidden = (0, _vueDemi.ref)(""); // "width: 1px;height: 0px;padding: 0;overflow: hidden;position: fixed;top: 0;left: 0;" var groupAttr = (0, _vueDemi.computed)(function () { return _defineProperty({}, _focusLock.constants.FOCUS_GROUP, group.value); }); var hasLeadingGuards = (0, _vueDemi.computed)(function () { return noFocusGuards.value !== true; }); var hasTailingGuards = (0, _vueDemi.computed)(function () { return hasLeadingGuards.value && noFocusGuards.value !== 'tail'; }); (0, _vueDemi.watch)(disabled, function () { data.value.disabled = disabled.value; emitChange(); }); var originalFocusedElement = void 0; (0, _vueDemi.onMounted)(function () { var currentInstance = (0, _vueDemi.getCurrentInstance)(); if (!currentInstance) { return; } data.value.instance = currentInstance.proxy; data.value.observed = rootEl.value.querySelector("[data-lock]"); data.value.disabled = disabled.value; data.value.onActivation = function () { originalFocusedElement = originalFocusedElement || document && document.activeElement; }; if (!instances.length) { attachHandler(); } instances.push(data.value); emitChange(); }); (0, _vueDemi.onUnmounted)(function () { var currentInstance = (0, _vueDemi.getCurrentInstance)(); if (!currentInstance) { return; } instances = instances.filter(function (_ref3) { var instance = _ref3.instance; return instance !== currentInstance.proxy; }); if (!instances.length) { detachHandler(); } if (returnFocus.value && originalFocusedElement && originalFocusedElement.focus) { originalFocusedElement.focus(); } emitChange(); }); return { groupAttr: groupAttr, hasLeadingGuards: hasLeadingGuards, hasTailingGuards: hasTailingGuards, hidden: hidden, onBlur: function onBlur() { return deferAction(emitChange); }, rootEl: rootEl }; } }; /***/ }), /* 15 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _Lock = __webpack_require__(13); var _Lock2 = _interopRequireDefault(_Lock); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = _Lock2.default; /***/ }), /* 16 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return focusInside; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__utils_DOMutils__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_all_affected__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_array__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_getActiveElement__ = __webpack_require__(5); var focusInFrame = function (frame, activeElement) { return frame === activeElement; }; var focusInsideIframe = function (topNode, activeElement) { return Boolean(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__utils_array__["b" /* toArray */])(topNode.querySelectorAll('iframe')).some(function (node) { return focusInFrame(node, activeElement); })); }; /** * @returns {Boolean} true, if the current focus is inside given node or nodes. * Supports nodes hidden inside shadowDom */ var focusInside = function (topNode, activeElement) { // const activeElement = document && getActiveElement(); if (activeElement === void 0) { activeElement = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__utils_getActiveElement__["a" /* getActiveElement */])(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__utils_array__["c" /* getFirst */])(topNode).ownerDocument); } if (!activeElement || (activeElement.dataset && activeElement.dataset.focusGuard)) { return false; } return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__utils_all_affected__["a" /* getAllAffectedNodes */])(topNode).some(function (node) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__utils_DOMutils__["c" /* contains */])(node, activeElement) || focusInsideIframe(node, activeElement); }); }; /***/ }), /* 17 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return focusIsHidden; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_DOMutils__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_array__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_getActiveElement__ = __webpack_require__(5); /** * checks if focus is hidden FROM the focus-lock * ie contained inside a node focus-lock shall ignore * * This is a utility function coupled with {@link FOCUS_ALLOW} constant * * @returns {boolean} focus is currently is in "allow" area */ var focusIsHidden = function (inDocument) { if (inDocument === void 0) { inDocument = document; } var activeElement = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__utils_getActiveElement__["a" /* getActiveElement */])(inDocument); if (!activeElement) { return false; } // this does not support setting FOCUS_ALLOW within shadow dom return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__utils_array__["b" /* toArray */])(inDocument.querySelectorAll("[".concat(__WEBPACK_IMPORTED_MODULE_0__constants__["FOCUS_ALLOW"], "]"))).some(function (node) { return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__utils_DOMutils__["c" /* contains */])(node, activeElement); }); }; /***/ }), /* 18 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return expandFocusableNodes; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__utils_all_affected__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_is__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_parenting__ = __webpack_require__(10); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_tabOrder__ = __webpack_require__(11); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__utils_tabUtils__ = __webpack_require__(12); /** * traverses all related nodes (including groups) returning a list of all nodes(outer and internal) with meta information * This is low-level API! * @returns list of focusable elements inside a given top(!) node. * @see {@link getFocusableNodes} providing a simpler API */ var expandFocusableNodes = function (topNode) { var entries = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__utils_all_affected__["a" /* getAllAffectedNodes */])(topNode).filter(__WEBPACK_IMPORTED_MODULE_1__utils_is__["d" /* isNotAGuard */]); var commonParent = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__utils_parenting__["a" /* getTopCommonParent */])(topNode, topNode, entries); var outerNodes = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__utils_tabOrder__["a" /* orderByTabIndex */])(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__utils_tabUtils__["a" /* getFocusables */])([commonParent], true), true, true); var innerElements = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__utils_tabUtils__["a" /* getFocusables */])(entries, false); return outerNodes.map(function (_a) { var node = _a.node, index = _a.index; return ({ node: node, index: index, lockItem: innerElements.indexOf(node) >= 0, guard: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__utils_is__["e" /* isGuard */])(node), }); }); }; /***/ }), /* 19 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "constants", function() { return constants; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__focusInside__ = __webpack_require__(16); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__focusIsHidden__ = __webpack_require__(17); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__focusSolver__ = __webpack_require__(7); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__focusables__ = __webpack_require__(18); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__moveFocusInside__ = __webpack_require__(20); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__return_focus__ = __webpack_require__(21); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__sibling__ = __webpack_require__(22); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__utils_DOMutils__ = __webpack_require__(0); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusInside", function() { return __WEBPACK_IMPORTED_MODULE_1__focusInside__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusIsHidden", function() { return __WEBPACK_IMPORTED_MODULE_2__focusIsHidden__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "moveFocusInside", function() { return __WEBPACK_IMPORTED_MODULE_5__moveFocusInside__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusSolver", function() { return __WEBPACK_IMPORTED_MODULE_3__focusSolver__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "expandFocusableNodes", function() { return __WEBPACK_IMPORTED_MODULE_4__focusables__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "getFocusableNodes", function() { return __WEBPACK_IMPORTED_MODULE_8__utils_DOMutils__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "getTabbableNodes", function() { return __WEBPACK_IMPORTED_MODULE_8__utils_DOMutils__["b"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusNextElement", function() { return __WEBPACK_IMPORTED_MODULE_7__sibling__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusPrevElement", function() { return __WEBPACK_IMPORTED_MODULE_7__sibling__["b"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusFirstElement", function() { return __WEBPACK_IMPORTED_MODULE_7__sibling__["c"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "focusLastElement", function() { return __WEBPACK_IMPORTED_MODULE_7__sibling__["d"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "getRelativeFocusable", function() { return __WEBPACK_IMPORTED_MODULE_7__sibling__["e"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "captureFocusRestore", function() { return __WEBPACK_IMPORTED_MODULE_6__return_focus__["a"]; }); /** * magic symbols to control focus behavior from DOM * see description of every particular one */ var constants = __WEBPACK_IMPORTED_MODULE_0__constants__; /** * @deprecated - please use {@link moveFocusInside} named export */ var deprecated_default_moveFocusInside = __WEBPACK_IMPORTED_MODULE_5__moveFocusInside__["a" /* moveFocusInside */]; /* harmony default export */ __webpack_exports__["default"] = (deprecated_default_moveFocusInside); // /***/ }), /* 20 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return moveFocusInside; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__commands__ = __webpack_require__(6); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__focusSolver__ = __webpack_require__(7); var guardCount = 0; var lockDisabled = false; /** * The main functionality of the focus-lock package * * Contains focus at a given node