@callbacksystems/focus-trap
Version:
A JavaScript utility for effective focus trapping within a specified element.
7 lines (6 loc) • 3.15 kB
JavaScript
/*
@callbacksystems/focus-trap 3.0.0
Copyright © Callback Systems
*/
var r=class{started=!1;constructor(t){this.controller=t}get element(){return this.controller.element}};var i=class extends r{start(){this.started||(document.addEventListener("focus",this.#t,{capture:!0}),this.started=!0)}stop(){this.started&&(document.removeEventListener("focus",this.#t,{capture:!0}),this.started=!1)}#t=()=>this.controller.captureFocus()};var o=class extends r{#t=new MutationObserver(t=>this.#s(t));start(){this.started||(this.#t.observe(document.body,{childList:!0,subtree:!0,attributes:!0}),this.started=!0)}stop(){this.started&&(this.#t.disconnect(),this.started=!1)}#s(t){if(this.#i)return this.controller.releaseFocus();this.controller.captureFocus(),this.#r(t)&&this.controller.makeOutsideElementsInert()}#r(t){return t.some(({target:s})=>!this.element.contains(s))}get#i(){return!this.element.isConnected||!this.element.checkVisibility()}};function l(e){return!!e&&e.checkVisibility()&&e.closest("[inert], :disabled")==null&&e.tabIndex>=0&&typeof e.focus=="function"}var a=class{#t=!1;constructor(t){this.controller=t}startRestricting(){this.#t||(this.#n.addEventListener("keydown",this.#s),this.#t=!0)}stopRestricting(){this.#t&&(this.#n.removeEventListener("keydown",this.#s),this.#t=!1)}#s=t=>{t.key==="Tab"&&this.#e.length===0?(t.preventDefault(),t.stopPropagation()):t.key==="Tab"&&t.shiftKey&&document.activeElement===this.#a?(t.preventDefault(),t.stopPropagation(),this.#i()):t.key==="Tab"&&!t.shiftKey&&document.activeElement===this.#o&&(t.preventDefault(),t.stopPropagation(),this.#r())};#r(){this.#e.length!==0&&this.#a.focus()}#i(){this.#e.length!==0&&this.#o.focus()}get#a(){return this.#e[0]}get#o(){return this.#e[this.#e.length-1]}get#e(){return Array.from(this.#n.querySelectorAll("*")).filter(l)}get#n(){return this.controller.element}};var n=class{#t=crypto.randomUUID();#s=new i(this);#r=new o(this);#i=new a(this);constructor(t){this.element=t}trapFocus(){this.#a||(this.element.dataset.focusTrapId=this.#t,this.element.dataset.focusTrapRoot=!0,this.captureFocus(),this.makeOutsideElementsInert(),this.#s.start(),this.#r.start(),this.#i.startRestricting())}releaseFocus(){this.#o&&(this.#i.stopRestricting(),this.#r.stop(),this.#s.stop(),this.element.removeAttribute("data-focus-trap-root"),this.#e.forEach(t=>{t.removeAttribute("data-focus-trap-id"),t.inert=!1}))}makeOutsideElementsInert(){if(!this.#o)return;let t=this.element;for(;t!==document.body;)Array.from(t.parentElement?.children||[]).filter(s=>s!==t&&!s.inert&&!s.hasAttribute("data-focus-trap-id")).forEach(s=>{s.dataset.focusTrapId=this.#t,s.inert=!0}),t=t.parentElement}captureFocus(){this.#o&&!this.element.contains(document.activeElement)&&this.element.focus()}get#a(){return this.element.hasAttribute("data-focus-trap-id")}get#o(){return this.element.dataset.focusTrapRoot&&this.element.dataset.focusTrapId===this.#t}get#e(){return document.querySelectorAll(`[data-focus-trap-id="${this.#t}"]`)}};var u=class{#t;constructor(t){this.#t=new n(t)}start(){this.#t.trapFocus()}stop(){this.#t.releaseFocus()}};export{u as default};
//# sourceMappingURL=focus-trap.js.map