-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: migrate addon to TypeScript
- Loading branch information
1 parent
88c1019
commit bd0e7da
Showing
2 changed files
with
71 additions
and
70 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { modifier } from "ember-modifier"; | ||
import { next } from "@ember/runloop"; | ||
|
||
const focusableElements = [ | ||
"BUTTON", | ||
"SUMMARY", | ||
"IFRAME", | ||
"INPUT", | ||
"SELECT", | ||
"TEXTAREA", | ||
]; | ||
|
||
const DEFAULT_SELECTOR = | ||
"input:not([disabled]):not([readonly]),textarea:not([disabled]):not([readonly])"; | ||
|
||
export default modifier(function autofocus( | ||
element: HTMLElement, | ||
[selector = DEFAULT_SELECTOR]: string[], | ||
{ disabled }: { disabled: boolean }, | ||
) { | ||
if (disabled) { | ||
return; | ||
} | ||
|
||
// Instead of selecting a child element by default, should this (in a major), | ||
// be a behavior that is changed via a passed flag? | ||
const targetElement: HTMLElement = element.querySelector(selector) || element; | ||
const isChildElement = targetElement !== element; | ||
|
||
/** | ||
* Only applies to the element that {{autofocus}} is applied to. | ||
* opts-out if we're selecting a child element. | ||
*/ | ||
const shouldMoveFocus = | ||
!isChildElement && | ||
!focusableElements.some( | ||
(item) => | ||
element.tagName === item || | ||
element.isContentEditable || | ||
element.hasAttribute("aria-disabled") || | ||
element.hasAttribute("href") || | ||
element.hasAttribute("tabindex"), | ||
); | ||
|
||
/** | ||
* if {{autofocus}} is applied to a non-focusable element, | ||
* For A11y purposes, this is used to move focus to the non-focusable element. | ||
* This is helpful when new elements are inserted on to the screen (yet not focus-trapped), | ||
* and we want the tab-behavior to move "near" the inserted content. | ||
* | ||
* This still prevents the non-focusable element from being tabbed to, as non-focusable | ||
* elements are still not focusable. | ||
* | ||
* But this is a behavior we can use to help out screen readers and keyboard users alike to | ||
* more smoothly interact with newly-inserted content (without needing to focus an interactive-specifically | ||
* maybe the inserted contents are just buttons, for example). | ||
*/ | ||
if (shouldMoveFocus) { | ||
element.setAttribute("tabindex", "-1"); | ||
} | ||
|
||
next(function () { | ||
targetElement.focus(); | ||
}); | ||
|
||
return (): void => { | ||
if (shouldMoveFocus) { | ||
element.removeAttribute("tabindex"); | ||
} | ||
}; | ||
}); |