focus-trap 5.0.2 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +1 -0
- package/dist/focus-trap.js +20 -63
- package/dist/focus-trap.min.js +1 -1
- package/index.d.ts +6 -0
- package/index.js +7 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.0
|
|
4
|
+
|
|
5
|
+
- Add `setReturnFocus` option that allows you to set which element receives focus when the trap closes.
|
|
6
|
+
|
|
3
7
|
## 5.0.2
|
|
4
8
|
|
|
5
9
|
- Add `allowOutsideClick` option that allows you to pass a click event through, even when `clickOutsideDeactivates` is `false`.
|
package/README.md
CHANGED
|
@@ -69,6 +69,7 @@ Returns a new focus trap on `element`.
|
|
|
69
69
|
- **escapeDeactivates** {boolean}: Default: `true`. If `false`, the `Escape` key will not trigger deactivation of the focus trap. This can be useful if you want to force the user to make a decision instead of allowing an easy way out.
|
|
70
70
|
- **clickOutsideDeactivates** {boolean}: Default: `false`. If `true`, a click outside the focus trap will deactivate the focus trap and allow the click event to do its thing.
|
|
71
71
|
- **returnFocusOnDeactivate** {boolean}: Default: `true`. If `false`, when the trap is deactivated, focus will *not* return to the element that had focus before activation.
|
|
72
|
+
- **setReturnFocus** {element|string|function}: By default, focus trap on deactivation will return to the element that was focused before activation. With this option you can specify another element to programmatically receive focus after deactivation. Can be a DOM node, or a selector string (which will be passed to `document.querySelector()` to find the DOM node), or a function that returns a DOM node.
|
|
72
73
|
- **allowOutsideClick** {function}: If set and returns `true`, a click outside the focus trap will not be prevented, even when `clickOutsideDeactivates` is `false`.
|
|
73
74
|
|
|
74
75
|
### focusTrap.activate([activateOptions])
|
package/dist/focus-trap.js
CHANGED
|
@@ -115,7 +115,7 @@ function focusTrap(element, userOptions) {
|
|
|
115
115
|
: config.returnFocusOnDeactivate;
|
|
116
116
|
if (returnFocus) {
|
|
117
117
|
delay(function() {
|
|
118
|
-
tryFocus(state.nodeFocusedBeforeActivation);
|
|
118
|
+
tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -213,13 +213,18 @@ function focusTrap(element, userOptions) {
|
|
|
213
213
|
|
|
214
214
|
if (!node) {
|
|
215
215
|
throw new Error(
|
|
216
|
-
|
|
216
|
+
'Your focus-trap needs to have at least one focusable element'
|
|
217
217
|
);
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
return node;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
function getReturnFocusNode(previousActiveElement) {
|
|
224
|
+
var node = getNodeForOption('setReturnFocus');
|
|
225
|
+
return node ? node : previousActiveElement;
|
|
226
|
+
}
|
|
227
|
+
|
|
223
228
|
// This needs to be done on mousedown and touchstart instead of click
|
|
224
229
|
// so that it precedes the focus event.
|
|
225
230
|
function checkPointerDown(e) {
|
|
@@ -302,7 +307,6 @@ function focusTrap(element, userOptions) {
|
|
|
302
307
|
tryFocus(getInitialFocusNode());
|
|
303
308
|
return;
|
|
304
309
|
}
|
|
305
|
-
|
|
306
310
|
node.focus();
|
|
307
311
|
state.mostRecentlyFocusedNode = node;
|
|
308
312
|
if (isSelectableInput(node)) {
|
|
@@ -354,11 +358,9 @@ var matches = typeof Element === 'undefined'
|
|
|
354
358
|
function tabbable(el, options) {
|
|
355
359
|
options = options || {};
|
|
356
360
|
|
|
357
|
-
var elementDocument = el.ownerDocument || el;
|
|
358
361
|
var regularTabbables = [];
|
|
359
362
|
var orderedTabbables = [];
|
|
360
363
|
|
|
361
|
-
var untouchabilityChecker = new UntouchabilityChecker(elementDocument);
|
|
362
364
|
var candidates = el.querySelectorAll(candidateSelector);
|
|
363
365
|
|
|
364
366
|
if (options.includeContainer) {
|
|
@@ -372,7 +374,7 @@ function tabbable(el, options) {
|
|
|
372
374
|
for (i = 0; i < candidates.length; i++) {
|
|
373
375
|
candidate = candidates[i];
|
|
374
376
|
|
|
375
|
-
if (!isNodeMatchingSelectorTabbable(candidate
|
|
377
|
+
if (!isNodeMatchingSelectorTabbable(candidate)) continue;
|
|
376
378
|
|
|
377
379
|
candidateTabindex = getTabindex(candidate);
|
|
378
380
|
if (candidateTabindex === 0) {
|
|
@@ -397,9 +399,9 @@ function tabbable(el, options) {
|
|
|
397
399
|
tabbable.isTabbable = isTabbable;
|
|
398
400
|
tabbable.isFocusable = isFocusable;
|
|
399
401
|
|
|
400
|
-
function isNodeMatchingSelectorTabbable(node
|
|
402
|
+
function isNodeMatchingSelectorTabbable(node) {
|
|
401
403
|
if (
|
|
402
|
-
!isNodeMatchingSelectorFocusable(node
|
|
404
|
+
!isNodeMatchingSelectorFocusable(node)
|
|
403
405
|
|| isNonTabbableRadio(node)
|
|
404
406
|
|| getTabindex(node) < 0
|
|
405
407
|
) {
|
|
@@ -408,18 +410,17 @@ function isNodeMatchingSelectorTabbable(node, untouchabilityChecker) {
|
|
|
408
410
|
return true;
|
|
409
411
|
}
|
|
410
412
|
|
|
411
|
-
function isTabbable(node
|
|
413
|
+
function isTabbable(node) {
|
|
412
414
|
if (!node) throw new Error('No node provided');
|
|
413
415
|
if (matches.call(node, candidateSelector) === false) return false;
|
|
414
|
-
return isNodeMatchingSelectorTabbable(node
|
|
416
|
+
return isNodeMatchingSelectorTabbable(node);
|
|
415
417
|
}
|
|
416
418
|
|
|
417
|
-
function isNodeMatchingSelectorFocusable(node
|
|
418
|
-
untouchabilityChecker = untouchabilityChecker || new UntouchabilityChecker(node.ownerDocument || node);
|
|
419
|
+
function isNodeMatchingSelectorFocusable(node) {
|
|
419
420
|
if (
|
|
420
421
|
node.disabled
|
|
421
422
|
|| isHiddenInput(node)
|
|
422
|
-
||
|
|
423
|
+
|| isHidden(node)
|
|
423
424
|
) {
|
|
424
425
|
return false;
|
|
425
426
|
}
|
|
@@ -427,10 +428,10 @@ function isNodeMatchingSelectorFocusable(node, untouchabilityChecker) {
|
|
|
427
428
|
}
|
|
428
429
|
|
|
429
430
|
var focusableCandidateSelector = candidateSelectors.concat('iframe').join(',');
|
|
430
|
-
function isFocusable(node
|
|
431
|
+
function isFocusable(node) {
|
|
431
432
|
if (!node) throw new Error('No node provided');
|
|
432
433
|
if (matches.call(node, focusableCandidateSelector) === false) return false;
|
|
433
|
-
return isNodeMatchingSelectorFocusable(node
|
|
434
|
+
return isNodeMatchingSelectorFocusable(node);
|
|
434
435
|
}
|
|
435
436
|
|
|
436
437
|
function getTabindex(node) {
|
|
@@ -446,13 +447,6 @@ function sortOrderedTabbables(a, b) {
|
|
|
446
447
|
return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
|
|
447
448
|
}
|
|
448
449
|
|
|
449
|
-
// Array.prototype.find not available in IE.
|
|
450
|
-
function find(list, predicate) {
|
|
451
|
-
for (var i = 0, length = list.length; i < length; i++) {
|
|
452
|
-
if (predicate(list[i])) return list[i];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
450
|
function isContentEditable(node) {
|
|
457
451
|
return node.contentEditable === 'true';
|
|
458
452
|
}
|
|
@@ -490,47 +484,10 @@ function isTabbableRadio(node) {
|
|
|
490
484
|
return !checked || checked === node;
|
|
491
485
|
}
|
|
492
486
|
|
|
493
|
-
|
|
494
|
-
//
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
// Node cache must be refreshed on every check, in case
|
|
498
|
-
// the content of the element has changed. The cache contains tuples
|
|
499
|
-
// mapping nodes to their boolean result.
|
|
500
|
-
this.cache = [];
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// getComputedStyle accurately reflects `visibility: hidden` of ancestors
|
|
504
|
-
// but not `display: none`, so we need to recursively check parents.
|
|
505
|
-
UntouchabilityChecker.prototype.hasDisplayNone = function hasDisplayNone(node, nodeComputedStyle) {
|
|
506
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return false;
|
|
507
|
-
|
|
508
|
-
// Search for a cached result.
|
|
509
|
-
var cached = find(this.cache, function(item) {
|
|
510
|
-
return item === node;
|
|
511
|
-
});
|
|
512
|
-
if (cached) return cached[1];
|
|
513
|
-
|
|
514
|
-
nodeComputedStyle = nodeComputedStyle || this.doc.defaultView.getComputedStyle(node);
|
|
515
|
-
|
|
516
|
-
var result = false;
|
|
517
|
-
|
|
518
|
-
if (nodeComputedStyle.display === 'none') {
|
|
519
|
-
result = true;
|
|
520
|
-
} else if (node.parentNode) {
|
|
521
|
-
result = this.hasDisplayNone(node.parentNode);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
this.cache.push([node, result]);
|
|
525
|
-
|
|
526
|
-
return result;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
UntouchabilityChecker.prototype.isUntouchable = function isUntouchable(node) {
|
|
530
|
-
if (node === this.doc.documentElement) return false;
|
|
531
|
-
var computedStyle = this.doc.defaultView.getComputedStyle(node);
|
|
532
|
-
if (this.hasDisplayNone(node, computedStyle)) return true;
|
|
533
|
-
return computedStyle.visibility === 'hidden';
|
|
487
|
+
function isHidden(node) {
|
|
488
|
+
// offsetParent being null will allow detecting cases where an element is invisible or inside an invisible element,
|
|
489
|
+
// as long as the element does not use position: fixed. For them, their visibility has to be checked directly as well.
|
|
490
|
+
return node.offsetParent === null || getComputedStyle(node).visibility === 'hidden';
|
|
534
491
|
}
|
|
535
492
|
|
|
536
493
|
module.exports = tabbable;
|
package/dist/focus-trap.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.focusTrap=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){var tabbable=require("tabbable");var xtend=require("xtend");var activeFocusDelay;var activeFocusTraps=function(){var trapQueue=[];return{activateTrap:function(trap){if(trapQueue.length>0){var activeTrap=trapQueue[trapQueue.length-1];if(activeTrap!==trap){activeTrap.pause()}}var trapIndex=trapQueue.indexOf(trap);if(trapIndex===-1){trapQueue.push(trap)}else{trapQueue.splice(trapIndex,1);trapQueue.push(trap)}},deactivateTrap:function(trap){var trapIndex=trapQueue.indexOf(trap);if(trapIndex!==-1){trapQueue.splice(trapIndex,1)}if(trapQueue.length>0){trapQueue[trapQueue.length-1].unpause()}}}}();function focusTrap(element,userOptions){var doc=document;var container=typeof element==="string"?doc.querySelector(element):element;var config=xtend({returnFocusOnDeactivate:true,escapeDeactivates:true},userOptions);var state={firstTabbableNode:null,lastTabbableNode:null,nodeFocusedBeforeActivation:null,mostRecentlyFocusedNode:null,active:false,paused:false};var trap={activate:activate,deactivate:deactivate,pause:pause,unpause:unpause};return trap;function activate(activateOptions){if(state.active)return;updateTabbableNodes();state.active=true;state.paused=false;state.nodeFocusedBeforeActivation=doc.activeElement;var onActivate=activateOptions&&activateOptions.onActivate?activateOptions.onActivate:config.onActivate;if(onActivate){onActivate()}addListeners();return trap}function deactivate(deactivateOptions){if(!state.active)return;clearTimeout(activeFocusDelay);removeListeners();state.active=false;state.paused=false;activeFocusTraps.deactivateTrap(trap);var onDeactivate=deactivateOptions&&deactivateOptions.onDeactivate!==undefined?deactivateOptions.onDeactivate:config.onDeactivate;if(onDeactivate){onDeactivate()}var returnFocus=deactivateOptions&&deactivateOptions.returnFocus!==undefined?deactivateOptions.returnFocus:config.returnFocusOnDeactivate;if(returnFocus){delay(function(){tryFocus(state.nodeFocusedBeforeActivation)})}return trap}function pause(){if(state.paused||!state.active)return;state.paused=true;removeListeners()}function unpause(){if(!state.paused||!state.active)return;state.paused=false;updateTabbableNodes();addListeners()}function addListeners(){if(!state.active)return;activeFocusTraps.activateTrap(trap);activeFocusDelay=delay(function(){tryFocus(getInitialFocusNode())});doc.addEventListener("focusin",checkFocusIn,true);doc.addEventListener("mousedown",checkPointerDown,{capture:true,passive:false});doc.addEventListener("touchstart",checkPointerDown,{capture:true,passive:false});doc.addEventListener("click",checkClick,{capture:true,passive:false});doc.addEventListener("keydown",checkKey,{capture:true,passive:false});return trap}function removeListeners(){if(!state.active)return;doc.removeEventListener("focusin",checkFocusIn,true);doc.removeEventListener("mousedown",checkPointerDown,true);doc.removeEventListener("touchstart",checkPointerDown,true);doc.removeEventListener("click",checkClick,true);doc.removeEventListener("keydown",checkKey,true);return trap}function getNodeForOption(optionName){var optionValue=config[optionName];var node=optionValue;if(!optionValue){return null}if(typeof optionValue==="string"){node=doc.querySelector(optionValue);if(!node){throw new Error("`"+optionName+"` refers to no known node")}}if(typeof optionValue==="function"){node=optionValue();if(!node){throw new Error("`"+optionName+"` did not return a node")}}return node}function getInitialFocusNode(){var node;if(getNodeForOption("initialFocus")!==null){node=getNodeForOption("initialFocus")}else if(container.contains(doc.activeElement)){node=doc.activeElement}else{node=state.firstTabbableNode||getNodeForOption("fallbackFocus")}if(!node){throw new Error("You can't have a focus-trap without at least one focusable element")}return node}function checkPointerDown(e){if(container.contains(e.target))return;if(config.clickOutsideDeactivates){deactivate({returnFocus:!tabbable.isFocusable(e.target)});return}if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault()}function checkFocusIn(e){if(container.contains(e.target)||e.target instanceof Document){return}e.stopImmediatePropagation();tryFocus(state.mostRecentlyFocusedNode||getInitialFocusNode())}function checkKey(e){if(config.escapeDeactivates!==false&&isEscapeEvent(e)){e.preventDefault();deactivate();return}if(isTabEvent(e)){checkTab(e);return}}function checkTab(e){updateTabbableNodes();if(e.shiftKey&&e.target===state.firstTabbableNode){e.preventDefault();tryFocus(state.lastTabbableNode);return}if(!e.shiftKey&&e.target===state.lastTabbableNode){e.preventDefault();tryFocus(state.firstTabbableNode);return}}function checkClick(e){if(config.clickOutsideDeactivates)return;if(container.contains(e.target))return;if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault();e.stopImmediatePropagation()}function updateTabbableNodes(){var tabbableNodes=tabbable(container);state.firstTabbableNode=tabbableNodes[0]||getInitialFocusNode();state.lastTabbableNode=tabbableNodes[tabbableNodes.length-1]||getInitialFocusNode()}function tryFocus(node){if(node===doc.activeElement)return;if(!node||!node.focus){tryFocus(getInitialFocusNode());return}node.focus();state.mostRecentlyFocusedNode=node;if(isSelectableInput(node)){node.select()}}}function isSelectableInput(node){return node.tagName&&node.tagName.toLowerCase()==="input"&&typeof node.select==="function"}function isEscapeEvent(e){return e.key==="Escape"||e.key==="Esc"||e.keyCode===27}function isTabEvent(e){return e.key==="Tab"||e.keyCode===9}function delay(fn){return setTimeout(fn,0)}module.exports=focusTrap},{tabbable:2,xtend:3}],2:[function(require,module,exports){var candidateSelectors=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])'];var candidateSelector=candidateSelectors.join(",");var matches=typeof Element==="undefined"?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function tabbable(el,options){options=options||{};var elementDocument=el.ownerDocument||el;var regularTabbables=[];var orderedTabbables=[];var untouchabilityChecker=new UntouchabilityChecker(elementDocument);var candidates=el.querySelectorAll(candidateSelector);if(options.includeContainer){if(matches.call(el,candidateSelector)){candidates=Array.prototype.slice.apply(candidates);candidates.unshift(el)}}var i,candidate,candidateTabindex;for(i=0;i<candidates.length;i++){candidate=candidates[i];if(!isNodeMatchingSelectorTabbable(candidate,untouchabilityChecker))continue;candidateTabindex=getTabindex(candidate);if(candidateTabindex===0){regularTabbables.push(candidate)}else{orderedTabbables.push({documentOrder:i,tabIndex:candidateTabindex,node:candidate})}}var tabbableNodes=orderedTabbables.sort(sortOrderedTabbables).map(function(a){return a.node}).concat(regularTabbables);return tabbableNodes}tabbable.isTabbable=isTabbable;tabbable.isFocusable=isFocusable;function isNodeMatchingSelectorTabbable(node,untouchabilityChecker){if(!isNodeMatchingSelectorFocusable(node,untouchabilityChecker)||isNonTabbableRadio(node)||getTabindex(node)<0){return false}return true}function isTabbable(node,untouchabilityChecker){if(!node)throw new Error("No node provided");if(matches.call(node,candidateSelector)===false)return false;return isNodeMatchingSelectorTabbable(node,untouchabilityChecker)}function isNodeMatchingSelectorFocusable(node,untouchabilityChecker){untouchabilityChecker=untouchabilityChecker||new UntouchabilityChecker(node.ownerDocument||node);if(node.disabled||isHiddenInput(node)||untouchabilityChecker.isUntouchable(node)){return false}return true}var focusableCandidateSelector=candidateSelectors.concat("iframe").join(",");function isFocusable(node,untouchabilityChecker){if(!node)throw new Error("No node provided");if(matches.call(node,focusableCandidateSelector)===false)return false;return isNodeMatchingSelectorFocusable(node,untouchabilityChecker)}function getTabindex(node){var tabindexAttr=parseInt(node.getAttribute("tabindex"),10);if(!isNaN(tabindexAttr))return tabindexAttr;if(isContentEditable(node))return 0;return node.tabIndex}function sortOrderedTabbables(a,b){return a.tabIndex===b.tabIndex?a.documentOrder-b.documentOrder:a.tabIndex-b.tabIndex}function find(list,predicate){for(var i=0,length=list.length;i<length;i++){if(predicate(list[i]))return list[i]}}function isContentEditable(node){return node.contentEditable==="true"}function isInput(node){return node.tagName==="INPUT"}function isHiddenInput(node){return isInput(node)&&node.type==="hidden"}function isRadio(node){return isInput(node)&&node.type==="radio"}function isNonTabbableRadio(node){return isRadio(node)&&!isTabbableRadio(node)}function getCheckedRadio(nodes){for(var i=0;i<nodes.length;i++){if(nodes[i].checked){return nodes[i]}}}function isTabbableRadio(node){if(!node.name)return true;var radioSet=node.ownerDocument.querySelectorAll('input[type="radio"][name="'+node.name+'"]');var checked=getCheckedRadio(radioSet);return!checked||checked===node}function UntouchabilityChecker(elementDocument){this.doc=elementDocument;this.cache=[]}UntouchabilityChecker.prototype.hasDisplayNone=function hasDisplayNone(node,nodeComputedStyle){if(node.nodeType!==Node.ELEMENT_NODE)return false;var cached=find(this.cache,function(item){return item===node});if(cached)return cached[1];nodeComputedStyle=nodeComputedStyle||this.doc.defaultView.getComputedStyle(node);var result=false;if(nodeComputedStyle.display==="none"){result=true}else if(node.parentNode){result=this.hasDisplayNone(node.parentNode)}this.cache.push([node,result]);return result};UntouchabilityChecker.prototype.isUntouchable=function isUntouchable(node){if(node===this.doc.documentElement)return false;var computedStyle=this.doc.defaultView.getComputedStyle(node);if(this.hasDisplayNone(node,computedStyle))return true;return computedStyle.visibility==="hidden"};module.exports=tabbable},{}],3:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target}},{}]},{},[1])(1)});
|
|
1
|
+
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.focusTrap=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){var tabbable=require("tabbable");var xtend=require("xtend");var activeFocusDelay;var activeFocusTraps=function(){var trapQueue=[];return{activateTrap:function(trap){if(trapQueue.length>0){var activeTrap=trapQueue[trapQueue.length-1];if(activeTrap!==trap){activeTrap.pause()}}var trapIndex=trapQueue.indexOf(trap);if(trapIndex===-1){trapQueue.push(trap)}else{trapQueue.splice(trapIndex,1);trapQueue.push(trap)}},deactivateTrap:function(trap){var trapIndex=trapQueue.indexOf(trap);if(trapIndex!==-1){trapQueue.splice(trapIndex,1)}if(trapQueue.length>0){trapQueue[trapQueue.length-1].unpause()}}}}();function focusTrap(element,userOptions){var doc=document;var container=typeof element==="string"?doc.querySelector(element):element;var config=xtend({returnFocusOnDeactivate:true,escapeDeactivates:true},userOptions);var state={firstTabbableNode:null,lastTabbableNode:null,nodeFocusedBeforeActivation:null,mostRecentlyFocusedNode:null,active:false,paused:false};var trap={activate:activate,deactivate:deactivate,pause:pause,unpause:unpause};return trap;function activate(activateOptions){if(state.active)return;updateTabbableNodes();state.active=true;state.paused=false;state.nodeFocusedBeforeActivation=doc.activeElement;var onActivate=activateOptions&&activateOptions.onActivate?activateOptions.onActivate:config.onActivate;if(onActivate){onActivate()}addListeners();return trap}function deactivate(deactivateOptions){if(!state.active)return;clearTimeout(activeFocusDelay);removeListeners();state.active=false;state.paused=false;activeFocusTraps.deactivateTrap(trap);var onDeactivate=deactivateOptions&&deactivateOptions.onDeactivate!==undefined?deactivateOptions.onDeactivate:config.onDeactivate;if(onDeactivate){onDeactivate()}var returnFocus=deactivateOptions&&deactivateOptions.returnFocus!==undefined?deactivateOptions.returnFocus:config.returnFocusOnDeactivate;if(returnFocus){delay(function(){tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation))})}return trap}function pause(){if(state.paused||!state.active)return;state.paused=true;removeListeners()}function unpause(){if(!state.paused||!state.active)return;state.paused=false;updateTabbableNodes();addListeners()}function addListeners(){if(!state.active)return;activeFocusTraps.activateTrap(trap);activeFocusDelay=delay(function(){tryFocus(getInitialFocusNode())});doc.addEventListener("focusin",checkFocusIn,true);doc.addEventListener("mousedown",checkPointerDown,{capture:true,passive:false});doc.addEventListener("touchstart",checkPointerDown,{capture:true,passive:false});doc.addEventListener("click",checkClick,{capture:true,passive:false});doc.addEventListener("keydown",checkKey,{capture:true,passive:false});return trap}function removeListeners(){if(!state.active)return;doc.removeEventListener("focusin",checkFocusIn,true);doc.removeEventListener("mousedown",checkPointerDown,true);doc.removeEventListener("touchstart",checkPointerDown,true);doc.removeEventListener("click",checkClick,true);doc.removeEventListener("keydown",checkKey,true);return trap}function getNodeForOption(optionName){var optionValue=config[optionName];var node=optionValue;if(!optionValue){return null}if(typeof optionValue==="string"){node=doc.querySelector(optionValue);if(!node){throw new Error("`"+optionName+"` refers to no known node")}}if(typeof optionValue==="function"){node=optionValue();if(!node){throw new Error("`"+optionName+"` did not return a node")}}return node}function getInitialFocusNode(){var node;if(getNodeForOption("initialFocus")!==null){node=getNodeForOption("initialFocus")}else if(container.contains(doc.activeElement)){node=doc.activeElement}else{node=state.firstTabbableNode||getNodeForOption("fallbackFocus")}if(!node){throw new Error("Your focus-trap needs to have at least one focusable element")}return node}function getReturnFocusNode(previousActiveElement){var node=getNodeForOption("setReturnFocus");return node?node:previousActiveElement}function checkPointerDown(e){if(container.contains(e.target))return;if(config.clickOutsideDeactivates){deactivate({returnFocus:!tabbable.isFocusable(e.target)});return}if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault()}function checkFocusIn(e){if(container.contains(e.target)||e.target instanceof Document){return}e.stopImmediatePropagation();tryFocus(state.mostRecentlyFocusedNode||getInitialFocusNode())}function checkKey(e){if(config.escapeDeactivates!==false&&isEscapeEvent(e)){e.preventDefault();deactivate();return}if(isTabEvent(e)){checkTab(e);return}}function checkTab(e){updateTabbableNodes();if(e.shiftKey&&e.target===state.firstTabbableNode){e.preventDefault();tryFocus(state.lastTabbableNode);return}if(!e.shiftKey&&e.target===state.lastTabbableNode){e.preventDefault();tryFocus(state.firstTabbableNode);return}}function checkClick(e){if(config.clickOutsideDeactivates)return;if(container.contains(e.target))return;if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault();e.stopImmediatePropagation()}function updateTabbableNodes(){var tabbableNodes=tabbable(container);state.firstTabbableNode=tabbableNodes[0]||getInitialFocusNode();state.lastTabbableNode=tabbableNodes[tabbableNodes.length-1]||getInitialFocusNode()}function tryFocus(node){if(node===doc.activeElement)return;if(!node||!node.focus){tryFocus(getInitialFocusNode());return}node.focus();state.mostRecentlyFocusedNode=node;if(isSelectableInput(node)){node.select()}}}function isSelectableInput(node){return node.tagName&&node.tagName.toLowerCase()==="input"&&typeof node.select==="function"}function isEscapeEvent(e){return e.key==="Escape"||e.key==="Esc"||e.keyCode===27}function isTabEvent(e){return e.key==="Tab"||e.keyCode===9}function delay(fn){return setTimeout(fn,0)}module.exports=focusTrap},{tabbable:2,xtend:3}],2:[function(require,module,exports){var candidateSelectors=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])'];var candidateSelector=candidateSelectors.join(",");var matches=typeof Element==="undefined"?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function tabbable(el,options){options=options||{};var regularTabbables=[];var orderedTabbables=[];var candidates=el.querySelectorAll(candidateSelector);if(options.includeContainer){if(matches.call(el,candidateSelector)){candidates=Array.prototype.slice.apply(candidates);candidates.unshift(el)}}var i,candidate,candidateTabindex;for(i=0;i<candidates.length;i++){candidate=candidates[i];if(!isNodeMatchingSelectorTabbable(candidate))continue;candidateTabindex=getTabindex(candidate);if(candidateTabindex===0){regularTabbables.push(candidate)}else{orderedTabbables.push({documentOrder:i,tabIndex:candidateTabindex,node:candidate})}}var tabbableNodes=orderedTabbables.sort(sortOrderedTabbables).map(function(a){return a.node}).concat(regularTabbables);return tabbableNodes}tabbable.isTabbable=isTabbable;tabbable.isFocusable=isFocusable;function isNodeMatchingSelectorTabbable(node){if(!isNodeMatchingSelectorFocusable(node)||isNonTabbableRadio(node)||getTabindex(node)<0){return false}return true}function isTabbable(node){if(!node)throw new Error("No node provided");if(matches.call(node,candidateSelector)===false)return false;return isNodeMatchingSelectorTabbable(node)}function isNodeMatchingSelectorFocusable(node){if(node.disabled||isHiddenInput(node)||isHidden(node)){return false}return true}var focusableCandidateSelector=candidateSelectors.concat("iframe").join(",");function isFocusable(node){if(!node)throw new Error("No node provided");if(matches.call(node,focusableCandidateSelector)===false)return false;return isNodeMatchingSelectorFocusable(node)}function getTabindex(node){var tabindexAttr=parseInt(node.getAttribute("tabindex"),10);if(!isNaN(tabindexAttr))return tabindexAttr;if(isContentEditable(node))return 0;return node.tabIndex}function sortOrderedTabbables(a,b){return a.tabIndex===b.tabIndex?a.documentOrder-b.documentOrder:a.tabIndex-b.tabIndex}function isContentEditable(node){return node.contentEditable==="true"}function isInput(node){return node.tagName==="INPUT"}function isHiddenInput(node){return isInput(node)&&node.type==="hidden"}function isRadio(node){return isInput(node)&&node.type==="radio"}function isNonTabbableRadio(node){return isRadio(node)&&!isTabbableRadio(node)}function getCheckedRadio(nodes){for(var i=0;i<nodes.length;i++){if(nodes[i].checked){return nodes[i]}}}function isTabbableRadio(node){if(!node.name)return true;var radioSet=node.ownerDocument.querySelectorAll('input[type="radio"][name="'+node.name+'"]');var checked=getCheckedRadio(radioSet);return!checked||checked===node}function isHidden(node){return node.offsetParent===null||getComputedStyle(node).visibility==="hidden"}module.exports=tabbable},{}],3:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target}},{}]},{},[1])(1)});
|
package/index.d.ts
CHANGED
|
@@ -41,6 +41,12 @@ declare module "focus-trap" {
|
|
|
41
41
|
*/
|
|
42
42
|
returnFocusOnDeactivate?: boolean;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* By default, focus trap on deactivation will return to the element
|
|
46
|
+
* that was focused before activation.
|
|
47
|
+
*/
|
|
48
|
+
setReturnFocus?: FocusTarget;
|
|
49
|
+
|
|
44
50
|
/**
|
|
45
51
|
* Default: `true`. If `false`, the `Escape` key will not trigger
|
|
46
52
|
* deactivation of the focus trap. This can be useful if you want
|
package/index.js
CHANGED
|
@@ -114,7 +114,7 @@ function focusTrap(element, userOptions) {
|
|
|
114
114
|
: config.returnFocusOnDeactivate;
|
|
115
115
|
if (returnFocus) {
|
|
116
116
|
delay(function() {
|
|
117
|
-
tryFocus(state.nodeFocusedBeforeActivation);
|
|
117
|
+
tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -212,13 +212,18 @@ function focusTrap(element, userOptions) {
|
|
|
212
212
|
|
|
213
213
|
if (!node) {
|
|
214
214
|
throw new Error(
|
|
215
|
-
|
|
215
|
+
'Your focus-trap needs to have at least one focusable element'
|
|
216
216
|
);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
return node;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
function getReturnFocusNode(previousActiveElement) {
|
|
223
|
+
var node = getNodeForOption('setReturnFocus');
|
|
224
|
+
return node ? node : previousActiveElement;
|
|
225
|
+
}
|
|
226
|
+
|
|
222
227
|
// This needs to be done on mousedown and touchstart instead of click
|
|
223
228
|
// so that it precedes the focus event.
|
|
224
229
|
function checkPointerDown(e) {
|
|
@@ -301,7 +306,6 @@ function focusTrap(element, userOptions) {
|
|
|
301
306
|
tryFocus(getInitialFocusNode());
|
|
302
307
|
return;
|
|
303
308
|
}
|
|
304
|
-
|
|
305
309
|
node.focus();
|
|
306
310
|
state.mostRecentlyFocusedNode = node;
|
|
307
311
|
if (isSelectableInput(node)) {
|