@flexilla/accordion
Version:
A versatile and interactive accordion component for creating collapsible sections in web applications, conserving space and improving user experience
2 lines (1 loc) • 9.02 kB
JavaScript
(function(l,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(l=typeof globalThis<"u"?globalThis:l||self,a(l["@flexilla/accordion"]={}))})(this,function(l){"use strict";var k=Object.defineProperty;var $=(l,a,r)=>a in l?k(l,a,{enumerable:!0,configurable:!0,writable:!0,value:r}):l[a]=r;var d=(l,a,r)=>$(l,typeof a!="symbol"?a+"":a,r);const a=(n,t=document.body)=>t.querySelector(n),r=(n,t=document.body)=>{const e=p(n,t);return Array.from(e).find(i=>i.parentElement===t)},p=(n,t=document.body)=>Array.from(t.querySelectorAll(n)),y=({element:n,callback:t,type:e,keysCheck:i})=>{const o=getComputedStyle(n),s=o.transition;if(s!=="none"&&s!==""&&!i.includes(s)){const c="transitionend",h=()=>{n.removeEventListener(c,h),t()};n.addEventListener(c,h,{once:!0})}else t()},A=({element:n,callback:t})=>{y({element:n,callback:t,type:"transition",keysCheck:["all 0s ease 0s","all"]})},I=(n,t,e)=>{const i=new CustomEvent(t,{detail:e});n.dispatchEvent(i)},w=({container:n,attributeToWatch:t,onChildAdded:e})=>{const i=new MutationObserver(o=>{for(const s of o)if(s.type==="childList"&&Array.from(s.addedNodes).some(c=>c instanceof HTMLElement&&c.hasAttribute(t))){e();break}});return i.observe(n,{childList:!0}),()=>{i.disconnect()}},b=n=>{const t=r("[data-accordion-trigger]",n),e=r("[data-accordion-content]",n),i=n.hasAttribute("data-default-open");if(!(t instanceof HTMLButtonElement))throw new Error("The element does't have a Valid Trigger");if(!(e instanceof HTMLDivElement))throw new Error("No Valid Content Element");const o=n.getAttribute("data-accordion-value")??"",s=t.getAttribute("aria-expanded")==="true";return{accordionTriggerElement:t,accordionContentElement:e,accordionItemValue:o,isItemExpanded:s,defaultOpened:i}},m=(n,t)=>{n.setAttribute("aria-hidden",t==="open"?"false":"true"),n.setAttribute("data-state",t)},x=(n,t="close",e="0px")=>{n.style.height=t==="open"?"auto":e,m(n,t)},T=n=>{if(n.getAttribute("data-state")==="open")return;m(n,"open");const t=n.scrollHeight;n.style.height=`${t}px`,A({element:n,callback:()=>{n.getAttribute("data-state")==="open"&&(n.style.height="auto")}})},C=(n,t="0px")=>{n.getAttribute("data-state")!=="close"&&(n.style.height=`${n.scrollHeight}px`,n.offsetHeight,n.style.height=t,m(n,"close"))},L=(n,t,e)=>{const o=p("[data-accordion-item]",e).filter(u=>u.parentElement===e),s=Array.from(o).indexOf(n.closest("[data-accordion-item]")),c=t?s-1:s+1;return r("[data-accordion-trigger]",o[c])??(t?r("[data-accordion-trigger]",o[o.length-1]):r("[data-accordion-trigger]",o[0]))},O=(n,t)=>{const e=document.activeElement;if(!(e instanceof HTMLElement))return;e.matches("[data-accordion-trigger]")&&(n.key==="ArrowUp"||n.key==="ArrowDown")&&(n.preventDefault(),L(e,n.key==="ArrowUp",t).focus())},E=(n,t)=>{n.ariaExpanded=t==="open"?"true":"false"},S=({collapsible:n,triggerElement:t,state:e,onInit:i})=>{i?(x(n,e),E(t,e)):e==="open"?(E(t,"open"),T(n)):(E(t,"close"),C(n))};class g{static initGlobalRegistry(){window.$flexillaInstances||(window.$flexillaInstances={})}static register(t,e,i){return this.initGlobalRegistry(),window.$flexillaInstances[t]||(window.$flexillaInstances[t]=[]),this.getInstance(t,e)||(window.$flexillaInstances[t].push({element:e,instance:i}),i)}static getInstance(t,e){var i,o;return this.initGlobalRegistry(),(o=(i=window.$flexillaInstances[t])==null?void 0:i.find(s=>s.element===e))==null?void 0:o.instance}static removeInstance(t,e){this.initGlobalRegistry(),window.$flexillaInstances[t]&&(window.$flexillaInstances[t]=window.$flexillaInstances[t].filter(i=>i.element!==e))}}const f=class f{constructor(t,e={}){d(this,"accordionEl");d(this,"options");d(this,"items");d(this,"eventListeners",[]);d(this,"cleanupObserver",null);d(this,"reload",()=>{this.cleanup(),this.items=p("[data-accordion-item]",this.accordionEl).filter(t=>t.parentElement&&t.parentElement===this.accordionEl),this.initAccordion()});d(this,"triggerItemState",(t,e,i)=>{this.options.preventClosingAll&&(this.options.accordionType==="single"&&i||this.options.accordionType==="multiple"&&this.items.filter(o=>o.getAttribute("data-state")==="open").length===1&&i)||(this.setItemState(t,e),this.options.accordionType==="single"&&this.closeOther({current:t}),this.dispatchedEvent(t))});d(this,"cleanup",()=>{this.accordionEl&&(this.items.forEach(t=>{t&&t.hasAttribute("data-state")&&t.removeAttribute("data-state")}),this.eventListeners.forEach(({element:t,type:e,listener:i})=>{t&&t.removeEventListener&&t.removeEventListener(e,i)}),this.cleanupObserver&&(this.cleanupObserver(),this.cleanupObserver=null),this.eventListeners=[],this.items=[],g.removeInstance("accordion",this.accordionEl))});if(this.accordionEl=typeof t=="string"?a(t):t,!this.accordionEl)throw new Error(`Accordion element not found: ${typeof t=="string"?`No element matches selector "${t}"`:"Provided HTMLElement is null or undefined"}`);const i=g.getInstance("accordion",this.accordionEl);if(i)return i;this.options={accordionType:this.accordionEl.dataset.accordionType||e.accordionType||"single",preventClosingAll:this.accordionEl.hasAttribute("data-prevent-closing-all")||e.preventClosingAll||!1,defaultValue:this.accordionEl.dataset.defaultValue||e.defaultValue||"",allowCloseFromContent:this.accordionEl.hasAttribute("data-allow-close-from-content")||e.allowCloseFromContent||!1,onChangeItem:e.onChangeItem},this.items=p("[data-accordion-item]",this.accordionEl).filter(o=>o.parentElement&&o.parentElement===this.accordionEl),this.initAccordion()}initAccordion(){if(!this.accordionEl)return;const{accordionType:t,defaultValue:e,preventClosingAll:i}=this.options;let o=r(`[data-accordion-item][data-accordion-value="${e}"]`,this.accordionEl);if(t==="single")this.options.preventClosingAll&&!(o instanceof HTMLElement)&&(o=this.items[0]),this.closeOther({current:o}),o&&this.setItemState(o,"open",!0);else{this.closeAll(!0);const c=this.items.some(h=>h.getAttribute("data-state")==="open");if(i&&!c)this.setItemState(this.items[0],"open",!0);else{const h=this.items.filter(u=>u.getAttribute("data-state")==="open");for(const u of h)this.setItemState(u,"open",!0)}}this.addEventListeners();const s=c=>{O(c,this.accordionEl)};this.accordionEl.addEventListener("keydown",s),this.eventListeners.push({element:this.accordionEl,type:"keydown",listener:s}),g.register("accordion",this.accordionEl,this),this.cleanupObserver=w({container:this.accordionEl,attributeToWatch:"data-accordion-item",onChildAdded:this.reload})}destroy(){this.accordionEl&&(this.items.forEach(t=>{t&&t.hasAttribute("data-state")&&t.removeAttribute("data-state")}),this.eventListeners.forEach(({element:t,type:e,listener:i})=>{t&&t.removeEventListener&&t.removeEventListener(e,i)}),this.eventListeners=[],this.items=[],g.removeInstance("accordion",this.accordionEl),this.cleanupObserver&&(this.cleanupObserver(),this.cleanupObserver=null))}setItemState(t,e,i){t.setAttribute("data-state",e);const{accordionContentElement:o,accordionTriggerElement:s}=b(t);S({collapsible:o,triggerElement:s,state:e,onInit:i})}closeOther({current:t,onInit:e}){this.items.forEach(i=>{i!==t&&(e&&this.options.accordionType==="multiple"?i.hasAttribute("data-default-open")?this.setItemState(i,"open"):this.setItemState(i,"close"):this.setItemState(i,"close"))})}closeAll(t){this.closeOther({onInit:t})}dispatchedEvent(t){const{accordionContentElement:e,accordionTriggerElement:i,isItemExpanded:o,accordionItemValue:s}=b(t);this.options.onChangeItem&&this.options.onChangeItem({expandedItem:{accordionItem:this.accordionEl,trigger:i,content:e,value:s,isExpanded:o}}),I(this.accordionEl,"change-item",{targetElement:{trigger:i,content:e,isExpanded:o},items:this.items})}addEventListeners(){this.items.forEach(t=>{const e=a("[data-accordion-trigger]",t),i=a("[data-accordion-content]",t),o=()=>this.triggerItemState(t,"close",!0),s=c=>{c.preventDefault();const h=t.getAttribute("data-state")==="open";let u=h?"close":"open";this.triggerItemState(t,u,h)};e&&(e.addEventListener("click",s),this.eventListeners.push({element:e,type:"click",listener:s})),this.options.allowCloseFromContent&&i&&(i.addEventListener("click",o),this.eventListeners.push({element:i,type:"click",listener:o}))})}show(t){const e=r(`[data-accordion-item][data-accordion-value="${t}"]`,this.accordionEl);!e||e.getAttribute("data-state")==="open"||(this.options.accordionType==="single"&&this.closeOther({current:e}),this.setItemState(e,"open"),this.dispatchedEvent(e))}hide(t){const e=r(`[data-accordion-item][data-accordion-value="${t}"]`,this.accordionEl);if(!(!e||!(e.getAttribute("data-state")==="open"))){if(this.options.preventClosingAll){const o=this.items.filter(s=>s.getAttribute("data-state")==="open");if(o.length===1&&e===o[0])return}this.setItemState(e,"close"),this.dispatchedEvent(e)}}};d(f,"autoInit",(t="[data-fx-accordion]")=>{const e=p(t,document.documentElement);for(const i of e)new f(i)}),d(f,"init",(t,e={})=>new f(t,e));let v=f;l.Accordion=v,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});