@instructure/ui-a11y-utils 11.7.3-snapshot-7 → 11.7.3-snapshot-26

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 CHANGED
@@ -3,9 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [11.7.3-snapshot-7](https://github.com/instructure/instructure-ui/compare/v11.7.2...v11.7.3-snapshot-7) (2026-04-29)
6
+ ## [11.7.3-snapshot-26](https://github.com/instructure/instructure-ui/compare/v11.7.2...v11.7.3-snapshot-26) (2026-05-05)
7
7
 
8
- **Note:** Version bump only for package @instructure/ui-a11y-utils
8
+
9
+ ### Bug Fixes
10
+
11
+ * **many:** update dependencies, remove lots of Babel plugins, remove Webpack 4 support ([f916fca](https://github.com/instructure/instructure-ui/commit/f916fcafdddcb2d7de401f93e8ff92cfdfa47bba))
9
12
 
10
13
 
11
14
 
package/es/FocusRegion.js CHANGED
@@ -41,70 +41,19 @@ import { KeyboardFocusRegion } from "./KeyboardFocusRegion.js";
41
41
  * @module FocusRegion
42
42
  */
43
43
  class FocusRegion {
44
+ _contextElement = null;
45
+ _options;
46
+ _screenReaderFocusRegion;
47
+ _keyboardFocusRegion;
48
+ _id;
49
+ _mouseDownListener;
50
+ _clickListener;
51
+ _mouseUpListener;
52
+ _keyUpListener;
53
+ _active = false;
54
+ _documentClickTarget = null;
55
+ _contextContainsTarget = false;
44
56
  constructor(element, options) {
45
- this._contextElement = null;
46
- this._options = void 0;
47
- this._screenReaderFocusRegion = void 0;
48
- this._keyboardFocusRegion = void 0;
49
- this._id = void 0;
50
- this._mouseDownListener = void 0;
51
- this._clickListener = void 0;
52
- this._mouseUpListener = void 0;
53
- this._keyUpListener = void 0;
54
- this._active = false;
55
- this._documentClickTarget = null;
56
- this._contextContainsTarget = false;
57
- this.handleDismiss = (event, documentClick) => {
58
- var _this$_options$onDism, _this$_options;
59
- (_this$_options$onDism = (_this$_options = this._options).onDismiss) === null || _this$_options$onDism === void 0 ? void 0 : _this$_options$onDism.call(_this$_options, event, documentClick);
60
- };
61
- this.captureDocumentMousedown = event => {
62
- this._documentClickTarget = event.target;
63
- this._contextContainsTarget = contains(this._contextElement, this._documentClickTarget);
64
- // Preemptively remove aria-hidden before focus moves to the clicked element
65
- // outside the region, preventing the "aria-hidden on focused ancestor" warning.
66
- if (!this._contextContainsTarget && this._options.shouldCloseOnDocumentClick) {
67
- this._screenReaderFocusRegion.deactivate();
68
- }
69
- };
70
- this.handleDocumentClick = event => {
71
- // we used event.pointerType === 'mouse' here, but it is not supported in Safari
72
- // https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerType
73
- // TODO: Check this in the future, because the linked Webkit bug is marked as fixed in 2025-09
74
- if (this._options.shouldCloseOnDocumentClick && event.button === 0 && event.detail > 0 &&
75
- // if event.detail is 0 then this is a keyboard and not a mouse press
76
- !this._contextContainsTarget &&
77
- //this prevents clicking on Tooltip from closing the parent dialog
78
- !(canUseDOM && this._documentClickTarget instanceof HTMLElement && this._documentClickTarget.closest('[role="tooltip"]'))) {
79
- this.handleDismiss(event, true);
80
- }
81
- };
82
- this.handleFrameClick = (event, frame) => {
83
- if (!contains(this._contextElement, frame)) {
84
- // dismiss if frame is not within the region
85
- this.handleDismiss(event, true);
86
- }
87
- };
88
- this.handleKeyUp = event => {
89
- if (this._options.shouldCloseOnEscape && event.keyCode === keycode.codes.esc && !event.defaultPrevented) {
90
- var _ownerDocument;
91
- // If a dialog contains an <input type="file"/> element and the user opens the file picker and closes it with the
92
- // escape key then Firefox passes through that event which could close the parent dialog. This code prevents that
93
- // from happening (listening for a `cancel` event doesn't seem to work in firefox)
94
- const activeElement = (_ownerDocument = ownerDocument(this._contextElement)) === null || _ownerDocument === void 0 ? void 0 : _ownerDocument.activeElement;
95
- const fileInputFocused = (activeElement === null || activeElement === void 0 ? void 0 : activeElement.tagName) === 'INPUT' && activeElement.type === 'file';
96
- if (fileInputFocused) {
97
- ;
98
- activeElement.blur();
99
- } else {
100
- //This should prevent a Tooltip from closing when inside of a Modal
101
- if (this._options.isTooltip) {
102
- event.stopPropagation();
103
- }
104
- this.handleDismiss(event);
105
- }
106
- }
107
- };
108
57
  this._options = options || {
109
58
  shouldCloseOnDocumentClick: true,
110
59
  shouldCloseOnEscape: true,
@@ -132,6 +81,55 @@ class FocusRegion {
132
81
  this._screenReaderFocusRegion.updateElement(element);
133
82
  }
134
83
  }
84
+ handleDismiss = (event, documentClick) => {
85
+ this._options.onDismiss?.(event, documentClick);
86
+ };
87
+ captureDocumentMousedown = event => {
88
+ this._documentClickTarget = event.target;
89
+ this._contextContainsTarget = contains(this._contextElement, this._documentClickTarget);
90
+ // Preemptively remove aria-hidden before focus moves to the clicked element
91
+ // outside the region, preventing the "aria-hidden on focused ancestor" warning.
92
+ if (!this._contextContainsTarget && this._options.shouldCloseOnDocumentClick) {
93
+ this._screenReaderFocusRegion.deactivate();
94
+ }
95
+ };
96
+ handleDocumentClick = event => {
97
+ // we used event.pointerType === 'mouse' here, but it is not supported in Safari
98
+ // https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerType
99
+ // TODO: Check this in the future, because the linked Webkit bug is marked as fixed in 2025-09
100
+ if (this._options.shouldCloseOnDocumentClick && event.button === 0 && event.detail > 0 &&
101
+ // if event.detail is 0 then this is a keyboard and not a mouse press
102
+ !this._contextContainsTarget &&
103
+ //this prevents clicking on Tooltip from closing the parent dialog
104
+ !(canUseDOM && this._documentClickTarget instanceof HTMLElement && this._documentClickTarget.closest('[role="tooltip"]'))) {
105
+ this.handleDismiss(event, true);
106
+ }
107
+ };
108
+ handleFrameClick = (event, frame) => {
109
+ if (!contains(this._contextElement, frame)) {
110
+ // dismiss if frame is not within the region
111
+ this.handleDismiss(event, true);
112
+ }
113
+ };
114
+ handleKeyUp = event => {
115
+ if (this._options.shouldCloseOnEscape && event.keyCode === keycode.codes.esc && !event.defaultPrevented) {
116
+ // If a dialog contains an <input type="file"/> element and the user opens the file picker and closes it with the
117
+ // escape key then Firefox passes through that event which could close the parent dialog. This code prevents that
118
+ // from happening (listening for a `cancel` event doesn't seem to work in firefox)
119
+ const activeElement = ownerDocument(this._contextElement)?.activeElement;
120
+ const fileInputFocused = activeElement?.tagName === 'INPUT' && activeElement.type === 'file';
121
+ if (fileInputFocused) {
122
+ ;
123
+ activeElement.blur();
124
+ } else {
125
+ //This should prevent a Tooltip from closing when inside of a Modal
126
+ if (this._options.isTooltip) {
127
+ event.stopPropagation();
128
+ }
129
+ this.handleDismiss(event);
130
+ }
131
+ }
132
+ };
135
133
  get id() {
136
134
  return this._id;
137
135
  }
@@ -169,13 +167,12 @@ class FocusRegion {
169
167
  }
170
168
  });
171
169
  } else {
172
- var _this$_mouseDownListe, _this$_clickListener, _this$_mouseUpListene;
173
- (_this$_mouseDownListe = this._mouseDownListener) === null || _this$_mouseDownListe === void 0 ? void 0 : _this$_mouseDownListe.remove();
174
- this._mouseDownListener = void 0;
175
- (_this$_clickListener = this._clickListener) === null || _this$_clickListener === void 0 ? void 0 : _this$_clickListener.remove();
176
- this._clickListener = void 0;
177
- (_this$_mouseUpListene = this._mouseUpListener) === null || _this$_mouseUpListene === void 0 ? void 0 : _this$_mouseUpListene.remove();
178
- this._mouseUpListener = void 0;
170
+ this._mouseDownListener?.remove();
171
+ this._mouseDownListener = undefined;
172
+ this._clickListener?.remove();
173
+ this._clickListener = undefined;
174
+ this._mouseUpListener?.remove();
175
+ this._mouseUpListener = undefined;
179
176
  }
180
177
  if (shouldCloseOnEscape) {
181
178
  if (!this._keyUpListener) {
@@ -186,9 +183,8 @@ class FocusRegion {
186
183
  this._keyUpListener = addEventListener(doc, 'keyup', this.handleKeyUp, useCapture);
187
184
  }
188
185
  } else {
189
- var _this$_keyUpListener;
190
- (_this$_keyUpListener = this._keyUpListener) === null || _this$_keyUpListener === void 0 ? void 0 : _this$_keyUpListener.remove();
191
- this._keyUpListener = void 0;
186
+ this._keyUpListener?.remove();
187
+ this._keyUpListener = undefined;
192
188
  }
193
189
  }
194
190
  activate() {
@@ -202,15 +198,14 @@ class FocusRegion {
202
198
  deactivate({
203
199
  keyboard = true
204
200
  } = {}) {
205
- var _this$_mouseDownListe2, _this$_clickListener2, _this$_mouseUpListene2, _this$_keyUpListener2;
206
- (_this$_mouseDownListe2 = this._mouseDownListener) === null || _this$_mouseDownListe2 === void 0 ? void 0 : _this$_mouseDownListe2.remove();
207
- this._mouseDownListener = void 0;
208
- (_this$_clickListener2 = this._clickListener) === null || _this$_clickListener2 === void 0 ? void 0 : _this$_clickListener2.remove();
209
- this._clickListener = void 0;
210
- (_this$_mouseUpListene2 = this._mouseUpListener) === null || _this$_mouseUpListene2 === void 0 ? void 0 : _this$_mouseUpListene2.remove();
211
- this._mouseUpListener = void 0;
212
- (_this$_keyUpListener2 = this._keyUpListener) === null || _this$_keyUpListener2 === void 0 ? void 0 : _this$_keyUpListener2.remove();
213
- this._keyUpListener = void 0;
201
+ this._mouseDownListener?.remove();
202
+ this._mouseDownListener = undefined;
203
+ this._clickListener?.remove();
204
+ this._clickListener = undefined;
205
+ this._mouseUpListener?.remove();
206
+ this._mouseUpListener = undefined;
207
+ this._keyUpListener?.remove();
208
+ this._keyUpListener = undefined;
214
209
  if (keyboard) {
215
210
  this._keyboardFocusRegion.deactivate();
216
211
  }
@@ -1,4 +1,3 @@
1
- var _FocusRegionManager;
2
1
  /*
3
2
  * The MIT License (MIT)
4
3
  *
@@ -38,123 +37,128 @@ let ENTRIES = [];
38
37
  * - Return focus to the marked element
39
38
  * @module FocusManager
40
39
  */
41
- class FocusRegionManager {}
42
- _FocusRegionManager = FocusRegionManager;
43
- FocusRegionManager.focusRegion = (element, idOrOptions = {}) => {
44
- let entry;
45
- if (typeof idOrOptions === 'string') {
46
- entry = _FocusRegionManager.getEntry(element, idOrOptions);
47
- } else {
48
- entry = _FocusRegionManager.addEntry(element, idOrOptions);
49
- }
50
- if (entry && entry.region && typeof entry.region.focus === 'function') {
51
- entry.region.focus();
52
- return entry.region;
53
- } else {
54
- error(false, `[FocusRegionManager] Could not focus region with element: ${element}`);
55
- }
56
- return;
57
- };
58
- FocusRegionManager.activateRegion = (element, options) => {
59
- const _FocusRegionManager$a = _FocusRegionManager.addEntry(element, options),
60
- region = _FocusRegionManager$a.region;
61
- return region;
62
- };
63
- FocusRegionManager.getActiveEntry = () => {
64
- return ENTRIES.find(({
65
- region
66
- }) => region.focused);
67
- };
68
- FocusRegionManager.findEntry = (element, id) => {
69
- let index;
70
- if (id) {
71
- index = ENTRIES.findIndex(entry => entry.id === id);
72
- } else {
73
- index = ENTRIES.findIndex(entry => entry.element === element);
74
- }
75
- return index;
76
- };
77
- FocusRegionManager.getEntry = (element, id) => {
78
- return ENTRIES[_FocusRegionManager.findEntry(element, id)];
79
- };
80
- FocusRegionManager.addEntry = (element, options = {}) => {
81
- const region = new FocusRegion(element, options);
82
- const activeEntry = _FocusRegionManager.getActiveEntry();
83
- const keyboardFocusable = region.keyboardFocusable;
84
- ENTRIES.forEach(({
85
- region
86
- }) => {
87
- if (region) {
88
- // If the active region is triggering a new focus region that does not have
89
- // keyboard focusable content, don't deactivate the active region's keyboard
90
- // focus region
91
- const keyboard = region.focused && !keyboardFocusable ? {
92
- keyboard: false
93
- } : void 0;
94
- region.deactivate(keyboard);
40
+ class FocusRegionManager {
41
+ static focusRegion = (element, idOrOptions = {}) => {
42
+ let entry;
43
+ if (typeof idOrOptions === 'string') {
44
+ entry = FocusRegionManager.getEntry(element, idOrOptions);
45
+ } else {
46
+ entry = FocusRegionManager.addEntry(element, idOrOptions);
95
47
  }
96
- });
97
- region.activate();
98
- if (options.shouldFocusOnOpen) {
99
- region.focus();
100
- }
101
- const entry = {
102
- id: region.id,
103
- element,
104
- region,
105
- children: [],
106
- parent: activeEntry
48
+ if (entry && entry.region && typeof entry.region.focus === 'function') {
49
+ entry.region.focus();
50
+ return entry.region;
51
+ } else {
52
+ error(false, `[FocusRegionManager] Could not focus region with element: ${element}`);
53
+ }
54
+ return;
55
+ };
56
+ static activateRegion = (element, options) => {
57
+ const {
58
+ region
59
+ } = FocusRegionManager.addEntry(element, options);
60
+ return region;
61
+ };
62
+ static getActiveEntry = () => {
63
+ return ENTRIES.find(({
64
+ region
65
+ }) => region.focused);
66
+ };
67
+ static findEntry = (element, id) => {
68
+ let index;
69
+ if (id) {
70
+ index = ENTRIES.findIndex(entry => entry.id === id);
71
+ } else {
72
+ index = ENTRIES.findIndex(entry => entry.element === element);
73
+ }
74
+ return index;
75
+ };
76
+ static getEntry = (element, id) => {
77
+ return ENTRIES[FocusRegionManager.findEntry(element, id)];
78
+ };
79
+ static addEntry = (element, options = {}) => {
80
+ const region = new FocusRegion(element, options);
81
+ const activeEntry = FocusRegionManager.getActiveEntry();
82
+ const {
83
+ keyboardFocusable
84
+ } = region;
85
+ ENTRIES.forEach(({
86
+ region
87
+ }) => {
88
+ if (region) {
89
+ // If the active region is triggering a new focus region that does not have
90
+ // keyboard focusable content, don't deactivate the active region's keyboard
91
+ // focus region
92
+ const keyboard = region.focused && !keyboardFocusable ? {
93
+ keyboard: false
94
+ } : undefined;
95
+ region.deactivate(keyboard);
96
+ }
97
+ });
98
+ region.activate();
99
+ if (options.shouldFocusOnOpen) {
100
+ region.focus();
101
+ }
102
+ const entry = {
103
+ id: region.id,
104
+ element,
105
+ region,
106
+ children: [],
107
+ parent: activeEntry
108
+ };
109
+ ENTRIES.push(entry);
110
+ if (activeEntry) {
111
+ activeEntry.children.push(entry);
112
+ }
113
+ return entry;
107
114
  };
108
- ENTRIES.push(entry);
109
- if (activeEntry) {
110
- activeEntry.children.push(entry);
111
- }
112
- return entry;
113
- };
114
- FocusRegionManager.removeEntry = (element, id) => {
115
- const index = _FocusRegionManager.findEntry(element, id);
116
- const entry = ENTRIES[index];
117
- if (index > -1) {
118
- ENTRIES.splice(index, 1);
119
- }
120
- return entry;
121
- };
122
- FocusRegionManager.isFocused = (element, id) => {
123
- const entry = _FocusRegionManager.getActiveEntry();
124
- if (id) {
125
- return entry && entry.region && entry.id === id;
126
- } else {
127
- return entry && entry.region && entry.element === element;
128
- }
129
- };
130
- FocusRegionManager.clearEntries = () => {
131
- ENTRIES = [];
132
- };
133
- FocusRegionManager.blurRegion = (element, id) => {
134
- const entry = _FocusRegionManager.removeEntry(element, id);
135
- if (entry) {
136
- const children = entry.children,
137
- region = entry.region,
138
- parent = entry.parent;
115
+ static removeEntry = (element, id) => {
116
+ const index = FocusRegionManager.findEntry(element, id);
117
+ const entry = ENTRIES[index];
118
+ if (index > -1) {
119
+ ENTRIES.splice(index, 1);
120
+ }
121
+ return entry;
122
+ };
123
+ static isFocused = (element, id) => {
124
+ const entry = FocusRegionManager.getActiveEntry();
125
+ if (id) {
126
+ return entry && entry.region && entry.id === id;
127
+ } else {
128
+ return entry && entry.region && entry.element === element;
129
+ }
130
+ };
131
+ static clearEntries = () => {
132
+ ENTRIES = [];
133
+ };
134
+ static blurRegion = (element, id) => {
135
+ const entry = FocusRegionManager.removeEntry(element, id);
136
+ if (entry) {
137
+ const {
138
+ children,
139
+ region,
140
+ parent
141
+ } = entry;
139
142
 
140
- // deactivate the region...
141
- region && region.deactivate();
143
+ // deactivate the region...
144
+ region && region.deactivate();
142
145
 
143
- // and any regions created from it
144
- if (children) {
145
- children.forEach(({
146
- id,
147
- element
148
- }) => {
149
- const entry = _FocusRegionManager.removeEntry(element, id);
150
- entry && entry.region && entry.region.deactivate();
151
- });
152
- }
146
+ // and any regions created from it
147
+ if (children) {
148
+ children.forEach(({
149
+ id,
150
+ element
151
+ }) => {
152
+ const entry = FocusRegionManager.removeEntry(element, id);
153
+ entry && entry.region && entry.region.deactivate();
154
+ });
155
+ }
153
156
 
154
- // activate the region's parent if it exists
155
- parent && parent.region && parent.region.activate();
156
- region && region.blur(); // this should focus the parent region
157
- }
158
- };
157
+ // activate the region's parent if it exists
158
+ parent && parent.region && parent.region.activate();
159
+ region && region.blur(); // this should focus the parent region
160
+ }
161
+ };
162
+ }
159
163
  export default FocusRegionManager;
160
164
  export { FocusRegionManager };
@@ -1,3 +1,4 @@
1
+ import "core-js/modules/es.array.includes.js";
1
2
  /*
2
3
  * The MIT License (MIT)
3
4
  *
@@ -38,61 +39,15 @@ import { scopeTab } from "./scopeTab.js";
38
39
  * @module KeyboardFocusRegion
39
40
  */
40
41
  class KeyboardFocusRegion {
42
+ _options;
43
+ _focusLaterElement = null;
44
+ _needToFocus = false;
45
+ _listeners = [];
46
+ _raf = [];
47
+ _active = false;
48
+ _wasDocumentClick;
49
+ _contextElement;
41
50
  constructor(element, options) {
42
- this._options = void 0;
43
- this._focusLaterElement = null;
44
- this._needToFocus = false;
45
- this._listeners = [];
46
- this._raf = [];
47
- this._active = false;
48
- this._wasDocumentClick = void 0;
49
- this._contextElement = void 0;
50
- this.handleKeyDown = event => {
51
- if (event.keyCode === keycode.codes.tab) {
52
- scopeTab(this._contextElement, event);
53
- }
54
- };
55
- this.handleClick = () => {
56
- this._wasDocumentClick = true;
57
- };
58
- this.handleWindowBlur = () => {
59
- if (this._wasDocumentClick) {
60
- this._wasDocumentClick = false;
61
- return;
62
- }
63
- this._needToFocus = true;
64
- };
65
- this.handleFocus = () => {
66
- if (this._needToFocus) {
67
- this._needToFocus = false;
68
- if (!this._contextElement) {
69
- return;
70
- }
71
- // need to see how jQuery shims document.on('focusin') so we don't need the
72
- // setTimeout, firefox doesn't support focusin, if it did, we could focus
73
- // the element outside of a setTimeout. Side-effect of this implementation
74
- // is that the document.body gets focus, and then we focus our element right
75
- // after, seems fine.
76
- this._raf.push(requestAnimationFrame(() => {
77
- if (containsActiveElement(this._contextElement)) {
78
- return;
79
- }
80
- this.focusDefaultElement();
81
- }));
82
- }
83
- };
84
- this.handleFirstTabbableKeyDown = event => {
85
- if (event.keyCode === keycode.codes.tab && event.shiftKey) {
86
- var _this$_options$onBlur, _this$_options;
87
- (_this$_options$onBlur = (_this$_options = this._options).onBlur) === null || _this$_options$onBlur === void 0 ? void 0 : _this$_options$onBlur.call(_this$_options, event);
88
- }
89
- };
90
- this.handleLastTabbableKeyDown = event => {
91
- if (event.keyCode === keycode.codes.tab && !event.shiftKey) {
92
- var _this$_options$onBlur2, _this$_options2;
93
- (_this$_options$onBlur2 = (_this$_options2 = this._options).onBlur) === null || _this$_options$onBlur2 === void 0 ? void 0 : _this$_options$onBlur2.call(_this$_options2, event);
94
- }
95
- };
96
51
  this._contextElement = findDOMNode(element);
97
52
  this._options = options || {
98
53
  shouldContainFocus: true,
@@ -107,7 +62,9 @@ class KeyboardFocusRegion {
107
62
  return containsActiveElement(this._contextElement);
108
63
  }
109
64
  get shouldContainFocus() {
110
- const shouldContainFocus = this._options.shouldContainFocus;
65
+ const {
66
+ shouldContainFocus
67
+ } = this._options;
111
68
  return shouldContainFocus === true || Array.isArray(shouldContainFocus) && shouldContainFocus.includes('keyboard');
112
69
  }
113
70
  get focusable() {
@@ -135,7 +92,9 @@ class KeyboardFocusRegion {
135
92
  return ownerWindow(this._contextElement);
136
93
  }
137
94
  get defaultFocusElement() {
138
- const defaultFocusElement = this._options.defaultFocusElement;
95
+ const {
96
+ defaultFocusElement
97
+ } = this._options;
139
98
  const element = findDOMNode(typeof defaultFocusElement === 'function' ? defaultFocusElement() : defaultFocusElement);
140
99
  if (element && this._contextElement && this._contextElement.contains(element)) {
141
100
  return element;
@@ -215,9 +174,55 @@ class KeyboardFocusRegion {
215
174
  this._focusLaterElement = null;
216
175
  }
217
176
  }
177
+ handleKeyDown = event => {
178
+ if (event.keyCode === keycode.codes.tab) {
179
+ scopeTab(this._contextElement, event);
180
+ }
181
+ };
182
+ handleClick = () => {
183
+ this._wasDocumentClick = true;
184
+ };
185
+ handleWindowBlur = () => {
186
+ if (this._wasDocumentClick) {
187
+ this._wasDocumentClick = false;
188
+ return;
189
+ }
190
+ this._needToFocus = true;
191
+ };
192
+ handleFocus = () => {
193
+ if (this._needToFocus) {
194
+ this._needToFocus = false;
195
+ if (!this._contextElement) {
196
+ return;
197
+ }
198
+ // need to see how jQuery shims document.on('focusin') so we don't need the
199
+ // setTimeout, firefox doesn't support focusin, if it did, we could focus
200
+ // the element outside of a setTimeout. Side-effect of this implementation
201
+ // is that the document.body gets focus, and then we focus our element right
202
+ // after, seems fine.
203
+ this._raf.push(requestAnimationFrame(() => {
204
+ if (containsActiveElement(this._contextElement)) {
205
+ return;
206
+ }
207
+ this.focusDefaultElement();
208
+ }));
209
+ }
210
+ };
211
+ handleFirstTabbableKeyDown = event => {
212
+ if (event.keyCode === keycode.codes.tab && event.shiftKey) {
213
+ this._options.onBlur?.(event);
214
+ }
215
+ };
216
+ handleLastTabbableKeyDown = event => {
217
+ if (event.keyCode === keycode.codes.tab && !event.shiftKey) {
218
+ this._options.onBlur?.(event);
219
+ }
220
+ };
218
221
  activate() {
219
- const defaultFocusElement = this.defaultFocusElement,
220
- shouldContainFocus = this.shouldContainFocus;
222
+ const {
223
+ defaultFocusElement,
224
+ shouldContainFocus
225
+ } = this;
221
226
  if (!this._active) {
222
227
  if (defaultFocusElement || shouldContainFocus) {
223
228
  if (shouldContainFocus) {