/** * `materialToolbar`: the arrow keys move focus between the controls of an ``, as * WAI-ARIA's toolbar pattern has them (left and right, or up and down when it is vertical; mirrored * on a right-to-left page; Home and End to its ends). Every control stays in the Tab order, so a * control added by a Livewire render is reachable without any bookkeeping. */ const CONTROLS = 'button:not([disabled]), a[href], input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])' document.addEventListener('alpine:init', () => { window.Alpine.data('materialToolbar', (vertical = false) => ({ move(event) { const keys = vertical ? { ArrowUp: -1, ArrowDown: 1 } : { ArrowLeft: -1, ArrowRight: 1 } const controls = [...this.$root.querySelectorAll(CONTROLS)].filter((control) => control.getClientRects().length > 0) const at = controls.indexOf(document.activeElement) if (at === -1 || controls.length === 0) { return } let next = null if (event.key === 'Home') { next = controls[0] } else if (event.key === 'End') { next = controls.at(-1) } else if (event.key in keys) { const rtl = !vertical && getComputedStyle(this.$root).direction === 'rtl' const by = keys[event.key] * (rtl ? -1 : 1) next = controls[(at + by + controls.length) % controls.length] } if (next) { event.preventDefault() next.focus() } }, })) })