@instructure/ui-a11y-utils 8.12.0 → 8.12.1-snapshot.15

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.
@@ -41,71 +41,65 @@ import { logError as error } from '@instructure/console'
41
41
  import keycode from 'keycode'
42
42
 
43
43
  import { scopeTab } from './scopeTab'
44
+ import type { UIElement } from '@instructure/shared-types'
45
+ import { FocusRegionOptions } from './FocusRegionOptions'
44
46
 
45
47
  class KeyboardFocusRegion {
46
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
47
- constructor(element, options) {
48
- this._contextElement = findDOMNode(element)
49
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
48
+ private readonly _options: FocusRegionOptions
49
+ private _focusLaterElement: Element | null = null
50
+ private _needToFocus = false
51
+ private _listeners: ReturnType<typeof addEventListener>[] = []
52
+ private _raf: RequestAnimationFrameType[] = []
53
+ private _active = false
54
+ private _wasDocumentClick?: boolean
55
+ public _contextElement?: Node
56
+
57
+ constructor(element: UIElement, options: FocusRegionOptions) {
58
+ this._contextElement = findDOMNode(element) as Node
50
59
  this._options = options || {
51
60
  shouldContainFocus: true,
52
61
  shouldReturnFocus: true,
53
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
54
- onBlur: (event) => {},
55
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
56
- onDismiss: (event) => {},
57
62
  defaultFocusElement: null
58
63
  }
59
-
60
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
61
64
  if (this._options.shouldReturnFocus) {
62
- this._focusLaterElement = this.activeElement
65
+ this._focusLaterElement = getActiveElement(this.doc)
63
66
  }
64
67
  }
65
68
 
66
- public _contextElement: null | undefined | Node | Window = null
67
- _focusLaterElement: Element | null = null
68
- _needToFocus = false
69
- _listeners = []
70
- _raf: RequestAnimationFrameType[] = []
71
- _active = false
72
-
73
69
  get focused() {
74
70
  return containsActiveElement(this._contextElement)
75
71
  }
76
72
 
77
73
  get shouldContainFocus() {
78
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
79
74
  const { shouldContainFocus } = this._options
80
75
  return (
81
76
  shouldContainFocus === true ||
82
77
  (Array.isArray(shouldContainFocus) &&
83
- // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
84
- shouldContainFocus.includes['keyboard'])
78
+ shouldContainFocus.includes('keyboard'))
85
79
  )
86
80
  }
87
81
 
88
- get focusable() {
82
+ get focusable(): Element[] {
89
83
  return findFocusable(this._contextElement, () => true, true) || []
90
84
  }
91
85
 
92
- get tabbable() {
86
+ get tabbable(): Element[] {
93
87
  return findTabbable(this._contextElement) || []
94
88
  }
95
89
 
96
- get firstTabbable() {
90
+ get firstTabbable(): Element | undefined {
97
91
  return this.tabbable[0]
98
92
  }
99
93
 
100
- get lastTabbable() {
94
+ get lastTabbable(): Element | undefined {
101
95
  return this.tabbable.pop()
102
96
  }
103
97
 
104
- get firstFocusable() {
98
+ get firstFocusable(): Element | undefined {
105
99
  return this.focusable[0]
106
100
  }
107
101
 
108
- get lastFocusable() {
102
+ get lastFocusable(): Element | undefined {
109
103
  return this.focusable.pop()
110
104
  }
111
105
 
@@ -117,65 +111,50 @@ class KeyboardFocusRegion {
117
111
  return ownerWindow(this._contextElement)
118
112
  }
119
113
 
120
- get activeElement() {
121
- return getActiveElement(this.doc)
122
- }
123
-
124
- get defaultFocusElement(): any {
125
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
114
+ get defaultFocusElement() {
126
115
  const { defaultFocusElement } = this._options
127
-
128
- const element = findDOMNode(
116
+ const element: Node | undefined = findDOMNode(
129
117
  typeof defaultFocusElement === 'function'
130
118
  ? defaultFocusElement()
131
119
  : defaultFocusElement
132
- )
133
-
120
+ ) as Node
134
121
  if (
135
122
  element &&
136
123
  this._contextElement &&
137
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
138
124
  this._contextElement.contains(element)
139
125
  ) {
140
126
  return element
141
127
  }
142
-
143
- const { firstTabbable } = this
144
- if (firstTabbable) {
145
- return firstTabbable
128
+ if (this.firstTabbable) {
129
+ return this.firstTabbable
146
130
  }
147
-
148
131
  if (
149
132
  this._contextElement &&
150
133
  this.focusable.includes(this._contextElement as Element)
151
134
  ) {
152
135
  return this._contextElement
153
136
  }
154
-
155
137
  return null
156
138
  }
157
139
 
158
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
159
- updateElement(element) {
160
- this._contextElement = findDOMNode(element)
140
+ updateElement(element: UIElement) {
141
+ this._contextElement = findDOMNode(element) as Node
161
142
  }
162
143
 
163
144
  focusDefaultElement() {
164
- const { defaultFocusElement, shouldContainFocus, activeElement } = this
165
-
166
- if (defaultFocusElement) {
167
- defaultFocusElement.focus()
145
+ if (this.defaultFocusElement) {
146
+ ;(this.defaultFocusElement as HTMLElement).focus()
168
147
  } else {
169
- if (shouldContainFocus) {
148
+ if (this.shouldContainFocus) {
170
149
  // Blur the active element to place focus on the document body
171
- activeElement && (activeElement as HTMLElement).blur()
172
-
150
+ getActiveElement(this.doc) &&
151
+ (getActiveElement(this.doc) as HTMLElement).blur()
173
152
  error(
174
153
  true,
175
154
  `
176
- [KeyboardFocusRegion] No \`defaultFocusElement\` was provided and \`shouldContainFocus\`
177
- was set to \`true\`. Focus has been moved to the document body instead.
178
- `
155
+ [KeyboardFocusRegion] No \`defaultFocusElement\` was provided and
156
+ \`shouldContainFocus\` was set to \`true\` or \`keyboard\`. Focus has
157
+ been moved to the document body instead.`
179
158
  )
180
159
  }
181
160
  }
@@ -194,12 +173,10 @@ class KeyboardFocusRegion {
194
173
  }
195
174
 
196
175
  blur() {
197
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
198
176
  if (this._options.shouldReturnFocus && this._focusLaterElement) {
199
177
  try {
200
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
201
- this._focusLaterElement.focus()
202
- } catch (e: any) {
178
+ ;(this._focusLaterElement as HTMLElement).focus()
179
+ } catch (e: unknown) {
203
180
  error(
204
181
  false,
205
182
  `
@@ -212,46 +189,31 @@ class KeyboardFocusRegion {
212
189
  }
213
190
  }
214
191
 
215
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
216
- handleDismiss = (event) => {
217
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
218
- this._options.onDismiss(event)
219
- }
220
-
221
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
222
- handleKeyDown = (event) => {
192
+ handleKeyDown = (event: KeyboardEvent) => {
223
193
  if (event.keyCode === keycode.codes.tab) {
224
- // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
225
194
  scopeTab(this._contextElement, event)
226
195
  }
227
196
  }
228
197
 
229
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
230
- handleClick = (event) => {
231
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_wasDocumentClick' does not exist on typ... Remove this comment to see the full error message
198
+ handleClick = () => {
232
199
  this._wasDocumentClick = true
233
200
  }
234
201
 
235
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
236
- handleWindowBlur = (event) => {
237
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_wasDocumentClick' does not exist on typ... Remove this comment to see the full error message
202
+ handleWindowBlur = () => {
238
203
  if (this._wasDocumentClick) {
239
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_wasDocumentClick' does not exist on typ... Remove this comment to see the full error message
240
204
  this._wasDocumentClick = false
241
205
  return
242
206
  }
243
207
  this._needToFocus = true
244
208
  }
245
209
 
246
- // @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
247
- handleFocus = (event) => {
210
+ handleFocus = () => {
248
211
  if (this._needToFocus) {
249
212
  this._needToFocus = false
250
213
 
251
214
  if (!this._contextElement) {
252
215
  return
253
216
  }
254
-
255
217
  // need to see how jQuery shims document.on('focusin') so we don't need the
256
218
  // setTimeout, firefox doesn't support focusin, if it did, we could focus
257
219
  // the element outside of a setTimeout. Side-effect of this implementation
@@ -268,62 +230,55 @@ class KeyboardFocusRegion {
268
230
  }
269
231
  }
270
232
 
271
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
272
- handleFirstTabbableKeyDown = (event) => {
233
+ handleFirstTabbableKeyDown = (event: KeyboardEvent) => {
273
234
  if (event.keyCode === keycode.codes.tab && event.shiftKey) {
274
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
275
- this._options.onBlur(event)
235
+ this._options.onBlur?.(event)
276
236
  }
277
237
  }
278
238
 
279
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
280
- handleLastTabbableKeyDown = (event) => {
239
+ handleLastTabbableKeyDown = (event: KeyboardEvent) => {
281
240
  if (event.keyCode === keycode.codes.tab && !event.shiftKey) {
282
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Keyboa... Remove this comment to see the full error message
283
- this._options.onBlur(event)
241
+ this._options.onBlur?.(event)
284
242
  }
285
243
  }
286
244
 
287
245
  activate() {
288
246
  const { defaultFocusElement, shouldContainFocus } = this
289
-
290
247
  if (!this._active) {
291
248
  if (defaultFocusElement || shouldContainFocus) {
292
249
  if (shouldContainFocus) {
293
250
  this._listeners.push(
294
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
295
- addEventListener(this.doc, 'keydown', this.handleKeyDown)
251
+ addEventListener(
252
+ this.doc,
253
+ 'keydown',
254
+ this.handleKeyDown as EventListener
255
+ )
296
256
  )
297
257
  } else {
298
258
  this._listeners.push(
299
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
300
259
  addEventListener(
301
- this.firstTabbable || defaultFocusElement,
260
+ this.firstTabbable || defaultFocusElement!,
302
261
  'keydown',
303
- this.handleFirstTabbableKeyDown
262
+ this.handleFirstTabbableKeyDown as EventListener
304
263
  )
305
264
  )
306
265
  this._listeners.push(
307
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
308
266
  addEventListener(
309
- this.lastTabbable || defaultFocusElement,
267
+ this.lastTabbable || defaultFocusElement!,
310
268
  'keydown',
311
- this.handleLastTabbableKeyDown
269
+ this.handleLastTabbableKeyDown as EventListener
312
270
  )
313
271
  )
314
272
  }
315
273
 
316
274
  this._listeners.push(
317
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
318
275
  addEventListener(this.doc, 'click', this.handleClick, true)
319
276
  )
320
277
 
321
278
  this._listeners.push(
322
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
323
- addEventListener(this.win, 'blur', this.handleWindowBlur, false)
279
+ addEventListener(this.win!, 'blur', this.handleWindowBlur, false)
324
280
  )
325
281
  this._listeners.push(
326
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
327
282
  addEventListener(this.doc, 'focus', this.handleFocus, true)
328
283
  )
329
284
 
@@ -335,17 +290,11 @@ class KeyboardFocusRegion {
335
290
  deactivate() {
336
291
  if (this._active) {
337
292
  this._listeners.forEach((listener) => {
338
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'remove' does not exist on type 'never'.
339
293
  listener.remove()
340
294
  })
341
295
  this._listeners = []
342
-
343
296
  this._raf.forEach((request) => request.cancel())
344
297
  this._raf = []
345
-
346
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_preventCloseOnDocumentClick' does not e... Remove this comment to see the full error message
347
- this._preventCloseOnDocumentClick = false
348
-
349
298
  this._active = false
350
299
  }
351
300
  }
@@ -357,11 +306,12 @@ export {
357
306
  * ---
358
307
  * category: utilities/a11y
359
308
  * ---
360
- * @module KeyboardFocusRegion
309
+ *
361
310
  * Class for focus operations.
362
311
  * - Scoping focus within a given context (DOM node),
363
312
  * - Mark active element for focus later
364
313
  * - Return focus to the marked element
314
+ * @module KeyboardFocusRegion
365
315
  */
366
316
  KeyboardFocusRegion
367
317
  }
@@ -23,42 +23,38 @@
23
23
  */
24
24
 
25
25
  import { logWarn as warn } from '@instructure/console'
26
+ import { FocusRegionOptions } from './FocusRegionOptions'
26
27
 
27
28
  class ScreenReaderFocusRegion {
29
+ private _parents: HTMLElement[] = []
30
+ private _nodes: Element[] = []
31
+ private _liveRegion: (Element | undefined)[]
32
+ private _contextElement?: Element | Node
33
+ private _options: FocusRegionOptions
34
+ private _observer: MutationObserver | null = null
35
+ private _attributes: [Element, string, string][] = []
36
+
28
37
  constructor(
29
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
30
- element,
31
- options = {
38
+ element: Element | Node,
39
+ options: FocusRegionOptions = {
32
40
  shouldContainFocus: true,
33
41
  liveRegion: []
34
42
  }
35
43
  ) {
36
44
  const liveRegion =
37
45
  typeof options.liveRegion === 'function'
38
- ? // @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
39
- options.liveRegion()
46
+ ? options.liveRegion()
40
47
  : options.liveRegion
41
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_liveRegion' does not exist on type 'Scr... Remove this comment to see the full error message
42
48
  this._liveRegion = Array.isArray(liveRegion) ? liveRegion : [liveRegion]
43
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_contextElement' does not exist on type ... Remove this comment to see the full error message
44
49
  this._contextElement = element
45
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Screen... Remove this comment to see the full error message
46
50
  this._options = options
47
51
  }
48
52
 
49
- _observer = null
50
- _attributes = []
51
- _nodes = []
52
- _parents = []
53
-
54
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
55
- updateElement(element) {
56
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_contextElement' does not exist on type ... Remove this comment to see the full error message
53
+ updateElement(element: Element | Node) {
57
54
  this._contextElement = element
58
55
  }
59
56
 
60
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
61
- muteNode(node) {
57
+ muteNode(node: Element) {
62
58
  if (node && node.tagName.toLowerCase() !== 'script') {
63
59
  // When we are trapping screen reader focus on an element that
64
60
  // is deep inside the DOM, we can't apply aria-hidden to the
@@ -74,20 +70,15 @@ class ScreenReaderFocusRegion {
74
70
  const value = node.getAttribute(attribute)
75
71
 
76
72
  if (value !== null) {
77
- // @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
78
73
  this._attributes.push([node, attribute, value])
79
74
  node.removeAttribute(attribute)
80
75
  }
81
76
  })
82
-
83
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
84
- this._observer.observe(node, { childList: true })
77
+ this._observer!.observe(node, { childList: true })
85
78
  }
86
79
  }
87
80
 
88
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'nodes' implicitly has an 'any' type.
89
- hideNodes(nodes) {
90
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
81
+ hideNodes(nodes: Element[]) {
91
82
  nodes.forEach((node) => {
92
83
  const ariaLive =
93
84
  typeof node.getAttribute === 'function' &&
@@ -98,21 +89,16 @@ class ScreenReaderFocusRegion {
98
89
  node.tagName.toLowerCase() !== 'script' &&
99
90
  ariaLive !== 'assertive' &&
100
91
  ariaLive !== 'polite' &&
101
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
102
- this._parents.indexOf(node) === -1 &&
103
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
92
+ this._parents.indexOf(node as HTMLElement) === -1 &&
104
93
  this._nodes.indexOf(node) === -1 &&
105
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_liveRegion' does not exist on type 'Scr... Remove this comment to see the full error message
106
94
  this._liveRegion.indexOf(node) === -1 &&
107
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_contextElement' does not exist on type ... Remove this comment to see the full error message
108
- !this._contextElement.contains(node)
95
+ !this._contextElement!.contains(node)
109
96
  ) {
110
97
  if (node.tagName.toLowerCase() !== 'iframe') {
111
98
  this.hideNode(node)
112
99
  }
113
100
 
114
101
  const iframeBodies = this.parseIframeBodies(node)
115
-
116
102
  iframeBodies.forEach((iframeBody) => {
117
103
  this.hideNode(iframeBody)
118
104
  })
@@ -120,32 +106,26 @@ class ScreenReaderFocusRegion {
120
106
  })
121
107
  }
122
108
 
123
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
124
- hideNode(node) {
109
+ hideNode(node: Element) {
125
110
  if (node.getAttribute('aria-hidden') !== 'true') {
126
111
  node.setAttribute('aria-hidden', 'true')
127
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
128
112
  this._nodes.push(node)
129
113
  }
130
114
  }
131
115
 
132
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'records' implicitly has an 'any' type.
133
- handleDOMMutation = (records) => {
134
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'record' implicitly has an 'any' type.
116
+ handleDOMMutation = (records: MutationRecord[]) => {
135
117
  records.forEach((record) => {
136
- const addedNodes = Array.from(record.addedNodes)
137
- const removedNodes = Array.from(record.removedNodes)
118
+ const addedNodes = Array.from(record.addedNodes) as Element[]
119
+ const removedNodes = Array.from(record.removedNodes) as Element[]
138
120
 
139
121
  this.hideNodes(addedNodes)
140
122
 
141
123
  removedNodes.forEach((removedNode) => {
142
124
  // Node has been removed from the DOM, make sure it is
143
125
  // removed from our list of hidden nodes as well
144
- // @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
145
126
  if (removedNode.tagName.toLowerCase() !== 'iframe') {
146
127
  this.restoreNode(removedNode)
147
128
  }
148
-
149
129
  const iframeBodies = this.parseIframeBodies(removedNode)
150
130
  iframeBodies.forEach((iframeBody) => {
151
131
  this.restoreNode(iframeBody)
@@ -154,9 +134,7 @@ class ScreenReaderFocusRegion {
154
134
  })
155
135
  }
156
136
 
157
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'removedNode' implicitly has an 'any' ty... Remove this comment to see the full error message
158
- restoreNode(removedNode) {
159
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
137
+ restoreNode(removedNode: Element) {
160
138
  const index = this._nodes.indexOf(removedNode)
161
139
 
162
140
  if (index >= 0) {
@@ -165,26 +143,22 @@ class ScreenReaderFocusRegion {
165
143
  }
166
144
  }
167
145
 
168
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
169
- parseIframeBodies(node) {
146
+ parseIframeBodies(node: Element): HTMLElement[] {
170
147
  if (!node) return []
171
-
172
- let iframes = []
173
-
148
+ let iframes: HTMLIFrameElement[] = []
174
149
  if (node.tagName.toLowerCase() === 'iframe') {
175
- iframes.push(node)
150
+ iframes.push(node as HTMLIFrameElement)
176
151
  } else {
177
152
  if (node.getElementsByTagName) {
178
153
  iframes = Array.from(node.getElementsByTagName('iframe'))
179
154
  }
180
155
  }
181
-
182
156
  return iframes
183
157
  .map((iframe) => {
184
158
  let body = null
185
159
  try {
186
- body = iframe.contentDocument.body
187
- } catch (e: any) {
160
+ body = iframe.contentDocument!.body
161
+ } catch (e: unknown) {
188
162
  warn(
189
163
  false,
190
164
  `[ui-a11y] could not find a document for iframe: ${e} ${iframe}`
@@ -192,60 +166,43 @@ class ScreenReaderFocusRegion {
192
166
  }
193
167
  return body
194
168
  })
195
- .filter((body) => body !== null)
169
+ .filter((body) => body !== null) as HTMLElement[]
196
170
  }
197
171
 
198
172
  activate() {
199
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'Screen... Remove this comment to see the full error message
200
173
  if (!this._options.shouldContainFocus) {
201
174
  return
202
175
  }
203
-
204
- // @ts-expect-error ts-migrate(2322) FIXME: Type 'MutationObserver' is not assignable to type ... Remove this comment to see the full error message
205
176
  this._observer = new MutationObserver(this.handleDOMMutation)
206
-
207
- // @ts-expect-error ts-migrate(2339) FIXME: Property '_contextElement' does not exist on type ... Remove this comment to see the full error message
208
177
  let node = this._contextElement
209
-
210
178
  while (
211
179
  node &&
212
- node.nodeType === 1 &&
213
- node.tagName.toLowerCase() !== 'body'
180
+ node.nodeType === Node.ELEMENT_NODE &&
181
+ (node as Element).tagName.toLowerCase() !== 'body'
214
182
  ) {
215
- const parent = node.parentElement // can be null
216
-
183
+ const parent = node.parentElement
217
184
  if (parent) {
218
- // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
219
185
  this._parents.push(parent)
220
-
221
186
  this.muteNode(parent)
222
-
223
187
  this.hideNodes(Array.prototype.slice.call(parent.childNodes))
224
188
  }
225
-
226
- node = node.parentNode // should never be null, will default to doc element
189
+ node = node.parentNode as Element // should never be null, will default to doc element
227
190
  }
228
191
  }
229
192
 
230
193
  deactivate() {
231
194
  if (this._observer) {
232
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
233
195
  this._observer.disconnect()
234
196
  this._observer = null
235
197
  }
236
-
237
198
  this._nodes.forEach((node) => {
238
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'removeAttribute' does not exist on type ... Remove this comment to see the full error message
239
199
  node.removeAttribute('aria-hidden')
240
200
  })
241
201
  this._nodes = []
242
-
243
202
  this._attributes.forEach((attribute) => {
244
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'setAttribute' does not exist on type 'ne... Remove this comment to see the full error message
245
203
  attribute[0].setAttribute(attribute[1], attribute[2] || '')
246
204
  })
247
205
  this._attributes = []
248
-
249
206
  this._parents = []
250
207
  }
251
208
  }
@@ -256,10 +213,11 @@ export {
256
213
  * ---
257
214
  * category: utilities/a11y
258
215
  * ---
259
- * @module ScreenReaderFocusRegion
216
+ *
260
217
  * Utility that hides all DOM elements outside of a specified node. Used,
261
218
  * for example, in overlay components where we want to restrict the screen
262
- * readers to the overlay content
219
+ * readers to the overlay content.
220
+ * @module ScreenReaderFocusRegion
263
221
  */
264
222
  ScreenReaderFocusRegion
265
223
  }
@@ -22,21 +22,18 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- import React from 'react'
25
+ import React, { ReactNode } from 'react'
26
26
  import { matchComponentTypes } from '@instructure/ui-react-utils'
27
27
 
28
28
  import { ScreenReaderContent } from '@instructure/ui-a11y-content'
29
29
 
30
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'children' implicitly has an 'any' type.
31
- function hasVisibleChildren(children) {
30
+ function hasVisibleChildren(children: ReactNode) {
32
31
  let visible = false
33
-
34
32
  React.Children.forEach(children, (child) => {
35
33
  if (child && !matchComponentTypes(child, [ScreenReaderContent])) {
36
34
  visible = true
37
35
  }
38
36
  })
39
-
40
37
  return visible
41
38
  }
42
39
 
package/src/index.ts CHANGED
@@ -28,3 +28,4 @@ export { hasVisibleChildren } from './hasVisibleChildren'
28
28
  export { KeyboardFocusRegion } from './KeyboardFocusRegion'
29
29
  export { scopeTab } from './scopeTab'
30
30
  export { ScreenReaderFocusRegion } from './ScreenReaderFocusRegion'
31
+ export type { FocusRegionOptions } from './FocusRegionOptions'
package/src/scopeTab.ts CHANGED
@@ -29,9 +29,13 @@ import {
29
29
  containsActiveElement,
30
30
  getActiveElement
31
31
  } from '@instructure/ui-dom-utils'
32
+ import type { UIElement } from '@instructure/shared-types'
32
33
 
33
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
34
- function scopeTab(element, event, onLeavingFinalTabbable) {
34
+ function scopeTab(
35
+ element: UIElement | undefined,
36
+ event: KeyboardEvent,
37
+ onLeavingFinalTabbable?: () => void
38
+ ) {
35
39
  const node = findDOMNode(element)
36
40
  const tabbable = findTabbable(node)
37
41
 
@@ -66,8 +70,7 @@ function scopeTab(element, event, onLeavingFinalTabbable) {
66
70
 
67
71
  event.preventDefault()
68
72
  const target = tabbable[event.shiftKey ? tabbable.length - 1 : 0]
69
- // @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
70
- target.focus()
73
+ ;(target as HTMLElement).focus()
71
74
  }
72
75
 
73
76
  export default scopeTab