@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.
- package/LICENSE.md +27 -0
- package/es/FocusRegion.js +15 -8
- package/es/FocusRegionManager.js +8 -4
- package/es/FocusRegionOptions.js +1 -0
- package/es/KeyboardFocusRegion.js +28 -35
- package/es/ScreenReaderFocusRegion.js +10 -6
- package/lib/FocusRegion.js +10 -7
- package/lib/FocusRegionManager.js +5 -2
- package/lib/FocusRegionOptions.js +1 -0
- package/lib/KeyboardFocusRegion.js +26 -34
- package/lib/ScreenReaderFocusRegion.js +7 -4
- package/package.json +12 -11
- package/src/FocusRegion.ts +42 -65
- package/src/FocusRegionManager.ts +35 -35
- package/src/FocusRegionOptions.ts +80 -0
- package/src/KeyboardFocusRegion.ts +58 -108
- package/src/ScreenReaderFocusRegion.ts +36 -78
- package/src/hasVisibleChildren.ts +2 -5
- package/src/index.ts +1 -0
- package/src/scopeTab.ts +7 -4
- package/types/FocusRegion.d.ts +22 -15
- package/types/FocusRegion.d.ts.map +1 -1
- package/types/FocusRegionManager.d.ts +23 -14
- package/types/FocusRegionManager.d.ts.map +1 -1
- package/types/FocusRegionOptions.d.ts +56 -0
- package/types/FocusRegionOptions.d.ts.map +1 -0
- package/types/KeyboardFocusRegion.d.ts +24 -22
- package/types/KeyboardFocusRegion.d.ts.map +1 -1
- package/types/ScreenReaderFocusRegion.d.ts +19 -17
- package/types/ScreenReaderFocusRegion.d.ts.map +1 -1
- package/types/hasVisibleChildren.d.ts +2 -1
- package/types/hasVisibleChildren.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/scopeTab.d.ts +2 -1
- package/types/scopeTab.d.ts.map +1 -1
package/src/FocusRegion.ts
CHANGED
|
@@ -27,7 +27,6 @@ import keycode from 'keycode'
|
|
|
27
27
|
import {
|
|
28
28
|
contains,
|
|
29
29
|
addEventListener,
|
|
30
|
-
getFrameDocumentSafe,
|
|
31
30
|
ownerDocument,
|
|
32
31
|
findTabbable
|
|
33
32
|
} from '@instructure/ui-dom-utils'
|
|
@@ -36,66 +35,54 @@ import { logError as error } from '@instructure/console'
|
|
|
36
35
|
|
|
37
36
|
import { ScreenReaderFocusRegion } from './ScreenReaderFocusRegion'
|
|
38
37
|
import { KeyboardFocusRegion } from './KeyboardFocusRegion'
|
|
38
|
+
import { FocusRegionOptions } from './FocusRegionOptions'
|
|
39
39
|
|
|
40
40
|
class FocusRegion {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
private _contextElement: Node | Element | null = null
|
|
42
|
+
private _preventCloseOnDocumentClick = false
|
|
43
|
+
private _options: FocusRegionOptions
|
|
44
|
+
private readonly _screenReaderFocusRegion: ScreenReaderFocusRegion
|
|
45
|
+
private readonly _keyboardFocusRegion: KeyboardFocusRegion
|
|
46
|
+
private readonly _id: string
|
|
47
|
+
private _listeners: ReturnType<typeof addEventListener>[] = []
|
|
48
|
+
private _active = false
|
|
49
|
+
|
|
50
|
+
constructor(element: Element | Node, options: FocusRegionOptions) {
|
|
44
51
|
this._options = options || {
|
|
45
52
|
shouldCloseOnDocumentClick: true,
|
|
46
|
-
shouldCloseOnEscape: true
|
|
47
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
48
|
-
onDismiss: (event) => {}
|
|
53
|
+
shouldCloseOnEscape: true
|
|
49
54
|
}
|
|
50
55
|
this._contextElement = element
|
|
51
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_screenReaderFocusRegion' does not exist... Remove this comment to see the full error message
|
|
52
56
|
this._screenReaderFocusRegion = new ScreenReaderFocusRegion(
|
|
53
57
|
element,
|
|
54
58
|
options
|
|
55
59
|
)
|
|
56
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
57
60
|
this._keyboardFocusRegion = new KeyboardFocusRegion(element, options)
|
|
58
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_id' does not exist on type 'FocusRegion... Remove this comment to see the full error message
|
|
59
61
|
this._id = uid()
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
_preventCloseOnDocumentClick = false
|
|
64
|
-
_listeners = []
|
|
65
|
-
_active = false
|
|
66
|
-
|
|
67
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'element' implicitly has an 'any' type.
|
|
68
|
-
updateElement(element) {
|
|
64
|
+
updateElement(element: Element | Node) {
|
|
69
65
|
this._contextElement = element
|
|
70
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
71
66
|
if (this._keyboardFocusRegion) {
|
|
72
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
73
67
|
this._keyboardFocusRegion.updateElement(element)
|
|
74
68
|
}
|
|
75
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_screenReaderFocusRegion' does not exist... Remove this comment to see the full error message
|
|
76
69
|
if (this._screenReaderFocusRegion) {
|
|
77
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_screenReaderFocusRegion' does not exist... Remove this comment to see the full error message
|
|
78
70
|
this._screenReaderFocusRegion.updateElement(element)
|
|
79
71
|
}
|
|
80
72
|
}
|
|
81
73
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'FocusR... Remove this comment to see the full error message
|
|
85
|
-
this._options.onDismiss(event, documentClick)
|
|
74
|
+
handleDismiss = (event: Event, documentClick?: boolean) => {
|
|
75
|
+
this._options.onDismiss?.(event, documentClick)
|
|
86
76
|
}
|
|
87
77
|
|
|
88
|
-
|
|
89
|
-
captureDocumentClick = (event) => {
|
|
78
|
+
captureDocumentClick = (event: MouseEvent) => {
|
|
90
79
|
const { target } = event
|
|
91
80
|
this._preventCloseOnDocumentClick =
|
|
92
|
-
event.button !== 0 || contains(this._contextElement, target)
|
|
81
|
+
event.button !== 0 || contains(this._contextElement, target as Node)
|
|
93
82
|
}
|
|
94
83
|
|
|
95
|
-
|
|
96
|
-
handleDocumentClick = (event) => {
|
|
84
|
+
handleDocumentClick = (event: MouseEvent) => {
|
|
97
85
|
if (
|
|
98
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'FocusR... Remove this comment to see the full error message
|
|
99
86
|
this._options.shouldCloseOnDocumentClick &&
|
|
100
87
|
!this._preventCloseOnDocumentClick
|
|
101
88
|
) {
|
|
@@ -103,30 +90,24 @@ class FocusRegion {
|
|
|
103
90
|
}
|
|
104
91
|
}
|
|
105
92
|
|
|
106
|
-
|
|
107
|
-
handleFrameClick = (event, frame) => {
|
|
93
|
+
handleFrameClick = (event: MouseEvent, frame: HTMLIFrameElement) => {
|
|
108
94
|
if (!contains(this._contextElement, frame)) {
|
|
109
95
|
// dismiss if frame is not within the region
|
|
110
96
|
this.handleDismiss(event, true)
|
|
111
97
|
}
|
|
112
98
|
}
|
|
113
99
|
|
|
114
|
-
|
|
115
|
-
handleKeyUp = (event) => {
|
|
100
|
+
handleKeyUp = (event: KeyboardEvent) => {
|
|
116
101
|
if (
|
|
117
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'FocusR... Remove this comment to see the full error message
|
|
118
102
|
this._options.shouldCloseOnEscape &&
|
|
119
|
-
|
|
120
|
-
event.keyCode === keycode.codes.escape &&
|
|
103
|
+
event.keyCode === keycode.codes.esc &&
|
|
121
104
|
!event.defaultPrevented
|
|
122
105
|
) {
|
|
123
|
-
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
124
106
|
this.handleDismiss(event)
|
|
125
107
|
}
|
|
126
108
|
}
|
|
127
109
|
|
|
128
110
|
get id() {
|
|
129
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_id' does not exist on type 'FocusRegion... Remove this comment to see the full error message
|
|
130
111
|
return this._id
|
|
131
112
|
}
|
|
132
113
|
|
|
@@ -144,63 +125,59 @@ class FocusRegion {
|
|
|
144
125
|
if (!this._active) {
|
|
145
126
|
const doc = ownerDocument(this._contextElement)
|
|
146
127
|
|
|
147
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
148
128
|
this._keyboardFocusRegion.activate()
|
|
149
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_screenReaderFocusRegion' does not exist... Remove this comment to see the full error message
|
|
150
129
|
this._screenReaderFocusRegion.activate()
|
|
151
130
|
|
|
152
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'FocusR... Remove this comment to see the full error message
|
|
153
131
|
if (this._options.shouldCloseOnDocumentClick) {
|
|
154
132
|
this._listeners.push(
|
|
155
|
-
|
|
156
|
-
|
|
133
|
+
addEventListener(
|
|
134
|
+
doc,
|
|
135
|
+
'click',
|
|
136
|
+
this.captureDocumentClick as EventListener,
|
|
137
|
+
true
|
|
138
|
+
)
|
|
157
139
|
)
|
|
158
140
|
this._listeners.push(
|
|
159
|
-
|
|
160
|
-
|
|
141
|
+
addEventListener(
|
|
142
|
+
doc,
|
|
143
|
+
'click',
|
|
144
|
+
this.handleDocumentClick as EventListener
|
|
145
|
+
)
|
|
161
146
|
)
|
|
162
147
|
|
|
163
148
|
Array.from(doc.getElementsByTagName('iframe')).forEach((el) => {
|
|
164
149
|
// listen for mouseup events on any iframes in the document
|
|
165
|
-
const frameDoc =
|
|
166
|
-
|
|
150
|
+
const frameDoc = el.contentDocument
|
|
167
151
|
if (frameDoc) {
|
|
168
152
|
this._listeners.push(
|
|
169
|
-
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ remove(): void; }' is not assi... Remove this comment to see the full error message
|
|
170
153
|
addEventListener(frameDoc, 'mouseup', (event) => {
|
|
171
|
-
this.handleFrameClick(event, el)
|
|
154
|
+
this.handleFrameClick(event as MouseEvent, el)
|
|
172
155
|
})
|
|
173
156
|
)
|
|
174
157
|
}
|
|
175
158
|
})
|
|
176
159
|
}
|
|
177
160
|
|
|
178
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_options' does not exist on type 'FocusR... Remove this comment to see the full error message
|
|
179
161
|
if (this._options.shouldCloseOnEscape) {
|
|
180
|
-
|
|
181
|
-
|
|
162
|
+
this._listeners.push(
|
|
163
|
+
addEventListener(doc, 'keyup', this.handleKeyUp as EventListener)
|
|
164
|
+
)
|
|
182
165
|
}
|
|
183
166
|
|
|
184
167
|
this._active = true
|
|
185
168
|
}
|
|
186
169
|
}
|
|
187
170
|
|
|
188
|
-
deactivate({ keyboard = true } = {}) {
|
|
171
|
+
deactivate({ keyboard = true }: { keyboard?: boolean } = {}) {
|
|
189
172
|
if (this._active) {
|
|
190
173
|
this._listeners.forEach((listener) => {
|
|
191
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'remove' does not exist on type 'never'.
|
|
192
174
|
listener.remove()
|
|
193
175
|
})
|
|
194
176
|
this._listeners = []
|
|
195
|
-
|
|
196
177
|
if (keyboard) {
|
|
197
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
198
178
|
this._keyboardFocusRegion.deactivate()
|
|
199
179
|
}
|
|
200
|
-
|
|
201
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_screenReaderFocusRegion' does not exist... Remove this comment to see the full error message
|
|
202
180
|
this._screenReaderFocusRegion.deactivate()
|
|
203
|
-
|
|
204
181
|
this._active = false
|
|
205
182
|
}
|
|
206
183
|
}
|
|
@@ -210,7 +187,6 @@ class FocusRegion {
|
|
|
210
187
|
this._active,
|
|
211
188
|
`[FocusRegion] Cannot call '.focus()' on a region that is not currently active.`
|
|
212
189
|
)
|
|
213
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
214
190
|
this._keyboardFocusRegion.focus()
|
|
215
191
|
}
|
|
216
192
|
|
|
@@ -219,7 +195,6 @@ class FocusRegion {
|
|
|
219
195
|
!this._active,
|
|
220
196
|
`[FocusRegion] Cannot call '.blur()' on a region that is currently active.`
|
|
221
197
|
)
|
|
222
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_keyboardFocusRegion' does not exist on ... Remove this comment to see the full error message
|
|
223
198
|
this._keyboardFocusRegion.blur()
|
|
224
199
|
}
|
|
225
200
|
}
|
|
@@ -230,11 +205,13 @@ export {
|
|
|
230
205
|
* ---
|
|
231
206
|
* category: utilities/a11y
|
|
232
207
|
* ---
|
|
233
|
-
*
|
|
234
|
-
* Class for focus operations
|
|
208
|
+
*
|
|
209
|
+
* Class for focus operations, manages [ScreenReaderFocusRegion](#ScreenReaderFocusRegion)
|
|
210
|
+
* and [KeyboardFocusRegion](#KeyboardFocusRegion) for the given DOM element.
|
|
235
211
|
* - Scoping focus within a given context (DOM node),
|
|
236
212
|
* - Mark active element for focus later
|
|
237
213
|
* - Return focus to the marked element
|
|
214
|
+
* @module FocusRegion
|
|
238
215
|
*/
|
|
239
216
|
FocusRegion
|
|
240
217
|
}
|
|
@@ -21,15 +21,25 @@
|
|
|
21
21
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
|
+
|
|
24
25
|
import { logError as error } from '@instructure/console'
|
|
25
26
|
import { FocusRegion } from './FocusRegion'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
import { FocusRegionOptions } from './FocusRegionOptions'
|
|
28
|
+
|
|
29
|
+
type Entry = {
|
|
30
|
+
id: string
|
|
31
|
+
element: Element | Node
|
|
32
|
+
region: FocusRegion
|
|
33
|
+
children: Entry[]
|
|
34
|
+
parent?: Entry
|
|
35
|
+
}
|
|
36
|
+
let ENTRIES: Entry[] = []
|
|
29
37
|
|
|
30
38
|
class FocusRegionManager {
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
static focusRegion = (
|
|
40
|
+
element: Element | Node,
|
|
41
|
+
idOrOptions: string | FocusRegionOptions = {}
|
|
42
|
+
) => {
|
|
33
43
|
let entry
|
|
34
44
|
if (typeof idOrOptions === 'string') {
|
|
35
45
|
entry = FocusRegionManager.getEntry(element, idOrOptions)
|
|
@@ -45,60 +55,57 @@ class FocusRegionManager {
|
|
|
45
55
|
`[FocusRegionManager] Could not focus region with element: ${element}`
|
|
46
56
|
)
|
|
47
57
|
}
|
|
58
|
+
return
|
|
48
59
|
}
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
static activateRegion = (
|
|
62
|
+
element: Element | Node,
|
|
63
|
+
options: FocusRegionOptions
|
|
64
|
+
) => {
|
|
52
65
|
const { region } = FocusRegionManager.addEntry(element, options)
|
|
53
66
|
return region
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
static getActiveEntry = () => {
|
|
57
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
58
70
|
return ENTRIES.find(({ region }) => region.focused)
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
static findEntry = (element, id) => {
|
|
73
|
+
static findEntry = (element: Element | Node, id?: string) => {
|
|
63
74
|
let index
|
|
64
75
|
if (id) {
|
|
65
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
66
76
|
index = ENTRIES.findIndex((entry) => entry.id === id)
|
|
67
77
|
} else {
|
|
68
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
69
78
|
index = ENTRIES.findIndex((entry) => entry.element === element)
|
|
70
79
|
}
|
|
71
80
|
return index
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
static getEntry = (element, id) => {
|
|
76
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
83
|
+
static getEntry = (element: Element | Node, id?: string) => {
|
|
77
84
|
return ENTRIES[FocusRegionManager.findEntry(element, id)]
|
|
78
85
|
}
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
static addEntry = (
|
|
88
|
+
element: Element | Node,
|
|
89
|
+
options: FocusRegionOptions = {}
|
|
90
|
+
) => {
|
|
82
91
|
const region = new FocusRegion(element, options)
|
|
83
92
|
const activeEntry = FocusRegionManager.getActiveEntry()
|
|
84
93
|
|
|
85
94
|
const { keyboardFocusable } = region
|
|
86
95
|
|
|
87
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
88
96
|
ENTRIES.forEach(({ region }) => {
|
|
89
97
|
if (region) {
|
|
90
98
|
// If the active region is triggering a new focus region that does not have
|
|
91
99
|
// keyboard focusable content, don't deactivate the active region's keyboard
|
|
92
100
|
// focus region
|
|
93
|
-
|
|
94
|
-
region.focused && !keyboardFocusable
|
|
95
|
-
)
|
|
101
|
+
const keyboard =
|
|
102
|
+
region.focused && !keyboardFocusable ? { keyboard: false } : undefined
|
|
103
|
+
region.deactivate(keyboard)
|
|
96
104
|
}
|
|
97
105
|
})
|
|
98
106
|
|
|
99
107
|
region.activate()
|
|
100
108
|
|
|
101
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'shouldFocusOnOpen' does not exist on typ... Remove this comment to see the full error message
|
|
102
109
|
if (options.shouldFocusOnOpen) {
|
|
103
110
|
region.focus()
|
|
104
111
|
}
|
|
@@ -117,22 +124,16 @@ class FocusRegionManager {
|
|
|
117
124
|
return entry
|
|
118
125
|
}
|
|
119
126
|
|
|
120
|
-
|
|
121
|
-
static removeEntry = (element, id) => {
|
|
127
|
+
static removeEntry = (element: Element | Node, id?: string) => {
|
|
122
128
|
const index = FocusRegionManager.findEntry(element, id)
|
|
123
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
124
129
|
const entry = ENTRIES[index]
|
|
125
|
-
|
|
126
130
|
if (index > -1) {
|
|
127
|
-
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'ENTRIES' implicitly has an 'any[]' type.
|
|
128
131
|
ENTRIES.splice(index, 1)
|
|
129
132
|
}
|
|
130
|
-
|
|
131
133
|
return entry
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
static isFocused = (element, id) => {
|
|
136
|
+
static isFocused = (element: Element | Node, id?: string) => {
|
|
136
137
|
const entry = FocusRegionManager.getActiveEntry()
|
|
137
138
|
if (id) {
|
|
138
139
|
return entry && entry.region && entry.id === id
|
|
@@ -145,8 +146,7 @@ class FocusRegionManager {
|
|
|
145
146
|
ENTRIES = []
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
static blurRegion = (element, id) => {
|
|
149
|
+
static blurRegion = (element: Element | Node, id?: string) => {
|
|
150
150
|
const entry = FocusRegionManager.removeEntry(element, id)
|
|
151
151
|
|
|
152
152
|
if (entry) {
|
|
@@ -157,7 +157,6 @@ class FocusRegionManager {
|
|
|
157
157
|
|
|
158
158
|
// and any regions created from it
|
|
159
159
|
if (children) {
|
|
160
|
-
// @ts-expect-error ts-migrate(7031) FIXME: Binding element 'id' implicitly has an 'any' type.
|
|
161
160
|
children.forEach(({ id, element }) => {
|
|
162
161
|
const entry = FocusRegionManager.removeEntry(element, id)
|
|
163
162
|
entry && entry.region && entry.region.deactivate()
|
|
@@ -178,11 +177,12 @@ export {
|
|
|
178
177
|
* ---
|
|
179
178
|
* category: utilities/a11y
|
|
180
179
|
* ---
|
|
181
|
-
*
|
|
182
|
-
* Class for focus operations.
|
|
180
|
+
*
|
|
181
|
+
* Class for focus operations, manages multiple [FocusRegion](#FocusRegion)s.
|
|
183
182
|
* - Scoping focus within a given context,
|
|
184
183
|
* - Mark active element for focus later
|
|
185
184
|
* - Return focus to the marked element
|
|
185
|
+
* @module FocusManager
|
|
186
186
|
*/
|
|
187
187
|
FocusRegionManager
|
|
188
188
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The MIT License (MIT)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type { LiveRegion, UIElement } from '@instructure/shared-types'
|
|
26
|
+
|
|
27
|
+
export type FocusRegionOptions = {
|
|
28
|
+
/**
|
|
29
|
+
* Function called when tab focus leaves the focusable content. This only
|
|
30
|
+
* occurs when `shouldContainFocus` is set to false.
|
|
31
|
+
*/
|
|
32
|
+
onBlur?: (event: Event) => void
|
|
33
|
+
/**
|
|
34
|
+
* Function called when a focus region is dismissed. This can happen when
|
|
35
|
+
* the user presses the escape key and `shouldCloseOnEscape` is true or
|
|
36
|
+
* when an IFrame is clicked or when anything outside the focus region
|
|
37
|
+
* is clicked if `shouldCloseOnDocumentClick` is true.
|
|
38
|
+
* @param event The event triggered the dismissal
|
|
39
|
+
* @param documentClick Whether the dismissal was triggered by a mouse click.
|
|
40
|
+
*/
|
|
41
|
+
onDismiss?: (event: Event, documentClick?: boolean) => void
|
|
42
|
+
/**
|
|
43
|
+
* An element or a function returning an element to focus by default
|
|
44
|
+
*/
|
|
45
|
+
defaultFocusElement?: UIElement
|
|
46
|
+
/**
|
|
47
|
+
* An element, function returning an element, or array of elements that will not be hidden from
|
|
48
|
+
* the screen reader when the focus region is active
|
|
49
|
+
*/
|
|
50
|
+
liveRegion?: LiveRegion
|
|
51
|
+
/**
|
|
52
|
+
* When set to true or its an array that includes the 'keyboard' string,
|
|
53
|
+
* the keyboard and screenreader focus is trapped; when set to 'screenreader'
|
|
54
|
+
* only the screenreader focus is trapped.
|
|
55
|
+
*/
|
|
56
|
+
shouldContainFocus?: boolean | ('keyboard' | 'screenreader')[]
|
|
57
|
+
/**
|
|
58
|
+
* When set to true the keyboard focus is returned to the active element
|
|
59
|
+
* before the focus region was activated.
|
|
60
|
+
*/
|
|
61
|
+
shouldReturnFocus?: boolean
|
|
62
|
+
/**
|
|
63
|
+
* When set to true the `onDismiss` function is called on a click outside
|
|
64
|
+
* the focus region.
|
|
65
|
+
*/
|
|
66
|
+
shouldCloseOnDocumentClick?: boolean
|
|
67
|
+
/**
|
|
68
|
+
* When set to true the `onDismiss` function is called on the `Escape`
|
|
69
|
+
* keypress
|
|
70
|
+
*/
|
|
71
|
+
shouldCloseOnEscape?: boolean
|
|
72
|
+
/**
|
|
73
|
+
* When set to true, the `defaultFocusElement` is focused on initialization.
|
|
74
|
+
*/
|
|
75
|
+
shouldFocusOnOpen?: boolean
|
|
76
|
+
/**
|
|
77
|
+
* provides a reference to the underlying html root element
|
|
78
|
+
*/
|
|
79
|
+
elementRef?: (element: Element | null) => void
|
|
80
|
+
}
|