|
| 1 | +/** |
| 2 | + * A11y Helpers |
| 3 | + * ----------------------------------------------------------------------------- |
| 4 | + * A collection of useful functions that help make your theme more accessible |
| 5 | + * to users with visual impairments. |
| 6 | + */ |
| 7 | + |
| 8 | +import $ from 'jquery'; |
| 9 | + |
| 10 | +/** |
| 11 | + * For use when focus shifts to a container rather than a link |
| 12 | + * eg for In-page links, after scroll, focus shifts to content area so that |
| 13 | + * next `tab` is where user expects if focusing a link, just $link.focus(); |
| 14 | + * |
| 15 | + * @param {JQuery} $element - The element to be acted upon |
| 16 | + */ |
| 17 | +export function pageLinkFocus($element) { |
| 18 | + const focusClass = 'js-focus-hidden'; |
| 19 | + |
| 20 | + $element |
| 21 | + .first() |
| 22 | + .attr('tabIndex', '-1') |
| 23 | + .focus() |
| 24 | + .addClass(focusClass) |
| 25 | + .one('blur', callback); |
| 26 | + |
| 27 | + function callback() { |
| 28 | + $element |
| 29 | + .first() |
| 30 | + .removeClass(focusClass) |
| 31 | + .removeAttr('tabindex'); |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +/** |
| 36 | + * If there's a hash in the url, focus the appropriate element |
| 37 | + */ |
| 38 | +export function focusHash() { |
| 39 | + const hash = window.location.hash; |
| 40 | + |
| 41 | + // is there a hash in the url? is it an element on the page? |
| 42 | + if (hash && document.getElementById(hash.slice(1))) { |
| 43 | + this.pageLinkFocus($(hash)); |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +/** |
| 48 | + * When an in-page (url w/hash) link is clicked, focus the appropriate element |
| 49 | + */ |
| 50 | +export function bindInPageLinks() { |
| 51 | + $('a[href*=#]').on( |
| 52 | + 'click', |
| 53 | + (evt) => { |
| 54 | + this.pageLinkFocus($(evt.currentTarget.hash)); |
| 55 | + } |
| 56 | + ); |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * Traps the focus in a particular container |
| 61 | + * |
| 62 | + * @param {object} options - Options to be used |
| 63 | + * @param {jQuery} options.$container - Container to trap focus within |
| 64 | + * @param {jQuery} options.$elementToFocus - Element to be focused when focus leaves container |
| 65 | + * @param {string} options.namespace - Namespace used for new focus event handler |
| 66 | + */ |
| 67 | +export function trapFocus(options) { |
| 68 | + const eventName = options.namespace |
| 69 | + ? `focusin.${options.namespace}` |
| 70 | + : 'focusin'; |
| 71 | + |
| 72 | + if (!options.$elementToFocus) { |
| 73 | + options.$elementToFocus = options.$container; |
| 74 | + } |
| 75 | + |
| 76 | + options.$container.attr('tabindex', '-1'); |
| 77 | + options.$elementToFocus.focus(); |
| 78 | + |
| 79 | + $(document).on(eventName, (evt) => { |
| 80 | + if ( |
| 81 | + options.$container[0] !== evt.target && |
| 82 | + !options.$container.has(evt.target).length |
| 83 | + ) { |
| 84 | + options.$container.focus(); |
| 85 | + } |
| 86 | + }); |
| 87 | +} |
| 88 | + |
| 89 | +/** |
| 90 | + * Removes the trap of focus in a particular container |
| 91 | + * |
| 92 | + * @param {object} options - Options to be used |
| 93 | + * @param {jQuery} options.$container - Container to trap focus within |
| 94 | + * @param {string} options.namespace - Namespace used for new focus event handler |
| 95 | + */ |
| 96 | +export function removeTrapFocus(options) { |
| 97 | + const eventName = options.namespace |
| 98 | + ? `focusin.${options.namespace}` |
| 99 | + : 'focusin'; |
| 100 | + |
| 101 | + if (options.$container && options.$container.length) { |
| 102 | + options.$container.removeAttr('tabindex'); |
| 103 | + } |
| 104 | + |
| 105 | + $(document).off(eventName); |
| 106 | +} |
0 commit comments