vendor: 102 bytes, lines 1-4
1/******/ (() => { // webpackBootstrap 2/******/ "use strict"; 3/******/ var __webpack_modules__ = ({ 4
vendor: 45,569 bytes, lines 5-1008
5/***/ "./node_modules/focus-trap/dist/focus-trap.esm.js": 6/*!********************************************************!*\ 7 !*** ./node_modules/focus-trap/dist/focus-trap.esm.js ***! 8 \********************************************************/ 9/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 10 11__webpack_require__.r(__webpack_exports__); 12/* harmony export */ __webpack_require__.d(__webpack_exports__, { 13/* harmony export */ createFocusTrap: () => (/* binding */ createFocusTrap) 14/* harmony export */ }); 15/* harmony import */ var tabbable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tabbable */ "./node_modules/tabbable/dist/index.esm.js"); 16/*! 17* focus-trap 7.6.5 18* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE 19*/ 20 21 22function _arrayLikeToArray(r, a) { 23 (null == a || a > r.length) && (a = r.length); 24 for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; 25 return n; 26} 27function _arrayWithoutHoles(r) { 28 if (Array.isArray(r)) return _arrayLikeToArray(r); 29} 30function _defineProperty(e, r, t) { 31 return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { 32 value: t, 33 enumerable: true, 34 configurable: true, 35 writable: true 36 }) : e[r] = t, e; 37} 38function _iterableToArray(r) { 39 if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); 40} 41function _nonIterableSpread() { 42 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 43} 44function ownKeys(e, r) { 45 var t = Object.keys(e); 46 if (Object.getOwnPropertySymbols) { 47 var o = Object.getOwnPropertySymbols(e); 48 r && (o = o.filter(function (r) { 49 return Object.getOwnPropertyDescriptor(e, r).enumerable; 50 })), t.push.apply(t, o); 51 } 52 return t; 53} 54function _objectSpread2(e) { 55 for (var r = 1; r < arguments.length; r++) { 56 var t = null != arguments[r] ? arguments[r] : {}; 57 r % 2 ? ownKeys(Object(t), true).forEach(function (r) { 58 _defineProperty(e, r, t[r]); 59 }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { 60 Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); 61 }); 62 } 63 return e; 64} 65function _toConsumableArray(r) { 66 return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); 67} 68function _toPrimitive(t, r) { 69 if ("object" != typeof t || !t) return t; 70 var e = t[Symbol.toPrimitive]; 71 if (void 0 !== e) { 72 var i = e.call(t, r); 73 if ("object" != typeof i) return i; 74 throw new TypeError("@@toPrimitive must return a primitive value."); 75 } 76 return ("string" === r ? String : Number)(t); 77} 78function _toPropertyKey(t) { 79 var i = _toPrimitive(t, "string"); 80 return "symbol" == typeof i ? i : i + ""; 81} 82function _unsupportedIterableToArray(r, a) { 83 if (r) { 84 if ("string" == typeof r) return _arrayLikeToArray(r, a); 85 var t = {}.toString.call(r).slice(8, -1); 86 return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; 87 } 88} 89 90var activeFocusTraps = { 91 activateTrap: function activateTrap(trapStack, trap) { 92 if (trapStack.length > 0) { 93 var activeTrap = trapStack[trapStack.length - 1]; 94 if (activeTrap !== trap) { 95 activeTrap._setPausedState(true); 96 } 97 } 98 var trapIndex = trapStack.indexOf(trap); 99 if (trapIndex === -1) { 100 trapStack.push(trap); 101 } else { 102 // move this existing trap to the front of the queue 103 trapStack.splice(trapIndex, 1); 104 trapStack.push(trap); 105 } 106 }, 107 deactivateTrap: function deactivateTrap(trapStack, trap) { 108 var trapIndex = trapStack.indexOf(trap); 109 if (trapIndex !== -1) { 110 trapStack.splice(trapIndex, 1); 111 } 112 if (trapStack.length > 0 && !trapStack[trapStack.length - 1]._isManuallyPaused()) { 113 trapStack[trapStack.length - 1]._setPausedState(false); 114 } 115 } 116}; 117var isSelectableInput = function isSelectableInput(node) { 118 return node.tagName && node.tagName.toLowerCase() === 'input' && typeof node.select === 'function'; 119}; 120var isEscapeEvent = function isEscapeEvent(e) { 121 return (e === null || e === void 0 ? void 0 : e.key) === 'Escape' || (e === null || e === void 0 ? void 0 : e.key) === 'Esc' || (e === null || e === void 0 ? void 0 : e.keyCode) === 27; 122}; 123var isTabEvent = function isTabEvent(e) { 124 return (e === null || e === void 0 ? void 0 : e.key) === 'Tab' || (e === null || e === void 0 ? void 0 : e.keyCode) === 9; 125}; 126 127// checks for TAB by default 128var isKeyForward = function isKeyForward(e) { 129 return isTabEvent(e) && !e.shiftKey; 130}; 131 132// checks for SHIFT+TAB by default 133var isKeyBackward = function isKeyBackward(e) { 134 return isTabEvent(e) && e.shiftKey; 135}; 136var delay = function delay(fn) { 137 return setTimeout(fn, 0); 138}; 139 140/** 141 * Get an option's value when it could be a plain value, or a handler that provides 142 * the value. 143 * @param {*} value Option's value to check. 144 * @param {...*} [params] Any parameters to pass to the handler, if `value` is a function. 145 * @returns {*} The `value`, or the handler's returned value. 146 */ 147var valueOrHandler = function valueOrHandler(value) { 148 for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 149 params[_key - 1] = arguments[_key]; 150 } 151 return typeof value === 'function' ? value.apply(void 0, params) : value; 152}; 153var getActualTarget = function getActualTarget(event) { 154 // NOTE: If the trap is _inside_ a shadow DOM, event.target will always be the 155 // shadow host. However, event.target.composedPath() will be an array of 156 // nodes "clicked" from inner-most (the actual element inside the shadow) to 157 // outer-most (the host HTML document). If we have access to composedPath(), 158 // then use its first element; otherwise, fall back to event.target (and 159 // this only works for an _open_ shadow DOM; otherwise, 160 // composedPath()[0] === event.target always). 161 return event.target.shadowRoot && typeof event.composedPath === 'function' ? event.composedPath()[0] : event.target; 162}; 163 164// NOTE: this must be _outside_ `createFocusTrap()` to make sure all traps in this 165// current instance use the same stack if `userOptions.trapStack` isn't specified 166var internalTrapStack = []; 167var createFocusTrap = function createFocusTrap(elements, userOptions) { 168 // SSR: a live trap shouldn't be created in this type of environment so this 169 // should be safe code to execute if the `document` option isn't specified 170 var doc = (userOptions === null || userOptions === void 0 ? void 0 : userOptions.document) || document; 171 var trapStack = (userOptions === null || userOptions === void 0 ? void 0 : userOptions.trapStack) || internalTrapStack; 172 var config = _objectSpread2({ 173 returnFocusOnDeactivate: true, 174 escapeDeactivates: true, 175 delayInitialFocus: true, 176 isKeyForward: isKeyForward, 177 isKeyBackward: isKeyBackward 178 }, userOptions); 179 var state = { 180 // containers given to createFocusTrap() 181 // @type {Array<HTMLElement>} 182 containers: [], 183 // list of objects identifying tabbable nodes in `containers` in the trap 184 // NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap 185 // is active, but the trap should never get to a state where there isn't at least one group 186 // with at least one tabbable node in it (that would lead to an error condition that would 187 // result in an error being thrown) 188 // @type {Array<{ 189 // container: HTMLElement, 190 // tabbableNodes: Array<HTMLElement>, // empty if none 191 // focusableNodes: Array<HTMLElement>, // empty if none 192 // posTabIndexesFound: boolean, 193 // firstTabbableNode: HTMLElement|undefined, 194 // lastTabbableNode: HTMLElement|undefined, 195 // firstDomTabbableNode: HTMLElement|undefined, 196 // lastDomTabbableNode: HTMLElement|undefined, 197 // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined 198 // }>} 199 containerGroups: [], 200 // same order/length as `containers` list 201 202 // references to objects in `containerGroups`, but only those that actually have 203 // tabbable nodes in them 204 // NOTE: same order as `containers` and `containerGroups`, but __not necessarily__ 205 // the same length 206 tabbableGroups: [], 207 nodeFocusedBeforeActivation: null, 208 mostRecentlyFocusedNode: null, 209 active: false, 210 paused: false, 211 manuallyPaused: false, 212 // timer ID for when delayInitialFocus is true and initial focus in this trap 213 // has been delayed during activation 214 delayInitialFocusTimer: undefined, 215 // the most recent KeyboardEvent for the configured nav key (typically [SHIFT+]TAB), if any 216 recentNavEvent: undefined 217 }; 218 var trap; // eslint-disable-line prefer-const -- some private functions reference it, and its methods reference private functions, so we must declare here and define later 219 220 /** 221 * Gets a configuration option value. 222 * @param {Object|undefined} configOverrideOptions If true, and option is defined in this set, 223 * value will be taken from this object. Otherwise, value will be taken from base configuration. 224 * @param {string} optionName Name of the option whose value is sought. 225 * @param {string|undefined} [configOptionName] Name of option to use __instead of__ `optionName` 226 * IIF `configOverrideOptions` is not defined. Otherwise, `optionName` is used. 227 */ 228 var getOption = function getOption(configOverrideOptions, optionName, configOptionName) { 229 return configOverrideOptions && configOverrideOptions[optionName] !== undefined ? configOverrideOptions[optionName] : config[configOptionName || optionName]; 230 }; 231 232 /** 233 * Finds the index of the container that contains the element. 234 * @param {HTMLElement} element 235 * @param {Event} [event] If available, and `element` isn't directly found in any container, 236 * the event's composed path is used to see if includes any known trap containers in the 237 * case where the element is inside a Shadow DOM. 238 * @returns {number} Index of the container in either `state.containers` or 239 * `state.containerGroups` (the order/length of these lists are the same); -1 240 * if the element isn't found. 241 */ 242 var findContainerIndex = function findContainerIndex(element, event) { 243 var composedPath = typeof (event === null || event === void 0 ? void 0 : event.composedPath) === 'function' ? event.composedPath() : undefined; 244 // NOTE: search `containerGroups` because it's possible a group contains no tabbable 245 // nodes, but still contains focusable nodes (e.g. if they all have `tabindex=-1`) 246 // and we still need to find the element in there 247 return state.containerGroups.findIndex(function (_ref) { 248 var container = _ref.container, 249 tabbableNodes = _ref.tabbableNodes; 250 return container.contains(element) || (// fall back to explicit tabbable search which will take into consideration any 251 // web components if the `tabbableOptions.getShadowRoot` option was used for 252 // the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't 253 // look inside web components even if open) 254 composedPath === null || composedPath === void 0 ? void 0 : composedPath.includes(container)) || tabbableNodes.find(function (node) { 255 return node === element; 256 }); 257 }); 258 }; 259 260 /** 261 * Gets the node for the given option, which is expected to be an option that 262 * can be either a DOM node, a string that is a selector to get a node, `false` 263 * (if a node is explicitly NOT given), or a function that returns any of these 264 * values. 265 * @param {string} optionName 266 * @param {Object} options 267 * @param {boolean} [options.hasFallback] True if the option could be a selector string 268 * and the option allows for a fallback scenario in the case where the selector is 269 * valid but does not match a node (i.e. the queried node doesn't exist in the DOM). 270 * @param {Array} [options.params] Params to pass to the option if it's a function. 271 * @returns {undefined | null | false | HTMLElement | SVGElement} Returns 272 * `undefined` if the option is not specified; `null` if the option didn't resolve 273 * to a node but `options.hasFallback=true`, `false` if the option resolved to `false` 274 * (node explicitly not given); otherwise, the resolved DOM node. 275 * @throws {Error} If the option is set, not `false`, and is not, or does not 276 * resolve to a node, unless the option is a selector string and `options.hasFallback=true`. 277 */ 278 var getNodeForOption = function getNodeForOption(optionName) { 279 var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, 280 _ref2$hasFallback = _ref2.hasFallback, 281 hasFallback = _ref2$hasFallback === void 0 ? false : _ref2$hasFallback, 282 _ref2$params = _ref2.params, 283 params = _ref2$params === void 0 ? [] : _ref2$params; 284 var optionValue = config[optionName]; 285 if (typeof optionValue === 'function') { 286 optionValue = optionValue.apply(void 0, _toConsumableArray(params)); 287 } 288 if (optionValue === true) { 289 optionValue = undefined; // use default value 290 } 291 if (!optionValue) { 292 if (optionValue === undefined || optionValue === false) { 293 return optionValue; 294 } 295 // else, empty string (invalid), null (invalid), 0 (invalid) 296 297 throw new Error("`".concat(optionName, "` was specified but was not a node, or did not return a node")); 298 } 299 var node = optionValue; // could be HTMLElement, SVGElement, or non-empty string at this point 300 301 if (typeof optionValue === 'string') { 302 try { 303 node = doc.querySelector(optionValue); // resolve to node, or null if fails 304 } catch (err) { 305 throw new Error("`".concat(optionName, "` appears to be an invalid selector; error=\"").concat(err.message, "\"")); 306 } 307 if (!node) { 308 if (!hasFallback) { 309 throw new Error("`".concat(optionName, "` as selector refers to no known node")); 310 } 311 // else, `node` MUST be `null` because that's what `Document.querySelector()` returns 312 // if the selector is valid but doesn't match anything 313 } 314 } 315 return node; 316 }; 317 var getInitialFocusNode = function getInitialFocusNode() { 318 var node = getNodeForOption('initialFocus', { 319 hasFallback: true 320 }); 321 322 // false explicitly indicates we want no initialFocus at all 323 if (node === false) { 324 return false; 325 } 326 if (node === undefined || node && !(0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isFocusable)(node, config.tabbableOptions)) { 327 // option not specified nor focusable: use fallback options 328 if (findContainerIndex(doc.activeElement) >= 0) { 329 node = doc.activeElement; 330 } else { 331 var firstTabbableGroup = state.tabbableGroups[0]; 332 var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; 333 334 // NOTE: `fallbackFocus` option function cannot return `false` (not supported) 335 node = firstTabbableNode || getNodeForOption('fallbackFocus'); 336 } 337 } else if (node === null) { 338 // option is a VALID selector string that doesn't yield a node: use the `fallbackFocus` 339 // option instead of the default behavior when the option isn't specified at all 340 node = getNodeForOption('fallbackFocus'); 341 } 342 if (!node) { 343 throw new Error('Your focus-trap needs to have at least one focusable element'); 344 } 345 return node; 346 }; 347 var updateTabbableNodes = function updateTabbableNodes() { 348 state.containerGroups = state.containers.map(function (container) { 349 var tabbableNodes = (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.tabbable)(container, config.tabbableOptions); 350 351 // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes 352 // are a superset of tabbable nodes since nodes with negative `tabindex` attributes 353 // are focusable but not tabbable 354 var focusableNodes = (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.focusable)(container, config.tabbableOptions); 355 var firstTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[0] : undefined; 356 var lastTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : undefined; 357 var firstDomTabbableNode = focusableNodes.find(function (node) { 358 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(node); 359 }); 360 var lastDomTabbableNode = focusableNodes.slice().reverse().find(function (node) { 361 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(node); 362 }); 363 var posTabIndexesFound = !!tabbableNodes.find(function (node) { 364 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.getTabIndex)(node) > 0; 365 }); 366 return { 367 container: container, 368 tabbableNodes: tabbableNodes, 369 focusableNodes: focusableNodes, 370 /** True if at least one node with positive `tabindex` was found in this container. */ 371 posTabIndexesFound: posTabIndexesFound, 372 /** First tabbable node in container, __tabindex__ order; `undefined` if none. */ 373 firstTabbableNode: firstTabbableNode, 374 /** Last tabbable node in container, __tabindex__ order; `undefined` if none. */ 375 lastTabbableNode: lastTabbableNode, 376 // NOTE: DOM order is NOT NECESSARILY "document position" order, but figuring that out 377 // would require more than just https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition 378 // because that API doesn't work with Shadow DOM as well as it should (@see 379 // https://github.com/whatwg/dom/issues/320) and since this first/last is only needed, so far, 380 // to address an edge case related to positive tabindex support, this seems like a much easier, 381 // "close enough most of the time" alternative for positive tabindexes which should generally 382 // be avoided anyway... 383 /** First tabbable node in container, __DOM__ order; `undefined` if none. */ 384 firstDomTabbableNode: firstDomTabbableNode, 385 /** Last tabbable node in container, __DOM__ order; `undefined` if none. */ 386 lastDomTabbableNode: lastDomTabbableNode, 387 /** 388 * Finds the __tabbable__ node that follows the given node in the specified direction, 389 * in this container, if any. 390 * @param {HTMLElement} node 391 * @param {boolean} [forward] True if going in forward tab order; false if going 392 * in reverse. 393 * @returns {HTMLElement|undefined} The next tabbable node, if any. 394 */ 395 nextTabbableNode: function nextTabbableNode(node) { 396 var forward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; 397 var nodeIdx = tabbableNodes.indexOf(node); 398 if (nodeIdx < 0) { 399 // either not tabbable nor focusable, or was focused but not tabbable (negative tabindex): 400 // since `node` should at least have been focusable, we assume that's the case and mimic 401 // what browsers do, which is set focus to the next node in __document position order__, 402 // regardless of positive tabindexes, if any -- and for reasons explained in the NOTE 403 // above related to `firstDomTabbable` and `lastDomTabbable` properties, we fall back to 404 // basic DOM order 405 if (forward) { 406 return focusableNodes.slice(focusableNodes.indexOf(node) + 1).find(function (el) { 407 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(el); 408 }); 409 } 410 return focusableNodes.slice(0, focusableNodes.indexOf(node)).reverse().find(function (el) { 411 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(el); 412 }); 413 } 414 return tabbableNodes[nodeIdx + (forward ? 1 : -1)]; 415 } 416 }; 417 }); 418 state.tabbableGroups = state.containerGroups.filter(function (group) { 419 return group.tabbableNodes.length > 0; 420 }); 421 422 // throw if no groups have tabbable nodes and we don't have a fallback focus node either 423 if (state.tabbableGroups.length <= 0 && !getNodeForOption('fallbackFocus') // returning false not supported for this option 424 ) { 425 throw new Error('Your focus-trap must have at least one container with at least one tabbable node in it at all times'); 426 } 427 428 // NOTE: Positive tabindexes are only properly supported in single-container traps because 429 // doing it across multiple containers where tabindexes could be all over the place 430 // would require Tabbable to support multiple containers, would require additional 431 // specialized Shadow DOM support, and would require Tabbable's multi-container support 432 // to look at those containers in document position order rather than user-provided 433 // order (as they are treated in Focus-trap, for legacy reasons). See discussion on 434 // https://github.com/focus-trap/focus-trap/issues/375 for more details. 435 if (state.containerGroups.find(function (g) { 436 return g.posTabIndexesFound; 437 }) && state.containerGroups.length > 1) { 438 throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps."); 439 } 440 }; 441 442 /** 443 * Gets the current activeElement. If it's a web-component and has open shadow-root 444 * it will recursively search inside shadow roots for the "true" activeElement. 445 * 446 * @param {Document | ShadowRoot} el 447 * 448 * @returns {HTMLElement} The element that currently has the focus 449 **/ 450 var _getActiveElement = function getActiveElement(el) { 451 var activeElement = el.activeElement; 452 if (!activeElement) { 453 return; 454 } 455 if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) { 456 return _getActiveElement(activeElement.shadowRoot); 457 } 458 return activeElement; 459 }; 460 var _tryFocus = function tryFocus(node) { 461 if (node === false) { 462 return; 463 } 464 if (node === _getActiveElement(document)) { 465 return; 466 } 467 if (!node || !node.focus) { 468 _tryFocus(getInitialFocusNode()); 469 return; 470 } 471 node.focus({ 472 preventScroll: !!config.preventScroll 473 }); 474 // NOTE: focus() API does not trigger focusIn event so set MRU node manually 475 state.mostRecentlyFocusedNode = node; 476 if (isSelectableInput(node)) { 477 node.select(); 478 } 479 }; 480 var getReturnFocusNode = function getReturnFocusNode(previousActiveElement) { 481 var node = getNodeForOption('setReturnFocus', { 482 params: [previousActiveElement] 483 }); 484 return node ? node : node === false ? false : previousActiveElement; 485 }; 486 487 /** 488 * Finds the next node (in either direction) where focus should move according to a 489 * keyboard focus-in event. 490 * @param {Object} params 491 * @param {Node} [params.target] Known target __from which__ to navigate, if any. 492 * @param {KeyboardEvent|FocusEvent} [params.event] Event to use if `target` isn't known (event 493 * will be used to determine the `target`). Ignored if `target` is specified. 494 * @param {boolean} [params.isBackward] True if focus should move backward. 495 * @returns {Node|undefined} The next node, or `undefined` if a next node couldn't be 496 * determined given the current state of the trap. 497 */ 498 var findNextNavNode = function findNextNavNode(_ref3) { 499 var target = _ref3.target, 500 event = _ref3.event, 501 _ref3$isBackward = _ref3.isBackward, 502 isBackward = _ref3$isBackward === void 0 ? false : _ref3$isBackward; 503 target = target || getActualTarget(event); 504 updateTabbableNodes(); 505 var destinationNode = null; 506 if (state.tabbableGroups.length > 0) { 507 // make sure the target is actually contained in a group 508 // NOTE: the target may also be the container itself if it's focusable 509 // with tabIndex='-1' and was given initial focus 510 var containerIndex = findContainerIndex(target, event); 511 var containerGroup = containerIndex >= 0 ? state.containerGroups[containerIndex] : undefined; 512 if (containerIndex < 0) { 513 // target not found in any group: quite possible focus has escaped the trap, 514 // so bring it back into... 515 if (isBackward) { 516 // ...the last node in the last group 517 destinationNode = state.tabbableGroups[state.tabbableGroups.length - 1].lastTabbableNode; 518 } else { 519 // ...the first node in the first group 520 destinationNode = state.tabbableGroups[0].firstTabbableNode; 521 } 522 } else if (isBackward) { 523 // REVERSE 524 525 // is the target the first tabbable node in a group? 526 var startOfGroupIndex = state.tabbableGroups.findIndex(function (_ref4) { 527 var firstTabbableNode = _ref4.firstTabbableNode; 528 return target === firstTabbableNode; 529 }); 530 if (startOfGroupIndex < 0 && (containerGroup.container === target || (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isFocusable)(target, config.tabbableOptions) && !(0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) { 531 // an exception case where the target is either the container itself, or 532 // a non-tabbable node that was given focus (i.e. tabindex is negative 533 // and user clicked on it or node was programmatically given focus) 534 // and is not followed by any other tabbable node, in which 535 // case, we should handle shift+tab as if focus were on the container's 536 // first tabbable node, and go to the last tabbable node of the LAST group 537 startOfGroupIndex = containerIndex; 538 } 539 if (startOfGroupIndex >= 0) { 540 // YES: then shift+tab should go to the last tabbable node in the 541 // previous group (and wrap around to the last tabbable node of 542 // the LAST group if it's the first tabbable node of the FIRST group) 543 var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1; 544 var destinationGroup = state.tabbableGroups[destinationGroupIndex]; 545 destinationNode = (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.getTabIndex)(target) >= 0 ? destinationGroup.lastTabbableNode : destinationGroup.lastDomTabbableNode; 546 } else if (!isTabEvent(event)) { 547 // user must have customized the nav keys so we have to move focus manually _within_ 548 // the active group: do this based on the order determined by tabbable() 549 destinationNode = containerGroup.nextTabbableNode(target, false); 550 } 551 } else { 552 // FORWARD 553 554 // is the target the last tabbable node in a group? 555 var lastOfGroupIndex = state.tabbableGroups.findIndex(function (_ref5) { 556 var lastTabbableNode = _ref5.lastTabbableNode; 557 return target === lastTabbableNode; 558 }); 559 if (lastOfGroupIndex < 0 && (containerGroup.container === target || (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isFocusable)(target, config.tabbableOptions) && !(0,tabbable__WEBPACK_IMPORTED_MODULE_0__.isTabbable)(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) { 560 // an exception case where the target is the container itself, or 561 // a non-tabbable node that was given focus (i.e. tabindex is negative 562 // and user clicked on it or node was programmatically given focus) 563 // and is not followed by any other tabbable node, in which 564 // case, we should handle tab as if focus were on the container's 565 // last tabbable node, and go to the first tabbable node of the FIRST group 566 lastOfGroupIndex = containerIndex; 567 } 568 if (lastOfGroupIndex >= 0) { 569 // YES: then tab should go to the first tabbable node in the next 570 // group (and wrap around to the first tabbable node of the FIRST 571 // group if it's the last tabbable node of the LAST group) 572 var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1; 573 var _destinationGroup = state.tabbableGroups[_destinationGroupIndex]; 574 destinationNode = (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.getTabIndex)(target) >= 0 ? _destinationGroup.firstTabbableNode : _destinationGroup.firstDomTabbableNode; 575 } else if (!isTabEvent(event)) { 576 // user must have customized the nav keys so we have to move focus manually _within_ 577 // the active group: do this based on the order determined by tabbable() 578 destinationNode = containerGroup.nextTabbableNode(target); 579 } 580 } 581 } else { 582 // no groups available 583 // NOTE: the fallbackFocus option does not support returning false to opt-out 584 destinationNode = getNodeForOption('fallbackFocus'); 585 } 586 return destinationNode; 587 }; 588 589 // This needs to be done on mousedown and touchstart instead of click 590 // so that it precedes the focus event. 591 var checkPointerDown = function checkPointerDown(e) { 592 var target = getActualTarget(e); 593 if (findContainerIndex(target, e) >= 0) { 594 // allow the click since it ocurred inside the trap 595 return; 596 } 597 if (valueOrHandler(config.clickOutsideDeactivates, e)) { 598 // immediately deactivate the trap 599 trap.deactivate({ 600 // NOTE: by setting `returnFocus: false`, deactivate() will do nothing, 601 // which will result in the outside click setting focus to the node 602 // that was clicked (and if not focusable, to "nothing"); by setting 603 // `returnFocus: true`, we'll attempt to re-focus the node originally-focused 604 // on activation (or the configured `setReturnFocus` node), whether the 605 // outside click was on a focusable node or not 606 returnFocus: config.returnFocusOnDeactivate 607 }); 608 return; 609 } 610 611 // This is needed for mobile devices. 612 // (If we'll only let `click` events through, 613 // then on mobile they will be blocked anyways if `touchstart` is blocked.) 614 if (valueOrHandler(config.allowOutsideClick, e)) { 615 // allow the click outside the trap to take place 616 return; 617 } 618 619 // otherwise, prevent the click 620 e.preventDefault(); 621 }; 622 623 // In case focus escapes the trap for some strange reason, pull it back in. 624 // NOTE: the focusIn event is NOT cancelable, so if focus escapes, it may cause unexpected 625 // scrolling if the node that got focused was out of view; there's nothing we can do to 626 // prevent that from happening by the time we discover that focus escaped 627 var checkFocusIn = function checkFocusIn(event) { 628 var target = getActualTarget(event); 629 var targetContained = findContainerIndex(target, event) >= 0; 630 631 // In Firefox when you Tab out of an iframe the Document is briefly focused. 632 if (targetContained || target instanceof Document) { 633 if (targetContained) { 634 state.mostRecentlyFocusedNode = target; 635 } 636 } else { 637 // escaped! pull it back in to where it just left 638 event.stopImmediatePropagation(); 639 640 // focus will escape if the MRU node had a positive tab index and user tried to nav forward; 641 // it will also escape if the MRU node had a 0 tab index and user tried to nav backward 642 // toward a node with a positive tab index 643 var nextNode; // next node to focus, if we find one 644 var navAcrossContainers = true; 645 if (state.mostRecentlyFocusedNode) { 646 if ((0,tabbable__WEBPACK_IMPORTED_MODULE_0__.getTabIndex)(state.mostRecentlyFocusedNode) > 0) { 647 // MRU container index must be >=0 otherwise we wouldn't have it as an MRU node... 648 var mruContainerIdx = findContainerIndex(state.mostRecentlyFocusedNode); 649 // there MAY not be any tabbable nodes in the container if there are at least 2 containers 650 // and the MRU node is focusable but not tabbable (focus-trap requires at least 1 container 651 // with at least one tabbable node in order to function, so this could be the other container 652 // with nothing tabbable in it) 653 var tabbableNodes = state.containerGroups[mruContainerIdx].tabbableNodes; 654 if (tabbableNodes.length > 0) { 655 // MRU tab index MAY not be found if the MRU node is focusable but not tabbable 656 var mruTabIdx = tabbableNodes.findIndex(function (node) { 657 return node === state.mostRecentlyFocusedNode; 658 }); 659 if (mruTabIdx >= 0) { 660 if (config.isKeyForward(state.recentNavEvent)) { 661 if (mruTabIdx + 1 < tabbableNodes.length) { 662 nextNode = tabbableNodes[mruTabIdx + 1]; 663 navAcrossContainers = false; 664 } 665 // else, don't wrap within the container as focus should move to next/previous 666 // container 667 } else { 668 if (mruTabIdx - 1 >= 0) { 669 nextNode = tabbableNodes[mruTabIdx - 1]; 670 navAcrossContainers = false; 671 } 672 // else, don't wrap within the container as focus should move to next/previous 673 // container 674 } 675 // else, don't find in container order without considering direction too 676 } 677 } 678 // else, no tabbable nodes in that container (which means we must have at least one other 679 // container with at least one tabbable node in it, otherwise focus-trap would've thrown 680 // an error the last time updateTabbableNodes() was run): find next node among all known 681 // containers 682 } else { 683 // check to see if there's at least one tabbable node with a positive tab index inside 684 // the trap because focus seems to escape when navigating backward from a tabbable node 685 // with tabindex=0 when this is the case (instead of wrapping to the tabbable node with 686 // the greatest positive tab index like it should) 687 if (!state.containerGroups.some(function (g) { 688 return g.tabbableNodes.some(function (n) { 689 return (0,tabbable__WEBPACK_IMPORTED_MODULE_0__.getTabIndex)(n) > 0; 690 }); 691 })) { 692 // no containers with tabbable nodes with positive tab indexes which means the focus 693 // escaped for some other reason and we should just execute the fallback to the 694 // MRU node or initial focus node, if any 695 navAcrossContainers = false; 696 } 697 } 698 } else { 699 // no MRU node means we're likely in some initial condition when the trap has just 700 // been activated and initial focus hasn't been given yet, in which case we should 701 // fall through to trying to focus the initial focus node, which is what should 702 // happen below at this point in the logic 703 navAcrossContainers = false; 704 } 705 if (navAcrossContainers) { 706 nextNode = findNextNavNode({ 707 // move FROM the MRU node, not event-related node (which will be the node that is 708 // outside the trap causing the focus escape we're trying to fix) 709 target: state.mostRecentlyFocusedNode, 710 isBackward: config.isKeyBackward(state.recentNavEvent) 711 }); 712 } 713 if (nextNode) { 714 _tryFocus(nextNode); 715 } else { 716 _tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode()); 717 } 718 } 719 state.recentNavEvent = undefined; // clear 720 }; 721 722 // Hijack key nav events on the first and last focusable nodes of the trap, 723 // in order to prevent focus from escaping. If it escapes for even a 724 // moment it can end up scrolling the page and causing confusion so we 725 // kind of need to capture the action at the keydown phase. 726 var checkKeyNav = function checkKeyNav(event) { 727 var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; 728 state.recentNavEvent = event; 729 var destinationNode = findNextNavNode({ 730 event: event, 731 isBackward: isBackward 732 }); 733 if (destinationNode) { 734 if (isTabEvent(event)) { 735 // since tab natively moves focus, we wouldn't have a destination node unless we 736 // were on the edge of a container and had to move to the next/previous edge, in 737 // which case we want to prevent default to keep the browser from moving focus 738 // to where it normally would 739 event.preventDefault(); 740 } 741 _tryFocus(destinationNode); 742 } 743 // else, let the browser take care of [shift+]tab and move the focus 744 }; 745 var checkTabKey = function checkTabKey(event) { 746 if (config.isKeyForward(event) || config.isKeyBackward(event)) { 747 checkKeyNav(event, config.isKeyBackward(event)); 748 } 749 }; 750 751 // we use a different event phase for the Escape key to allow canceling the event and checking for this in escapeDeactivates 752 var checkEscapeKey = function checkEscapeKey(event) { 753 if (isEscapeEvent(event) && valueOrHandler(config.escapeDeactivates, event) !== false) { 754 event.preventDefault(); 755 trap.deactivate(); 756 } 757 }; 758 var checkClick = function checkClick(e) { 759 var target = getActualTarget(e); 760 if (findContainerIndex(target, e) >= 0) { 761 return; 762 } 763 if (valueOrHandler(config.clickOutsideDeactivates, e)) { 764 return; 765 } 766 if (valueOrHandler(config.allowOutsideClick, e)) { 767 return; 768 } 769 e.preventDefault(); 770 e.stopImmediatePropagation(); 771 }; 772 773 // 774 // EVENT LISTENERS 775 // 776 777 var addListeners = function addListeners() { 778 if (!state.active) { 779 return; 780 } 781 782 // There can be only one listening focus trap at a time 783 activeFocusTraps.activateTrap(trapStack, trap); 784 785 // Delay ensures that the focused element doesn't capture the event 786 // that caused the focus trap activation. 787 state.delayInitialFocusTimer = config.delayInitialFocus ? delay(function () { 788 _tryFocus(getInitialFocusNode()); 789 }) : _tryFocus(getInitialFocusNode()); 790 doc.addEventListener('focusin', checkFocusIn, true); 791 doc.addEventListener('mousedown', checkPointerDown, { 792 capture: true, 793 passive: false 794 }); 795 doc.addEventListener('touchstart', checkPointerDown, { 796 capture: true, 797 passive: false 798 }); 799 doc.addEventListener('click', checkClick, { 800 capture: true, 801 passive: false 802 }); 803 doc.addEventListener('keydown', checkTabKey, { 804 capture: true, 805 passive: false 806 }); 807 doc.addEventListener('keydown', checkEscapeKey); 808 return trap; 809 }; 810 var removeListeners = function removeListeners() { 811 if (!state.active) { 812 return; 813 } 814 doc.removeEventListener('focusin', checkFocusIn, true); 815 doc.removeEventListener('mousedown', checkPointerDown, true); 816 doc.removeEventListener('touchstart', checkPointerDown, true); 817 doc.removeEventListener('click', checkClick, true); 818 doc.removeEventListener('keydown', checkTabKey, true); 819 doc.removeEventListener('keydown', checkEscapeKey); 820 return trap; 821 }; 822 823 // 824 // MUTATION OBSERVER 825 // 826 827 var checkDomRemoval = function checkDomRemoval(mutations) { 828 var isFocusedNodeRemoved = mutations.some(function (mutation) { 829 var removedNodes = Array.from(mutation.removedNodes); 830 return removedNodes.some(function (node) { 831 return node === state.mostRecentlyFocusedNode; 832 }); 833 }); 834 835 // If the currently focused is removed then browsers will move focus to the 836 // <body> element. If this happens, try to move focus back into the trap. 837 if (isFocusedNodeRemoved) { 838 _tryFocus(getInitialFocusNode()); 839 } 840 }; 841 842 // Use MutationObserver - if supported - to detect if focused node is removed 843 // from the DOM. 844 var mutationObserver = typeof window !== 'undefined' && 'MutationObserver' in window ? new MutationObserver(checkDomRemoval) : undefined; 845 var updateObservedNodes = function updateObservedNodes() { 846 if (!mutationObserver) { 847 return; 848 } 849 mutationObserver.disconnect(); 850 if (state.active && !state.paused) { 851 state.containers.map(function (container) { 852 mutationObserver.observe(container, { 853 subtree: true, 854 childList: true 855 }); 856 }); 857 } 858 }; 859 860 // 861 // TRAP DEFINITION 862 // 863 864 trap = { 865 get active() { 866 return state.active; 867 }, 868 get paused() { 869 return state.paused; 870 }, 871 activate: function activate(activateOptions) { 872 if (state.active) { 873 return this; 874 } 875 var onActivate = getOption(activateOptions, 'onActivate'); 876 var onPostActivate = getOption(activateOptions, 'onPostActivate'); 877 var checkCanFocusTrap = getOption(activateOptions, 'checkCanFocusTrap'); 878 if (!checkCanFocusTrap) { 879 updateTabbableNodes(); 880 } 881 state.active = true; 882 state.paused = false; 883 state.nodeFocusedBeforeActivation = _getActiveElement(doc); 884 onActivate === null || onActivate === void 0 || onActivate(); 885 var finishActivation = function finishActivation() { 886 if (checkCanFocusTrap) { 887 updateTabbableNodes(); 888 } 889 addListeners(); 890 updateObservedNodes(); 891 onPostActivate === null || onPostActivate === void 0 || onPostActivate(); 892 }; 893 if (checkCanFocusTrap) { 894 checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation); 895 return this; 896 } 897 finishActivation(); 898 return this; 899 }, 900 deactivate: function deactivate(deactivateOptions) { 901 if (!state.active) { 902 return this; 903 } 904 var options = _objectSpread2({ 905 onDeactivate: config.onDeactivate, 906 onPostDeactivate: config.onPostDeactivate, 907 checkCanReturnFocus: config.checkCanReturnFocus 908 }, deactivateOptions); 909 clearTimeout(state.delayInitialFocusTimer); // noop if undefined 910 state.delayInitialFocusTimer = undefined; 911 removeListeners(); 912 state.active = false; 913 state.paused = false; 914 updateObservedNodes(); 915 activeFocusTraps.deactivateTrap(trapStack, trap); 916 var onDeactivate = getOption(options, 'onDeactivate'); 917 var onPostDeactivate = getOption(options, 'onPostDeactivate'); 918 var checkCanReturnFocus = getOption(options, 'checkCanReturnFocus'); 919 var returnFocus = getOption(options, 'returnFocus', 'returnFocusOnDeactivate'); 920 onDeactivate === null || onDeactivate === void 0 || onDeactivate(); 921 var finishDeactivation = function finishDeactivation() { 922 delay(function () { 923 if (returnFocus) { 924 _tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)); 925 } 926 onPostDeactivate === null || onPostDeactivate === void 0 || onPostDeactivate(); 927 }); 928 }; 929 if (returnFocus && checkCanReturnFocus) { 930 checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation); 931 return this; 932 } 933 finishDeactivation(); 934 return this; 935 }, 936 pause: function pause(pauseOptions) { 937 if (!state.active) { 938 return this; 939 } 940 state.manuallyPaused = true; 941 return this._setPausedState(true, pauseOptions); 942 }, 943 unpause: function unpause(unpauseOptions) { 944 if (!state.active) { 945 return this; 946 } 947 state.manuallyPaused = false; 948 if (trapStack[trapStack.length - 1] !== this) { 949 return this; 950 } 951 return this._setPausedState(false, unpauseOptions); 952 }, 953 updateContainerElements: function updateContainerElements(containerElements) { 954 var elementsAsArray = [].concat(containerElements).filter(Boolean); 955 state.containers = elementsAsArray.map(function (element) { 956 return typeof element === 'string' ? doc.querySelector(element) : element; 957 }); 958 if (state.active) { 959 updateTabbableNodes(); 960 } 961 updateObservedNodes(); 962 return this; 963 } 964 }; 965 Object.defineProperties(trap, { 966 _isManuallyPaused: { 967 value: function value() { 968 return state.manuallyPaused; 969 } 970 }, 971 _setPausedState: { 972 value: function value(paused, options) { 973 if (state.paused === paused) { 974 return this; 975 } 976 state.paused = paused; 977 if (paused) { 978 var onPause = getOption(options, 'onPause'); 979 var onPostPause = getOption(options, 'onPostPause'); 980 onPause === null || onPause === void 0 || onPause(); 981 removeListeners(); 982 updateObservedNodes(); 983 onPostPause === null || onPostPause === void 0 || onPostPause(); 984 } else { 985 var onUnpause = getOption(options, 'onUnpause'); 986 var onPostUnpause = getOption(options, 'onPostUnpause'); 987 onUnpause === null || onUnpause === void 0 || onUnpause(); 988 updateTabbableNodes(); 989 addListeners(); 990 updateObservedNodes(); 991 onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause(); 992 } 993 return this; 994 } 995 } 996 }); 997 998 // initialize container elements 999 trap.updateContainerElements(elements); 1000 return trap; 1001}; 1002 1003 1004//# sourceMappingURL=focus-trap.esm.js.map 1005 1006 1007/***/ }), 1008
vendor: 27,652 bytes, lines 1009-1596
1009/***/ "./node_modules/tabbable/dist/index.esm.js": 1010/*!*************************************************!*\ 1011 !*** ./node_modules/tabbable/dist/index.esm.js ***! 1012 \*************************************************/ 1013/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 1014 1015__webpack_require__.r(__webpack_exports__); 1016/* harmony export */ __webpack_require__.d(__webpack_exports__, { 1017/* harmony export */ focusable: () => (/* binding */ focusable), 1018/* harmony export */ getTabIndex: () => (/* binding */ getTabIndex), 1019/* harmony export */ isFocusable: () => (/* binding */ isFocusable), 1020/* harmony export */ isTabbable: () => (/* binding */ isTabbable), 1021/* harmony export */ tabbable: () => (/* binding */ tabbable) 1022/* harmony export */ }); 1023/*! 1024* tabbable 6.2.0 1025* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE 1026*/ 1027// NOTE: separate `:not()` selectors has broader browser support than the newer 1028// `:not([inert], [inert] *)` (Feb 2023) 1029// CAREFUL: JSDom does not support `:not([inert] *)` as a selector; using it causes 1030// the entire query to fail, resulting in no nodes found, which will break a lot 1031// of things... so we have to rely on JS to identify nodes inside an inert container 1032var candidateSelectors = ['input:not([inert])', 'select:not([inert])', 'textarea:not([inert])', 'a[href]:not([inert])', 'button:not([inert])', '[tabindex]:not(slot):not([inert])', 'audio[controls]:not([inert])', 'video[controls]:not([inert])', '[contenteditable]:not([contenteditable="false"]):not([inert])', 'details>summary:first-of-type:not([inert])', 'details:not([inert])']; 1033var candidateSelector = /* #__PURE__ */candidateSelectors.join(','); 1034var NoElement = typeof Element === 'undefined'; 1035var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1036var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) { 1037 var _element$getRootNode; 1038 return element === null || element === void 0 ? void 0 : (_element$getRootNode = element.getRootNode) === null || _element$getRootNode === void 0 ? void 0 : _element$getRootNode.call(element); 1039} : function (element) { 1040 return element === null || element === void 0 ? void 0 : element.ownerDocument; 1041}; 1042 1043/** 1044 * Determines if a node is inert or in an inert ancestor. 1045 * @param {Element} [node] 1046 * @param {boolean} [lookUp] If true and `node` is not inert, looks up at ancestors to 1047 * see if any of them are inert. If false, only `node` itself is considered. 1048 * @returns {boolean} True if inert itself or by way of being in an inert ancestor. 1049 * False if `node` is falsy. 1050 */ 1051var isInert = function isInert(node, lookUp) { 1052 var _node$getAttribute; 1053 if (lookUp === void 0) { 1054 lookUp = true; 1055 } 1056 // CAREFUL: JSDom does not support inert at all, so we can't use the `HTMLElement.inert` 1057 // JS API property; we have to check the attribute, which can either be empty or 'true'; 1058 // if it's `null` (not specified) or 'false', it's an active element 1059 var inertAtt = node === null || node === void 0 ? void 0 : (_node$getAttribute = node.getAttribute) === null || _node$getAttribute === void 0 ? void 0 : _node$getAttribute.call(node, 'inert'); 1060 var inert = inertAtt === '' || inertAtt === 'true'; 1061 1062 // NOTE: this could also be handled with `node.matches('[inert], :is([inert] *)')` 1063 // if it weren't for `matches()` not being a function on shadow roots; the following 1064 // code works for any kind of node 1065 // CAREFUL: JSDom does not appear to support certain selectors like `:not([inert] *)` 1066 // so it likely would not support `:is([inert] *)` either... 1067 var result = inert || lookUp && node && isInert(node.parentNode); // recursive 1068 1069 return result; 1070}; 1071 1072/** 1073 * Determines if a node's content is editable. 1074 * @param {Element} [node] 1075 * @returns True if it's content-editable; false if it's not or `node` is falsy. 1076 */ 1077var isContentEditable = function isContentEditable(node) { 1078 var _node$getAttribute2; 1079 // CAREFUL: JSDom does not support the `HTMLElement.isContentEditable` API so we have 1080 // to use the attribute directly to check for this, which can either be empty or 'true'; 1081 // if it's `null` (not specified) or 'false', it's a non-editable element 1082 var attValue = node === null || node === void 0 ? void 0 : (_node$getAttribute2 = node.getAttribute) === null || _node$getAttribute2 === void 0 ? void 0 : _node$getAttribute2.call(node, 'contenteditable'); 1083 return attValue === '' || attValue === 'true'; 1084}; 1085 1086/** 1087 * @param {Element} el container to check in 1088 * @param {boolean} includeContainer add container to check 1089 * @param {(node: Element) => boolean} filter filter candidates 1090 * @returns {Element[]} 1091 */ 1092var getCandidates = function getCandidates(el, includeContainer, filter) { 1093 // even if `includeContainer=false`, we still have to check it for inertness because 1094 // if it's inert, all its children are inert 1095 if (isInert(el)) { 1096 return []; 1097 } 1098 var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); 1099 if (includeContainer && matches.call(el, candidateSelector)) { 1100 candidates.unshift(el); 1101 } 1102 candidates = candidates.filter(filter); 1103 return candidates; 1104}; 1105 1106/** 1107 * @callback GetShadowRoot 1108 * @param {Element} element to check for shadow root 1109 * @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available. 1110 */ 1111 1112/** 1113 * @callback ShadowRootFilter 1114 * @param {Element} shadowHostNode the element which contains shadow content 1115 * @returns {boolean} true if a shadow root could potentially contain valid candidates. 1116 */ 1117 1118/** 1119 * @typedef {Object} CandidateScope 1120 * @property {Element} scopeParent contains inner candidates 1121 * @property {Element[]} candidates list of candidates found in the scope parent 1122 */ 1123 1124/** 1125 * @typedef {Object} IterativeOptions 1126 * @property {GetShadowRoot|boolean} getShadowRoot true if shadow support is enabled; falsy if not; 1127 * if a function, implies shadow support is enabled and either returns the shadow root of an element 1128 * or a boolean stating if it has an undisclosed shadow root 1129 * @property {(node: Element) => boolean} filter filter candidates 1130 * @property {boolean} flatten if true then result will flatten any CandidateScope into the returned list 1131 * @property {ShadowRootFilter} shadowRootFilter filter shadow roots; 1132 */ 1133 1134/** 1135 * @param {Element[]} elements list of element containers to match candidates from 1136 * @param {boolean} includeContainer add container list to check 1137 * @param {IterativeOptions} options 1138 * @returns {Array.<Element|CandidateScope>} 1139 */ 1140var getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) { 1141 var candidates = []; 1142 var elementsToCheck = Array.from(elements); 1143 while (elementsToCheck.length) { 1144 var element = elementsToCheck.shift(); 1145 if (isInert(element, false)) { 1146 // no need to look up since we're drilling down 1147 // anything inside this container will also be inert 1148 continue; 1149 } 1150 if (element.tagName === 'SLOT') { 1151 // add shadow dom slot scope (slot itself cannot be focusable) 1152 var assigned = element.assignedElements(); 1153 var content = assigned.length ? assigned : element.children; 1154 var nestedCandidates = getCandidatesIteratively(content, true, options); 1155 if (options.flatten) { 1156 candidates.push.apply(candidates, nestedCandidates); 1157 } else { 1158 candidates.push({ 1159 scopeParent: element, 1160 candidates: nestedCandidates 1161 }); 1162 } 1163 } else { 1164 // check candidate element 1165 var validCandidate = matches.call(element, candidateSelector); 1166 if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) { 1167 candidates.push(element); 1168 } 1169 1170 // iterate over shadow content if possible 1171 var shadowRoot = element.shadowRoot || 1172 // check for an undisclosed shadow 1173 typeof options.getShadowRoot === 'function' && options.getShadowRoot(element); 1174 1175 // no inert look up because we're already drilling down and checking for inertness 1176 // on the way down, so all containers to this root node should have already been 1177 // vetted as non-inert 1178 var validShadowRoot = !isInert(shadowRoot, false) && (!options.shadowRootFilter || options.shadowRootFilter(element)); 1179 if (shadowRoot && validShadowRoot) { 1180 // add shadow dom scope IIF a shadow root node was given; otherwise, an undisclosed 1181 // shadow exists, so look at light dom children as fallback BUT create a scope for any 1182 // child candidates found because they're likely slotted elements (elements that are 1183 // children of the web component element (which has the shadow), in the light dom, but 1184 // slotted somewhere _inside_ the undisclosed shadow) -- the scope is created below, 1185 // _after_ we return from this recursive call 1186 var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options); 1187 if (options.flatten) { 1188 candidates.push.apply(candidates, _nestedCandidates); 1189 } else { 1190 candidates.push({ 1191 scopeParent: element, 1192 candidates: _nestedCandidates 1193 }); 1194 } 1195 } else { 1196 // there's not shadow so just dig into the element's (light dom) children 1197 // __without__ giving the element special scope treatment 1198 elementsToCheck.unshift.apply(elementsToCheck, element.children); 1199 } 1200 } 1201 } 1202 return candidates; 1203}; 1204 1205/** 1206 * @private 1207 * Determines if the node has an explicitly specified `tabindex` attribute. 1208 * @param {HTMLElement} node 1209 * @returns {boolean} True if so; false if not. 1210 */ 1211var hasTabIndex = function hasTabIndex(node) { 1212 return !isNaN(parseInt(node.getAttribute('tabindex'), 10)); 1213}; 1214 1215/** 1216 * Determine the tab index of a given node. 1217 * @param {HTMLElement} node 1218 * @returns {number} Tab order (negative, 0, or positive number). 1219 * @throws {Error} If `node` is falsy. 1220 */ 1221var getTabIndex = function getTabIndex(node) { 1222 if (!node) { 1223 throw new Error('No node provided'); 1224 } 1225 if (node.tabIndex < 0) { 1226 // in Chrome, <details/>, <audio controls/> and <video controls/> elements get a default 1227 // `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM, 1228 // yet they are still part of the regular tab order; in FF, they get a default 1229 // `tabIndex` of 0; since Chrome still puts those elements in the regular tab 1230 // order, consider their tab index to be 0. 1231 // Also browsers do not return `tabIndex` correctly for contentEditable nodes; 1232 // so if they don't have a tabindex attribute specifically set, assume it's 0. 1233 if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) { 1234 return 0; 1235 } 1236 } 1237 return node.tabIndex; 1238}; 1239 1240/** 1241 * Determine the tab index of a given node __for sort order purposes__. 1242 * @param {HTMLElement} node 1243 * @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default, 1244 * has tabIndex -1, but needs to be sorted by document order in order for its content to be 1245 * inserted into the correct sort position. 1246 * @returns {number} Tab order (negative, 0, or positive number). 1247 */ 1248var getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) { 1249 var tabIndex = getTabIndex(node); 1250 if (tabIndex < 0 && isScope && !hasTabIndex(node)) { 1251 return 0; 1252 } 1253 return tabIndex; 1254}; 1255var sortOrderedTabbables = function sortOrderedTabbables(a, b) { 1256 return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex; 1257}; 1258var isInput = function isInput(node) { 1259 return node.tagName === 'INPUT'; 1260}; 1261var isHiddenInput = function isHiddenInput(node) { 1262 return isInput(node) && node.type === 'hidden'; 1263}; 1264var isDetailsWithSummary = function isDetailsWithSummary(node) { 1265 var r = node.tagName === 'DETAILS' && Array.prototype.slice.apply(node.children).some(function (child) { 1266 return child.tagName === 'SUMMARY'; 1267 }); 1268 return r; 1269}; 1270var getCheckedRadio = function getCheckedRadio(nodes, form) { 1271 for (var i = 0; i < nodes.length; i++) { 1272 if (nodes[i].checked && nodes[i].form === form) { 1273 return nodes[i]; 1274 } 1275 } 1276}; 1277var isTabbableRadio = function isTabbableRadio(node) { 1278 if (!node.name) { 1279 return true; 1280 } 1281 var radioScope = node.form || getRootNode(node); 1282 var queryRadios = function queryRadios(name) { 1283 return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]'); 1284 }; 1285 var radioSet; 1286 if (typeof window !== 'undefined' && typeof window.CSS !== 'undefined' && typeof window.CSS.escape === 'function') { 1287 radioSet = queryRadios(window.CSS.escape(node.name)); 1288 } else { 1289 try { 1290 radioSet = queryRadios(node.name); 1291 } catch (err) { 1292 // eslint-disable-next-line no-console 1293 console.error('Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s', err.message); 1294 return false; 1295 } 1296 } 1297 var checked = getCheckedRadio(radioSet, node.form); 1298 return !checked || checked === node; 1299}; 1300var isRadio = function isRadio(node) { 1301 return isInput(node) && node.type === 'radio'; 1302}; 1303var isNonTabbableRadio = function isNonTabbableRadio(node) { 1304 return isRadio(node) && !isTabbableRadio(node); 1305}; 1306 1307// determines if a node is ultimately attached to the window's document 1308var isNodeAttached = function isNodeAttached(node) { 1309 var _nodeRoot; 1310 // The root node is the shadow root if the node is in a shadow DOM; some document otherwise 1311 // (but NOT _the_ document; see second 'If' comment below for more). 1312 // If rootNode is shadow root, it'll have a host, which is the element to which the shadow 1313 // is attached, and the one we need to check if it's in the document or not (because the 1314 // shadow, and all nodes it contains, is never considered in the document since shadows 1315 // behave like self-contained DOMs; but if the shadow's HOST, which is part of the document, 1316 // is hidden, or is not in the document itself but is detached, it will affect the shadow's 1317 // visibility, including all the nodes it contains). The host could be any normal node, 1318 // or a custom element (i.e. web component). Either way, that's the one that is considered 1319 // part of the document, not the shadow root, nor any of its children (i.e. the node being 1320 // tested). 1321 // To further complicate things, we have to look all the way up until we find a shadow HOST 1322 // that is attached (or find none) because the node might be in nested shadows... 1323 // If rootNode is not a shadow root, it won't have a host, and so rootNode should be the 1324 // document (per the docs) and while it's a Document-type object, that document does not 1325 // appear to be the same as the node's `ownerDocument` for some reason, so it's safer 1326 // to ignore the rootNode at this point, and use `node.ownerDocument`. Otherwise, 1327 // using `rootNode.contains(node)` will _always_ be true we'll get false-positives when 1328 // node is actually detached. 1329 // NOTE: If `nodeRootHost` or `node` happens to be the `document` itself (which is possible 1330 // if a tabbable/focusable node was quickly added to the DOM, focused, and then removed 1331 // from the DOM as in https://github.com/focus-trap/focus-trap-react/issues/905), then 1332 // `ownerDocument` will be `null`, hence the optional chaining on it. 1333 var nodeRoot = node && getRootNode(node); 1334 var nodeRootHost = (_nodeRoot = nodeRoot) === null || _nodeRoot === void 0 ? void 0 : _nodeRoot.host; 1335 1336 // in some cases, a detached node will return itself as the root instead of a document or 1337 // shadow root object, in which case, we shouldn't try to look further up the host chain 1338 var attached = false; 1339 if (nodeRoot && nodeRoot !== node) { 1340 var _nodeRootHost, _nodeRootHost$ownerDo, _node$ownerDocument; 1341 attached = !!((_nodeRootHost = nodeRootHost) !== null && _nodeRootHost !== void 0 && (_nodeRootHost$ownerDo = _nodeRootHost.ownerDocument) !== null && _nodeRootHost$ownerDo !== void 0 && _nodeRootHost$ownerDo.contains(nodeRootHost) || node !== null && node !== void 0 && (_node$ownerDocument = node.ownerDocument) !== null && _node$ownerDocument !== void 0 && _node$ownerDocument.contains(node)); 1342 while (!attached && nodeRootHost) { 1343 var _nodeRoot2, _nodeRootHost2, _nodeRootHost2$ownerD; 1344 // since it's not attached and we have a root host, the node MUST be in a nested shadow DOM, 1345 // which means we need to get the host's host and check if that parent host is contained 1346 // in (i.e. attached to) the document 1347 nodeRoot = getRootNode(nodeRootHost); 1348 nodeRootHost = (_nodeRoot2 = nodeRoot) === null || _nodeRoot2 === void 0 ? void 0 : _nodeRoot2.host; 1349 attached = !!((_nodeRootHost2 = nodeRootHost) !== null && _nodeRootHost2 !== void 0 && (_nodeRootHost2$ownerD = _nodeRootHost2.ownerDocument) !== null && _nodeRootHost2$ownerD !== void 0 && _nodeRootHost2$ownerD.contains(nodeRootHost)); 1350 } 1351 } 1352 return attached; 1353}; 1354var isZeroArea = function isZeroArea(node) { 1355 var _node$getBoundingClie = node.getBoundingClientRect(), 1356 width = _node$getBoundingClie.width, 1357 height = _node$getBoundingClie.height; 1358 return width === 0 && height === 0; 1359}; 1360var isHidden = function isHidden(node, _ref) { 1361 var displayCheck = _ref.displayCheck, 1362 getShadowRoot = _ref.getShadowRoot; 1363 // NOTE: visibility will be `undefined` if node is detached from the document 1364 // (see notes about this further down), which means we will consider it visible 1365 // (this is legacy behavior from a very long way back) 1366 // NOTE: we check this regardless of `displayCheck="none"` because this is a 1367 // _visibility_ check, not a _display_ check 1368 if (getComputedStyle(node).visibility === 'hidden') { 1369 return true; 1370 } 1371 var isDirectSummary = matches.call(node, 'details>summary:first-of-type'); 1372 var nodeUnderDetails = isDirectSummary ? node.parentElement : node; 1373 if (matches.call(nodeUnderDetails, 'details:not([open]) *')) { 1374 return true; 1375 } 1376 if (!displayCheck || displayCheck === 'full' || displayCheck === 'legacy-full') { 1377 if (typeof getShadowRoot === 'function') { 1378 // figure out if we should consider the node to be in an undisclosed shadow and use the 1379 // 'non-zero-area' fallback 1380 var originalNode = node; 1381 while (node) { 1382 var parentElement = node.parentElement; 1383 var rootNode = getRootNode(node); 1384 if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true // check if there's an undisclosed shadow 1385 ) { 1386 // node has an undisclosed shadow which means we can only treat it as a black box, so we 1387 // fall back to a non-zero-area test 1388 return isZeroArea(node); 1389 } else if (node.assignedSlot) { 1390 // iterate up slot 1391 node = node.assignedSlot; 1392 } else if (!parentElement && rootNode !== node.ownerDocument) { 1393 // cross shadow boundary 1394 node = rootNode.host; 1395 } else { 1396 // iterate up normal dom 1397 node = parentElement; 1398 } 1399 } 1400 node = originalNode; 1401 } 1402 // else, `getShadowRoot` might be true, but all that does is enable shadow DOM support 1403 // (i.e. it does not also presume that all nodes might have undisclosed shadows); or 1404 // it might be a falsy value, which means shadow DOM support is disabled 1405 1406 // Since we didn't find it sitting in an undisclosed shadow (or shadows are disabled) 1407 // now we can just test to see if it would normally be visible or not, provided it's 1408 // attached to the main document. 1409 // NOTE: We must consider case where node is inside a shadow DOM and given directly to 1410 // `isTabbable()` or `isFocusable()` -- regardless of `getShadowRoot` option setting. 1411 1412 if (isNodeAttached(node)) { 1413 // this works wherever the node is: if there's at least one client rect, it's 1414 // somehow displayed; it also covers the CSS 'display: contents' case where the 1415 // node itself is hidden in place of its contents; and there's no need to search 1416 // up the hierarchy either 1417 return !node.getClientRects().length; 1418 } 1419 1420 // Else, the node isn't attached to the document, which means the `getClientRects()` 1421 // API will __always__ return zero rects (this can happen, for example, if React 1422 // is used to render nodes onto a detached tree, as confirmed in this thread: 1423 // https://github.com/facebook/react/issues/9117#issuecomment-284228870) 1424 // 1425 // It also means that even window.getComputedStyle(node).display will return `undefined` 1426 // because styles are only computed for nodes that are in the document. 1427 // 1428 // NOTE: THIS HAS BEEN THE CASE FOR YEARS. It is not new, nor is it caused by tabbable 1429 // somehow. Though it was never stated officially, anyone who has ever used tabbable 1430 // APIs on nodes in detached containers has actually implicitly used tabbable in what 1431 // was later (as of v5.2.0 on Apr 9, 2021) called `displayCheck="none"` mode -- essentially 1432 // considering __everything__ to be visible because of the innability to determine styles. 1433 // 1434 // v6.0.0: As of this major release, the default 'full' option __no longer treats detached 1435 // nodes as visible with the 'none' fallback.__ 1436 if (displayCheck !== 'legacy-full') { 1437 return true; // hidden 1438 } 1439 // else, fallback to 'none' mode and consider the node visible 1440 } else if (displayCheck === 'non-zero-area') { 1441 // NOTE: Even though this tests that the node's client rect is non-zero to determine 1442 // whether it's displayed, and that a detached node will __always__ have a zero-area 1443 // client rect, we don't special-case for whether the node is attached or not. In 1444 // this mode, we do want to consider nodes that have a zero area to be hidden at all 1445 // times, and that includes attached or not. 1446 return isZeroArea(node); 1447 } 1448 1449 // visible, as far as we can tell, or per current `displayCheck=none` mode, we assume 1450 // it's visible 1451 return false; 1452}; 1453 1454// form fields (nested) inside a disabled fieldset are not focusable/tabbable 1455// unless they are in the _first_ <legend> element of the top-most disabled 1456// fieldset 1457var isDisabledFromFieldset = function isDisabledFromFieldset(node) { 1458 if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) { 1459 var parentNode = node.parentElement; 1460 // check if `node` is contained in a disabled <fieldset> 1461 while (parentNode) { 1462 if (parentNode.tagName === 'FIELDSET' && parentNode.disabled) { 1463 // look for the first <legend> among the children of the disabled <fieldset> 1464 for (var i = 0; i < parentNode.children.length; i++) { 1465 var child = parentNode.children.item(i); 1466 // when the first <legend> (in document order) is found 1467 if (child.tagName === 'LEGEND') { 1468 // if its parent <fieldset> is not nested in another disabled <fieldset>, 1469 // return whether `node` is a descendant of its first <legend> 1470 return matches.call(parentNode, 'fieldset[disabled] *') ? true : !child.contains(node); 1471 } 1472 } 1473 // the disabled <fieldset> containing `node` has no <legend> 1474 return true; 1475 } 1476 parentNode = parentNode.parentElement; 1477 } 1478 } 1479 1480 // else, node's tabbable/focusable state should not be affected by a fieldset's 1481 // enabled/disabled state 1482 return false; 1483}; 1484var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) { 1485 if (node.disabled || 1486 // we must do an inert look up to filter out any elements inside an inert ancestor 1487 // because we're limited in the type of selectors we can use in JSDom (see related 1488 // note related to `candidateSelectors`) 1489 isInert(node) || isHiddenInput(node) || isHidden(node, options) || 1490 // For a details element with a summary, the summary element gets the focus 1491 isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { 1492 return false; 1493 } 1494 return true; 1495}; 1496var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable(options, node) { 1497 if (isNonTabbableRadio(node) || getTabIndex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) { 1498 return false; 1499 } 1500 return true; 1501}; 1502var isValidShadowRootTabbable = function isValidShadowRootTabbable(shadowHostNode) { 1503 var tabIndex = parseInt(shadowHostNode.getAttribute('tabindex'), 10); 1504 if (isNaN(tabIndex) || tabIndex >= 0) { 1505 return true; 1506 } 1507 // If a custom element has an explicit negative tabindex, 1508 // browsers will not allow tab targeting said element's children. 1509 return false; 1510}; 1511 1512/** 1513 * @param {Array.<Element|CandidateScope>} candidates 1514 * @returns Element[] 1515 */ 1516var sortByOrder = function sortByOrder(candidates) { 1517 var regularTabbables = []; 1518 var orderedTabbables = []; 1519 candidates.forEach(function (item, i) { 1520 var isScope = !!item.scopeParent; 1521 var element = isScope ? item.scopeParent : item; 1522 var candidateTabindex = getSortOrderTabIndex(element, isScope); 1523 var elements = isScope ? sortByOrder(item.candidates) : element; 1524 if (candidateTabindex === 0) { 1525 isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element); 1526 } else { 1527 orderedTabbables.push({ 1528 documentOrder: i, 1529 tabIndex: candidateTabindex, 1530 item: item, 1531 isScope: isScope, 1532 content: elements 1533 }); 1534 } 1535 }); 1536 return orderedTabbables.sort(sortOrderedTabbables).reduce(function (acc, sortable) { 1537 sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content); 1538 return acc; 1539 }, []).concat(regularTabbables); 1540}; 1541var tabbable = function tabbable(container, options) { 1542 options = options || {}; 1543 var candidates; 1544 if (options.getShadowRoot) { 1545 candidates = getCandidatesIteratively([container], options.includeContainer, { 1546 filter: isNodeMatchingSelectorTabbable.bind(null, options), 1547 flatten: false, 1548 getShadowRoot: options.getShadowRoot, 1549 shadowRootFilter: isValidShadowRootTabbable 1550 }); 1551 } else { 1552 candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); 1553 } 1554 return sortByOrder(candidates); 1555}; 1556var focusable = function focusable(container, options) { 1557 options = options || {}; 1558 var candidates; 1559 if (options.getShadowRoot) { 1560 candidates = getCandidatesIteratively([container], options.includeContainer, { 1561 filter: isNodeMatchingSelectorFocusable.bind(null, options), 1562 flatten: true, 1563 getShadowRoot: options.getShadowRoot 1564 }); 1565 } else { 1566 candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); 1567 } 1568 return candidates; 1569}; 1570var isTabbable = function isTabbable(node, options) { 1571 options = options || {}; 1572 if (!node) { 1573 throw new Error('No node provided'); 1574 } 1575 if (matches.call(node, candidateSelector) === false) { 1576 return false; 1577 } 1578 return isNodeMatchingSelectorTabbable(options, node); 1579}; 1580var focusableCandidateSelector = /* #__PURE__ */candidateSelectors.concat('iframe').join(','); 1581var isFocusable = function isFocusable(node, options) { 1582 options = options || {}; 1583 if (!node) { 1584 throw new Error('No node provided'); 1585 } 1586 if (matches.call(node, focusableCandidateSelector) === false) { 1587 return false; 1588 } 1589 return isNodeMatchingSelectorFocusable(options, node); 1590}; 1591 1592 1593//# sourceMappingURL=index.esm.js.map 1594 1595 1596/***/ })
1596 1597 1598/******/ }); 1599/************************************************************************/ 1600/******/ // The module cache 1601/******/ var __webpack_module_cache__ = {}; 1602/******/ 1603/******/ // The require function 1604/******/ function __webpack_require__(moduleId) { 1605/******/ // Check if module is in cache 1606/******/ var cachedModule = __webpack_module_cache__[moduleId]; 1607/******/ if (cachedModule !== undefined) { 1608/******/ return cachedModule.exports; 1609/******/ } 1610/******/ // Create a new module (and put it into the cache) 1611/******/ var module = __webpack_module_cache__[moduleId] = { 1612/******/ // no module.id needed 1613/******/ // no module.loaded needed 1614/******/ exports: {} 1615/******/ }; 1616/******/ 1617/******/ // Execute the module function 1618/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 1619/******/ 1620/******/ // Return the exports of the module 1621/******/ return module.exports; 1622/******/ } 1623/******/ 1624/************************************************************************/ 1625/******/ /* webpack/runtime/define property getters */ 1626/******/ (() => { 1627/******/ // define getter functions for harmony exports 1628/******/ __webpack_require__.d = (exports, definition) => { 1629/******/ for(var key in definition) { 1630/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 1631/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 1632/******/ } 1633/******/ } 1634/******/ }; 1635/******/ })(); 1636/******/ 1637/******/ /* webpack/runtime/hasOwnProperty shorthand */ 1638/******/ (() => { 1639/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 1640/******/ })(); 1641/******/ 1642/******/ /* webpack/runtime/make namespace object */ 1643/******/ (() => { 1644/******/ // define __esModule on exports 1645/******/ __webpack_require__.r = (exports) => { 1646/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 1647/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 1648/******/ } 1649/******/ Object.defineProperty(exports, '__esModule', { value: true }); 1650/******/ }; 1651/******/ })(); 1652/******/ 1653/************************************************************************/ 1654var __webpack_exports__ = {}; 1655// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. 1656(() => { 1657/*!**********************************!*\ 1658 !*** ./src/assets/js/scripts.js ***! 1659 \**********************************/ 1660__webpack_require__.r(__webpack_exports__); 1661/* harmony import */ var focus_trap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! focus-trap */ "./node_modules/focus-trap/dist/focus-trap.esm.js"); 1662// cspell:ignore accordian resizehandle 1663 1664 1665jQuery(function ($) { 1666 // LearnDash Notes Panel accordion and accessibility scripts. 1667 1668 // Hide panel body and set hidden attribute on page load. 1669 document.querySelectorAll('.ld-notes-panel__body').forEach(function (panelBody) { 1670 panelBody.hidden = true; 1671 }); 1672 1673 // Panel header button click handler. 1674 document.addEventListener('click', function (e) { 1675 if (!e.target.closest('.ld-notes-panel__header')) { 1676 return; 1677 } 1678 const panel = e.target.closest('.ld-notes-panel'); 1679 if (!panel || !panel.id) { 1680 return; 1681 } 1682 const header = document.getElementById(panel.id + '-header'); 1683 const body = document.getElementById(panel.id + '-body'); 1684 const expanded = header.getAttribute('aria-expanded') === 'true'; 1685 panel.classList.toggle('ld-notes-panel--active'); 1686 header.setAttribute('aria-expanded', !expanded); 1687 body.hidden = expanded; 1688 }); 1689 1690 // Floating button and note form scripts. 1691 1692 (function () { 1693 /** 1694 * Position the modal based on the button position. 1695 * 1696 * @param {jQuery} btn The button element. 1697 * @param {boolean} initialLoad Whether this is the initial load. 1698 * 1699 * @return {void} 1700 */ 1701 function positionModal(btn, initialLoad = false) { 1702 let thisPos = btn.position(); 1703 const storedPosition = localStorage.getItem('learndash_notes_draggable_points'); 1704 if (storedPosition && initialLoad) { 1705 const position = JSON.parse(storedPosition); 1706 thisPos = { 1707 top: position.x, 1708 left: position.y 1709 }; 1710 } 1711 1712 // Calculate if button is in right or left half of window. 1713 const windowWidth = $(window).width(); 1714 const isRightSide = thisPos.left > windowWidth / 2; 1715 1716 // Position modal 10px below button. 1717 const modalTop = thisPos.top + btn.outerHeight() + 10 + 'px'; 1718 1719 // Check if viewport is below 660px for responsive behavior 1720 const isSmallScreen = windowWidth < 660; 1721 1722 // Align modal with button based on window position. 1723 const modalLeft = isRightSide ? 'auto' : thisPos.left + 'px'; 1724 const modalRight = isRightSide ? windowWidth - (thisPos.left + btn.outerWidth()) + 'px' : 'auto'; 1725 1726 // Apply responsive modal positioning and sizing 1727 const modalStyles = { 1728 top: modalTop 1729 }; 1730 if (isSmallScreen) { 1731 // For small screens, expand to screen edges with 10px padding 1732 modalStyles.left = '10px'; 1733 modalStyles.right = '10px'; 1734 // Ensure width never exceeds viewport width 1735 modalStyles.width = Math.min(windowWidth - 20, $('.ld-notes-modal').outerWidth() || 400) + 'px'; 1736 } else { 1737 // Normal positioning for larger screens 1738 modalStyles.left = modalLeft; 1739 modalStyles.right = modalRight; 1740 } 1741 $('.ld-notes-modal').css(modalStyles); 1742 } 1743 const $notesTriggerModal = $('.ld-notes-trigger-modal'); 1744 const $notesModal = $('.ld-notes-modal'); 1745 if ($notesTriggerModal.length < 1 || $notesModal.length < 1) { 1746 return; 1747 } 1748 $(document).ready(function () { 1749 positionModal($('.ld-notes-trigger-modal'), true); 1750 $('#wp-llms_note_text_popup-wrap iframe').css('height', '100px'); 1751 1752 // Set modal height to match content. 1753 const $modal = $('.ld-notes-modal'); 1754 const $header = $modal.find('.ld-notes-modal__header'); 1755 const $content = $modal.find('.ld-notes-modal__content'); 1756 const totalHeight = $header.outerHeight() + $content.outerHeight(); 1757 $modal.height(totalHeight); 1758 1759 // Set initial button position from storage or default to top right. 1760 const $button = $('.ld-notes-trigger-modal'); 1761 const storedPosition = localStorage.getItem('learndash_notes_draggable_points'); 1762 1763 // Calculate dynamic top position based on admin bar and focus header heights. 1764 const calculateTopPosition = () => { 1765 let topOffset = 0; 1766 1767 // Get wpadminbar height if it exists 1768 const wpAdminBar = document.getElementById('wpadminbar'); 1769 if (wpAdminBar) { 1770 topOffset += wpAdminBar.offsetHeight; 1771 } 1772 1773 // Get ld-focus-header height if it exists 1774 const ldFocusHeader = document.getElementById('ld-focus-header'); 1775 if (ldFocusHeader) { 1776 topOffset += ldFocusHeader.offsetHeight; 1777 } 1778 1779 // Add 6px for extra padding 1780 topOffset += 6; 1781 return topOffset + 'px'; 1782 }; 1783 const topPosition = calculateTopPosition(); 1784 const defaultPosition = { 1785 top: topPosition, 1786 right: '20px', 1787 left: 'unset' // Must be unset to allow the button to be on the right side of the screen. 1788 }; 1789 if (storedPosition) { 1790 const position = JSON.parse(storedPosition); 1791 if (position.x < 0 || position.x === 'unset' || position.y < 0 || position.y === 'unset') { 1792 $button.css(defaultPosition); 1793 } else { 1794 $button.css({ 1795 top: position.x, 1796 right: position.y, 1797 left: 'unset' 1798 }); 1799 } 1800 } else { 1801 $button.css(defaultPosition); 1802 } 1803 }); 1804 const localStorage = window.localStorage; 1805 const learndashNotesDraggablePoints = JSON.parse(localStorage.getItem('learndash_notes_draggable_points')); 1806 if (learndashNotesDraggablePoints !== null && learndashNotesDraggablePoints.x && learndashNotesDraggablePoints.y) { 1807 const element = jQuery('.ld-notes-modal'); 1808 element.css('top', learndashNotesDraggablePoints.x); 1809 element.css('left', learndashNotesDraggablePoints.y); 1810 } 1811 const learndashNotesDraggableResize = JSON.parse(localStorage.getItem('learndash_notes_draggable_resize')); 1812 if (learndashNotesDraggableResize !== null && learndashNotesDraggableResize.width && learndashNotesDraggableResize.height) { 1813 const element = jQuery('.ld-notes-modal'); 1814 element.css('width', learndashNotesDraggableResize.width); 1815 element.css('height', learndashNotesDraggableResize.height); 1816 } 1817 $('.ld-notes-trigger-modal').draggable({ 1818 containment: 'body', 1819 cancel: 'input[name="ld-notes-title-input"], .ui-resizable-se', 1820 drag() { 1821 const $this = $(this); 1822 positionModal($this); 1823 }, 1824 stop() { 1825 const thisPos = $(this).position(); 1826 const winWidth = $(window).width(); 1827 const btnWidth = $(this).outerWidth(); 1828 // Calculate right relative position 1829 const right = winWidth - (thisPos.left + btnWidth); 1830 localStorage.setItem('learndash_notes_draggable_points', JSON.stringify({ 1831 x: thisPos.top, 1832 y: right + 'px' 1833 })); 1834 // Set CSS 1835 $(this).css({ 1836 top: thisPos.top + 'px', 1837 right: right + 'px', 1838 left: 'unset' 1839 }); 1840 } 1841 }); 1842 $('.ld-notes-modal').resizable({ 1843 classes: { 1844 'ui-resizable-se': 'ld-notes-modal__resizable-icon' 1845 }, 1846 create() {
1847 const trap = focus_trap__WEBPACK_IMPORTED_MODULE_0__.createFocusTrap(this, { 1848 clickOutsideDeactivates: true 1849 }); 1850 $(this).data('ld-focus-trap', trap); 1851 $(this).css('display', 'none'); 1852 }, 1853 resize(event, ui) { 1854 const modalHeight = ui.size.height; 1855 // Set editor to 30% of modal height and can't be less than 100px. 1856 let editorHeight = Math.floor(modalHeight * 0.3); 1857 if (editorHeight < 100) { 1858 editorHeight = 100; 1859 } 1860 $('#wp-llms_note_text_popup-wrap iframe').css('height', editorHeight + 'px'); 1861 $('.ld-notes-modal').css('height', modalHeight + 'px'); 1862 1863 // Calculate minimum height based on components. 1864 const headerHeight = $('.ld-notes-modal__header').outerHeight(); 1865 const contentHeight = $('.ld-notes-modal__content').outerHeight(); 1866 1867 // Add some padding between components. 1868 const minHeight = headerHeight + contentHeight; 1869 $('.ld-notes-modal').css('min-height', minHeight + 'px'); 1870 }, 1871 stop(e, ui) { 1872 localStorage.setItem('learndash_notes_draggable_resize', JSON.stringify({ 1873 width: ui.size.width, 1874 height: ui.size.height 1875 })); 1876 } 1877 }); 1878 $('.ld-notes-modal__minimize').click(function () { 1879 const $modal = $(this).closest('.ld-notes-modal'); 1880 const trap = $modal.data('ld-focus-trap'); 1881 trap.deactivate(); 1882 $modal.toggleClass('ld-notes-modal--active'); 1883 $modal.siblings('.ld-notes-trigger-modal').toggleClass('ld-notes-trigger-modal--active'); 1884 $('.mce-resizehandle').css('visibility', 'hidden'); 1885 localStorage.setItem('learndash_notes_draggable_mode', 'minimize'); 1886 }); 1887 $('.ld-notes-trigger-modal').click(function () { 1888 positionModal($('.ld-notes-trigger-modal')); 1889 const $modal = $('.ld-notes-modal'); 1890 const $resizeHandle = $('.mce-resizehandle'); 1891 let isVisible = $modal.is(':visible'); 1892 $(this).toggleClass('ld-notes-trigger-modal--active'); 1893 $modal.toggleClass('ld-notes-modal--active'); 1894 $resizeHandle.css('visibility', isVisible ? 'hidden' : 'visible'); 1895 isVisible = $modal.is(':visible'); 1896 const trap = $modal.data('ld-focus-trap'); 1897 if (isVisible) { 1898 trap.activate(); 1899 } else { 1900 trap.deactivate(); 1901 } 1902 localStorage.setItem('learndash_notes_draggable_mode', 'maximize'); 1903 }); 1904 })(); 1905 (function () { 1906 // TinyMCE focus state scripts. 1907 window.addEventListener('load', function () { 1908 // Set focus state for tinymce editors. 1909 if (window.tinymce && tinymce.editors) { 1910 Object.keys(tinymce.editors).forEach(function (editor) { 1911 tinymce.editors[editor].on('focus', function () { 1912 const tinymceElement = $('#' + 'wp-' + editor + '-wrap').find('.mce-tinymce'); 1913 tinymceElement.addClass('mce-tinymce--focus'); 1914 }); 1915 tinymce.editors[editor].on('focusout', function () { 1916 const tinymceElement = $('#' + 'wp-' + editor + '-wrap').find('.mce-tinymce'); 1917 tinymceElement.removeClass('mce-tinymce--focus'); 1918 }); 1919 }); 1920 } 1921 }); 1922 1923 // Character count scripts. 1924 window.addEventListener('load', tinyMceTextDataPopupCounter); 1925 function tinyMceTextDataPopupCounter() { 1926 if (window.tinymce && tinymce.editors) { 1927 setInterval(function () { 1928 const tinyMceTextData = tinymce.get('llms_note_text').getContent(); 1929 // Legacy regex pattern. The regex pattern removes all HTML tags, WP shortcodes, and whitespaces. 1930 const regexPattern = /(<[a-zA-Z\/][^<>]*>|\[([^\]]+)\])|(\s+)/gi; 1931 if (tinyMceTextData) { 1932 const content = tinyMceTextData.replace(regexPattern, ''); 1933 $('#learndash-notes-form .ld-notes-form__char-count').text(content.length); 1934 } 1935 const tinyMceTextDataPopup = tinymce.get('llms_note_text_popup').getContent(); 1936 if (tinyMceTextDataPopup) { 1937 const content = tinyMceTextDataPopup.replace(regexPattern, ''); 1938 $('#learndash-notes-form-popup .ld-notes-form__char-count').text(content.length); 1939 } 1940 }, 300); 1941 } 1942 } 1943 1944 // Ensure draggable button stays within viewport on window resize. 1945 $(window).on('resize', function () { 1946 const localStorage = window.localStorage; 1947 const $button = $('.ld-notes-trigger-modal'); 1948 const storedPosition = localStorage.getItem('learndash_notes_draggable_points'); 1949 const storedSize = localStorage.getItem('learndash_notes_draggable_resize'); 1950 if ($button.length && storedPosition && storedSize) { 1951 const position = JSON.parse(storedPosition); 1952 let top = parseInt(position.x, 10); 1953 let right = parseInt(position.y, 10); 1954 const btnWidth = $button.outerWidth(); 1955 const btnHeight = $button.outerHeight(); 1956 const winWidth = $(window).width(); 1957 const winHeight = $(window).height(); 1958 const size = JSON.parse(storedSize); 1959 let modalWidth = size.width;
1960 let modalHeight = size.height; 1961 let changed = false; 1962 if (top + btnHeight > winHeight) { 1963 top = winHeight - btnHeight - 10; 1964 changed = true; 1965 } 1966 if (top < 0) { 1967 top = 0; 1968 changed = true; 1969 } 1970 if (right + btnWidth > winWidth) { 1971 right = winWidth - btnWidth - 10; 1972 changed = true; 1973 } 1974 if (right < 0) { 1975 right = 10; 1976 changed = true; 1977 } 1978 if (modalWidth > winWidth) { 1979 modalWidth = winWidth - 10; 1980 changed = true; 1981 } 1982 if (modalHeight > winHeight) { 1983 modalHeight = winHeight - 10; 1984 changed = true; 1985 } 1986 if (changed) { 1987 // To simplify the repositioning, we set the position relative to the right side of the screen. 1988 $button.css({ 1989 top: top + 'px', 1990 right: right + 'px', 1991 left: 'unset' 1992 }); 1993 localStorage.setItem('learndash_notes_draggable_points', JSON.stringify({ 1994 x: top, 1995 y: right + 'px' 1996 })); 1997 1998 // Check if viewport is below 660px for responsive behavior 1999 const isSmallScreen = winWidth < 660; 2000 2001 // Apply responsive modal positioning and sizing 2002 const modalStyles = { 2003 height: modalHeight + 'px' 2004 }; 2005 if (isSmallScreen) { 2006 // For small screens, expand to screen edges with 10px padding 2007 modalStyles.left = '10px'; 2008 modalStyles.right = '10px'; 2009 // Ensure width never exceeds viewport width 2010 modalStyles.width = Math.min(winWidth - 20, modalWidth) + 'px'; 2011 } else { 2012 // Normal sizing for larger screens 2013 modalStyles.width = modalWidth + 'px'; 2014 } 2015 $('.ld-notes-modal').css(modalStyles); 2016 localStorage.setItem('learndash_notes_draggable_resize', JSON.stringify({ 2017 width: modalWidth, 2018 height: modalHeight 2019 })); 2020 } 2021 } 2022 }); 2023 })(); 2024}); 2025})(); 2026 2027/******/ })() 2028;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.