|
| 1 | +const TAB_KEYCODE = 9; |
| 2 | +const FOCUS_ATTR = 'data-is-focused'; |
| 3 | +const BLUR_EVENT = 'blur'; |
| 4 | +const FOCUS_EVENT = 'focus'; |
| 5 | +const KEYDOWN_EVENT = 'keydown'; |
| 6 | +const MOUSEDOWN_EVENT = 'mousedown'; |
| 7 | + |
| 8 | +let IS_MOUSE_EVENT = false; |
| 9 | + |
| 10 | +/** |
| 11 | + * Attaches listeners for keydown, mousedown, focus, and blur to the document, |
| 12 | + * which handle adding or removing focus outline css class for mouse events. |
| 13 | + */ |
| 14 | +export function addFocusOutlineListeners() { |
| 15 | + const docEl = window.document.documentElement; |
| 16 | + IS_MOUSE_EVENT = false; |
| 17 | + |
| 18 | + docEl.addEventListener(KEYDOWN_EVENT, handleKeyDown, false); |
| 19 | + docEl.addEventListener(MOUSEDOWN_EVENT, handleMouseDown, false); |
| 20 | + docEl.addEventListener(FOCUS_EVENT, handleFocus, true); |
| 21 | + docEl.addEventListener(BLUR_EVENT, handleBlur, true); |
| 22 | +} |
| 23 | + |
| 24 | +/** |
| 25 | + * Detaches listeners |
| 26 | + */ |
| 27 | +export function removeFocusOutlineListeners() { |
| 28 | + const docEl = window.document.documentElement; |
| 29 | + |
| 30 | + if (docEl) { |
| 31 | + docEl.removeEventListener(KEYDOWN_EVENT, handleKeyDown, false); |
| 32 | + docEl.removeEventListener(MOUSEDOWN_EVENT, handleMouseDown, false); |
| 33 | + docEl.removeEventListener(FOCUS_EVENT, handleFocus, true); |
| 34 | + docEl.removeEventListener(BLUR_EVENT, handleBlur, true); |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +export function handleKeyDown(event: KeyboardEvent) { |
| 39 | + if (event.keyCode === TAB_KEYCODE) { |
| 40 | + IS_MOUSE_EVENT = false; |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +export function handleMouseDown(event: MouseEvent) { |
| 45 | + IS_MOUSE_EVENT = true; |
| 46 | +} |
| 47 | + |
| 48 | +export function handleFocus(event: Event) { |
| 49 | + if (IS_MOUSE_EVENT && event.target && event.target !== event.currentTarget) { |
| 50 | + (event.target as Element).setAttribute(FOCUS_ATTR, 'true'); |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +export function handleBlur(event: Event) { |
| 55 | + if (event.target !== event.currentTarget) { |
| 56 | + (event.target as Element).removeAttribute(FOCUS_ATTR); |
| 57 | + } |
| 58 | +} |
0 commit comments