@pdanpdan/vue-keyboard-trap
Advanced tools
Comparing version 1.0.9 to 1.0.10
@@ -691,7 +691,5 @@ import * as Vue from 'vue'; | ||
const VueKeyboardTrapDirectiveFactory = (options) => { | ||
directiveFactory(options, markRaw); | ||
}; | ||
const VueKeyboardTrapDirectiveFactory = (options) => directiveFactory(options, markRaw); | ||
export { VueKeyboardTrapDirectiveFactory, directivePlugin as VueKeyboardTrapDirectivePlugin }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -1,2 +0,2 @@ | ||
(function(y,C){typeof exports=="object"&&typeof module<"u"?C(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],C):(y=typeof globalThis<"u"?globalThis:y||self,C(y.VueKeyboardTrap={},y.Vue))})(this,function(y,C){"use strict";function W(o){if(o&&o.__esModule)return o;var a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});return o&&Object.keys(o).forEach(function(r){if(r!=="default"){var u=Object.getOwnPropertyDescriptor(o,r);Object.defineProperty(a,r,u.get?u:{enumerable:!0,get:function(){return o[r]}})}}),a.default=o,Object.freeze(a)}var H=W(C);function B(o){const a={name:"kbd-trap",focusableSelector:[":focus",'a[href]:not([tabindex^="-"])','area[href]:not([tabindex^="-"])','input:not([disabled]):not([tabindex^="-"])','select:not([disabled]):not([tabindex^="-"])','textarea:not([disabled]):not([tabindex^="-"])','button:not([disabled]):not([tabindex^="-"])','iframe:not([tabindex^="-"])','[tabindex]:not([tabindex^="-"])','[contenteditable]:not([tabindex^="-"]):not([contenteditable="false"])','[class*="focusable"]:not([disabled]):not([tabindex^="-"])'].join(","),rovingSkipSelector:['input:not([disabled]):not([type="button"]):not([type="checkbox"]):not([type="file"]):not([type="image"]):not([type="radio"]):not([type="reset"]):not([type="submit"])',"select:not([disabled])","select:not([disabled]) *","textarea:not([disabled])",'[contenteditable]:not([contenteditable="false"])','[contenteditable]:not([contenteditable="false"]) *'].join(","),gridSkipSelector:[":not([disabled])",':not([tabindex^="-"])'].join(""),autofocusSelector:['[autofocus]:not([disabled]):not([autofocus="false"])','[data-autofocus]:not([disabled]):not([data-autofocus="false"])'].join(","),trapTabIndex:-9999,...o},r=a.name.toLocaleLowerCase().split(/[^a-z0-9]+/).filter(f=>f.length>0).map(f=>`${f[0].toLocaleUpperCase()}${f.slice(1)}`).join("");a.datasetName===void 0&&(a.datasetName=`v${r}`),a.datasetNameActive=`${a.datasetName}Active`,a.datasetNamePreventRefocus=`${a.datasetName}PreventRefocus`;const u=document.createElement("span");u.dataset[a.datasetName]="";const s=u.getAttributeNames()[0];return a.datasetNameSelector=`[${s}]`,a.datasetNameSelectorRovingHorizontal=`[${s}~="roving"][${s}~="horizontal"],[${s}~="roving"]:not([${s}~="vertical"])`,a.datasetNameSelectorRovingVertical=`[${s}~="roving"][${s}~="vertical"],[${s}~="roving"]:not([${s}~="horizontal"])`,a.datasetNameRow=`${a.datasetName}Row`,a.datasetNameRowSelector=f=>`:focus,[${s}-row~="${f}"]${a.gridSkipSelector},[${s}-row~="*"]${a.gridSkipSelector}`,a.datasetNameCol=`${a.datasetName}Col`,a.datasetNameColSelector=f=>`:focus,[${s}-col~="${f}"]${a.gridSkipSelector},[${s}-col~="*"]${a.gridSkipSelector}`,a}function G(){return!0}function M(o,a=!1){const{left:r,top:u}=o.getBoundingClientRect(),s=document.elementFromPoint(r,u);if(s===null&&a!==!0&&typeof o.scrollIntoView=="function"){const f=[];let S=o.parentElement;for(;S!==null;)f.push([S,S.scrollLeft,S.scrollTop]),S=S.parentElement;o.scrollIntoView();const q=M(o,!0);for(let h=f.length-1;h>=0;h-=1){const[e,m,g]=f[h];e.scrollLeft=m,e.scrollTop=g}return q}return s===null||o.contains(s)===!0}function x(o,a=G){return o===null||typeof o.focus!="function"||a(o)!==!0?!1:(o.focus(),o===document.activeElement)}const J=/(\d+)/;function j(o){const a=J.exec(o);return a===null?"":a[1]}function V(o,a){const r=(o&&o!==a&&o.parentElement||a).closest('[dir="rtl"],[dir="ltr"]');return r&&r.matches('[dir="rtl"]')}let v=null;function D(o,a){const r=B(o),u=e=>{v!==e&&(e!==null&&(e.dataset[r.datasetNameActive]="",e.__vKbdTrapActiveClean=()=>{delete e.dataset[r.datasetNameActive],e.__vKbdTrapActiveClean=void 0}),v!==null&&typeof v.__vKbdTrapActiveClean=="function"&&v.__vKbdTrapActiveClean(),v=e)},s=e=>{const m=(e||{}).__vKbdTrap;return m===Object(m)?m:null},f=(e,m,g)=>{m===!0?(delete e.dataset[r.datasetName],e.tabIndex===r.trapTabIndex&&e.removeAttribute("tabindex")):(e.dataset[r.datasetName]=Object.keys(g.modifiers).filter(t=>g.modifiers[t]===!0).join(" "),e.tabIndex<0&&e.getAttribute("tabindex")===null&&(e.tabIndex=r.trapTabIndex))},S=(e,{value:m,modifiers:g})=>{const t={disable:m===!1,modifiers:g,focusTarget:null,relatedFocusTarget:null,bind(){e.__vKbdTrap=t,e.addEventListener("keydown",t.trap),e.addEventListener("focusin",t.activate),e.addEventListener("focusout",t.deactivate),e.addEventListener("pointerdown",t.overwiteFocusTarget,{passive:!0}),t.disable===!1&&f(e,t.disable,t)},unbind(){delete e.__vKbdTrap,e.removeEventListener("keydown",t.trap),e.removeEventListener("focusin",t.activate),e.removeEventListener("focusout",t.deactivate),e.removeEventListener("pointerdown",t.overwiteFocusTarget),f(e,!0,t)},activate(n){if(t.disable===!0||n.__vKbdTrap===!0)return;n.__vKbdTrap=!0;const i=n.relatedTarget;v!==e&&(i===null||i.closest(r.datasetNameSelector)!==e)&&(u(e),t.relatedFocusTarget=i,(i===null||i.dataset[r.datasetNamePreventRefocus]===void 0||e.contains(i)===!1)&&requestAnimationFrame(()=>{t.refocus(t.modifiers.roving!==!0)}))},deactivate(n){if(t.disable===!0||n.__vKbdTrap===!0)return;n.__vKbdTrap=!0;const i=n.relatedTarget;v===e&&(i===null||i.closest(r.datasetNameSelector)!==e)&&(t.focusTarget=n.target,u(null))},trap(n){if(t.disable===!0||n.__vKbdTrap===!0)return;const{code:i,shiftKey:z}=n,{activeElement:T}=document;if(i==="Escape"){if(n.__vKbdTrap=!0,v===e){if(t.focusTarget=T,u(e.parentElement===null?null:e.parentElement.closest(r.datasetNameSelector)),t.modifiers.escexits===!0){const c=s(v);if(c!==null&&c.refocus()===!0)return}t.modifiers.escrefocus===!0&&x(t.relatedFocusTarget)}else u(e);return}if(v!==e)return;n.__vKbdTrap=!0;let b=0,N=c=>c,$=!1,_=!1;if(t.modifiers.roving===!0){const c=T.matches(r.rovingSkipSelector);if(i!=="Tab"&&c===!0)return;if(i==="Tab")c===!1&&t.modifiers.tabinside!==!0?($=!0,z===!0?(b=1,N=(l,d)=>d):(b=-1,N=()=>0)):b=z===!0?-1:1;else if(i==="Home")b=1,N=(l,d)=>d;else if(i==="End")b=-1,N=()=>0;else if(e.parentElement!==null&&(t.modifiers.vertical===!0&&t.modifiers.horizontal!==!0&&(i==="ArrowLeft"||i==="ArrowRight")||t.modifiers.horizontal===!0&&t.modifiers.vertical!==!0&&(i==="ArrowUp"||i==="ArrowDown"))){const l=e.parentElement.closest(t.modifiers.vertical===!0?r.datasetNameSelectorRovingHorizontal:r.datasetNameSelectorRovingVertical);l!==null&&($=l,n.__vKbdTrap=void 0,i===(V(T,e)===!0?"ArrowRight":"ArrowLeft")||i==="ArrowUp"?(b=1,N=(d,w)=>w):(b=-1,N=()=>0))}else(t.modifiers.vertical===!0||t.modifiers.horizontal!==!0)&&(i==="ArrowUp"?(b=-1,_="v"):i==="ArrowDown"&&(b=1,_="v")),(t.modifiers.vertical!==!0||t.modifiers.horizontal===!0)&&(i==="ArrowLeft"?(b=-1,_="h"):i==="ArrowRight"&&(b=1,_="h"),b!==0&&_==="h"&&V(T,e)===!0&&(b*=-1))}else i==="Tab"&&(b=z===!0?-1:1);if(b===0)return;$===!1?n.preventDefault():(t.focusTarget=T,t.focusTarget.dataset[r.datasetNamePreventRefocus]="",requestAnimationFrame(()=>{t.focusTarget&&delete t.focusTarget.dataset[r.datasetNamePreventRefocus]}));let p=[];if(_!==!1){let c;if(t.modifiers.grid===!0){const l=j(T.dataset[r.datasetNameRow]),d=j(T.dataset[r.datasetNameCol]),w=_==="v"?r.datasetNameColSelector(d):r.datasetNameRowSelector(l);p=Array.from(e.querySelectorAll(w)),c=new WeakMap(p.map(E=>{const A=j(E.dataset[r.datasetNameRow]),R=j(E.dataset[r.datasetNameCol]);let L;return _==="v"?(A!==l||R===d)&&(L=1e3*A+1*R):(R!==d||A===l)&&(L=1e3*R+1*A),[E,L]}))}else if(e.matches('[role="grid"]')===!0&&T.matches('[role="row"] [role="gridcell"]')){const l=Array.from(e.querySelectorAll('[role="row"]')),d=new WeakMap,w=l.map((P,O)=>{const k=Array.from(P.querySelectorAll('[role="gridcell"]'));return k.forEach((F,Y)=>{d.set(F,[O+1,Y+1])}),k}),E=T.closest('[role="row"]'),A=l.indexOf(E)+1,R=w[A-1].indexOf(T)+1,{focusableSelector:L}=r;p=Array.from(e.querySelectorAll(L)),c=new WeakMap(p.map(P=>{const[O,k]=d.get(P)||[null,null];let F;return _==="v"?k===R&&(F=1*O):O===A&&(F=1*k),[P,F]}))}c!==void 0&&(p=p.filter(l=>c.get(l)!==void 0),p.sort((l,d)=>c.get(l)-c.get(d)))}if(p.length===0){const{focusableSelector:c}=r;if(p=Array.from(e.querySelectorAll(c)),g.indexorder===!0){const l=new WeakMap(p.map(d=>[d,Math.max(d.tabIndex||0,0)]));p.sort((d,w)=>l.get(d)-l.get(w))}e.matches(c)&&p.unshift(e)}const I=p.length-1;let K=N(p.indexOf(T),I);for(let c=0;c<I;c+=1)if(K+=b,K<0?K=I:K>I&&(K=0),x(p[K])===!0){$!==!1&&u($===!0?null:$);return}},overwiteFocusTarget(n){t.disable===!1&&n.__vKbdTrap!==!0&&(n.__vKbdTrap=!0,t.focusTarget=n.target)},refocus(n){return t.disable===!1&&v===e&&t.focusTarget&&t.focusTarget.closest(r.datasetNameSelector)===e?t.focusTarget.tabIndex===r.trapTabIndex?t.modifiers.autofocus===!0&&x(e.querySelector(r.autofocusSelector))===!0||x(e.querySelector(r.focusableSelector))===!0||x(t.focusTarget)===!0:n===!0?!1:x(t.focusTarget)===!0||x(e.querySelector(r.focusableSelector))===!0:!1},autofocus(){requestAnimationFrame(()=>{t.disable===!1&&x(e.querySelector(r.autofocusSelector),M)===!1&&x(e.querySelector(r.focusableSelector),M)})}};t.bind(),g.autofocus===!0&&t.autofocus()},q=(e,{value:m,modifiers:g})=>{const t=s(e);if(t!==null){const n=m===!1;t.modifiers=g,f(e,n,t),v===e&&(n===!0?u(null):e.dataset[r.datasetNameActive]=""),t.disable!==n&&(t.disable=n,g.autofocus===!0&&t.autofocus())}else a!==void 0?S(e,{value:m,modifiers:g}):v===e&&u(null)},h=e=>{const m=s(e);m!==null&&m.unbind(),v===e&&u(null)};return a!==void 0?a({name:r.name,directive:{beforeMount:S,updated:q,unmounted:h,getSSRProps(){}}}):{name:r.name,directive:{bind:S,update:q,unbind:h}}}const{markRaw:U}=H,Q={install(o,a){const{name:r,directive:u}=D(a,U);o.directive(r,u)}},X=o=>{D(o,U)};y.VueKeyboardTrapDirectiveFactory=X,y.VueKeyboardTrapDirectivePlugin=Q,Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
(function(y,C){typeof exports=="object"&&typeof module<"u"?C(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],C):(y=typeof globalThis<"u"?globalThis:y||self,C(y.VueKeyboardTrap={},y.Vue))})(this,function(y,C){"use strict";function W(o){if(o&&o.__esModule)return o;var a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});return o&&Object.keys(o).forEach(function(r){if(r!=="default"){var u=Object.getOwnPropertyDescriptor(o,r);Object.defineProperty(a,r,u.get?u:{enumerable:!0,get:function(){return o[r]}})}}),a.default=o,Object.freeze(a)}var H=W(C);function B(o){const a={name:"kbd-trap",focusableSelector:[":focus",'a[href]:not([tabindex^="-"])','area[href]:not([tabindex^="-"])','input:not([disabled]):not([tabindex^="-"])','select:not([disabled]):not([tabindex^="-"])','textarea:not([disabled]):not([tabindex^="-"])','button:not([disabled]):not([tabindex^="-"])','iframe:not([tabindex^="-"])','[tabindex]:not([tabindex^="-"])','[contenteditable]:not([tabindex^="-"]):not([contenteditable="false"])','[class*="focusable"]:not([disabled]):not([tabindex^="-"])'].join(","),rovingSkipSelector:['input:not([disabled]):not([type="button"]):not([type="checkbox"]):not([type="file"]):not([type="image"]):not([type="radio"]):not([type="reset"]):not([type="submit"])',"select:not([disabled])","select:not([disabled]) *","textarea:not([disabled])",'[contenteditable]:not([contenteditable="false"])','[contenteditable]:not([contenteditable="false"]) *'].join(","),gridSkipSelector:[":not([disabled])",':not([tabindex^="-"])'].join(""),autofocusSelector:['[autofocus]:not([disabled]):not([autofocus="false"])','[data-autofocus]:not([disabled]):not([data-autofocus="false"])'].join(","),trapTabIndex:-9999,...o},r=a.name.toLocaleLowerCase().split(/[^a-z0-9]+/).filter(f=>f.length>0).map(f=>`${f[0].toLocaleUpperCase()}${f.slice(1)}`).join("");a.datasetName===void 0&&(a.datasetName=`v${r}`),a.datasetNameActive=`${a.datasetName}Active`,a.datasetNamePreventRefocus=`${a.datasetName}PreventRefocus`;const u=document.createElement("span");u.dataset[a.datasetName]="";const s=u.getAttributeNames()[0];return a.datasetNameSelector=`[${s}]`,a.datasetNameSelectorRovingHorizontal=`[${s}~="roving"][${s}~="horizontal"],[${s}~="roving"]:not([${s}~="vertical"])`,a.datasetNameSelectorRovingVertical=`[${s}~="roving"][${s}~="vertical"],[${s}~="roving"]:not([${s}~="horizontal"])`,a.datasetNameRow=`${a.datasetName}Row`,a.datasetNameRowSelector=f=>`:focus,[${s}-row~="${f}"]${a.gridSkipSelector},[${s}-row~="*"]${a.gridSkipSelector}`,a.datasetNameCol=`${a.datasetName}Col`,a.datasetNameColSelector=f=>`:focus,[${s}-col~="${f}"]${a.gridSkipSelector},[${s}-col~="*"]${a.gridSkipSelector}`,a}function G(){return!0}function M(o,a=!1){const{left:r,top:u}=o.getBoundingClientRect(),s=document.elementFromPoint(r,u);if(s===null&&a!==!0&&typeof o.scrollIntoView=="function"){const f=[];let S=o.parentElement;for(;S!==null;)f.push([S,S.scrollLeft,S.scrollTop]),S=S.parentElement;o.scrollIntoView();const q=M(o,!0);for(let h=f.length-1;h>=0;h-=1){const[e,m,g]=f[h];e.scrollLeft=m,e.scrollTop=g}return q}return s===null||o.contains(s)===!0}function x(o,a=G){return o===null||typeof o.focus!="function"||a(o)!==!0?!1:(o.focus(),o===document.activeElement)}const J=/(\d+)/;function j(o){const a=J.exec(o);return a===null?"":a[1]}function V(o,a){const r=(o&&o!==a&&o.parentElement||a).closest('[dir="rtl"],[dir="ltr"]');return r&&r.matches('[dir="rtl"]')}let v=null;function D(o,a){const r=B(o),u=e=>{v!==e&&(e!==null&&(e.dataset[r.datasetNameActive]="",e.__vKbdTrapActiveClean=()=>{delete e.dataset[r.datasetNameActive],e.__vKbdTrapActiveClean=void 0}),v!==null&&typeof v.__vKbdTrapActiveClean=="function"&&v.__vKbdTrapActiveClean(),v=e)},s=e=>{const m=(e||{}).__vKbdTrap;return m===Object(m)?m:null},f=(e,m,g)=>{m===!0?(delete e.dataset[r.datasetName],e.tabIndex===r.trapTabIndex&&e.removeAttribute("tabindex")):(e.dataset[r.datasetName]=Object.keys(g.modifiers).filter(t=>g.modifiers[t]===!0).join(" "),e.tabIndex<0&&e.getAttribute("tabindex")===null&&(e.tabIndex=r.trapTabIndex))},S=(e,{value:m,modifiers:g})=>{const t={disable:m===!1,modifiers:g,focusTarget:null,relatedFocusTarget:null,bind(){e.__vKbdTrap=t,e.addEventListener("keydown",t.trap),e.addEventListener("focusin",t.activate),e.addEventListener("focusout",t.deactivate),e.addEventListener("pointerdown",t.overwiteFocusTarget,{passive:!0}),t.disable===!1&&f(e,t.disable,t)},unbind(){delete e.__vKbdTrap,e.removeEventListener("keydown",t.trap),e.removeEventListener("focusin",t.activate),e.removeEventListener("focusout",t.deactivate),e.removeEventListener("pointerdown",t.overwiteFocusTarget),f(e,!0,t)},activate(n){if(t.disable===!0||n.__vKbdTrap===!0)return;n.__vKbdTrap=!0;const i=n.relatedTarget;v!==e&&(i===null||i.closest(r.datasetNameSelector)!==e)&&(u(e),t.relatedFocusTarget=i,(i===null||i.dataset[r.datasetNamePreventRefocus]===void 0||e.contains(i)===!1)&&requestAnimationFrame(()=>{t.refocus(t.modifiers.roving!==!0)}))},deactivate(n){if(t.disable===!0||n.__vKbdTrap===!0)return;n.__vKbdTrap=!0;const i=n.relatedTarget;v===e&&(i===null||i.closest(r.datasetNameSelector)!==e)&&(t.focusTarget=n.target,u(null))},trap(n){if(t.disable===!0||n.__vKbdTrap===!0)return;const{code:i,shiftKey:z}=n,{activeElement:T}=document;if(i==="Escape"){if(n.__vKbdTrap=!0,v===e){if(t.focusTarget=T,u(e.parentElement===null?null:e.parentElement.closest(r.datasetNameSelector)),t.modifiers.escexits===!0){const c=s(v);if(c!==null&&c.refocus()===!0)return}t.modifiers.escrefocus===!0&&x(t.relatedFocusTarget)}else u(e);return}if(v!==e)return;n.__vKbdTrap=!0;let b=0,N=c=>c,$=!1,_=!1;if(t.modifiers.roving===!0){const c=T.matches(r.rovingSkipSelector);if(i!=="Tab"&&c===!0)return;if(i==="Tab")c===!1&&t.modifiers.tabinside!==!0?($=!0,z===!0?(b=1,N=(l,d)=>d):(b=-1,N=()=>0)):b=z===!0?-1:1;else if(i==="Home")b=1,N=(l,d)=>d;else if(i==="End")b=-1,N=()=>0;else if(e.parentElement!==null&&(t.modifiers.vertical===!0&&t.modifiers.horizontal!==!0&&(i==="ArrowLeft"||i==="ArrowRight")||t.modifiers.horizontal===!0&&t.modifiers.vertical!==!0&&(i==="ArrowUp"||i==="ArrowDown"))){const l=e.parentElement.closest(t.modifiers.vertical===!0?r.datasetNameSelectorRovingHorizontal:r.datasetNameSelectorRovingVertical);l!==null&&($=l,n.__vKbdTrap=void 0,i===(V(T,e)===!0?"ArrowRight":"ArrowLeft")||i==="ArrowUp"?(b=1,N=(d,w)=>w):(b=-1,N=()=>0))}else(t.modifiers.vertical===!0||t.modifiers.horizontal!==!0)&&(i==="ArrowUp"?(b=-1,_="v"):i==="ArrowDown"&&(b=1,_="v")),(t.modifiers.vertical!==!0||t.modifiers.horizontal===!0)&&(i==="ArrowLeft"?(b=-1,_="h"):i==="ArrowRight"&&(b=1,_="h"),b!==0&&_==="h"&&V(T,e)===!0&&(b*=-1))}else i==="Tab"&&(b=z===!0?-1:1);if(b===0)return;$===!1?n.preventDefault():(t.focusTarget=T,t.focusTarget.dataset[r.datasetNamePreventRefocus]="",requestAnimationFrame(()=>{t.focusTarget&&delete t.focusTarget.dataset[r.datasetNamePreventRefocus]}));let p=[];if(_!==!1){let c;if(t.modifiers.grid===!0){const l=j(T.dataset[r.datasetNameRow]),d=j(T.dataset[r.datasetNameCol]),w=_==="v"?r.datasetNameColSelector(d):r.datasetNameRowSelector(l);p=Array.from(e.querySelectorAll(w)),c=new WeakMap(p.map(E=>{const A=j(E.dataset[r.datasetNameRow]),R=j(E.dataset[r.datasetNameCol]);let L;return _==="v"?(A!==l||R===d)&&(L=1e3*A+1*R):(R!==d||A===l)&&(L=1e3*R+1*A),[E,L]}))}else if(e.matches('[role="grid"]')===!0&&T.matches('[role="row"] [role="gridcell"]')){const l=Array.from(e.querySelectorAll('[role="row"]')),d=new WeakMap,w=l.map((P,O)=>{const k=Array.from(P.querySelectorAll('[role="gridcell"]'));return k.forEach((F,Y)=>{d.set(F,[O+1,Y+1])}),k}),E=T.closest('[role="row"]'),A=l.indexOf(E)+1,R=w[A-1].indexOf(T)+1,{focusableSelector:L}=r;p=Array.from(e.querySelectorAll(L)),c=new WeakMap(p.map(P=>{const[O,k]=d.get(P)||[null,null];let F;return _==="v"?k===R&&(F=1*O):O===A&&(F=1*k),[P,F]}))}c!==void 0&&(p=p.filter(l=>c.get(l)!==void 0),p.sort((l,d)=>c.get(l)-c.get(d)))}if(p.length===0){const{focusableSelector:c}=r;if(p=Array.from(e.querySelectorAll(c)),g.indexorder===!0){const l=new WeakMap(p.map(d=>[d,Math.max(d.tabIndex||0,0)]));p.sort((d,w)=>l.get(d)-l.get(w))}e.matches(c)&&p.unshift(e)}const I=p.length-1;let K=N(p.indexOf(T),I);for(let c=0;c<I;c+=1)if(K+=b,K<0?K=I:K>I&&(K=0),x(p[K])===!0){$!==!1&&u($===!0?null:$);return}},overwiteFocusTarget(n){t.disable===!1&&n.__vKbdTrap!==!0&&(n.__vKbdTrap=!0,t.focusTarget=n.target)},refocus(n){return t.disable===!1&&v===e&&t.focusTarget&&t.focusTarget.closest(r.datasetNameSelector)===e?t.focusTarget.tabIndex===r.trapTabIndex?t.modifiers.autofocus===!0&&x(e.querySelector(r.autofocusSelector))===!0||x(e.querySelector(r.focusableSelector))===!0||x(t.focusTarget)===!0:n===!0?!1:x(t.focusTarget)===!0||x(e.querySelector(r.focusableSelector))===!0:!1},autofocus(){requestAnimationFrame(()=>{t.disable===!1&&x(e.querySelector(r.autofocusSelector),M)===!1&&x(e.querySelector(r.focusableSelector),M)})}};t.bind(),g.autofocus===!0&&t.autofocus()},q=(e,{value:m,modifiers:g})=>{const t=s(e);if(t!==null){const n=m===!1;t.modifiers=g,f(e,n,t),v===e&&(n===!0?u(null):e.dataset[r.datasetNameActive]=""),t.disable!==n&&(t.disable=n,g.autofocus===!0&&t.autofocus())}else a!==void 0?S(e,{value:m,modifiers:g}):v===e&&u(null)},h=e=>{const m=s(e);m!==null&&m.unbind(),v===e&&u(null)};return a!==void 0?a({name:r.name,directive:{beforeMount:S,updated:q,unmounted:h,getSSRProps(){}}}):{name:r.name,directive:{bind:S,update:q,unbind:h}}}const{markRaw:U}=H,Q={install(o,a){const{name:r,directive:u}=D(a,U);o.directive(r,u)}},X=o=>D(o,U);y.VueKeyboardTrapDirectiveFactory=X,y.VueKeyboardTrapDirectivePlugin=Q,Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "@pdanpdan/vue-keyboard-trap", | ||
"version": "1.0.9", | ||
"version": "1.0.10", | ||
"description": "Vue3 and Vue2 directive for keyboard navigation - roving movement and trapping inside container", | ||
@@ -5,0 +5,0 @@ "productName": "Vue Keyboard Trap", |
184
README.md
# VueKeyboardTrap (vue-keyboard-trap) | ||
[![License: MIT](https://img.shields.io/github/license/pdanpdan/vue-keyboard-trap?style=for-the-badge)](https://opensource.org/licenses/MIT) | ||
[![minzip](https://img.shields.io/bundlephobia/minzip/@pdanpdan/vue-keyboard-trap/latest?style=for-the-badge)](https://bundlephobia.com/result?p=@pdanpdan/vue-keyboard-trap@latest) | ||
![github release](https://img.shields.io/github/v/tag/pdanpdan/vue-keyboard-trap?sort=semver&style=for-the-badge) | ||
![jsdelivr hits](https://img.shields.io/jsdelivr/gh/hm/pdanpdan/vue-keyboard-trap?style=for-the-badge) | ||
![npm release](https://img.shields.io/npm/v/@pdanpdan/vue-keyboard-trap?style=for-the-badge) | ||
[![License: MIT](https://img.shields.io/github/license/pdanpdan/vue-keyboard-trap?style=for-the-badge)](https://opensource.org/licenses/MIT) | ||
[![minzip](https://img.shields.io/bundlephobia/minzip/@pdanpdan/vue-keyboard-trap/latest?style=for-the-badge)](https://bundlephobia.com/result?p=@pdanpdan/vue-keyboard-trap@latest) | ||
![github release](https://img.shields.io/github/v/tag/pdanpdan/vue-keyboard-trap?sort=semver&style=for-the-badge) | ||
![jsdelivr hits](https://img.shields.io/jsdelivr/gh/hm/pdanpdan/vue-keyboard-trap?style=for-the-badge) | ||
![npm release](https://img.shields.io/npm/v/@pdanpdan/vue-keyboard-trap?style=for-the-badge) | ||
![npm downloads](https://img.shields.io/npm/dm/@pdanpdan/vue-keyboard-trap?style=for-the-badge) | ||
@@ -41,3 +41,3 @@ | ||
Can be globally registered on the App (plugin mode) | ||
```javascript | ||
```javascript{2,7-9} | ||
import { createApp } from 'vue'; | ||
@@ -57,27 +57,31 @@ import { VueKeyboardTrapDirectivePlugin } from '@pdanpdan/vue-keyboard-trap'; | ||
or included in specific components (script) | ||
```javascript | ||
import { defineComponent } from 'vue'; | ||
import { VueKeyboardTrapDirectiveFactory } from '@pdanpdan/vue-keyboard-trap'; | ||
```html{3,5-7,10-12} | ||
<script> | ||
import { defineComponent } from 'vue'; | ||
import { VueKeyboardTrapDirectiveFactory } from '@pdanpdan/vue-keyboard-trap'; | ||
const KbdTrap = VueKeyboardTrapDirectiveFactory({ | ||
// ...options if required | ||
}).directive; | ||
const KbdTrap = VueKeyboardTrapDirectiveFactory({ | ||
// ...options if required | ||
}).directive; | ||
export default defineComponent({ | ||
directives: { | ||
KbdTrap, | ||
}, | ||
}); | ||
export default defineComponent({ | ||
directives: { | ||
KbdTrap, | ||
}, | ||
}); | ||
</script> | ||
``` | ||
or included in specific components (script setup) | ||
```javascript | ||
import { VueKeyboardTrapDirectiveFactory } from '@pdanpdan/vue-keyboard-trap'; | ||
```html{2-6} | ||
<script setup> | ||
import { VueKeyboardTrapDirectiveFactory } from '@pdanpdan/vue-keyboard-trap'; | ||
const vKbdTrap = VueKeyboardTrapDirectiveFactory({ | ||
// ...options if required | ||
}).directive; | ||
const vKbdTrap = VueKeyboardTrapDirectiveFactory({ | ||
// ...options if required | ||
}).directive; | ||
</script> | ||
``` | ||
The directive does not require any CSS styles to work, but for cosmetic purposes some example styles are provided in `dist/styles/index.sass`. | ||
The directive does not require any CSS styles to work, but for cosmetic purposes (as user hints) some example styles are provided in `dist/styles/index.sass`. | ||
@@ -88,3 +92,3 @@ ```javascript | ||
or (if the `/styles` export is not used by your packer) | ||
or (if the `/styles` export is not used by your bundler) | ||
@@ -99,5 +103,6 @@ ```javascript | ||
It will expose a global object `VueKeyboardTrap` with `VueKeyboardTrap.VueKeyboardTrapDirectivePlugin` and `VueKeyboardTrap.VueKeyboardTrapDirectiveFactory`. | ||
It will expose a global object `VueKeyboardTrap` with `VueKeyboardTrapDirectivePlugin` and `VueKeyboardTrapDirectiveFactory` keys. | ||
```javascript | ||
Use as plugin | ||
```javascript{2,6-8} | ||
const { createApp } = Vue; | ||
@@ -116,3 +121,3 @@ const { VueKeyboardTrapDirectivePlugin } = VueKeyboardTrap; | ||
or as directive | ||
```javascript | ||
```javascript{2,6-8,10} | ||
const { createApp } = Vue; | ||
@@ -132,13 +137,15 @@ const { VueKeyboardTrapDirectiveFactory } = VueKeyboardTrap; | ||
If you want you can access the SASS cosmetic style from [https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass](https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass). | ||
If you want you can access the SASS cosmetic style (user hints) from [https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass](https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass). | ||
### Directive configuration options | ||
- `name`: snake-case name of the directive (without `v-` prefix) - default `kbd-trap` | ||
- `datasetName`: camelCase name of the `data-attribute` to be set on element when trap is enabled - default `v${ PascalCase from name}` | ||
- `focusableSelector`: CSS selector for focusable elements | ||
- `rovingSkipSelector`: CSS selector for elements that should not respond to roving key navigation (input, textarea, ...) | ||
- `gridSkipSelector`: CSS selector that will be applied in .roving.grid mode to exclude elements - must be a series of `:not()` selectors | ||
- `autofocusSelector`: CSS selector for the elements that should be autofocused | ||
- `trapTabIndex`: tabIndex value to be used when trap element has a tabIndex of -1 and has no `tabindex` attribute (default -9999) | ||
| Option | Description | Default | | ||
|--------|-------------|:-------:| | ||
| `name` | snake-case name of the directive (without `v-` prefix) | `kbd-trap` | | ||
| `datasetName` | camelCase name of the `data-attribute` to be set on element when trap is enabled | `v${PascalCase from name}` | | ||
| `focusableSelector` | CSS selector for focusable elements | [see here](#default-focusableselector) | | ||
| `rovingSkipSelector` | CSS selector for elements that should not respond to roving key navigation (input, textarea, ...) | [see here](#default-rovingskipselector) | | ||
| `gridSkipSelector` | CSS selector that will be applied in .roving.grid mode to exclude elements - must be a series of `:not()` selectors | [see here](#default-gridskipselector) | | ||
| `autofocusSelector` | CSS selector for the elements that should be autofocused | [see here](#default-autofocusselector) | | ||
| `trapTabIndex` | tabIndex value to be used when trap element has a tabIndex of -1 and has no `tabindex` attribute | -9999 | | ||
@@ -201,12 +208,14 @@ #### Default `focusableSelector`: | ||
- `.autofocus` - autofocuses the first element that matches `autofocusSelector` or (if no such element is found) the first focusable child element when the directive is mounted or enabled (only if it not covered by another element) | ||
- `.roving` (or `.roving.vertical.horizontal`) - allow roving navigation (Home, End, ArrowKeys) | ||
- `.roving.vertical` - allow roving navigation (Home, End, ArrowUp, ArrowDown) | ||
- `.roving.horizontal` - allow roving navigation (Home, End, ArrowLeft, ArrowRight) | ||
- `.roving.grid` - allow roving navigation (Home, End, ArrowKeys) using dataset attrs on elements `[data-${ camelCase from datasetName }-(row|col)]`; `[data-${ camelCase from datasetName }-(row|col)~="*"]` is a catchall | ||
- `.roving` used on an element with `[role="grid"]` - allow roving navigation (Home, End, ArrowKeys) using role attrs on elements `[role="row|gridcell"]` | ||
- `.roving.tabinside` - Tab key navigates to next/prev element inside trap (by default Tab key navigates to next/prev element outside trap in roving mode) | ||
- `.escrefocus` - refocus element that was in focus before activating the trap on Esc | ||
- `.escexits` - refocus a parent trap on Esc (has priority over `.escrefocus`) | ||
- `.indexorder` used without `.grid` modifier and on elements without `[role="grid"]` - force usage of order in `tabindex` (`tabindex` in ascending order and then DOM order) | ||
| Modifier | Description | | ||
|----------|-------------| | ||
| `.autofocus` | autofocuses the first element that matches [autofocusSelector](#default-autofocusselector) or (if no such element is found) the first focusable child element **when the directive is mounted or enabled** (**only if it not covered by another element**) | | ||
| `.roving` or `.roving.vertical.horizontal` | allow roving navigation (`Home`, `End`, `ArrowKeys`) | | ||
| `.roving.vertical` | allow roving navigation (`Home`, `End`, `ArrowUp`, `ArrowDown`) | | ||
| `.roving.horizontal` | allow roving navigation (`Home`, `End`, `ArrowLeft`, `ArrowRight`) | | ||
| `.roving.grid` | allow roving navigation (`Home`, `End`, `ArrowKeys`) using dataset attrs on elements `[data-${camelCase from datasetName}-(row/col)]`; `[data-${camelCase from datasetName}-(row/col)~="*"]` is a catchall | | ||
| `.roving` used on an element with `[role="grid"]` | allow roving navigation (`Home`, `End`, `ArrowKeys`) using role attrs on elements `[role="row/gridcell"]` | | ||
| `.roving.tabinside` | `Tab` key navigates to next/prev element inside trap (by default `Tab` key navigates to next/prev element outside trap in roving mode) | | ||
| `.escrefocus` | refocus element that was in focus before activating the trap on `Esc` | | ||
| `.escexits` | refocus a parent trap on `Esc` (has priority over `.escrefocus`) | | ||
| `.indexorder` used without `.grid` modifier and on elements without `[role="grid"]` | force usage of order in `tabindex` (`tabindex` in ascending order and then DOM order) | | ||
@@ -265,3 +274,3 @@ ## Keyboard navigation | ||
If the direction is RTL the `ARROW_LEFT` and `ARROW_RIGHT` keys move in reverse (according to document order of the focusable elements) but consistent to the way the elements are order on screen. | ||
If the direction is RTL the `ARROW_LEFT` and `ARROW_RIGHT` keys move in reverse (according to document order of the focusable elements) but consistent to the way the elements are ordered on screen. | ||
@@ -272,72 +281,27 @@ ## CSS (visual hints for users) | ||
A default style is provided in `dist/styles/index.sass` (can be imported as `import from '@pdapdan/vue-keyboard-trap/styles'`, as `import from '@pdapdan/vue-keyboard-trap/dist/styles/index.sass'` (if the packer does not use the `/styles` export) or included from [https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass](https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass)). | ||
A default style is provided in `dist/styles/index.sass` (can be imported as `import from '@pdapdan/vue-keyboard-trap/styles'`, as `import from '@pdapdan/vue-keyboard-trap/dist/styles/index.sass'` (if the bundler does not use the `/styles` export) or included from [https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass](https://cdn.jsdelivr.net/gh/pdanpdan/vue-keyboard-trap@latest/dist/styles/index.sass)). | ||
There are 3 CSS variables that can be used to customize the aspect of the hints: | ||
There are some CSS variables that can be used to customize the aspect of the hints: | ||
- `--color-v-kbd-trap-enabled` - the text color when directive is enabled | ||
- `--color-v-kbd-trap-disabled` - the text color when directive is disabled | ||
- `--color-v-kbd-trap-background` - the background color of the hint area | ||
| Variable | Role | Default | | ||
|----------|------|:-------:| | ||
| `--color-v-kbd-trap-enabled` | the text color when directive is enabled | `#c33` <span style="color: #c33">■</span> | | ||
| `--color-v-kbd-trap-disabled` | the text color when directive is disabled | `#999` <span style="color: #999">■</span> | | ||
| `--color-v-kbd-trap-background` | the background color of the hint area | `#eeee` <span style="color: #eeee">■</span> | | ||
| `--text-v-kbd-trap-separator` | separator between elements | `/` | | ||
| `--text-v-kbd-trap-enabled` | indicator for enabled but not active trap | `Trap` | | ||
| `--text-v-kbd-trap-esc` | indicator for `Esc` key active | `Esc` | | ||
| `--text-v-kbd-trap-esc-refocus` | indicator for `Esc` key active when it refocuses | `Esc\2949` / `Esc⥉` | | ||
| `--text-v-kbd-trap-esc-exits` | indicator for `Esc` key active when it exits trap | `Esc\2923` / `Esc⤣` | | ||
| `--text-v-kbd-trap-tab` | indicator for `Tab` key active inside trap | `Tab` | | ||
| `--text-v-kbd-trap-tab-exits` | indicator for `Tab` key active when it exits trap | `Tab\21C5` / `Tab⇅` | | ||
| `--text-v-kbd-trap-grid` | indicator for grid mode active | `\229E` / `⊞` | | ||
| `--text-v-kbd-trap-arrows-all` | indicator for move keys active in roving mode | `\2962\2963\2965\2964` / `⥢⥣⥥⥤` | | ||
| `--text-v-kbd-trap-arrows-horizontal` | indicator for move keys active in roving mode horizontal | `\2962\2964` / `⥢⥤` | | ||
| `--text-v-kbd-trap-arrows-vertical` | indicator for move keys active in roving mode vertical | `\2963\2965` / `⥣⥥` | | ||
In the default style the hint is positioned on the top-right corner of the trap group. | ||
```sass | ||
// defaults | ||
$ColorVKeyboardTrapEnabled: #c33 !default | ||
$ColorVKeyboardTrapDisabled: #999 !default | ||
$ColorVKeyboardTrapBackground: #eeee !default | ||
<<< @/../src/public/styles/index.sass | ||
// place your custom colors on any element and they will be applied on children | ||
// :root | ||
// --color-v-kbd-trap-enabled: #c33 | ||
// --color-v-kbd-trap-disabled: #999 | ||
// --color-v-kbd-trap-background: #eeee | ||
[data-v-kbd-trap]:after | ||
content: var(--v-kbd-trap, '') var(--v-kbd-trap-esc, '') var(--v-kbd-trap-tab, '') var(--v-kbd-trap-roving, '') | ||
pointer-events: none | ||
position: absolute | ||
top: 2px | ||
right: 2px | ||
font: italic small-caps bold 14px monospace | ||
line-height: 1em | ||
padding: 4px | ||
color: var(--color-v-kbd-trap-disabled, $ColorVKeyboardTrapDisabled) | ||
background-color: var(--color-v-kbd-trap-background, $ColorVKeyboardTrapBackground) | ||
border-radius: 2px | ||
z-index: 1 | ||
[data-v-kbd-trap] | ||
--v-kbd-trap: 'Trap' | ||
--v-kbd-trap-esc: '' | ||
--v-kbd-trap-tab: '' | ||
--v-kbd-trap-roving: '' | ||
[data-v-kbd-trap]:focus-within | ||
--v-kbd-trap: 'Trap/' | ||
--v-kbd-trap-esc: 'Esc' | ||
[data-v-kbd-trap-active] | ||
--v-kbd-trap: '' !important | ||
--v-kbd-trap-esc: 'Esc' | ||
--v-kbd-trap-tab: '/Tab' | ||
--v-kbd-trap-roving: '' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"] | ||
--v-kbd-trap-tab: '/Tab\21C5' | ||
--v-kbd-trap-roving: '/\2962\2963\2965\2964' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"][data-v-kbd-trap~="tabinside"] | ||
--v-kbd-trap-tab: '/Tab' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"][data-v-kbd-trap~="vertical"] | ||
--v-kbd-trap-roving: '/\2963\2965' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"][data-v-kbd-trap~="horizontal"] | ||
--v-kbd-trap-roving: '/\2962\2964' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"][data-v-kbd-trap~="grid"], | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="roving"][role="grid"] | ||
--v-kbd-trap-roving: '/\229E' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="escrefocus"] | ||
--v-kbd-trap-esc: 'Esc\2949' | ||
[data-v-kbd-trap-active][data-v-kbd-trap~="escexits"] | ||
--v-kbd-trap-esc: 'Esc\2923' | ||
[data-v-kbd-trap][tabindex="-9999"] | ||
outline: none | ||
[data-v-kbd-trap][data-v-kbd-trap-active]:after | ||
color: var(--color-v-kbd-trap-enabled, $ColorVKeyboardTrapEnabled) | ||
``` | ||
## Development | ||
@@ -344,0 +308,0 @@ |
@@ -17,5 +17,3 @@ import * as Vue from 'vue'; | ||
const VueKeyboardTrapDirectiveFactory = (options) => { | ||
directiveFactory(options, markRaw); | ||
}; | ||
const VueKeyboardTrapDirectiveFactory = (options) => directiveFactory(options, markRaw); | ||
@@ -22,0 +20,0 @@ export { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
192436
1357
340