UNPKG

@appnest/masonry-layout

Version:

An efficient and fast web component that gives you a beautiful masonry layout

2 lines (1 loc) 4.38 kB
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self)["masonry-layout"]={})}(this,(function(t){"use strict";const e="--_masonry-layout-col-count",n="--_masonry-layout-gap",o=new Map;function s(t,e,n){const o=parseFloat(t.getAttribute(e)||"");return isNaN(o)?n:o}function i(t,e,n){return isNaN(e)?Math.max(1,Math.ceil(t/n)):e}function l(t){let e=0,n=1/0;return t.forEach(((t,o)=>{t<n&&(n=t,e=o)})),e}const r=document.createElement("template");r.innerHTML=`\n <style>\n :host {\n display: flex;\n align-items: flex-start;\n justify-content: stretch;\n }\n\n .column {\n\t max-width: calc((100% / var(${e}, 1) - ((var(${n}, 24px) * (var(${e}, 1) - 1) / var(${e}, 1)))));\n\t width: 100%;\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n\n .column:not(:last-child) {\n margin-inline-end: var(${n}, 24px);\n }\n\n .column ::slotted(*) {\n margin-block-end: var(${n}, 24px);\n box-sizing: border-box;\n width: 100%;\n }\n\n /* Hide the items that has not yet found the correct slot */\n #unset-items {\n opacity: 0;\n position: absolute;\n pointer-events: none;\n }\n </style>\n <div id="unset-items">\n <slot></slot>\n </div>\n`;class a extends HTMLElement{static get observedAttributes(){return["maxcolwidth","gap","cols"]}set maxColWidth(t){this.setAttribute("maxcolwidth",t.toString())}get maxColWidth(){return s(this,"maxcolwidth",500)}set cols(t){this.setAttribute("cols",t.toString())}get cols(){return s(this,"cols","auto")}set gap(t){this.setAttribute("gap",t.toString())}get gap(){return s(this,"gap",24)}set debounce(t){this.setAttribute("debounce",t.toString())}get debounce(){return s(this,"debounce",300)}get $columns(){return Array.from(this.shadowRoot.querySelectorAll(".column"))}debounceId=`layout_${Math.random()}`;$unsetElementsSlot;ro=void 0;currentRequestAnimationFrameCallback=void 0;constructor(){super();this.attachShadow({mode:"open"}).appendChild(r.content.cloneNode(!0)),this.onSlotChange=this.onSlotChange.bind(this),this.onResize=this.onResize.bind(this),this.layout=this.layout.bind(this),this.$unsetElementsSlot=this.shadowRoot.querySelector("#unset-items > slot")}connectedCallback(){this.$unsetElementsSlot.addEventListener("slotchange",this.onSlotChange),"ResizeObserver"in window?(this.ro=new ResizeObserver(this.onResize),this.ro.observe(this)):window.addEventListener("resize",this.onResize)}disconnectedCallback(){this.$unsetElementsSlot.removeEventListener("slotchange",this.onSlotChange),window.removeEventListener("resize",this.onResize),null!=this.ro&&this.ro.unobserve(this)}attributeChangedCallback(t){if("gap"===t)this.style.setProperty(n,`${this.gap}px`);this.scheduleLayout()}onSlotChange(){(this.$unsetElementsSlot.assignedNodes()||[]).filter((t=>1===t.nodeType)).length>0&&this.layout()}onResize(t){const{width:e}=null!=t&&Array.isArray(t)&&t.length>0?t[0].contentRect:{width:this.offsetWidth};i(e,this.cols,this.maxColWidth)!==this.$columns.length&&this.scheduleLayout()}renderCols(t){const n=this.$columns;if(n.length!==t){for(const t of n)t.parentNode&&t.parentNode.removeChild(t);for(let e=0;e<t;e++){const t=document.createElement("div");t.classList.add("column"),t.setAttribute("part",`column column-${e}`);const n=document.createElement("slot");n.setAttribute("name",e.toString()),t.appendChild(n),this.shadowRoot.appendChild(t)}this.style.setProperty(e,t.toString())}}scheduleLayout(t=this.debounce){!function(t,e,n){const s=o.get(n);null!=s&&window.clearTimeout(s),o.set(n,window.setTimeout(t,e))}(this.layout,t,this.debounceId)}layout(){null!=this.currentRequestAnimationFrameCallback&&window.cancelAnimationFrame(this.currentRequestAnimationFrameCallback),this.currentRequestAnimationFrameCallback=requestAnimationFrame((()=>{const t=this.gap,e=Array.from(this.children).filter((t=>1===t.nodeType)),n=i(this.offsetWidth,this.cols,this.maxColWidth),o=Array(n).fill(0),s=[];for(const n of e){const e=n.getBoundingClientRect().height;let i=l(o);o[i]+=e+t;const r=i.toString();n.slot!==r&&s.push((()=>n.slot=r))}for(const t of s)t();this.renderCols(n)}))}}customElements.define("masonry-layout",a),t.MasonryLayout=a,Object.defineProperty(t,"__esModule",{value:!0})}));