PageSourceSearch

https://www.lyleandscott.com/cdn/shop/t/458/assets/lyle-colour-swatches.js?v=46542948519546422241788364389

js lyleandscott.com collected 2026-09-24 23:00:17 UTC 10,678 bytes, 18 lines download raw bytes

1import{AlgoliaProductFetcher}from"@lyle/algolia-product-fetcher";import{isLightSwatchColour,isSwatchSoldOut,isWhiteSwatch,metafieldValue}from"@lyle/algolia-product-utils";import{bindProductColourNav,getColourFamilyCache,setColourFamilyCache}from"@lyle/product-colour-nav";class LyleColourSwatches extends HTMLElement{#abortController=null;#formatter=null;#products=[];#currentHandle="";#config=null;#selectedOptionValues=[];#variantHandler=null;#sizeClickHandler=null;connectedCallback(){const familyTag=this.dataset.familyTag;if(!familyTag)return;bindProductColourNav(),this.#abortController=new AbortController,this.#variantHandler=e=>{this.#selectedOptionValues=e.detail?.optionValues??[],this.#refreshSoldOutState()},document.addEventListener("product:variant-change",this.#variantHandler),this.#sizeClickHandler=e=>{const btn=e.target.closest("[data-size-btn]");!btn||btn.disabled||queueMicrotask(()=>{this.#selectedOptionValues=this.#readSelectedOptionValues(),this.#refreshSoldOutState()})},document.addEventListener("click",this.#sizeClickHandler),this.#selectedOptionValues=this.#readSelectedOptionValues();const cached=getColourFamilyCache(familyTag);cached?.length&&this.#renderFromProducts(cached).catch(()=>{}),this.#fetchAndRender(familyTag).catch(()=>{this.querySelector("[data-swatches-container]")?.remove()}).finally(()=>this.#markResolved())}disconnectedCallback(){this.#abortController?.abort(),this.#abortController=null,this.#formatter=null,this.#products=[],this.#variantHandler&&(document.removeEventListener("product:variant-change",this.#variantHandler),this.#variantHandler=null),this.#sizeClickHandler&&(document.removeEventListener("click",this.#sizeClickHandler),this.#sizeClickHandler=null)}async#fetchAndRender(familyTag){const config=this.#parseJson("[data-colour-swatches-config]"),productData=this.#parseJson("[data-colour-swatches-product]");if(!config||!productData)return;const{signal}=this.#abortController;let related=await this.#fetchThemeProducts(familyTag,config);related.length||(related=(await new AlgoliaProductFetcher({config,signal}).fetchRelatedProductsBatch([familyTag])).get(familyTag)||[]),!signal.aborted&&(setColourFamilyCache(familyTag,related),await this.#renderFromProducts(related,config,productData))}async#fetchThemeProducts(familyTag,config){try{const params=new URLSearchParams({section_id:"colour-swatches-data"}),rootUrl=config.market.rootUrl||"/",response=await fetch(`${rootUrl}collections/all/${encodeURIComponent(familyTag)}?${params}`,{signal:this.#abortController.signal});if(!response.ok)return[];const html=await response.text(),data=new DOMParser().parseFromString(html,"text/html").querySelector("[data-colour-swatches-products]");return data?JSON.parse(data.textContent):[]}catch{return[]}}async#renderFromProducts(related,config,productData){const resolvedConfig=config??this.#parseJson("[data-colour-swatches-config]"),resolvedProduct=productData??this.#parseJson("[data-colour-swatches-product]");if(!resolvedConfig||!resolvedProduct)return;this.#config=resolvedConfig,this.#currentHandle=resolvedProduct.handle;const colourFamily=resolvedProduct.tags?.find(t=>t.startsWith("ProductColourFamily-")),allColourProducts=related.filter(p=>(!colourFamily||p.tags?.includes(colourFamily))&&!!metafieldValue(p,"swatch_code")),container=this.querySelector("[data-swatches-container]");if(!container)return;if(!allColourProducts.length){container.remove();return}document.dispatchEvent(new CustomEvent("colour-swatches:siblings",{bubbles:!1,detail:{products:allColourProducts,currentHandle:resolvedProduct.handle,config:resolvedConfig}}));const sizeTag=resolvedProduct.tags?.find(t=>t.startsWith("ProductSize-")&&!t.startsWith("ProductSizeFamily-")),swatchProducts=sizeTag?allColourProducts.filter(p=>p.tags?.includes(sizeTag)):allColourProducts;if(!swatchProducts.length){container.remove();return}this.#products=swatchProducts.map(product=>product.handle===resolvedProduct.handle&&typeof resolvedProduct.available=="boolean"?{...product,available:resolvedProduct.available}:product),this.#selectedOptionValues=this.#readSelectedOptionValues(),this.#updateSubtitle(resolvedProduct.handle);const groups=this.#groupByPriceTier(this.#products,!!resolvedProduct.isCustomer);container.classList.remove("colour-swatches__swatches--loading"),this.#renderGroups(groups,resolvedProduct.handle,container,resolvedConfig)}#groupByPriceTier(products,isCustomer){const groups=new Map;for(const product of products){const priceKey=String(product.price?.min??product.price?.amount??0),memberDiscount=isCustomer?LyleColourSwatches.#memberDiscount(product):0,key=`${priceKey}|${memberDiscount}`;groups.has(key)||groups.set(key,{price:product.price,compareAtPrice:product.compareAtPrice,memberDiscount,priceKey,products:[]});const group=groups.get(key);group.products.find(p=>p.handle===product.handle)||group.products.push(product)}return new Map([...groups.entries()].sort((a,b)=>Number(b[1].priceKey)-Number(a[1].priceKey)))}#renderGroups(groups,currentHandle,container,config){const entries=[...groups.values()];if(this.querySelector("[data-colour-price]")?.toggleAttribute("hidden",entries.length>1),entries.length<=1){const group=entries[0];container.innerHTML=`<div class="colour-swatches__group-swatches">${(group?.products??[]).map(p=>this.#swatchHtml(p,currentHandle)).join("")}</div>`}else container.innerHTML=entries.map(group=>`<div class="colour-swatches__price-group">
2            <div class="colour-swatches__price-label text-body-sm-bold">${this.#priceLabelHtml(group,config)}</div>
3            <div class="colour-swatches__group-swatches">
4              ${group.products.map(p=>this.#swatchHtml(p,currentHandle)).join("")}
5            </div>
6          </div>`).join("");this.#markResolved()}#markResolved(){this.setAttribute("data-groups-resolved","")}#priceLabelHtml(group,config){const memberDiscount=group.memberDiscount,compareAt=group.compareAtPrice?.amount,price=group.price?.amount,onSale=compareAt&&price&&compareAt>price;if(memberDiscount>0&&price){const discounted=price-price*memberDiscount,compareFormatted=LyleColourSwatches.#esc(this.#formatPrice(onSale?group.compareAtPrice:group.price,config)),memberFormatted=LyleColourSwatches.#esc(this.#formatPrice({...group.price,amount:discounted},config)),badge=this.#memberBadgeHtml();
6return`<span class="colour-swatches__compare-at-price">${compareFormatted}</span><span class="colour-swatches__member-price">${memberFormatted}</span>${badge}`}if(onSale){const compareFormatted=LyleColourSwatches.#esc(this.#formatPrice(group.compareAtPrice,config)),priceFormatted=LyleColourSwatches.#esc(this.#formatPrice(group.price,config));return`<span class="colour-swatches__compare-at-price">${compareFormatted}</span><span class="colour-swatches__sale-price">${priceFormatted}</span>`}return LyleColourSwatches.#esc(this.#formatPrice(group.price,config))}#memberBadgeHtml(){const template=this.querySelector("[data-colour-price] [data-member-price-badge]");if(!template)return"";const badge=template.cloneNode(!0);return badge.removeAttribute("hidden"),badge.removeAttribute("data-member-price-badge"),badge.outerHTML}#swatchHtml(product,currentHandle){const swatchCode=metafieldValue(product,"swatch_code"),isActive=product.handle===currentHandle,isWhite=isWhiteSwatch(swatchCode),isLight=isLightSwatchColour(swatchCode),soldOut=isSwatchSoldOut(product,this.#selectedOptionValues);let classes="colour-swatches__swatch";isActive&&(classes+=" is-active"),isWhite&&(classes+=" colour-swatches__swatch--white"),soldOut&&(classes+=" colour-swatches__swatch--sold-out"),soldOut&&isLight&&(classes+=" colour-swatches__swatch--light");const safeSwatchCode=/^[a-zA-Z0-9#(),.% +\-]+$/.test(swatchCode??"")?swatchCode:"",prefetchImages=(product.images||[]).slice(0,3).map(image=>image.src).filter(Boolean);return`<a
7      class="${classes}"
8      href="${LyleColourSwatches.#esc(product.url)}"
9      aria-label="${LyleColourSwatches.#esc(product.title??"")}"
10      ${isActive?'aria-current="page"':""}
11      ${soldOut?"data-sold-out":""}
12      data-swatch
13      data-product-colour-nav
14      data-product-handle="${LyleColourSwatches.#esc(product.handle)}"
15      data-prefetch-images="${LyleColourSwatches.#esc(JSON.stringify(prefetchImages))}"
16      style="--swatch-color: ${LyleColourSwatches.#esc(safeSwatchCode)};"
17    ><span class="colour-swatches__swatch-inner"></span></a>`}#refreshSoldOutState(){for(const product of this.#products){const swatch=this.querySelector(`[data-swatch][data-product-handle="${CSS.escape(product.handle)}"]`);if(!swatch)continue;const swatchCode=metafieldValue(product,"swatch_code"),soldOut=isSwatchSoldOut(product,this.#selectedOptionValues),isLight=isLightSwatchColour(swatchCode);swatch.classList.toggle("colour-swatches__swatch--sold-out",soldOut),swatch.classList.toggle("colour-swatches__swatch--light",soldOut&&isLight),swatch.toggleAttribute("data-sold-out",soldOut)}}#updateSubtitle(handle){const product=this.#products.find(p=>p.handle===handle),name=metafieldValue(product,"swatch_name");if(!name)return;const subtitle=this.querySelector(".colour-swatches__subtitle");subtitle&&(subtitle.textContent=name)}#readSelectedOptionValues(){const root=this.closest("lyle-main-product")||document,values=[];if(root.querySelectorAll("[data-size-btn][data-selected]").forEach(btn=>{btn.dataset.optionValue&&values.push(btn.dataset.optionValue)}),values.length)return values;const hasSizeOption=!!root.querySelector("[data-size-buttons]"),hasVariantParam=new URLSearchParams(window.location.search).has("variant");return hasSizeOption&&!hasVariantParam?[]:(root.querySelectorAll("select[data-option-position]").forEach(select=>{select.value&&values.push(select.value)}),values)}#formatPrice(price,config){if(!price?.amount)return"";if(!this.#formatter)try{this.#formatter=new Intl.NumberFormat(config?.market?.language||"en-GB",{style:"currency",currency:price.currencyCode||"GBP",minimumFractionDigits:2})}catch{return String(price.amount)}return this.#formatter.format(price.amount)}#parseJson(selector){const script=this.querySelector(selector);if(!script?.textContent)return null;try{return JSON.parse(script.textContent)}catch{return null}}static#memberDiscount(product){const raw=Number(metafieldValue(product,"member_discount_percentage"));return!raw||Number.isNaN(raw)?0:raw>1?raw/100:raw}static#esc(s){return String(s??"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}}customElements.get("lyle-colour-swatches")||customElements.define("lyle-colour-swatches",LyleColourSwatches);
18//# sourceMappingURL=/cdn/shop/t/458/assets/lyle-colour-swatches.js.map?v=46542948519546422241788364389

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.