UNPKG

react-a11y-dialog

Version:

A React component wrapper and React hook around a11y-dialog.

3 lines (2 loc) 6.1 kB
/*! react-a11y-dialog 7.4.1 — © Kitty Giraudel */ import*as e from"react";import*as t from"react-dom";const i=":not([inert]):not([inert] *)",n=':not([tabindex^="-"])',o=":not(:disabled)";var s=[`a[href]${i}${n}`,`area[href]${i}${n}`,`input:not([type="hidden"]):not([type="radio"])${i}${n}${o}`,`input[type="radio"]${i}${n}${o}`,`select${i}${n}${o}`,`textarea${i}${n}${o}`,`button${i}${n}${o}`,`details${i} > summary:first-of-type${n}`,`iframe${i}${n}`,`audio[controls]${i}${n}`,`video[controls]${i}${n}`,`[contenteditable]${i}${n}`,`[tabindex]${i}${n}`];function r(e){(e.querySelector("[autofocus]")||e).focus()}function l(e,t){if(t&&u(e))return e;if(function(e){return(!e.shadowRoot||"-1"!==e.getAttribute("tabindex"))&&!e.matches(":disabled,[hidden],[inert]")}(e))if(e.shadowRoot){let i=a(e.shadowRoot,t);for(;i;){const e=l(i,t);if(e)return e;i=d(i,t)}}else if("slot"===e.localName){const i=e.assignedElements({flatten:!0});t||i.reverse();for(const e of i){const i=l(e,t);if(i)return i}}else{let i=a(e,t);for(;i;){const e=l(i,t);if(e)return e;i=d(i,t)}}return!t&&u(e)?e:null}function a(e,t){return t?e.firstElementChild:e.lastElementChild}function d(e,t){return t?e.nextElementSibling:e.previousElementSibling}const u=e=>!e.shadowRoot?.delegatesFocus&&(e.matches(s.join(","))&&!(e=>!(!e.matches("details:not([open]) *")||e.matches("details>summary:first-of-type"))||!(e.offsetWidth||e.offsetHeight||e.getClientRects().length))(e));function c(e=document){const t=e.activeElement;return t?t.shadowRoot?c(t.shadowRoot)||document.activeElement:t:null}function h(e,t){const[i,n]=function(e){const t=l(e,!0);return[t,t?l(e,!1)||t:null]}(e);if(!i)return t.preventDefault();const o=c();t.shiftKey&&o===i?(n.focus(),t.preventDefault()):t.shiftKey||o!==n||(i.focus(),t.preventDefault())}function f(e,t){return function t(i){if(!i||i===document||i===window)return null;const n=m(i);return n&&(i=n),i.closest(e)||t(i.getRootNode().host)}(t)}function m(e){return e.assignedSlot||(e.parentNode?m(e.parentNode):null)}const $="data-a11y-dialog";let v=class{$el;id;previouslyFocused;shown;constructor(e){this.$el=e,this.id=this.$el.getAttribute($)||this.$el.id,this.previouslyFocused=null,this.shown=!1,this.maintainFocus=this.maintainFocus.bind(this),this.bindKeypress=this.bindKeypress.bind(this),this.handleTriggerClicks=this.handleTriggerClicks.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.$el.setAttribute("aria-hidden","true"),this.$el.setAttribute("aria-modal","true"),this.$el.setAttribute("tabindex","-1"),this.$el.hasAttribute("role")||this.$el.setAttribute("role","dialog"),document.addEventListener("click",this.handleTriggerClicks,!0)}destroy(){return this.fire("destroy").defaultPrevented||(this.hide(),document.removeEventListener("click",this.handleTriggerClicks,!0),this.$el.replaceWith(this.$el.cloneNode(!0))),this}show(e){if(this.shown)return this;return this.fire("show",e).defaultPrevented||(this.shown=!0,this.$el.removeAttribute("aria-hidden"),this.previouslyFocused=c(),"BODY"===this.previouslyFocused?.tagName&&e?.target&&(this.previouslyFocused=e.target),"focus"===e?.type?this.maintainFocus():r(this.$el),document.body.addEventListener("focus",this.maintainFocus,!0),this.$el.addEventListener("keydown",this.bindKeypress,!0)),this}hide(e){if(!this.shown)return this;return this.fire("hide",e).defaultPrevented||(this.shown=!1,this.$el.setAttribute("aria-hidden","true"),this.previouslyFocused?.focus?.(),document.body.removeEventListener("focus",this.maintainFocus,!0),this.$el.removeEventListener("keydown",this.bindKeypress,!0)),this}on(e,t,i){return this.$el.addEventListener(e,t,i),this}off(e,t,i){return this.$el.removeEventListener(e,t,i),this}fire(e,t){const i=new CustomEvent(e,{detail:t,cancelable:!0});return this.$el.dispatchEvent(i),i}handleTriggerClicks(e){const t=e.composedPath()[0],i=f(`[${$}-show="${this.id}"]`,t),n=f(`[${$}-hide="${this.id}"]`,t),o=f(`[${$}-hide]`,t)&&f('[aria-modal="true"]',t)===this.$el;i&&this.show(e),(n||o)&&this.hide(e)}bindKeypress(e){if(f('[aria-modal="true"]',c())!==this.$el)return;let t=!1;try{t=!!this.$el.querySelector('[popover]:not([popover="manual"]):popover-open')}catch{}"Escape"!==e.key||"alertdialog"===this.$el.getAttribute("role")||t||(e.preventDefault(),this.hide(e)),"Tab"===e.key&&h(this.$el,e)}maintainFocus(){const e=c();f(`[aria-modal="true"], [${$}-ignore-focus-trap]`,e)||r(this.$el)}};function y(){for(const e of document.querySelectorAll("[data-a11y-dialog]"))new v(e)}"undefined"!=typeof document&&("loading"===document.readyState?document.addEventListener("DOMContentLoaded",y):y());const p=t=>{const{role:i="dialog",id:n,titleId:o=`${n}-title`}=t,[s,r]=(()=>{const[t,i]=e.useState(null);return[t,e.useCallback((e=>{null!==e&&i(new v(e))}),[])]})(),l=e.useCallback((()=>s?.hide()),[s]),a="alertdialog"===i;return e.useEffect((()=>()=>{s&&s.destroy()}),[s]),[s,{container:{id:n,ref:r,role:i,tabIndex:-1,"aria-modal":!0,"aria-hidden":!0,"aria-labelledby":o},overlay:{onClick:a?void 0:l},dialog:{role:"document"},closeButton:{type:"button",onClick:l},title:{role:"heading","aria-level":1,id:o}}]},b=i=>{const{role:n="dialog",id:o,titleId:s=`${o}-title`,closeButtonLabel:r="Close this dialog window",closeButtonContent:l="×",closeButtonPosition:a="first",classNames:d={},dialogRef:u=(()=>{}),dialogRoot:c,title:h,children:f}=i,m=(()=>{const[t,i]=e.useState(!1);return e.useEffect((()=>i(!0)),[]),t})(),[$,v]=p({role:n,id:o,titleId:s});if(e.useEffect((()=>($&&u($),()=>{u(void 0)})),[u,$]),!m)return null;const y=(e=>{if(e instanceof Element)return e;if("string"==typeof e){const t=document.querySelector(e);if(t)return t}return document.body})(c),b=e.createElement("button",{...v.closeButton,className:d.closeButton,"aria-label":r,key:"button"},l);return t.createPortal(e.createElement("div",{...v.container,className:d.container},e.createElement("div",{...v.overlay,className:d.overlay}),e.createElement("div",{...v.dialog,className:d.dialog},"first"===a&&b,e.createElement("p",{...v.title,className:d.title},h),f,"last"===a&&b)),y)};export{b as A11yDialog,p as useA11yDialog};