1class RoutineButton extends HTMLElement{constructor(){super(),this._cache=null,this._containerEl=null,this._overlayEl=null,this._isOpen=!1,this._hoverTimeout=null,this._leaveTimeout=null,this._fetching=!1,this._onCartAdd=()=>this._hide()}connectedCallback(){const btn=this.querySelector(".btn--routine");btn&&(btn.addEventListener("mouseenter",()=>{this._isMobile()||(clearTimeout(this._leaveTimeout),this._hoverTimeout=setTimeout(()=>{this._showDesktop()},150))}),btn.addEventListener("mouseleave",()=>{this._isMobile()||(clearTimeout(this._hoverTimeout),this._scheduleHide())}),btn.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this._isMobile()&&this._showMobile()}))}disconnectedCallback(){this._hide()}get handles(){try{return JSON.parse(this.dataset.products||"[]")}catch{return[]}}get labelHeading(){return this.dataset.labelHeading||"Routine"}get labelAddAll(){return this.dataset.labelAddAll||"Add both to cart"}get labelMobileHeading(){return this.dataset.labelMobileHeading||"Complete your routine"}get labelMobileSubheading(){return this.dataset.labelMobileSubheading||"These products work best together"}get labelDesktop(){return this.dataset.labelDesktop||"Combine with:"}get iconAddCart(){return this.querySelector(".routine-add-all-icon")?.innerHTML||""}_isMobile(){return window.innerWidth<=1024}async _fetchProducts(){if(this._cache)return this._cache;if(this._fetching)return null;this._fetching=!0,this.classList.add("loading");try{const fetches=this.handles.map(handle=>fetch(`/products/${handle}?section_id=routine-content`).then(res=>{if(!res.ok)throw new Error(`Failed to fetch ${handle}`);return res.text()}).then(html=>{const div=document.createElement("div");div.innerHTML=html;const section=div.querySelector(".routine-product-card");return section?section.outerHTML:null}).catch(err=>(console.error(`[routine-button] ${err.message}`),null))),results=await Promise.all(fetches);return this._cache=results.filter(Boolean),this._cache}finally{this._fetching=!1,this.classList.remove("loading")}}async _showDesktop(){if(this._isOpen)return;document.querySelectorAll("routine-button").forEach(el=>el!==this&&el._isOpen&&el._hide()),this._isOpen=!0;const products=await this._fetchProducts();if(!products||products.length===0){this._isOpen=!1;return}if(!this._isOpen)return;this._containerEl=document.createElement("div"),this._containerEl.classList.add("routine-context-window");const label=document.createElement("p");label.className="routine-context-window__label p5",label.textContent=this.labelDesktop;const productsRow=document.createElement("div");if(productsRow.classList.add("routine-products-row"),productsRow.innerHTML=products.join(""),this._containerEl.appendChild(label),this._containerEl.appendChild(productsRow),productsRow.querySelectorAll('[data-variant-id][data-available="true"]').length>=1){const footer=document.createElement("div");footer.classList.add("routine-context-window__footer");const addAllBtn=document.createElement("button");addAllBtn.type="button",addAllBtn.className="btn btn--primary full-width routine-add-all-btn",addAllBtn.innerHTML=`${this.iconAddCart} ${this.labelAddAll}`,addAllBtn.addEventListener("click",()=>this._addAllToCart()),footer.appendChild(addAllBtn),this._containerEl.appendChild(footer)}this._containerEl.addEventListener("mouseenter",()=>{clearTimeout(this._leaveTimeout)}),this._containerEl.addEventListener("mouseleave",()=>{this._scheduleHide()}),document.body.appendChild(this._containerEl),this._positionDesktopTooltip(),window.addEventListener("cart:add",this._onCartAdd)}_positionDesktopTooltip(){if(!this._containerEl)return;const btnRect=this.getBoundingClientRect(),tooltipRect=this._containerEl.getBoundingClientRect();let left=btnRect.left+btnRect.width/2-tooltipRect.width/2;const top=btnRect.top-tooltipRect.height-12,margin=8;left=Math.max(margin,Math.min(left,window.innerWidth-tooltipRect.width-margin));const arrowLeft=btnRect.left+btnRect.width/2-left;this._containerEl.style.setProperty("--arrow-left",`${arrowLeft}px`),this._containerEl.style.left=`${left}px`,this._containerEl.style.top=`${top}px`}async _showMobile(){if(this._isOpen)return;document.querySelectorAll("routine-button").forEach(el=>el!==this&&el._isOpen&&el._hide()),this._isOpen=!0;const products=await this._fetchProducts();if(!products||products.length===0){this._isOpen=!1;return}if(!this._isOpen)return;this._overlayEl=document.createElement("div"),this._overlayEl.classList.add("routine-bottom-sheet-overlay"),this._overlayEl.addEventListener("click",()=>this._hide()),this._containerEl=document.createElement("div"),this._containerEl.classList.add("routine-bottom-sheet");const handle=document.createElement("div");handle.classList.add("routine-bottom-sheet__handle");const header=document.createElement("div");header.classList.add("routine-bottom-sheet__header"),header.innerHTML=` 2 <div class="routine-bottom-sheet__titles"> 3 <p class="p4 routine-bottom-sheet__heading">${this.labelMobileHeading}</p> 4 <p class="note routine-bottom-sheet__subheading">${this.labelMobileSubheading}</p> 5 </div> 6 <button type="button" class="routine-bottom-sheet__close" aria-label="Close"> 7 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> 8 <path d="M14.9983 4.99915L5 14.9975" stroke="#888780" stroke-width="1.66639" stroke-linecap="round" stroke-linejoin="round"/> 9 <path d="M5 4.99915L14.9983 14.9975" stroke="#888780" stroke-width="1.66639" stroke-linecap="round" stroke-linejoin="round"/> 10 </svg> 11 </button> 12 `,header.querySelector(".routine-bottom-sheet__close").addEventListener("click",()=>this._hide());const body=document.createElement("div");body.classList.add("routine-bottom-sheet__body"),body.innerHTML=products.join("");const availableCount=body.querySelectorAll('[data-variant-id][data-available="true"]').length,footer=document.createElement("div");if(footer.classList.add("routine-bottom-sheet__footer"),availableCount>=1){const addAllBtn=document.createElement("button");addAllBtn.type="button",addAllBtn.className="btn btn--primary full-width routine-add-all-btn",addAllBtn.innerHTML=`${this.iconAddCart} ${this.labelAddAll}`,addAllBtn.addEventListener("click",()=>this._addAllToCart()),footer.appendChild(addAllBtn)}this._containerEl.appendChild(handle),this._containerEl.appendChild(header),this._containerEl.appendChild(body),footer.children.length>0&&this._containerEl.appendChild(footer),document.body.appendChild(this._overlayEl),document.body.appendChild(this._containerEl),requestAnimationFrame(()=>{this._containerEl.setAttribute("open","")}),window.theme?.scroll?.disable&&window.theme.scroll.disable(),window.addEventListener("cart:add",this._onCartAdd)}_scheduleHide(){this._leaveTimeout=setTimeout(()=>this._hide(),100)}_hide(){this._isOpen&&(this._isOpen=!1,clearTimeout(this._hoverTimeout),clearTimeout(this._leaveTimeout),window.removeEventListener("cart:add",this._onCartAdd),this._containerEl&&(this._containerEl.classList.contains("routine-bottom-sheet")?(this._containerEl.removeAttribute("open"),setTimeout(()=>{this._containerEl?.remove(),this._containerEl=null},300)):(this._containerEl.remove(),this._containerEl=null)),this._overlayEl&&(this._overlayEl.remove(),this._overlayEl=null,window.theme?.scroll?.enable&&window.theme.scroll.enable()))}_addVariantToCart(variantId,cardEl){cardEl&&cardEl.classList.add("loading"),fetch(window.Shopify.routes.root+"cart/add.js",{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{id:variantId,quantity:1}
12],sections:["cart-drawer","cart-main"]})}).then(res=>res.json()).then(response=>{if(response.status)throw new Error(response.description||response.message);window.dispatchEvent(new CustomEvent("cart:add",{detail:{...response,added_count:1}}))}).catch(err=>{console.error("[routine-button]",err),cardEl&&cardEl.classList.remove("loading")})}_addAllToCart(){if(!this._containerEl)return;const cards=this._containerEl.querySelectorAll('[data-variant-id][data-available="true"]'),items=Array.from(cards).map(card=>({id:Number(card.dataset.variantId),quantity:1})),parentVariantId=Number(this.dataset.parentVariantId);if(parentVariantId&&items.push({id:parentVariantId,quantity:1}),items.length===0)return;const addBtn=this._containerEl.querySelector(".routine-add-all-btn");addBtn&&addBtn.classList.add("loading"),fetch(window.Shopify.routes.root+"cart/add.js",{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({items,sections:["cart-drawer","cart-main"]})}).then(res=>res.json()).then(response=>{if(response.status)throw new Error(response.description||response.message);window.dispatchEvent(new CustomEvent("cart:add",{detail:{...response,added_count:items.length}}))}).catch(err=>{console.error("[routine-button] Add all failed:",err),addBtn&&addBtn.classList.remove("loading")})}}customElements.define("routine-button",RoutineButton); 13//# sourceMappingURL=/cdn/shop/t/676/assets/routine-button-component.js.map?v=175790395349105532151779880691
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.