PageSourceSearch

https://www.lyleandscott.com/cdn/shop/t/458/assets/lyle-main-search.js?v=166387193700761270121788364387

js lyleandscott.com collected 2026-09-24 23:00:09 UTC 42,835 bytes, 223 lines download raw bytes

1import{AlgoliaProductCardRenderer}from"@lyle/algolia-product-card";import{algoliaProductAttributes,AlgoliaProductFetcher}from"@lyle/algolia-product-fetcher";import{buildAlgoliaFilters,clamp,defaultSearchFilterOptions,isPriceAttribute,rangeBounds,rangePercent,rangeStyle,rangeTicks,resolveFilterOptions}from"@lyle/algolia-filter-utils";import{algoliaUserToken,escapeHtml,parseJson,trackAlgoliaProductClick}from"@lyle/algolia-product-utils";import{getLocalisedRoute,translateWeglotSearchRequests}from"@lyle/weglot";const ALGOLIA_QUERY_ENDPOINT=appId=>`https://${appId}-dsn.algolia.net/1/indexes/*/queries`,DRAWER_ANIMATION_MS=300,RESOURCE_ATTRIBUTES=["blog","body_html_safe","handle","image","objectID","title"];class LyleMainSearch extends HTMLElement{#abortController=null;#cardRenderer=null;#config=null;#drawerAnimationTimer=null;#fetcher=null;#requestId=0;#state={drawerOpen:!1,facets:{},openPanel:null,pageSize:16,pages:{product:0,collection:0,article:0,page:0},query:"",ranges:{},resource:"product",sortIndex:""};#swatchRequestId=0;connectedCallback(){if(this.#config=this.#parseConfig(),!this.#config)return;this.#abortController=new AbortController,this.#state.query=this.#queryFromUrl()||this.#config.initialQuery||"",this.#state.pageSize=Number(this.#config.pagination.defaultPageSize)||this.#state.pageSize;const sortId=new URLSearchParams(window.location.search).get("sort"),sort=this.#config.algolia.sortByOptions.find(option=>option.id===sortId);this.#state.sortIndex=sort?.value||this.#config.algolia.indexName,this.#state.pages.product=this.#pageFromUrl(),this.#state.facets=this.#facetsFromUrl(),this.#state.ranges=this.#rangesFromUrl(),this.#cardRenderer=new AlgoliaProductCardRenderer({config:this.#config,icons:window.icons||{},isMobile:()=>this.#isMobile()}),this.#fetcher=new AlgoliaProductFetcher({config:this.#config,signal:this.#abortController.signal}),this.#bindEvents(),this.#search()}disconnectedCallback(){this.#abortController?.abort(),document.documentElement.classList.remove("overflow-hidden"),this.#drawerAnimationTimer&&clearTimeout(this.#drawerAnimationTimer),document.body.style.overflow=""}#bindEvents(){this.addEventListener("input",this.#handleRangeInput,{signal:this.#abortController.signal}),this.addEventListener("change",this.#handleRangeChange,{signal:this.#abortController.signal}),this.addEventListener("click",this.#handleClick,{signal:this.#abortController.signal})}#handleRangeInput=event=>{const input=event.target.closest("[data-range-input], [data-range-text]");input&&this.#syncRangeControls(input)};#handleRangeChange=event=>{const input=event.target.closest("[data-range-input], [data-range-text]");input&&this.#syncRangeControls(input,{commit:!0})};#handleClick=event=>{const target=event.target,resourceButton=target.closest("[data-resource-type]"),pageButton=target.closest("[data-search-page]"),mobileFiltersButton=target.closest("[data-main-search-mobile-filters]"),drawerClose=target.closest("[data-main-search-drawer-close]"),drawerViewResults=target.closest(".main-search__drawer-view-results"),sortButton=target.closest("[data-sort-value]"),rangeReset=target.closest("[data-range-reset]"),facetButton=target.closest("[data-facet-value]"),activeFilter=target.closest("[data-active-filter]"),clearAll=target.closest("[data-clear-all]"),panelToggle=target.closest("[data-search-panel-toggle]"),popularButton=target.closest("[data-popular-search]"),productLink=target.closest("[data-product-link]"),swatch=target.closest("[data-card-swatch]");if(resourceButton){event.preventDefault(),this.#state.resource=resourceButton.dataset.resourceType||"product",this.#renderPanels();return}if(pageButton){event.preventDefault();const resource=pageButton.dataset.searchPageResource||this.#state.resource;this.#state.pages[resource]=Number(pageButton.dataset.searchPage)||0,this.#writeSearchUrl(),this.#search();return}if(mobileFiltersButton){event.preventDefault(),this.#openDrawer();return}if(drawerClose||drawerViewResults){event.preventDefault(),this.#closeDrawer();return}if(sortButton){event.preventDefault(),this.#state.sortIndex=sortButton.dataset.sortValue||this.#state.sortIndex,this.#state.pages.product=0,this.#closePanels(),this.#writeSearchUrl(),this.#search();return}if(rangeReset){event.preventDefault(),this.#resetRange(rangeReset.dataset.rangeReset||"");return}if(facetButton){event.preventDefault(),this.#toggleFacet(facetButton.dataset.facetAttribute||"",facetButton.dataset.facetValue||"");return}if(activeFilter){event.preventDefault(),this.#removeActiveFilter(activeFilter.dataset.f
1ilterAttribute||"",activeFilter.dataset.filterValue||"",activeFilter.dataset.filterRangeSide||"");return}if(clearAll){event.preventDefault(),this.#clearAllFilters();return}if(panelToggle){event.preventDefault(),this.#togglePanel(panelToggle.dataset.searchPanelToggle||"");return}if(popularButton){event.preventDefault(),this.#state.query=popularButton.dataset.popularSearch||"",this.#resetPages(),this.#writeSearchUrl(),this.#search();return}if(swatch){event.preventDefault(),this.#selectSwatch(swatch);return}productLink&&trackAlgoliaProductClick(this.#config,this.#state.sortIndex,productLink)};async#search(){const requestId=++this.#requestId;if(!this.#hasAlgoliaConfig()){this.#renderError();return}this.#setLoading(!0);try{const requests=await translateWeglotSearchRequests(this.#buildRequests()),response=await fetch(ALGOLIA_QUERY_ENDPOINT(this.#config.algolia.appId),{method:"POST",headers:{"Content-Type":"application/json","X-Algolia-API-Key":this.#config.algolia.apiKey,"X-Algolia-Application-Id":this.#config.algolia.appId},signal:this.#abortController.signal,body:JSON.stringify({requests})});if(!response.ok)throw new Error("Algolia request failed");const payload=await response.json();if(requestId!==this.#requestId)return;this.#render(payload.results||[])}catch{requestId===this.#requestId&&this.#renderError()}finally{requestId===this.#requestId&&this.#setLoading(!1)}}#buildRequests(){const indexes=this.#config.algolia.indexes;return[{indexName:this.#state.sortIndex||indexes.products,params:this.#productParams().toString()},{indexName:this.#state.sortIndex||indexes.products,params:this.#productFacetParams().toString()},{indexName:indexes.collections,params:this.#resourceParams("collection").toString()},{indexName:indexes.articles,params:this.#resourceParams("article").toString()},{indexName:indexes.pages,params:this.#resourceParams("page").toString()},{indexName:indexes.suggestions,params:this.#suggestionParams().toString()},{indexName:indexes.trendingProducts,params:this.#trendingParams().toString()}]}#productParams(){const params=this.#baseParams("product");return params.set("hitsPerPage",String(this.#state.pageSize)),params.set("page",String(this.#state.pages.product)),params.set("filters",this.#buildFilters()),params.set("facets",JSON.stringify(this.#resolvedFilterOptions().map(filter=>filter.value))),params.set("maxValuesPerFacet","70"),params.set("distinct","true"),params.set("facetingAfterDistinct","true"),params.set("attributesToRetrieve",JSON.stringify(algoliaProductAttributes(this.#config.market.handle))),params.set("attributesToHighlight","[]"),params}#productFacetParams(){const params=this.#baseParams("product");return params.set("hitsPerPage","0"),params.set("page","0"),params.set("filters",this.#buildFilters({includeRefinements:!1})),params.set("facets",JSON.stringify(this.#resolvedFilterOptions().map(filter=>filter.value))),params.set("maxValuesPerFacet","70"),params.set("distinct","true"),params.set("facetingAfterDistinct","true"),params}#buildFilters(options={}){return buildAlgoliaFilters({baseFilters:[this.#config.algolia.defaultFilters],facets:this.#state.facets,ranges:this.#state.ranges,...options})}#resourceParams(resource){const params=this.#baseParams(resource);return params.set("hitsPerPage",String(this.#resourcePageSize())),params.set("page",String(this.#state.pages[resource]||0)),params.set("attributesToRetrieve",JSON.stringify(RESOURCE_ATTRIBUTES)),params}#suggestionParams(){const params=new URLSearchParams;return params.set("query",""),params.set("hitsPerPage","5"),params.set("attributesToRetrieve",JSON.stringify(["objectID","query"])),params}#trendingParams(){const params=new URLSearchParams;return params.set("query",""),params.set("hitsPerPage","4"),params.set("filters",this.#config.algolia.defaultFilters),params.set("distinct","true"),params.set("attributesToRetrieve",JSON.stringify(algoliaProductAttributes(this.#config.market.handle))),params.set("attributesToHighlight","[]"),params}#resourcePageSize(){const pageSize=Number(this.#config.pagination.resourcePageSize);return!Number.isInteger(pageSize)||pageSize<1?12:pageSize}#baseParams(resource){const params=new URLSearchParams;return params.set("query",this.#state.query.trim()),params.set("clickAnalytics","true"),params.set("ruleContexts",JSON.stringify(["search"])),params.set("userToken",algoliaUserToken()),resource!=="product"&&(params.set("highlightPreTag","__ais-highlight__"),params.set("highlightPostTag","__/ais-highlight__")),params}#render(results){const[productsResult={},productFacetsResult=productsResult,collectionsResult={},articlesResult={},pagesResult={},suggestionsResult={},trendingResult={}]=results,counts={product:productsResult.nbHits||0,collection:collectionsResult.nbHits||0,article:articlesResult.nbHits||0,page:pagesResult.nbHits||0};counts[this.#state.resource]===0&&this.#state.resource!=="product"&&(this.#state.resource="product"),this.#renderTitle(counts),this.#render
1Switcher(counts),this.#renderProductToolbar(counts.product,productFacetsResult),this.#renderDrawer(productFacetsResult),this.#renderActiveFilters(),this.#renderProducts(productsResult),this.#renderResources("collection",collectionsResult),this.#renderResources("article",articlesResult),this.#renderResources("page",pagesResult),this.#renderEmptyState(productsResult,suggestionsResult,trendingResult),this.#renderPanels()}#renderTitle(counts){const title=this.querySelector("[data-main-search-title]"),total=this.#totalCount(counts);title&&(title.textContent=this.#state.query?this.#config.strings.title.replace("__num__",total).replace("__query__",this.#state.query):this.#config.strings.searchNoQuery)}#renderSwitcher(counts){const switcher=this.querySelector("[data-main-search-switcher]"),total=this.#totalCount(counts),types=["product","collection","article","page"];if(!switcher||total<=0){switcher&&(switcher.hidden=!0,switcher.innerHTML="");return}switcher.hidden=!1,switcher.innerHTML=`
2      <div class="content-switcher__content">
3        <div class="content-switcher__group">
4          ${types.filter(type=>counts[type]>0||type==="product").map(type=>`
5                <button class="content-switcher__button text-body-md ${this.#state.resource===type?"is-active":""}" type="button" data-resource-type="${type}">
6                  ${this.#escapeHtml(this.#contentTypeLabel(type,counts[type]))}
7                </button>
8              `).join("")}
9        </div>
10        <span class="content-switcher__results text-body-md">
11          ${this.#escapeHtml(`${total} ${this.#config.strings.results}`)}
12        </span>
13      </div>
14    `}#renderProductToolbar(productCount,response){const toolbar=this.querySelector("[data-main-search-product-toolbar]"),activeSort=this.#config.algolia.sortByOptions.find(option=>option.value===this.#state.sortIndex)||this.#config.algolia.sortByOptions[0];
14if(!toolbar||productCount<=0){toolbar&&(toolbar.hidden=!0);return}toolbar.hidden=!1,toolbar.innerHTML=`
15      <button class="main-search__filters" type="button" data-main-search-mobile-filters>
16        <span class="main-search__filter-icon" aria-hidden="true">
17          ${this.#config.icons?.filter||this.#icon("filter")}
18        </span>
19        <span class="algolia-filter__button-mobile text-body-sm">
20          ${this.#escapeHtml(this.#config.strings.filter)}
21        </span>
22      </button>
23      <div class="main-search__sort-input">
24        <div class="algolia-filter">
25          <div class="algolia-filter__inner">
26            <div class="algolia-filter__facets-wrap">
27              ${this.#resolvedFilterOptions().map(filter=>this.#renderFacet(filter,response)).join("")}
28            </div>
29            <div class="algolia-filter__controls">
30              <div class="main-search__facet">
31                <button class="main-search__sort-button text-eyebrow-2xs" type="button" data-search-panel-toggle="sort" aria-expanded="false">
32                  <span>${this.#escapeHtml(activeSort?.label||this.#config.strings.sortBy)}</span>
33                  ${this.#icon("chevron-down")}
34                </button>
35                <div class="main-search__sort-panel" data-search-panel="sort" role="radiogroup" hidden>
36                  ${this.#config.algolia.sortByOptions.map(sort=>`
37                        <button class="main-search__sort-option text-body-sm ${sort.value===this.#state.sortIndex?"is-refined":""}" type="button" data-sort-value="${this.#escapeHtml(sort.value)}" role="radio" aria-checked="${sort.value===this.#state.sortIndex?"true":"false"}">
38                          ${this.#escapeHtml(sort.label)}
39                        </button>
40                      `).join("")}
41                </div>
42              </div>
43            </div>
44          </div>
45        </div>
46      </div>
47    `,this.#positionOpenPanels()}#renderDrawer(response){const drawer=this.querySelector("[data-main-search-drawer]"),content=this.querySelector("[data-main-search-drawer-content]");!drawer||!content||(content.innerHTML=this.#resolvedFilterOptions().map(filter=>this.#renderFacet(filter,response,{mobile:!0})).join(""),this.#syncMobileAccordions())}#renderFacet(filter,response,options={}){const{mobile=!1}=options,attribute=filter.value,panelId=`${mobile?"mobile-":""}facet-${this.#handleize(attribute)}`,isOpen=this.#state.openPanel===panelId;if(isPriceAttribute(attribute))return this.#renderRangeFacet(filter,response,panelId,{isOpen,mobile});const isColour=this.#isColourAttribute(attribute),facetValues=Object.entries(response?.facets?.[attribute]||{}).map(([value,count])=>({value,count})).sort((a,b)=>b.count-a.count);if(!facetValues.length)return"";const panelClasses=["main-search__facet-panel","main-search__facet-panel--options",isColour?"main-search__facet-panel--colour":"",mobile&&isOpen?"is-open":""].filter(Boolean).join(" "),wrapperClasses=["main-search__facet",mobile&&isOpen?"is-active":""].filter(Boolean).join(" ");return`
48      <div class="${this.#escapeHtml(wrapperClasses)}" data-facet="${this.#escapeHtml(attribute)}">
49        <button class="main-search__facet-button text-eyebrow-2xs" type="button" data-search-panel-toggle="${this.#escapeHtml(panelId)}" aria-expanded="${isOpen?"true":"false"}">
50          <span>${this.#escapeHtml(filter.label)}</span>
51          ${this.#icon("chevron-down")}
52        </button>
53        <div class="${this.#escapeHtml(panelClasses)}" data-search-panel="${this.#escapeHtml(panelId)}" ${mobile||isOpen?"":"hidden"}>
54          <ul class="main-search__facet-list ${isColour?"main-search__facet-list--colour":""}" role="list">
55            ${facetValues.map(facet=>this.#renderFacetValue(attribute,facet)).join("")}
56          </ul>
57        </div>
58      </div>
59    `}#renderRangeFacet(filter,response,panelId,options={}){const{isOpen=!1,mobile=!1}=options,attribute=filter.value,stats=response?.facets_stats?.[attribute];if(!stats||stats.min===stats.max)return"";const selected=this.#state.ranges[attribute]||{},bounds=rangeBounds(stats),min=selected.min??Math.floor(stats.min),max=selected.max??Math.ceil(stats.max),ticks=rangeTicks(bounds.min,bounds.max),wrapperClasses=["main-search__facet",mobile&&isOpen?"is-active":""].filter(
59Boolean).join(" "),panelClasses=["main-search__facet-panel","main-search__facet-panel--range",mobile&&isOpen?"is-open":""].filter(Boolean).join(" ");return`
60      <div class="${this.#escapeHtml(wrapperClasses)}" data-facet="${this.#escapeHtml(attribute)}">
61        <button class="main-search__facet-button text-eyebrow-2xs" type="button" data-search-panel-toggle="${this.#escapeHtml(panelId)}" aria-expanded="${isOpen?"true":"false"}">
62          <span>${this.#escapeHtml(filter.label)}</span>
63          ${this.#icon("chevron-down")}
64        </button>
65
66        <div class="${this.#escapeHtml(panelClasses)}" data-search-panel="${this.#escapeHtml(panelId)}" ${mobile||isOpen?"":"hidden"}>
67          <div
68            class="algolia-range-slider"
69            data-range-slider
70            data-range-attribute="${this.#escapeHtml(attribute)}"
71            data-range-min="${this.#escapeHtml(bounds.min)}"
72            data-range-max="${this.#escapeHtml(bounds.max)}"
73            style="${rangeStyle(min,max,bounds)}"
74          >
75            <div class="algolia-range-slider__inputs">
76              ${this.#rangeTextInput(attribute,"min",min,bounds.min,max)}
77              <div class="algolia-range-slider__inputs-divider" aria-hidden="true"></div>
78              ${this.#rangeTextInput(attribute,"max",max,min,bounds.max)}
79            </div>
80
81            <div class="algolia-range-slider__wrap" role="group" aria-label="${this.#escapeHtml(filter.label)}">
82              <label class="main-search__visually-hidden" for="${this.#escapeHtml(panelId)}-min">${this.#escapeHtml(this.#config.strings.priceMin)}</label>
83              <input
84                id="${this.#escapeHtml(panelId)}-min"
85                aria-label="${this.#escapeHtml(this.#config.strings.priceMin)}"
86                data-range-input
87                data-range-attribute="${this.#escapeHtml(attribute)}"
88                data-range-side="min"
89                type="range"
90                min="${this.#escapeHtml(bounds.min)}"
91                max="${this.#escapeHtml(bounds.max)}"
92                step="1"
93                value="${this.#escapeHtml(min)}"
94              >
95              <label class="main-search__visually-hidden" for="${this.#escapeHtml(panelId)}-max">${this.#escapeHtml(this.#config.strings.priceMax)}</label>
96              <input
97                id="${this.#escapeHtml(panelId)}-max"
98                aria-label="${this.#escapeHtml(this.#config.strings.priceMax)}"
99                data-range-input
100                data-range-attribute="${this.#escapeHtml(attribute)}"
101                data-range-side="max"
102                type="range"
103                min="${this.#escapeHtml(bounds.min)}"
104                max="${this.#escapeHtml(bounds.max)}"
105                step="1"
106                value="${this.#escapeHtml(max)}"
107              >
108            </div>
109
110            <div class="algolia-range-slider__indicators">
111              ${ticks.map(tick=>`
112                    <div class="algolia-range-slider__indicators-notch">
113                      <div class="algolia-range-slider__indicators-line"></div>
114                      <p class="algolia-range-slider__indicators-value text-body-sm">${this.#escapeHtml(tick)}</p>
115                    </div>
116                  `).join("")}
117            </div>
118          </div>
119
120          <div class="main-search__range-footer">
121            <p class="main-search__range-highest text-eyebrow-2xs">
122              ${this.#escapeHtml(this.#config.strings.highestPrice.replace("__price__",this.#formatMoney(stats.max)))}
123            </p>
124
125            <button class="main-search__range-reset text-eyebrow-2xs" type="button" data-range-reset="${this.#escapeHtml(attribute)}">
126              ${this.#escapeHtml(this.#config.strings.reset)}
127            </button>
128          </div>
129        </div>
130      </div>
131    `}#rangeTextInput(attribute,side,value,min,max){const label=side==="min"?this.#config.strings.priceMin:this.#config.strings.priceMax;return`
132      <div class="algolia-range-slider__inputs-wrapper">
133        <span class="algolia-range-slider__inputs-currency text-eyebrow-2xs">${this.#escapeHtml(this.#config.market.currencySymbol||"")}</span>
134        <input
135          aria-label="${this.#escapeHtml(label)}"
136          class="algolia-range-slider__inputs-input text-body-sm"
137          data-range-text
138          data-range-attribute="${this.#escapeHtml(attribute)}"
139          data-range-side="${this.#escapeHtml(side)}"
140          inputmode="numeric"
141          min="${this.#escapeHtml(min)}"
142          max="${this.#escapeHtml(max)}"
143          type="text"
144          value="${this.#escapeHtml(value)}"
145        >
146      </div>
147    `}#renderFacetValue(attribute,facet){const selected=this.#state.facets[attribute]?.includes(facet.value)||!1,isColour=this.#isColourAttribute(attribute),label=this.#formatFacetLabel(attribute,facet.value);return`
148      <li>
149        <button
150          class="main-search__facet-option ${isColour?"main-search__facet-option--colour":""} text-body-sm ${selected?"is-refined":""}"
151          type="button"
152          data-facet-attribute="${this.#escapeHtml(attribute)}"
153          data-facet-value="${this.#escapeHtml(facet.value)}"
154          aria-label="${this.#escapeHtml(`${label} (${String(facet.count).padStart(2,"0")})`)}"
155        >
156          ${isColour?this.#renderFacetSwatch(facet.value):'<span class="main-search__facet-checkbox"></span>'}
157          <span class="${isColour?"main-search__visually-hidden":""}">${this.#escapeHtml(label)}</span>
158          <span class="main-search__facet-count">(${String(facet.count).padStart(2,"0")})</span>
159        </button>
160      </li>
161    `}#renderProducts(response){const grid=this.querySelector("[data-main-search-products]"),pagination=this.querySelector('[data-main-search-pagination="product"]'),hits=response.hits||[];if(!grid)return;if(!hits.length){grid.innerHTML="",this.#renderPagination(pagination,response,"product");return}const products=hits.map((hit,index)=>this.#formatProduct(hit,{indexName:this.#state.sortIndex,position:(response.page||0)*(response.hitsPerPage||this.#state.pageSize)+index+1,queryID:response.queryID}));grid.innerHTML=products.map((product,index)=>this.#cardRenderer.render(product,index)).join(""),this.#hydrateProductSwatches(grid,products),this.#renderPagination(pagination,response,"product")}#renderActiveFilters(){const existing=this.querySelector("[data-main-search-active-filters]"),drawerContainer=this.querySelector("[data-main-search-drawer-active-filters]"),drawerClear=this.querySelector(".main-search__drawer-clear"),facetFilters=Object.entries(this.#state.facets).flatMap(([attribute,values])=>values.map(value=>({attribute,label:this.#formatFacetLabel(attribute,value),value}))),rangeFilters=Object.entries(this.#state.ranges).flatMap(([attribute,range])=>{const filters=[];return range.min!==null&&range.min!==void 0&&range.min!==""&&filters.push({attribute,label:`\u2265 ${this.#formatFacetLabel(attribute,range.min)}`,rangeSide:"min",value:String(range.min)}),range.max!==null&&range.max!==void 0&&range.max!==""&&filters.push({attribute,label:`\u2264 ${this.#formatFacetLabel(attribute,range.max)}`,rangeSide:"max",value:String(range.max)}),filters}),activeFilters=[...facetFilters,...rangeFilters],activeFilterButtons=className=>activeFilters.map(filter=>`
162            <button
163              class="${this.#escapeHtml(className)}"
164              type="button"
165              data-active-filter
166              data-filter-attribute="${this.#escapeHtml(filter.attribute)}"
167              data-filter-value="${this.#escapeHtml(filter.value)}"
168              ${filter.rangeSide?`data-filter-range-side="${this.#escapeHtml(filter.rangeSide)}"`:""}
169            >
170              <span>${this.#escapeHtml(filter.label)}</span>
171              ${this.#icon("close")}
172            </button>
173          `).join("");if(existing&&existing.remove(),!activeFilters.length){drawerContainer&&(drawerContainer.hidden=!0,drawerContainer.innerHTML=""),drawerClear&&(drawerClear.hidden=!0);return}drawerContainer&&(drawerContainer.hidden=!1,drawerContainer.innerHTML=activeFilterButtons("main-search__drawer-active-filter text-eyebrow-2xs")),drawerClear&&(drawerClear.hidden=!1);const container=document.createElement("div");container.className="main-search__active-filters container",container.dataset.mainSearchActiveFilters="",container.innerHTML=activeFilterButtons("main-search__active-filter text-body-sm")+`
174        <button class="main-search__active-clear text-body-sm" type="button" data-clear-all>
175          ${this.#escapeHtml(this.#config.strings.clearAll)}
176        </button>
177      `,this.querySelector("[data-main-search-product-toolbar]")?.after(container)}#renderResources(type,response){const container=this.querySelector(`[data-main-search-${type}s]`),pagination=this.querySelector(`[data-main-search-pagination="${type}"]`),hits=response.hits||[];container&&(container.innerHTML=hits.map(hit=>type==="collection"?this.#collectionTile(hit):this.#pageTile(hit,type)).join(""),this.#renderPagination(pagination,response,type))}#renderEmptyState(productsResult,suggestionsResult,trendingResult){const empty=this.querySelector("[data-main-search-empty]"),trending=this.querySelector("[data-main-search-trending]"),trendingGrid=this.querySelector("[data-main-search-trending-products]"),hasProducts=(productsResult.nbHits||0)>0,query=this.#state.query.trim();if(!empty||!trending||!trendingGrid)return;if(!query||hasProducts){empty.hidden=!0,trending.hidden=!0,trendingGrid.innerHTML="";return}const suggestions=suggestionsResult.hits||[];empty.hidden=!1,empty.innerHTML=`
178      <p class="algolia-filter__error-message container text-body-xs text-body-sm-desktop">
179        ${this.#escapeHtml(this.#stripHtml(this.#config.strings.noResults).replace("__query__",query))}
180      </p>
181      <p class="algolia-filter__error-message container text-body-xs text-body-sm-desktop">
182        ${this.#escapeHtml(this.#stripHtml(this.#config.strings.noResultsAdditional))}
183      </p>
184      ${suggestions.length?`
185        <div class="main-search__popular-searches">
186          <p class="text-eyebrow-2xs">${this.#escapeHtml(this.#config.strings.popularSearches)}</p>
187          <ul class="main-search__popular-list">
188            ${suggestions.map(suggestion=>`
189                  <li>
190                    <button class="main-search__popular-search text-eyebrow-2xs" type="button" data-popular-search="${this.#escapeHtml(suggestion.query||"")}">
191                      ${this.#escapeHtml(suggestion.query||"")}
192                    </button>
193                  </li>
194                `).join("")}
195          </ul>
196        </div>
197      `:""}
198    `;const trendingProducts=(trendingResult.hits||[]).map((hit,index)=>this.#formatProduct(hit,{indexName:this.#config.algolia.indexes.trendingProducts,position:index+1,queryID:trendingResult.queryID}));trending.hidden=!trendingProducts.length,trendingGrid.innerHTML=trendingProducts.map((product,index)=>this.#cardRenderer.render(product,index)).join(""),this.#hydrateProductSwatches(trendingGrid,trendingProducts)}#renderPagination(container,response,resource){const totalPages=response.nbPages||0,currentPage=this.#state.pages[resource]||0;if(!container||totalPages<=1){container&&(container.hidden=!0,container.innerHTML="");return}container.hidden=!1,container.innerHTML=`
199      <button class="main-search__pagination-button" type="button" data-search-page-resource="${resource}" data-search-page="${Math.max(currentPage-1,0)}" ${currentPage===0?"disabled":""}>
200        ${this.#icon("chevron-left")}
201      </button>
202      ${this.#visiblePages(currentPage,totalPages).map(page=>page===null?'<span class="main-search__pagination-ellipsis text-body-sm">...</span>':`<button class="main-search__pagination-button text-body-sm ${page===currentPage?"is-active":""}" type="button" data-search-page-resource="${resource}" data-search-page="${page}">${page+1}</button>`).join("")}
203      <button class="main-search__pagination-button" type="button" data-search-page-resource="${resource}" data-search-page="${Math.min(currentPage+1,totalPages-1)}" ${currentPage>=totalPages-1?"disabled":""}>
204        ${this.#icon("chevron-right")}
205      </button>
206    `}#renderPanels(){this.querySelectorAll("[data-resource-panel]").forEach(panel=>{panel.hidden=panel.dataset.resourcePanel!==this.#state.resource}),this.querySelectorAll("[data-resource-type]").forEach(button=>{button.classList.toggle("is-active",button.dataset.resourceType===this.#state.resource)})}async#hydrateProductSwatches(grid,products){const requestId=++this.#swatchRequestId,cards=[...grid.querySelectorAll("[data-product-card]")],familyTags=products.map(product=>
206this.#fetcher.familyTag(product)).filter(Boolean);if(!familyTags.length)return;const relatedProductsByTag=await this.#fetcher.fetchRelatedProductsBatch(familyTags);requestId===this.#swatchRequestId&&cards.forEach((card,index)=>{const product=products[index],familyTag=product?this.#fetcher.familyTag(product):"",relatedProducts=relatedProductsByTag.get(familyTag)||[];!product||!familyTag||!card.isConnected||this.#cardRenderer.renderSwatches(card,product,this.#fetcher.filterColourProducts(product,relatedProducts))})}#selectSwatch(swatch){const card=swatch.closest("[data-product-card]"),product=parseJson(swatch.dataset.product),currentProduct=this.#cardProduct(card);!card||!product||product.handle===currentProduct?.handle||this.#replaceCard(card,{...product,__indexName:currentProduct?.__indexName||product.__indexName,__position:currentProduct?.__position||product.__position,__queryID:currentProduct?.__queryID||product.__queryID})}#replaceCard(card,product){const cards=[...card.closest(".main-search__grid")?.querySelectorAll("[data-product-card]")||[]],index=Math.max(cards.indexOf(card),0),template=document.createElement("template");template.innerHTML=this.#cardRenderer.render(product,index).trim();const newCard=template.content.firstElementChild;newCard&&(newCard.className=card.className,card.replaceWith(newCard),this.#hydrateCardSwatches(newCard,product))}async#hydrateCardSwatches(card,product){const familyTag=this.#fetcher.familyTag(product);if(!familyTag)return;const relatedProducts=(await this.#fetcher.fetchRelatedProductsBatch([familyTag])).get(familyTag)||[];card.isConnected&&this.#cardRenderer.renderSwatches(card,product,this.#fetcher.filterColourProducts(product,relatedProducts))}#collectionTile(collection){return`
207      <a class="main-search__collection-tile text-body-xs text-body-sm-desktop" href="${this.#escapeHtml(this.#resourceUrl("collections",collection.handle))}">
208        <span>${this.#escapeHtml(collection.title||"")}</span>
209        ${this.#icon("chevron-right")}
210      </a>
211    `}#pageTile(item,type){const image=type==="article"&&item.image?item.image:"";return`
212      <a class="main-search__page-tile" href="${this.#escapeHtml(this.#resourceUrl(type==="article"?"articles":"pages",item.handle,item))}">
213        ${image?`<img class="main-search__page-tile-image" src="${this.#escapeHtml(image)}" alt="${this.#escapeHtml(item.title||"")}" loading="lazy" decoding="async">`:""}
214        <div class="main-search__page-tile-content">
215          <div class="main-search__page-tile-title">
216            <p class="text-title-sans-sm">${this.#escapeHtml(item.title||"")}</p>
217            ${this.#icon("chevron-right")}
218          </div>
219          ${item.body_html_safe?`<p class="main-search__page-tile-excerpt text-body-xs">${this.#escapeHtml(this.#stripHtml(item.body_html_safe))}</p>`:""}
220        </div>
221      </a>
222    `}#formatProduct(hit,options={}){return this.#fetcher.formatProduct(hit,options)}#contentTypeLabel(type,total){return(this.#config.strings.contentSwitcher[type]||this.#config.strings.contentSwitcher.type).replace("__type__",type).replace("__total__",total)}#visiblePages(currentPage,totalPages){const pages=new Set([0,totalPages-1,currentPage]);currentPage>0&&pages.add(currentPage-1),currentPage<totalPages-1&&pages.add(currentPage+1);const sorted=[...pages].sort((a,b)=>a-b),visible=[];return sorted.forEach((page,index)=>{index>0&&page-sorted[index-1]>1&&visible.push(null),visible.push(page)}),visible}#togglePanel(name){if(name.startsWith("mobile-")){this.#state.openPanel=this.#state.openPanel===name?null:name,this.#syncMobileAccordions();return}const panel=this.querySelector(`[data-search-panel="${name}"]`),toggle=this.querySelector(`[data-search-panel-toggle="${name}"]`);if(!panel||!toggle)return;const isOpen=panel.hidden;this.#closePanels(),this.#state.openPanel=isOpen?name:null,panel.hidden=!isOpen,toggle.setAttribute("aria-expanded",String(isOpen)),isOpen&&this.#positionOpenPanels()}#openDrawer(){this.#state.drawerOpen=!0,this.#state.openPanel=null;const drawer=this.querySelector("[data-main-search-drawer]");drawer&&(clearTimeout(this.#drawerAnimationTimer),drawer.classList.remove("is-closing"),drawer.classList.add("is-open")),this.#syncMobileAccordions(),document.body.style.overflow="hidden",document.documentElement.classList.add("overflow-hidden")}#closeDrawer(){this.#state.drawerOpen=!1;const drawer=this.querySelector("[data-main-search-drawer]");if(drawer){clearTimeout(this.#drawerAnimationTimer),drawer.classList.remove("is-open"),drawer.classList.add("is-closing"),this.#drawerAnimationTimer=setTimeout(()=>{drawer.classList.remove("is-closing"),document.body.style.overflow="",document.documentElement.classList.remove("overflow-hidden")},DRAWER_ANIMATION_MS);return}document.body.style.overflow="",document.documentElement.classList.remove("overflow-hidden")}#toggleFacet(attribute,value){if(!attribute||!value)return;const values=this.#state.facets[attribute]||[];values.includes(value)?this.#state.facets[attribute]=values.filter(item=>item!==value):this.#state.facets[attribute]=[...values,value],this.#state.facets[attribute].length||delete this.#state.facets[attribute],this.#state.pages.product=0,this.#writeSearchUrl(),this.#search()}#removeActiveFilter(attribute,value,rangeSide=""){if(rangeSide&&this.#state.ranges[attribute]){delete this.#state.ranges[attribute][rangeSide],!this.#state.ranges[attribute].min&&!this.#state.ranges[attribute].max&&delete this.#state.ranges[attribute],this.#state.pages.product=0,this.#writeSearchUrl(),this.#search();return}!attribute||!value||!this.#state.facets[attribute]||(this.#state.facets[attribute]=this.#state.facets[attribute].filter(item=>item!==value),this.#state.facets[attribute].length||delete this.#state.facets[attribute],this.#state.pages.product=0,this.#writeSearchUrl(),this.#search())}#clearAllFilters(){this.#state.facets={},this.#state.ranges={},this.#state.openPanel=null,this.#state.pages.product=0,this.#closeDrawer(),this.#writeSearchUrl(),this.#search()}#resolvedFilterOptions(){const options=this.#config.algolia.filterOptions?.length?this.#config.algolia.filterOptions:this.#defaultFilterOptions();return resolveFilterOptions({filterOptions:options,includeFilter:filter=>this.#isSearchFacet(filter),marketHandle:this.#config.market.handle})}#defaultFilterOptions(){return defaultSearchFilterOptions(this.#config.strings.filterLabels)}#isSearchFacet(filter){const label=String(filter.label||"").toLowerCase(),value=String(filter.value||"").toLowerCase();return label!=="subcategory"&&!value.includes("subcategory")}#closePanels(){const panelId=this.#state.openPanel;if(this.#state.openPanel=null,panelId?.startsWith("mobile-")){this.#syncMobileAccordions();return}this.querySelectorAll("[data-search-panel]").forEach(panel=>{panel.hidden=!0,panel.classList.remove("is-flipped")}),this.querySelectorAll("[data-search-panel-toggle]").forEach(toggle=>
222{toggle.setAttribute("aria-expanded","false")})}#syncMobileAccordions(){const drawer=this.querySelector("[data-main-search-drawer]");drawer&&drawer.querySelectorAll('[data-search-panel-toggle^="mobile-"]').forEach(toggle=>{const isOpen=toggle.dataset.searchPanelToggle===this.#state.openPanel,facet=toggle.closest(".main-search__facet"),panel=facet?.querySelector(".main-search__facet-panel");toggle.setAttribute("aria-expanded",isOpen?"true":"false"),panel?.style.setProperty("--mobile-panel-height",`${panel.scrollHeight}px`),facet?.classList.toggle("is-active",isOpen),panel?.classList.toggle("is-open",isOpen)})}#positionOpenPanels(){const toolbar=this.querySelector("[data-main-search-product-toolbar]");if(!toolbar)return;const panels=toolbar.querySelectorAll(".main-search__facet-panel, .main-search__sort-panel"),viewportWidth=document.documentElement.clientWidth,gutter=16;panels.forEach(panel=>{if(panel.classList.remove("is-flipped"),panel.hidden)return;panel.getBoundingClientRect().right>viewportWidth-gutter&&panel.classList.add("is-flipped")})}#resetPages(){this.#state.resource="product",this.#state.facets={},this.#state.ranges={},this.#state.openPanel=null,this.#state.pages={product:0,collection:0,article:0,page:0}}#writeSearchUrl(){const params=new URLSearchParams(window.location.search);this.#state.query.trim()?params.set("query",this.#state.query.trim()):params.delete("query"),params.delete("q"),this.#state.pages.product>0?params.set("page",String(this.#state.pages.product+1)):params.delete("page");const sort=this.#config.algolia.sortByOptions.find(option=>option.value===this.#state.sortIndex);sort&&sort.id!=="relevance"?params.set("sort",sort.id):params.delete("sort"),this.#resolvedFilterOptions().forEach(filter=>{const key=this.#urlKey(filter);if(isPriceAttribute(filter.value)){const range=this.#state.ranges[filter.value];range?params.set(key,`${range.min||""}:${range.max||""}`):params.delete(key);return}this.#state.facets[filter.value]?.length?params.set(key,this.#state.facets[filter.value].map(value=>this.#cleanValue(value)).join(",")):params.delete(key)});const query=params.toString();window.history.replaceState({},"",query?`${window.location.pathname}?${query}`:window.location.pathname)}#setLoading(isLoading){this.classList.toggle("is-loading",isLoading)}#renderError(){const grid=this.querySelector("[data-main-search-products]");grid&&(grid.innerHTML=`<p class="main-search__empty text-body-md">${this.#escapeHtml(this.#config.strings.noProducts)}</p>`)}#totalCount(counts){return Object.values(counts).reduce((sum,count)=>sum+count,0)}#resourceUrl(type,handle,item={}){if(!handle)return getLocalisedRoute(this.#config.routes.root);if(type==="articles"){const blogHandle=item.blog?.handle||item.blog_handle||"news";return getLocalisedRoute(`${this.#config.market.rootUrl}blogs/${blogHandle}/${handle}`)}return getLocalisedRoute(`${this.#config.market.rootUrl}${type}/${handle}`)}#pageFromUrl(){const page=new URLSearchParams(window.location.search).get("page");return this.#pageIndexFromParam(page)}#pageIndexFromParam(value){const page=Number(value);return!Number.isInteger(page)||page<1?0:page-1}#queryFromUrl(){return new URLSearchParams(window.location.search).get("query")||""}#facetsFromUrl(){const params=new URLSearchParams(window.location.search),facets={};return this.#resolvedFilterOptions().forEach(filter=>{if(isPriceAttribute(filter.value))return;const value=params.get(this.#urlKey(filter));value&&(facets[filter.value]=value.split(",").map(item=>item.trim()).filter(Boolean))}),facets}#rangesFromUrl(){const params=new URLSearchParams(window.location.search),ranges={};return this.#resolvedFilterOptions().forEach(filter=>{if(!isPriceAttribute(filter.value))return;const value=params.get(this.#urlKey(filter));if(!value)return;const[min,max]=value.split(":");ranges[filter.value]={min,max}}),ranges}#hasAlgoliaConfig(){return!!(this.#config.algolia.appId&&this.#config.algolia.apiKey&&this.#config.algolia.indexName)}#cardProduct(card){return parseJson(card?.querySelector("[data-card-product]")?.textContent)}#stripHtml(value){const element=document.createElement("div");return element.innerHTML=value||"",element.textContent||""}#syncRangeControls(input,options={}){const{commit=!1}=options,slider=input.closest("[data-range-slider]");if(!slider?.dataset.rangeAttribute)return;const attribute=slider.dataset.rangeAttribute,minAllowed=Number(slider.dataset.rangeMin||0),maxAllowed=Number(slider.dataset.rangeMax||0),minRange=slider.querySelector('[data-range-input][data-range-side="min"]'),maxRange=slider.querySelector('[data-range-input][data-range-side="max"]'),minText=slider.querySelector('[data-range-text][data-range-side="min"]'),maxText=slider.querySelector('[data-range-text][data-range-side="max"]'),side=input.dataset.rangeSide;let min=Number(minRange?.value||minAllowed),max=Number(maxRange?.value||maxAllowed);const rawValue=input.value.trim();if(!commit&&input.matches("[data-range-text]")&&rawValue==="")return;const inputValue=Number(rawValue);Number.isFinite(inputValue)&&(side==="min"?min=clamp(inputValue,minAllowed,max):max=clamp(inputValue,min,maxAllowed)),min=Math.round(clamp(min,minAllowed,maxAllowed)),max=Math.round(clamp(max,minAllowed,maxAllowed)),min>max&&(side==="min"?min=max:max=min),minRange&&(minRange.value=String(min)),maxRange&&(maxRange.value=String(max)),minText&&(minText.value=String(min),minText.max=String(max)),maxText&&(maxText.value=String(max),maxText.min=String(min));const bounds={min:minAllowed,max:maxAllowed};slider.style.setProperty("--range-start",`${rangePercent(min,bounds)}%`),slider.style.setProperty("--range-end",`${rangePercent(max,bounds)}%`),commit&&this.#commitRange(attribute,min,max,bounds)}#commitRange(attribute,min,max,bounds){attribute&&(this.#state.ranges[attribute]={min:String(min),max:String(max)},this.#state.pages.product=0,this.#writeSearchUrl(),this.#search())}#resetRange(attribute){attribute&&(delete this.#state.ranges[attribute],this.#state.pages.product=0,this.#writeSearchUrl(),this.#search())}#formatMoney(value){return`${this.#config.market.currencySymbol||""}${Math.round(Number(value)||0)}`}#formatFacetLabel(attribute,value){if(this.#isColourAttribute(attribute)){const parts=String(value).split("-");return parts.length>2?`${parts[0]}/${parts[2]}`:parts[0]||value}return isPriceAttribute(attribute)?`${this.#config.market.currencySymbol||""}${value}`:String(value).replace(/-/g," ")}#isColourAttribute(attribute){const normalized=String(attribute).toLowerCase();return normalized.includes("colour")||normalized==="color"}#renderFacetSwatch(value){const parts=String(value).split("-"),color=parts[1]||"#ffffff",colorTwo=p
222arts[3]||"",gradient=colorTwo?`background: linear-gradient(90deg, ${this.#escapeHtml(color)} 50%, ${this.#escapeHtml(colorTwo)} 50%)`:"";return`<span class="main-search__swatch" style="--swatch-color: ${this.#escapeHtml(color)}; ${gradient}"></span>`}#urlKey(filter){return`filter.${this.#handleize(filter.value)}`}#cleanValue(value){return String(value)}#handleize(value){return String(value).trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}#icon(name){return window.icons?.[name]||""}#isMobile(){return window.matchMedia("(width < 1024px)").matches}#escapeHtml(value){return escapeHtml(value)}#parseConfig(){return parseJson(this.querySelector("[data-main-search-config]")?.textContent)}}customElements.get("lyle-main-search")||customElements.define("lyle-main-search",LyleMainSearch);
223//# sourceMappingURL=/cdn/shop/t/458/assets/lyle-main-search.js.map?v=166387193700761270121788364387

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.