focus-trap 6.4.0 → 6.6.1

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/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import { tabbable, isFocusable } from 'tabbable';
2
2
 
3
- let activeFocusDelay;
4
-
5
3
  const activeFocusTraps = (function () {
6
4
  const trapQueue = [];
7
5
  return {
@@ -111,10 +109,21 @@ const createFocusTrap = function (elements, userOptions) {
111
109
  mostRecentlyFocusedNode: null,
112
110
  active: false,
113
111
  paused: false,
112
+
113
+ // timer ID for when delayInitialFocus is true and initial focus in this trap
114
+ // has been delayed during activation
115
+ delayInitialFocusTimer: undefined,
114
116
  };
115
117
 
116
118
  let 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
117
119
 
120
+ const getOption = (configOverrideOptions, optionName, configOptionName) => {
121
+ return configOverrideOptions &&
122
+ configOverrideOptions[optionName] !== undefined
123
+ ? configOverrideOptions[optionName]
124
+ : config[configOptionName || optionName];
125
+ };
126
+
118
127
  const containersContain = function (element) {
119
128
  return state.containers.some((container) => container.contains(element));
120
129
  };
@@ -147,6 +156,11 @@ const createFocusTrap = function (elements, userOptions) {
147
156
  const getInitialFocusNode = function () {
148
157
  let node;
149
158
 
159
+ // false indicates we want no initialFocus at all
160
+ if (getOption({}, 'initialFocus') === false) {
161
+ return false;
162
+ }
163
+
150
164
  if (getNodeForOption('initialFocus') !== null) {
151
165
  node = getNodeForOption('initialFocus');
152
166
  } else if (containersContain(doc.activeElement)) {
@@ -196,9 +210,14 @@ const createFocusTrap = function (elements, userOptions) {
196
210
  };
197
211
 
198
212
  const tryFocus = function (node) {
213
+ if (node === false) {
214
+ return;
215
+ }
216
+
199
217
  if (node === doc.activeElement) {
200
218
  return;
201
219
  }
220
+
202
221
  if (!node || !node.focus) {
203
222
  tryFocus(getInitialFocusNode());
204
223
  return;
@@ -376,7 +395,10 @@ const createFocusTrap = function (elements, userOptions) {
376
395
  };
377
396
 
378
397
  const checkKey = function (e) {
379
- if (config.escapeDeactivates !== false && isEscapeEvent(e)) {
398
+ if (
399
+ isEscapeEvent(e) &&
400
+ valueOrHandler(config.escapeDeactivates) !== false
401
+ ) {
380
402
  e.preventDefault();
381
403
  trap.deactivate();
382
404
  return;
@@ -419,7 +441,7 @@ const createFocusTrap = function (elements, userOptions) {
419
441
 
420
442
  // Delay ensures that the focused element doesn't capture the event
421
443
  // that caused the focus trap activation.
422
- activeFocusDelay = config.delayInitialFocus
444
+ state.delayInitialFocusTimer = config.delayInitialFocus
423
445
  ? delay(function () {
424
446
  tryFocus(getInitialFocusNode());
425
447
  })
@@ -470,21 +492,41 @@ const createFocusTrap = function (elements, userOptions) {
470
492
  return this;
471
493
  }
472
494
 
473
- updateTabbableNodes();
495
+ const onActivate = getOption(activateOptions, 'onActivate');
496
+ const onPostActivate = getOption(activateOptions, 'onPostActivate');
497
+ const checkCanFocusTrap = getOption(activateOptions, 'checkCanFocusTrap');
498
+
499
+ if (!checkCanFocusTrap) {
500
+ updateTabbableNodes();
501
+ }
474
502
 
475
503
  state.active = true;
476
504
  state.paused = false;
477
505
  state.nodeFocusedBeforeActivation = doc.activeElement;
478
506
 
479
- const onActivate =
480
- activateOptions && activateOptions.onActivate
481
- ? activateOptions.onActivate
482
- : config.onActivate;
483
507
  if (onActivate) {
484
508
  onActivate();
485
509
  }
486
510
 
487
- addListeners();
511
+ const finishActivation = () => {
512
+ if (checkCanFocusTrap) {
513
+ updateTabbableNodes();
514
+ }
515
+ addListeners();
516
+ if (onPostActivate) {
517
+ onPostActivate();
518
+ }
519
+ };
520
+
521
+ if (checkCanFocusTrap) {
522
+ checkCanFocusTrap(state.containers.concat()).then(
523
+ finishActivation,
524
+ finishActivation
525
+ );
526
+ return this;
527
+ }
528
+
529
+ finishActivation();
488
530
  return this;
489
531
  },
490
532
 
@@ -493,7 +535,8 @@ const createFocusTrap = function (elements, userOptions) {
493
535
  return this;
494
536
  }
495
537
 
496
- clearTimeout(activeFocusDelay);
538
+ clearTimeout(state.delayInitialFocusTimer); // noop if undefined
539
+ state.delayInitialFocusTimer = undefined;
497
540
 
498
541
  removeListeners();
499
542
  state.active = false;
@@ -501,25 +544,42 @@ const createFocusTrap = function (elements, userOptions) {
501
544
 
502
545
  activeFocusTraps.deactivateTrap(trap);
503
546
 
504
- const onDeactivate =
505
- deactivateOptions && deactivateOptions.onDeactivate !== undefined
506
- ? deactivateOptions.onDeactivate
507
- : config.onDeactivate;
547
+ const onDeactivate = getOption(deactivateOptions, 'onDeactivate');
548
+ const onPostDeactivate = getOption(deactivateOptions, 'onPostDeactivate');
549
+ const checkCanReturnFocus = getOption(
550
+ deactivateOptions,
551
+ 'checkCanReturnFocus'
552
+ );
553
+
508
554
  if (onDeactivate) {
509
555
  onDeactivate();
510
556
  }
511
557
 
512
- const returnFocus =
513
- deactivateOptions && deactivateOptions.returnFocus !== undefined
514
- ? deactivateOptions.returnFocus
515
- : config.returnFocusOnDeactivate;
558
+ const returnFocus = getOption(
559
+ deactivateOptions,
560
+ 'returnFocus',
561
+ 'returnFocusOnDeactivate'
562
+ );
516
563
 
517
- if (returnFocus) {
518
- delay(function () {
519
- tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
564
+ const finishDeactivation = () => {
565
+ delay(() => {
566
+ if (returnFocus) {
567
+ tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
568
+ }
569
+ if (onPostDeactivate) {
570
+ onPostDeactivate();
571
+ }
520
572
  });
573
+ };
574
+
575
+ if (returnFocus && checkCanReturnFocus) {
576
+ checkCanReturnFocus(
577
+ getReturnFocusNode(state.nodeFocusedBeforeActivation)
578
+ ).then(finishDeactivation, finishDeactivation);
579
+ return this;
521
580
  }
522
581
 
582
+ finishDeactivation();
523
583
  return this;
524
584
  },
525
585
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "focus-trap",
3
- "version": "6.4.0",
3
+ "version": "6.6.1",
4
4
  "description": "Trap focus within a DOM node.",
5
5
  "main": "dist/focus-trap.js",
6
6
  "module": "dist/focus-trap.esm.js",
@@ -17,18 +17,18 @@
17
17
  "dist"
18
18
  ],
19
19
  "scripts": {
20
- "demo-bundle": "browserify demo/js/index.js -o demo/demo-bundle.js",
21
- "format": "prettier --write \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
22
- "format:check": "prettier --check \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
23
- "format:watch": "onchange \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\" -- prettier --write {{changed}}",
24
- "lint": "eslint \"*.js\" \"demo/**/*.js\" \"cypress/**/*.js\"",
20
+ "demo-bundle": "browserify docs/js/index.js -o docs/demo-bundle.js",
21
+ "format": "prettier --write \"{*,src/**/*,test/**/*,docs/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
22
+ "format:check": "prettier --check \"{*,src/**/*,test/**/*,docs/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
23
+ "format:watch": "onchange \"{*,src/**/*,test/**/*,docs/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\" -- prettier --write {{changed}}",
24
+ "lint": "eslint \"*.js\" \"docs/js/**/*.js\" \"cypress/**/*.js\"",
25
25
  "clean": "rm -rf ./dist",
26
- "compile:esm": "BUILD_ENV=esm BABEL_ENV=esm rollup -c",
27
- "compile:cjs": "BUILD_ENV=cjs BABEL_ENV=es5 rollup -c",
28
- "compile:umd": "BUILD_ENV=umd BABEL_ENV=es5 rollup -c",
26
+ "compile:esm": "cross-env BUILD_ENV=esm BABEL_ENV=esm rollup -c",
27
+ "compile:cjs": "cross-env BUILD_ENV=cjs BABEL_ENV=es5 rollup -c",
28
+ "compile:umd": "cross-env BUILD_ENV=umd BABEL_ENV=es5 rollup -c",
29
29
  "compile": "yarn compile:esm && yarn compile:cjs && yarn compile:umd",
30
30
  "build": "yarn clean && yarn compile",
31
- "start": "yarn compile:cjs && budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify",
31
+ "start": "yarn compile:cjs && budo docs/js/index.js:demo-bundle.js --dir docs --live -- -t babelify",
32
32
  "test:types": "tsc index.d.ts",
33
33
  "test:unit": "echo \"No unit tests to run!\"",
34
34
  "test:cypress": "start-server-and-test start 9966 'cypress open'",
@@ -60,35 +60,36 @@
60
60
  },
61
61
  "homepage": "https://github.com/focus-trap/focus-trap#readme",
62
62
  "dependencies": {
63
- "tabbable": "^5.2.0"
63
+ "tabbable": "^5.2.1"
64
64
  },
65
65
  "devDependencies": {
66
- "@babel/cli": "^7.13.14",
67
- "@babel/core": "^7.13.15",
68
- "@babel/preset-env": "^7.13.15",
66
+ "@babel/cli": "^7.14.8",
67
+ "@babel/core": "^7.15.0",
68
+ "@babel/preset-env": "^7.15.0",
69
69
  "@changesets/cli": "^2.16.0",
70
70
  "@rollup/plugin-babel": "^5.3.0",
71
- "@rollup/plugin-commonjs": "^18.0.0",
72
- "@rollup/plugin-node-resolve": "^11.2.1",
73
- "@testing-library/cypress": "^7.0.5",
74
- "@types/jquery": "^3.5.5",
71
+ "@rollup/plugin-commonjs": "^20.0.0",
72
+ "@rollup/plugin-node-resolve": "^13.0.4",
73
+ "@testing-library/cypress": "^8.0.0",
74
+ "@types/jquery": "^3.5.6",
75
75
  "all-contributors-cli": "^6.20.0",
76
76
  "babel-eslint": "^10.1.0",
77
77
  "babel-loader": "^8.2.2",
78
78
  "babelify": "^10.0.0",
79
79
  "browserify": "^17.0.0",
80
80
  "budo": "^11.6.4",
81
- "cypress": "^7.1.0",
81
+ "cross-env": "^7.0.3",
82
+ "cypress": "^8.2.0",
82
83
  "cypress-plugin-tab": "^1.0.5",
83
- "eslint": "^7.24.0",
84
- "eslint-config-prettier": "^8.2.0",
85
- "eslint-plugin-cypress": "^2.11.2",
84
+ "eslint": "^7.32.0",
85
+ "eslint-config-prettier": "^8.3.0",
86
+ "eslint-plugin-cypress": "^2.11.3",
86
87
  "onchange": "^7.1.0",
87
- "prettier": "^2.2.1",
88
- "rollup": "^2.45.2",
88
+ "prettier": "^2.3.2",
89
+ "rollup": "^2.56.2",
89
90
  "rollup-plugin-sourcemaps": "^0.6.3",
90
91
  "rollup-plugin-terser": "^7.0.1",
91
- "start-server-and-test": "^1.12.1",
92
- "typescript": "^4.2.4"
92
+ "start-server-and-test": "^1.13.1",
93
+ "typescript": "^4.3.5"
93
94
  }
94
95
  }