inclusive-elements 0.1.0-beta.8 → 0.1.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,14 +4,14 @@
4
4
 
5
5
  ![Size](https://img.shields.io/bundlephobia/minzip/inclusive-elements)
6
6
 
7
- [**Demo**](https://tobyzerner.github.io/inclusive-elements/demo.html)
7
+ [**Demo**](https://tobyzerner.github.io/inclusive-elements/demo/index.html)
8
8
 
9
9
  Basic interactive UI patterns like popup menus, tooltips, and modals are surprisingly hard to get right on the web. Component libraries tend to be weighty, opinionated, and come tightly coupled with styles you don't want. On the other hand, rolling your own components feels like you're reinventing the wheel and puts accessibility at risk.
10
10
 
11
11
  `inclusive-elements` provides those basic behaviors in the form of Custom Elements, without any of the cruft. They are:
12
12
 
13
13
  - **🦮 Accessible.** Designed following the [WAI-ARIA Authoring Practices](https://w3c.github.io/aria-practices) so everyone can use them.
14
- - **🌳 Lightweight.** 3kB gzipped in total, zero dependencies. Less if you tree-shake only the elements you need.
14
+ - **🌳 Lightweight.** 3kB gzipped in total, with minimal dependencies. Less if you tree-shake only the elements you need.
15
15
  - **🎨 Unstyled.** Easily integrate with your design bottom-up without having to fight defaults.
16
16
  - **🚀 Easy to use.** Simple API, works with any framework that supports Custom Elements.
17
17
 
@@ -29,6 +29,7 @@ Detailed descriptions and usage instructions are contained within each element:
29
29
  - [Menu](src/menu)
30
30
  - [Modal](src/modal)
31
31
  - [Popup](src/popup)
32
+ - [Toolbar](src/toolbar)
32
33
  - [Tooltip](src/tooltip)
33
34
 
34
35
  ## Contributing
@@ -1,16 +1,17 @@
1
- declare type AlertOptions = {
1
+ export declare type AlertOptions = {
2
2
  key?: string;
3
3
  duration?: number;
4
4
  };
5
- declare class AlertsElement extends HTMLElement {
5
+ export default class AlertsElement extends HTMLElement {
6
6
  static duration: number;
7
7
  private timeouts;
8
8
  private index;
9
9
  connectedCallback(): void;
10
10
  show(el: HTMLElement, options?: AlertOptions): string;
11
- dismiss(elOrKey: HTMLElement | string): void;
11
+ dismiss(el: HTMLElement): void;
12
+ dismiss(key: string): void;
13
+ clear(): void;
12
14
  speak(message: string): void;
13
15
  private startTimeout;
14
16
  private clearTimeout;
15
17
  }
16
- export default AlertsElement;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { default as PopupElement } from './popup/popup';
2
- export { default as TooltipElement } from './tooltip/tooltip';
1
+ export { default as AlertsElement } from './alerts/alerts';
3
2
  export { default as MenuElement } from './menu/menu';
4
3
  export { default as ModalElement } from './modal/modal';
5
- export { default as AlertsElement } from './alerts/alerts';
4
+ export { default as PopupElement } from './popup/popup';
5
+ export { default as ToolbarElement } from './toolbar/toolbar';
6
+ export { default as TooltipElement } from './tooltip/tooltip';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const t={x:{start:"left",Start:"Left",end:"right",End:"Right",size:"width",Size:"Width"},y:{start:"top",Start:"Top",end:"bottom",End:"Bottom",size:"height",Size:"Height"}};function e(e,i,n){var s;const o=i.style;Object.assign(o,{position:"absolute",maxWidth:"",maxHeight:""});let[r="bottom",a="center"]=n.placement.split("-");const h=["top","bottom"].includes(r)?"y":"x";let d=r===t[h].start?t[h].end:t[h].start;const l="x"===h?"y":"x",c=e.getBoundingClientRect(),u=(null===(s=function(t){for(;(t=t.parentNode)&&t instanceof Element;){const e=getComputedStyle(t).overflow;if(["auto","scroll"].includes(e))return t}}(i))||void 0===s?void 0:s.getBoundingClientRect())||new DOMRect(0,0,window.innerWidth,window.innerHeight),m=i.offsetParent||document.body,p=m===document.body?new DOMRect(-pageXOffset,-pageYOffset,window.innerWidth,window.innerHeight):m.getBoundingClientRect(),f=getComputedStyle(m),v=getComputedStyle(i);if(n.flip||void 0===n.flip){const e=t=>Math.abs(c[t]-u[t]),n=e(r);i["offset"+t[h].Size]>n&&e(d)>n&&([r,d]=[d,r])}if(i.dataset.placement=`${r}-${a}`,n.cap||void 0===n.cap){const e=(e,n)=>{const s=v["max"+t[e].Size];n-=parseInt(v["margin"+t[e].Start])+parseInt(v["margin"+t[e].End]),("none"===s||n<parseInt(s))&&(i.style["max"+t[e].Size]=n+"px")};e(h,Math.abs(u[r]-c[r])),e(l,u[t[l].size])}Object.assign(o,{[r]:"auto",[d]:(r===t[h].start?p[t[h].end]-c[t[h].start]:c[t[h].end]-p[t[h].start])-parseInt(f["border"+t[h].Start+"Width"])+"px"});const b="end"===a?"end":"start",E="end"===a?"start":"end",g=c[l]-p[l],y=c[t[l].size],w=i["offset"+t[l].Size];let C="end"===a?p[t[l].size]-g-y:g+("start"!==a?y/2-w/2:0);if(n.bound||void 0===n.bound){const e="end"===a?-1:1;C=Math.max(e*(u[t[l][b]]-p[t[l][b]]),Math.min(C,e*(u[t[l][E]]-p[t[l][b]])-w))}Object.assign(o,{[t[l][E]]:"auto",[t[l][b]]:C-parseInt(f["border"+t[l].Start+"Width"])+"px"})}function i(t,e,i={}){const n=new WeakMap,s=h(i);t instanceof HTMLCollection&&(t=Array.from(t)),t.forEach((t=>{"none"!==getComputedStyle(t).display&&n.set(t,t.getBoundingClientRect())})),e(),t.forEach((t=>{const e=n.get(t);if(!e)return;const i=e.left-t.getBoundingClientRect().left,o=e.top-t.getBoundingClientRect().top;if(!i&&!o)return;const r=t.style;r.transitionDuration="0s",r.transform=`translate(${i}px, ${o}px)`,document.body.offsetWidth,r.transitionDuration=r.transform="",t.classList.add(s+"move"),a(t,(()=>{t.classList.remove(s+"move")}))}))}function n(t){t._currentTransition&&(t.classList.remove(...["active","from","to"].map((e=>t._currentTransition+e))),t._currentTransition=null)}function s(t,e,i={}){const s=h(i)+e+"-",o=t.classList;var r;n(t),t._currentTransition=s,o.add(s+"active",s+"from"),r=()=>{o.add(s+"to"),o.remove(s+"from"),a(t,(()=>{o.remove(s+"to",s+"active"),t._currentTransition===s&&(i.finish&&i.finish(),t._currentTransition=null)}))},requestAnimationFrame((()=>{requestAnimationFrame(r)}))}function o(t,e={}){s(t,"enter",e)}function r(t,e={}){s(t,"leave",e)}function a(t,e){if(getComputedStyle(t).transitionDuration.startsWith("0s"))e();else{const i=()=>{e(),t.removeEventListener("transitionend",i),t.removeEventListener("transitioncancel",i)};t.addEventListener("transitionend",i),t.addEventListener("transitioncancel",i)}}function h(t){return t.prefix?t.prefix+"-":""}class d extends HTMLElement{constructor(){super();let t=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML='<div part="backdrop" hidden style="position: fixed; top: 0; left: 0; right: 0; bottom: 0"></div><slot></slot>',t.appendChild(e.content.cloneNode(!0)),this.shadowRoot.firstElementChild.onclick=()=>this.open=!1}static get observedAttributes(){return["open"]}connectedCallback(){this.shadowRoot.firstElementChild.hidden=!0,this.menu.hidden=!0,this.button.setAttribute("aria-haspopup","true"),this.button.setAttribute("aria-expanded","false"),this.button.addEventListener("click",(()=>{this.open=!0})),this.button.addEventListener("keydown",(t=>{"ArrowDown"===t.key&&(t.preventDefault(),this.open=!0)})),this.addEventListener("keydown",(t=>{"Escape"===t.key&&this.open&&(t.preventDefault(),t.stopPropagation(),this.open=!1,this.button.focus())})),this.menu.addEventListener("click",(t=>{const e=t.target instanceof Element?t.target:null;("menuitem"===(null==e?void 0:e.getAttribute("role"))||"menuitemradio"===(null==e?void 0:e.getAttribute("role"))||(null==e?void 0:e.closest("[role=menuitem], [role=menuitemradio]")))&&(this.open=!1)})),this.open=!1}disconnectedCallback(){n(this.shadowRoot.firstElementChild),n(this.menu)}get button(){return this.querySelector("button, [role=button]")}get menu(){return this.children[1]}get open(){return this.hasAttribute("open")}set open(t){t?this.setAttribute("open",""):this.removeAttribute("open")}attributeChangedCallback(t,i,n){if("open"===t)if(null!==n){if(!this.menu.hidden)return;this.menu.hidden=!1,o(this.menu),this.button.setAttribute("aria-expanded","true"),e(this.button,this.menu,{placement:this.getAttribute("placement")||"bottom"});const t=this.shadowRoot.firstElementChild;t.hidden=!1,o(t),this.dispatchEvent(new Event("open"))}else if(!this.menu.hidden){this.button.setAttribute("aria-expanded","false");const t=this.shadowRoot.firstElementChild;r(t,{finish:()=>t.hidden=!0}),r(this.menu,{finish:()=>this.menu.hidden=!0}),this.dispatchEvent(new Event("close"))}}}class l extends HTMLElement{constructor(){super(...arguments),this.handleMouseEnter=this.afterDelay.bind(this,this.show),this.handleFocus=this.show.bind(this),this.handleMouseLeave=this.afterDelay.bind(this,this.hide),this.handleBlur=this.hide.bind(this),this.handleKeyDown=this.keyDown.bind(this)}connectedCallback(){this.parent=this.parentNode,this.parent&&(this.parent.tabIndex=this.parent.tabIndex||0,this.parent.addEventListener("mouseenter",this.handleMouseEnter),this.parent.addEventListener("focus",this.handleFocus),this.parent.addEventListener("mouseleave",this.handleMouseLeave),this.parent.addEventListener("blur",this.handleBlur),this.parent.addEventListener("click",this.handleBlur),this.observer=new MutationObserver((t=>{t.forEach((t=>{"disabled"===t.attributeName&&this.hide()}))})),this.observer.observe(this.parent,{attributes:!0})),document.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){this.hide(),this.observer.disconnect(),this.parent&&(this.parent.removeEventListener("mouseenter",this.handleMouseEnter),this.parent.removeEventListener("focus",this.handleFocus),this.parent.removeEventListener("mouseleave",this.handleMouseLeave),this.parent.removeEventListener("blur",this.handleBlur),this.parent.removeEventListener("click",this.handleBlur),this.parent=null),document.removeEventListener("keydown",this.handleKeyDown)}keyDown(t){"Escape"===t.key&&this.hide()}show(){const t=this.createTooltip();clearTimeout(this.timeout),t.hidden=!1,o(t),t.innerHTML=this.innerHTML,e(this.parent,t,{placement:this.getAttribute("placement")||l.placement})}hide(){clearTimeout(this.timeout),this.tooltip&&r(this.tooltip,{finish:()=>{this.tooltip&&(this.tooltip.hidden=!0)}})}afterDelay(t){clearTimeout(this.timeout);const e=parseInt(this.getAttribute("delay")||"");this.timeout=window.setTimeout(t.bind(this),isNaN(e)?l.delay:e)}createTooltip(){return this.tooltip||(this.tooltip=document.createElement("div"),this.tooltip.className=this.getAttribute("tooltip-class")||l.tooltipClass,this.tooltip.hidden=!0,document.body.appendChild(this.tooltip)),this.tooltip}}l.delay=100,l.placement="top",l.tooltipClass="tooltip";class c extends HTMLElement{constructor(){super(...arguments),this.search="",this.handleKeydown=t=>{if(!this.hidden)if("ArrowUp"===t.key)this.navigate(-1),t.preventDefault();else if("ArrowDown"===t.key)this.navigate(1),t.preventDefault();else{if(t.key.length>1)return;if(t.ctrlKey||t.metaKey||t.altKey)return;t.preventDefault(),this.search+=t.key.toLowerCase(),clearTimeout(this.searchTimeout),this.searchTimeout=window.setTimeout((()=>{this.search=""}),c.searchDelay),this.focusableItems.some((t=>{var e;if(0===(null===(e=t.textContent)||void 0===e?void 0:e.trim().toLowerCase().indexOf(this.search)))return t.focus(),!0}))}}}connectedCallback(){this.setAttribute("role","menu"),Array.from(this.focusableItems).forEach((t=>{t.setAttribute("tabindex","-1")})),document.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){document.removeEventListener("keydown",this.handleKeydown)}navigate(t){const e=this.focusableItems;let i=document.activeElement instanceof HTMLElement?e.indexOf(document.activeElement):-1;i+=t,i<0&&(i=e.length-1),i>=e.length&&(i=0),e[i]&&e[i].focus()}get focusableItems(){return Array.from(this.querySelectorAll("[role^=menuitem]"))}}c.searchDelay=800;class u extends HTMLElement{constructor(){var t;super(),this.inertCache=new Map;let e=this.attachShadow({mode:"open"});const i=document.createElement("template");i.innerHTML='<div part="backdrop" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0"></div><div part="content" style="position: relative"><slot></slot></div>',e.appendChild(i.content.cloneNode(!0)),null===(t=e.querySelector("[part=backdrop]"))||void 0===t||t.addEventListener("click",(()=>{this.hasAttribute("static")?u.attention&&u.attention(e.children[1]):this.close()}))}static get observedAttributes(){return["open"]}connectedCallback(){this.firstElementChild&&(this.firstElementChild.setAttribute("role","dialog"),this.firstElementChild.setAttribute("aria-modal","true"),this.firstElementChild.setAttribute("tabindex","-1")),this.addEventListener("keydown",(t=>{"Escape"!==t.key||this.hidden||(t.preventDefault(),t.stopPropagation(),this.close())}))}disconnectedCallback(){this.undoInert()}get open(){return this.hasAttribute("open")}set open(t){t?this.setAttribute("open",""):this.removeAttribute("open")}close(){if(!this.open)return;const t=new Event("beforeclose",{cancelable:!0});this.dispatchEvent(t)&&(this.open=!1)}undoInert(){this.inertCache.forEach(((t,e)=>{e.inert=!1})),this.inertCache.clear()}attributeChangedCallback(t,e,i){var n,s,a;if("open"===t)if(null!==i){this.trigger=document.activeElement,this.hidden=!1,o(this);const t=this.querySelector("[autofocus]");t?t.focus():null===(n=this.firstElementChild)||void 0===n||n.focus(),Array.from(document.body.children).filter((t=>t!==this)).forEach((t=>{this.inertCache.set(t,t.inert),t.inert=!0})),this.dispatchEvent(new Event("open"))}else this.undoInert(),this.trigger&&("menuitem"===this.trigger.getAttribute("role")?null===(a=null===(s=this.trigger.parentElement)||void 0===s?void 0:s.previousElementSibling)||void 0===a||a.focus():this.trigger.focus()),r(this,{finish:()=>this.hidden=!0}),this.dispatchEvent(new Event("close"))}}u.attention=t=>t.animate([{transform:"scale(1)"},{transform:"scale(1.1)"},{transform:"scale(1)"}],300);class m extends HTMLElement{constructor(){super(...arguments),this.timeouts=new Map,this.index=0}connectedCallback(){this.setAttribute("role","status"),this.setAttribute("aria-live","polite"),this.setAttribute("aria-relevant","additions")}show(t,e={}){const n=e.key||String(this.index++);this.dismiss(n),t.dataset.key=n,i(this.children,(()=>{this.append(t),o(t)}));const s=void 0!==e.duration?Number(e.duration):m.duration;return s>0&&(this.startTimeout(t,s),t.addEventListener("mouseenter",this.clearTimeout.bind(this,t)),t.addEventListener("focusin",this.clearTimeout.bind(this,t)),t.addEventListener("mouseleave",this.startTimeout.bind(this,t,s)),t.addEventListener("focusout",this.startTimeout.bind(this,t,s))),n}dismiss(t){if("string"!=typeof t)i(this.children,(()=>{r(t,{finish:()=>this.removeChild(t)})})),this.clearTimeout(t);else{const e=this.querySelector(`[data-key="${t}"]`);e&&this.dismiss(e)}}speak(t){const e=document.createElement("div");Object.assign(e.style,{clip:"rect(0 0 0 0)",clipPath:"inset(50%)",height:"1px",overflow:"hidden",position:"absolute",whiteSpace:"nowrap",width:"1px"}),e.textContent=t,this.show(e)}startTimeout(t,e){this.clearTimeout(t),this.timeouts.set(t,window.setTimeout((()=>{this.dismiss(t)}),e))}clearTimeout(t){this.timeouts.has(t)&&clearTimeout(this.timeouts.get(t))}}m.duration=1e4;export{m as AlertsElement,c as MenuElement,u as ModalElement,d as PopupElement,l as TooltipElement};
1
+ import{move as t,hello as e,goodbye as i,cancel as s}from"hello-goodbye";import{createFocusTrap as n}from"focus-trap";import{computePosition as o,shift as r,flip as a,size as h}from"@floating-ui/dom";import{focusable as d}from"tabbable";class c extends HTMLElement{static duration=1e4;timeouts=new Map;index=0;connectedCallback(){this.hasAttribute("role")||this.setAttribute("role","status"),this.hasAttribute("aria-live")||this.setAttribute("aria-live","polite"),this.hasAttribute("aria-relevant")||this.setAttribute("aria-relevant","additions")}show(i,s={}){const n=s.key||String(this.index++);this.dismiss(n),i.dataset.key=n,t(this.children,(()=>{this.append(i),e(i)}));const o=void 0!==s.duration?Number(s.duration):c.duration;return o>0&&(this.startTimeout(i,o),i.addEventListener("mouseenter",this.clearTimeout.bind(this,i)),i.addEventListener("focusin",this.clearTimeout.bind(this,i)),i.addEventListener("mouseleave",this.startTimeout.bind(this,i,o)),i.addEventListener("focusout",this.startTimeout.bind(this,i,o))),n}dismiss(e){if("string"!=typeof e)t(this.children,(()=>{i(e,{finish:()=>this.removeChild(e)})})),this.clearTimeout(e);else{const t=this.querySelector(`[data-key="${e}"]`);t&&this.dismiss(t)}}clear(){for(const t of this.children)this.dismiss(t)}speak(t){const e=document.createElement("div");Object.assign(e.style,{clip:"rect(0 0 0 0)",clipPath:"inset(50%)",height:"1px",overflow:"hidden",position:"absolute",whiteSpace:"nowrap",width:"1px"}),e.textContent=t,this.show(e)}startTimeout(t,e){this.clearTimeout(t),this.timeouts.set(t,window.setTimeout((()=>{this.dismiss(t)}),e))}clearTimeout(t){this.timeouts.has(t)&&clearTimeout(this.timeouts.get(t))}}class l extends HTMLElement{static searchDelay=800;search="";searchTimeout;connectedCallback(){this.hasAttribute("role")||this.setAttribute("role","menu"),this.hasAttribute("tabindex")||this.setAttribute("tabindex","-1"),this.items.forEach((t=>{t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1")})),this.addEventListener("keydown",this.onKeyDown)}disconnectedCallback(){this.removeEventListener("keydown",this.onKeyDown)}get items(){return Array.from(this.querySelectorAll("[role^=menuitem]"))}onKeyDown=t=>{if(!this.hidden)return"ArrowUp"===t.key?(this.navigate(-1),void t.preventDefault()):"ArrowDown"===t.key?(this.navigate(1),void t.preventDefault()):void(t.key.length>1||t.ctrlKey||t.metaKey||t.altKey||(this.search+=t.key.toLowerCase(),t.preventDefault(),clearTimeout(this.searchTimeout),this.searchTimeout=window.setTimeout((()=>{this.search=""}),l.searchDelay),this.items.some((t=>{if(0===t.textContent?.trim().toLowerCase().indexOf(this.search))return t.focus(),!0}))))};navigate(t){const e=this.items;let i=(document.activeElement instanceof HTMLElement?e.indexOf(document.activeElement):-1)+t;i<0&&(i=e.length-1),i>=e.length&&(i=0),e[i]?.focus()}}class u extends HTMLElement{static attention=t=>t.animate([{transform:"scale(1)"},{transform:"scale(1.1)"},{transform:"scale(1)"}],300);static get observedAttributes(){return["open"]}trigger;focusTrap;constructor(){super();const t=document.createElement("template");t.innerHTML='\n <div part="backdrop" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0"></div>\n <div part="content" style="z-index: 1"><slot></slot></div>\n ';const e=this.attachShadow({mode:"open"});e.appendChild(t.content.cloneNode(!0)),this.backdrop.addEventListener("click",(()=>{this.hasAttribute("static")?u.attention?.(e.children[1]):this.close()})),this.focusTrap=n(this,{escapeDeactivates:!1,allowOutsideClick:!0})}connectedCallback(){this.content?.hasAttribute("role")||this.content?.setAttribute("role","dialog"),this.content?.hasAttribute("aria-modal")||this.content?.setAttribute("aria-modal","true"),this.content?.hasAttribute("tabindex")||this.content?.setAttribute("tabindex","-1"),this.addEventListener("keydown",(t=>{"Escape"===t.key&&this.open&&(t.preventDefault(),t.stopPropagation(),this.close())}))}get open(){return this.hasAttribute("open")}set open(t){t?this.setAttribute("open",""):this.removeAttribute("open")}close(){if(!this.open)return;const t=new Event("beforeclose",{cancelable:!0});this.dispatchEvent(t)&&(this.open=!1)}attributeChangedCallback(t,e,i){"open"===t&&(null!==i?this.wasOpened():this.wasClosed())}wasOpened(){this.trigger=document.activeElement,this.hidden=!1,e(this),this.focusTrap.activate();const t=this.querySelector("[autofocus]");t?t.focus():this.content?.focus(),this.dispatchEvent(new Event("open"))}wasClosed(){this.focusTrap.deactivate(),this.trigger?.focus(),i(this,{finish:()=>this.hidden=!0}),this.dispatchEvent(new Event("close"))}get backdrop(){return this.shadowRoot?.firstElementChild}get content(){return this.firstElementChild}}class p extends HTMLElement{static get observedAttributes(){return["open"]}constructor(){super();const t=document.createElement("template");t.innerHTML='\n <div part="backdrop" hidden style="position: fixed; top: 0; left: 0; right: 0; bottom: 0"></div>\n <slot></slot>\n ';this.attachShadow({mode:"open"}).appendChild(t.content.cloneNode(!0)),this.backdrop.onclick=()=>this.open=!1}connectedCallback(){this.backdrop.hidden=!0,this.content.hidden=!0,this.open=!1,this.button.setAttribute("aria-expanded","false"),setTimeout((()=>{"menu"===this.content.getAttribute("role")&&this.button.setAttribute("aria-haspopup","true")})),this.button.addEventListener("click",(()=>{this.open=!this.open})),this.button.addEventListener("keydown",(t=>{"ArrowDown"===t.key&&(t.preventDefault(),this.open=!0,d(this.content)[0]?.focus())})),this.addEventListener("keydown",(t=>{"Escape"===t.key&&this.open&&(t.preventDefault(),t.stopPropagation(),this.open=!1,this.button.focus())})),this.addEventListener("focusout",(t=>{t.relatedTarget instanceof Node&&this.contains(t.relatedTarget)||(this.open=!1)})),this.content.addEventListener("click",(t=>{t.target instanceof Element&&t.target.closest("[role=menuitem], [role=menuitemradio]")&&(this.open=!1,this.button.focus())}))}disconnectedCallback(){s(this.backdrop),s(this.content)}get open(){return this.hasAttribute("open")}set open(t){t?this.setAttribute("open",""):this.removeAttribute("open")}attributeChangedCallback(t,e,i){"open"===t&&(null!==i?this.wasOpened():this.wasClosed())}wasOpened(){if(!this.content.hidden)return;this.content.hidden=!1,this.backdrop.hidden=!1,e(this.content),e(this.backdrop),this.button.setAttribute("aria-expanded","true"),this.content.style.position="absolute",o(this.button,this.content,{placement:this.getAttribute("placement")||"bottom",middleware:[r(),a(),h()]}).then((({x:t,y:e,placement:i})=>{Object.assign(this.content.style,{left:`${t}px`,top:`${e}px`}),this.content.dataset.placement=i}));const t=this.content.querySelector("[autofocus]");t?t.focus():this.content.focus(),this.dispatchEvent(new Event("open"))}wasClosed(){this.content.hidden||(this.button.setAttribute("aria-expanded","false"),i(this.backdrop,{finish:()=>this.backdrop.hidden=!0}),i(this.content,{finish:()=>this.content.hidden=!0}),this.dispatchEvent(new Event("close")))}get backdrop(){return this.shadowRoot?.firstElementChild}get button(){return this.children[0]}get content(){return this.children[1]}}class m extends HTMLElement{connectedCallback(){this.hasAttribute("role")||this.setAttribute("role","toolbar"),this.setAttribute("tabindex","0"),this.addEventListener("focus",this.onInitialFocus,{once:!0}),this.addEventListener("keydown",this.onKeyDown)}disconnectedCallback(){this.removeEventListener("keydown",this.onKeyDown)}onInitialFocus=t=>{this.removeAttribute("tabindex"),this.focusControlAtIndex(0)};onKeyDown=t=>{if("ArrowRight"!==t.key&&"ArrowLeft"!==t.key&&"Home"!==t.key&&"End"!==t.key)return;const e=this.controls,i=this.controls.length,s=e.indexOf(t.target);if(-1===s)return;let n=0;"ArrowLeft"===t.key&&(n=s-1),"ArrowRight"===t.key&&(n=s+1),"End"===t.key&&(n=i-1),n<0&&(n=i-1),n>i-1&&(n=0),this.focusControlAtIndex(n),t.preventDefault()};focusControlAtIndex(t){this.controls.forEach(((e,i)=>{i===t?(e.setAttribute("tabindex","0"),e.focus()):e.setAttribute("tabindex","-1")}))}get controls(){return d(this)}}class b extends HTMLElement{static delay=100;static placement="top";static tooltipClass="tooltip";parent;tooltip;timeout;observer;showing=!1;onMouseEnter=this.afterDelay.bind(this,this.show);onFocus=this.show.bind(this);onMouseLeave=this.afterDelay.bind(this,this.hide);onBlur=this.hide.bind(this);connectedCallback(){this.parent=this.parentNode,this.parent&&(this.parent.addEventListener("mouseenter",this.onMouseEnter),this.parent.addEventListener("focus",this.onFocus),this.parent.addEventListener("mouseleave",this.onMouseLeave),this.parent.addEventListener("blur",this.onBlur),this.parent.addEventListener("click",this.onBlur),this.observer=new MutationObserver((t=>{t.forEach((t=>{"disabled"===t.attributeName&&this.hide()}))})),this.observer.observe(this.parent,{attributes:!0})),document.addEventListener("keydown",this.onKeyDown),document.addEventListener("scroll",this.onBlur)}disconnectedCallback(){this.tooltip&&(this.tooltip.remove(),this.tooltip=void 0),this.parent&&(this.parent.removeEventListener("mouseenter",this.onMouseEnter),this.parent.removeEventListener("focus",this.onFocus),this.parent.removeEventListener("mouseleave",this.onMouseLeave),this.parent.removeEventListener("blur",this.onBlur),this.parent.removeEventListener("click",this.onBlur),this.parent=void 0),document.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("scroll",this.onBlur),this.observer.disconnect()}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}onKeyDown=t=>{"Escape"===t.key&&this.hide()};show(){if(this.disabled)return;const t=this.createTooltip();clearTimeout(this.timeout),this.showing||(t.hidden=!1,e(t),this.showing=!0),t.innerHTML!==this.innerHTML&&(t.innerHTML=this.innerHTML),t.style.position="absolute",o(this.parent,t,{placement:this.getAttribute("placement")||b.placement,middleware:[r(),a()]}).then((({x:e,y:i,placement:s})=>{Object.assign(t.style,{left:`${e}px`,top:`${i}px`}),t.dataset.placement=s}))}hide(){clearTimeout(this.timeout),this.showing&&(this.showing=!1,i(this.tooltip,{finish:()=>{this.tooltip&&(this.tooltip.hidden=!0)}}))}afterDelay(t){clearTimeout(this.timeout);const e=parseInt(this.getAttribute("delay")||"");this.timeout=window.setTimeout(t.bind(this),isNaN(e)?b.delay:e)}createTooltip(){return this.tooltip||(this.tooltip=document.createElement("div"),this.tooltip.className=this.getAttribute("tooltip-class")||b.tooltipClass,this.tooltip.hidden=!0,this.tooltip.addEventListener("mouseenter",this.show.bind(this)),this.tooltip.addEventListener("mouseleave",this.afterDelay.bind(this,this.hide)),document.body.appendChild(this.tooltip)),this.tooltip}}export{c as AlertsElement,l as MenuElement,u as ModalElement,p as PopupElement,m as ToolbarElement,b as TooltipElement};
@@ -1,9 +1,10 @@
1
- declare class MenuElement extends HTMLElement {
1
+ export default class MenuElement extends HTMLElement {
2
2
  static searchDelay: number;
3
3
  private search;
4
4
  private searchTimeout?;
5
5
  connectedCallback(): void;
6
+ disconnectedCallback(): void;
7
+ get items(): HTMLElement[];
8
+ private onKeyDown;
6
9
  private navigate;
7
- get focusableItems(): HTMLElement[];
8
10
  }
9
- export default MenuElement;
@@ -1,13 +1,16 @@
1
- declare class ModalElement extends HTMLElement {
1
+ export default class ModalElement extends HTMLElement {
2
2
  static attention: (el: Element) => void;
3
3
  static get observedAttributes(): string[];
4
4
  private trigger?;
5
- private inertCache;
5
+ private focusTrap?;
6
6
  constructor();
7
7
  connectedCallback(): void;
8
8
  get open(): boolean;
9
9
  set open(val: boolean);
10
10
  close(): void;
11
11
  attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
12
+ private wasOpened;
13
+ private wasClosed;
14
+ private get backdrop();
15
+ private get content();
12
16
  }
13
- export default ModalElement;
@@ -1,12 +1,14 @@
1
- declare class PopupElement extends HTMLElement {
1
+ export default class PopupElement extends HTMLElement {
2
2
  static get observedAttributes(): string[];
3
- private overlay?;
4
3
  constructor();
5
4
  connectedCallback(): void;
6
- private get button();
7
- private get menu();
5
+ disconnectedCallback(): void;
8
6
  get open(): boolean;
9
7
  set open(val: boolean);
10
8
  attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
9
+ private wasOpened;
10
+ private wasClosed;
11
+ private get backdrop();
12
+ private get button();
13
+ private get content();
11
14
  }
12
- export default PopupElement;
@@ -0,0 +1,8 @@
1
+ export default class ToolbarElement extends HTMLElement {
2
+ connectedCallback(): void;
3
+ disconnectedCallback(): void;
4
+ private onInitialFocus;
5
+ private onKeyDown;
6
+ private focusControlAtIndex;
7
+ private get controls();
8
+ }
@@ -1,14 +1,23 @@
1
- declare class TooltipElement extends HTMLElement {
1
+ export default class TooltipElement extends HTMLElement {
2
2
  static delay: number;
3
3
  static placement: string;
4
4
  static tooltipClass: string;
5
+ private parent?;
5
6
  private tooltip?;
6
7
  private timeout?;
8
+ private observer?;
9
+ private showing;
10
+ private onMouseEnter;
11
+ private onFocus;
12
+ private onMouseLeave;
13
+ private onBlur;
7
14
  connectedCallback(): void;
8
- private get parent();
15
+ disconnectedCallback(): void;
16
+ get disabled(): boolean;
17
+ set disabled(val: boolean);
18
+ private onKeyDown;
9
19
  private show;
10
20
  private hide;
11
21
  private afterDelay;
12
22
  private createTooltip;
13
23
  }
14
- export default TooltipElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inclusive-elements",
3
- "version": "0.1.0-beta.8",
3
+ "version": "0.1.0-beta.9",
4
4
  "description": "Accessible, lightweight, unstyled implementations of common UI controls.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -14,24 +14,27 @@
14
14
  ],
15
15
  "sideEffects": false,
16
16
  "scripts": {
17
- "build": "rollup -c",
17
+ "build": "tsc && rollup -c",
18
18
  "build:watch": "rollup -cw",
19
+ "build:demo": "rollup -c demo/rollup.config.js",
19
20
  "release": "release-it --npm.tag=latest"
20
21
  },
21
- "devDependencies": {
22
- "@release-it/keep-a-changelog": "^2.2.2",
23
- "@rollup/plugin-multi-entry": "^4.0.0",
24
- "@rollup/plugin-node-resolve": "^11.2.0",
25
- "@rollup/plugin-typescript": "^8.2.0",
22
+ "dependencies": {
23
+ "@floating-ui/dom": "^0.2.0",
24
+ "focus-trap": "^6.7.2",
26
25
  "hello-goodbye": "^0.1.0-beta.5",
27
- "placement.js": "^1.0.0-beta.5",
28
- "release-it": "^14.6.1",
29
- "rollup": "^2.40.0",
30
- "rollup-plugin-filesize": "^9.1.1",
26
+ "tabbable": "^5.2.1"
27
+ },
28
+ "devDependencies": {
29
+ "@release-it/keep-a-changelog": "^2.3.0",
30
+ "@rollup/plugin-node-resolve": "^11.2.1",
31
+ "@rollup/plugin-typescript": "^8.3.0",
32
+ "release-it": "^14.12.4",
33
+ "rollup": "^2.66.1",
34
+ "rollup-plugin-filesize": "^9.1.2",
31
35
  "rollup-plugin-terser": "^7.0.2",
32
- "tslib": "^2.1.0",
33
- "typescript": "^4.2.2",
34
- "wicg-inert": "^3.1.1"
36
+ "tslib": "^2.3.1",
37
+ "typescript": "^4.5.5"
35
38
  },
36
39
  "release-it": {
37
40
  "github": {