@nosto/search-js 3.21.0 → 3.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,5 +8,22 @@ export type SearchHitWithSku = SearchHit & {
8
8
  * @param type - The type of search that the hit belongs to.
9
9
  * @param hit - The search hit to add to the cart.
10
10
  * @param quantity - The quantity of the hit to add to the cart.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { addToCart } from '@nosto/search-js'
15
+ *
16
+ * // Add a single product to cart
17
+ * await addToCart('serp', {
18
+ * productId: '123',
19
+ * skuId: 'sku-123'
20
+ * })
21
+ *
22
+ * // Add multiple quantities
23
+ * await addToCart('serp', {
24
+ * productId: '456',
25
+ * skuId: 'sku-456'
26
+ * }, 3)
27
+ * ```
11
28
  */
12
29
  export declare function addToCart(type: SearchTrackOptions, hit: SearchHitWithSku, quantity?: number): Promise<void>;
@@ -6,5 +6,33 @@ import { DecoratedResult, HitDecorator, SearchOptions } from './types';
6
6
  * @param query - The search query to be executed.
7
7
  * @param options - An object containing optional parameters for the search.
8
8
  * @returns A promise that resolves to the search result.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { search } from '@nosto/search-js'
13
+ * import { priceDecorator } from '@nosto/search-js/currencies'
14
+ *
15
+ * // Basic search
16
+ * const results = await search({ query: 'shoes' })
17
+ *
18
+ * // Search with decorators
19
+ * const decoratedResults = await search(
20
+ * { query: 'shoes' },
21
+ * { hitDecorators: [priceDecorator()] }
22
+ * )
23
+ * ```
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { search } from '@nosto/search-js'
28
+ *
29
+ * // Search with filters
30
+ * const results = await search({
31
+ * query: 'shoes',
32
+ * filters: {
33
+ * color: ['red', 'blue']
34
+ * }
35
+ * })
36
+ * ```
9
37
  */
10
38
  export declare function search<HD extends readonly HitDecorator[]>(query: SearchQuery, options?: SearchOptions<HD>): Promise<DecoratedResult<HD>>;
@@ -5,6 +5,43 @@ export interface CurrencyConfig {
5
5
  defaultLocale: string;
6
6
  currencySettings: CurrencyFormats;
7
7
  }
8
+ /**
9
+ * Creates a currency formatting function with customizable settings.
10
+ *
11
+ * @param overrides - Optional configuration to override default currency settings.
12
+ * @returns An object containing the formatCurrency function.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { getCurrencyFormatting } from '@nosto/search-js/currencies'
17
+ *
18
+ * // Use default settings from Nosto
19
+ * const { formatCurrency } = getCurrencyFormatting()
20
+ * console.log(formatCurrency(1234.56)) // Uses default currency
21
+ * console.log(formatCurrency(1234.56, 'USD')) // "$1,234.56"
22
+ * ```
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { getCurrencyFormatting } from '@nosto/search-js/currencies'
27
+ *
28
+ * // Override with custom settings
29
+ * const { formatCurrency } = getCurrencyFormatting({
30
+ * defaultCurrency: 'EUR',
31
+ * defaultLocale: 'de-DE',
32
+ * currencySettings: {
33
+ * EUR: {
34
+ * currencyBeforeAmount: false,
35
+ * currencyToken: '€',
36
+ * decimalCharacter: ',',
37
+ * groupingSeparator: '.',
38
+ * decimalPlaces: 2
39
+ * }
40
+ * }
41
+ * })
42
+ * console.log(formatCurrency(1234.56)) // "1.234,56€"
43
+ * ```
44
+ */
8
45
  export declare function getCurrencyFormatting(overrides?: Partial<CurrencyConfig>): {
9
46
  formatCurrency: (value: number, currency?: string) => string;
10
47
  };
@@ -8,8 +8,49 @@ export type Result = SearchProduct & FormattedPrices & {
8
8
  skus?: (SearchProductSku & FormattedPrices)[];
9
9
  };
10
10
  /**
11
- * Exposes currency formatting logic as a SearchProduct decorator
12
- * Sets priceText and listPriceText fields on product and SKU level
13
- * Requires price, listPrice and priceCurrencyCode fields to be present
11
+ * Exposes currency formatting logic as a SearchProduct decorator.
12
+ * Sets priceText and listPriceText fields on product and SKU level.
13
+ * Requires price, listPrice and priceCurrencyCode fields to be present.
14
+ *
15
+ * @param config - Optional configuration to customize currency formatting.
16
+ * @returns A decorator function that adds formatted price text to search products.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { search } from '@nosto/search-js'
21
+ * import { priceDecorator } from '@nosto/search-js/currencies'
22
+ *
23
+ * // Use with default settings
24
+ * const results = await search(
25
+ * { query: 'shoes' },
26
+ * { hitDecorators: [priceDecorator()] }
27
+ * )
28
+ * console.log(results.products.hits[0].priceText) // "$99.99"
29
+ * ```
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { search } from '@nosto/search-js'
34
+ * import { priceDecorator } from '@nosto/search-js/currencies'
35
+ *
36
+ * // Use with custom currency settings
37
+ * const customDecorator = priceDecorator({
38
+ * defaultCurrency: 'EUR',
39
+ * currencySettings: {
40
+ * EUR: {
41
+ * currencyBeforeAmount: true,
42
+ * currencyToken: '€',
43
+ * decimalCharacter: ',',
44
+ * groupingSeparator: '.',
45
+ * decimalPlaces: 2
46
+ * }
47
+ * }
48
+ * })
49
+ * const results = await search(
50
+ * { query: 'shoes' },
51
+ * { hitDecorators: [customDecorator] }
52
+ * )
53
+ * console.log(results.products.hits[0].priceText) // "€99,99"
54
+ * ```
14
55
  */
15
56
  export declare function priceDecorator(config?: Partial<CurrencyConfig>): (hit: SearchProduct) => Result;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("../../useActions-CY9uts_o.cjs"),P=require("../../logger-Boh_C6Bz.cjs"),h=require("../../useLoadMore-CBshMpps.cjs"),R=require("../../eventBusSubscribe-oONOUGH8.cjs"),l=require("preact/hooks"),C=require("../../useHistory-rc2PvSkv.cjs"),q=require("../../index.es-Dp6Iaxz3.cjs"),z=require("../../eventBusDispatch-BKQcSHAB.cjs"),F=require("../../parseNumber-FsZ8w61u.cjs");function O(e){const s=h.useNostoAppState(t=>t.response);return e&&Array.isArray(e)||e&&P.isPlainObject(e)?e:s}function X(e,s){const t=e.data?.filter(f=>f.selected).length??0,{active:o}={active:t>0,...s},[n,u]=l.useState(o),{toggleProductFilter:c}=A.useActions(),a=l.useCallback(()=>{u(!n)},[n]);return R.useEventBusSubscribe({event:"events/removeAllFilters",callback:()=>{u(!1)}}),{active:n,selectedFiltersCount:t,toggleActive:a,toggleProductFilter:c}}function E(){const{loading:e,facets:s}=h.useNostoAppState(t=>({loading:t.loading,facets:t.response?.products?.facets??[]}));return{loading:e,facets:s}}function j(e,s){const t=s-e;return!isNaN(t)&&t>0?new Array(s-e).fill(void 0).map((o,n)=>n+e):[]}function B(e){const{query:s,products:t}=h.useNostoAppState(o=>({query:o.query,products:o.response.products}));return l.useMemo(()=>{if(!t)return{totalPages:0,resultsFrom:0,resultsTo:0,pages:[]};const o=s.products?.from??0,n=e?.width??1/0,u=Math.max(Math.floor(n-1)/2,1),c=t.size>0?Math.floor(o/t.size)+1:1,a=t.size>0?Math.ceil(t.total/t.size):0,f=y=>y>=c-u&&y<=c+u,r=o+1,i=Math.min(o+t.total,t.total),d={from:o,page:c,current:!0},p=y=>({from:(y-1)*t.size,page:y,current:y===c}),S=c>1?p(c-1):void 0,v=c<a?p(c+1):void 0,m=c-u-1>1?p(1):void 0,g=c+u+1<a?p(a):void 0,b=j(1,a+1).filter(f).map(p);return!m&&b[0]?.page===2&&b.unshift(p(1)),!g&&b[b.length-1]?.page===a-1&&b.push(p(a)),{totalPages:a,resultsFrom:r,resultsTo:i,current:d,prev:S,next:v,first:m,last:g,pages:b}},[s,t,e?.width])}function V(){const[e,s]=l.useState([]),[t,o]=l.useState([]);return l.useEffect(()=>{q.s(async n=>{const{products:u,segments:c}=await n.getSearchSessionParams();s(c??[]),o(u?.personalizationBoost??[])})},[]),{segments:e,boost:t}}function D(){const{facets:e}=h.useNostoAppState(r=>({facets:r.response.products?.facets??[]})),{replaceFilter:s,toggleProductFilter:t}=A.useActions(),o=l.useCallback(r=>{const i=e?.find(d=>d.type==="stats"&&d.field===r);if(i&&"min"in i&&"max"in i)return i},[e]),n=l.useCallback(r=>e?.find(i=>i.field===r)?.name??r,[e]),u=l.useCallback(r=>"field"in r&&(r.value instanceof Array||r.range instanceof Array),[]),c=l.useCallback(r=>({...r,range:r.range?.map(i=>({gt:i.gt?Number(i.gt):i.gt,gte:i.gte?Number(i.gte):i.gte,lt:i.lt?Number(i.lt):i.lt,lte:i.lte?Number(i.lte):i.lte}))}),[]),a=l.useCallback(r=>(r.value??[]).map(d=>({value:d,field:r.field,name:n(r.field),filter:c(r),remove:()=>{t(r.field,d,!1)}})),[c,n,t]),f=l.useCallback(r=>(r.range??[]).map(d=>{const p=d.gte??d.gt??o(r.field)?.min,S=d.lte??d.lt??o(r.field)?.max;if(p!==void 0&&S!==void 0)return{value:`${p} - ${S}`,field:r.field,name:n(r.field),filter:c(r),remove:()=>{s(r.field,void 0)}}}).filter(Boolean),[c,o,n,s]);return{selectFilters:u,toValueFilter:a,toRangeFilter:f}}function L(){const{filter:e}=h.useNostoAppState(a=>({filter:a.query.products?.filter??[]})),{updateSearch:s}=A.useActions(),{selectFilters:t,toValueFilter:o,toRangeFilter:n}=D(),u=l.useMemo(()=>e?e.filter(t).flatMap(a=>"value"in a?o(a):"range"in a?n(a):[]).filter(Boolean):[],[e,t,n,o]),c=l.useCallback(()=>{s({products:{filter:[]}}),z.dispatchNostoEvent({event:"events/removeAllFilters",params:null})},[s]);return{filters:u,removeAll:c}}function T(e){const{replaceFilter:s}=A.useActions(),{query:t,products:o}=h.useNostoAppState(g=>({query:g.query,products:g.response.products})),n=o?.facets?.find(g=>g.id===e),u=t.products?.filter?.find(g=>g.field===n?.field),[c,a]=_(u),f=n&&"min"in n?Math.floor(n.min??0):0,r=n&&"max"in n?Math.ceil(n.max??0):0,i=l.useMemo(()=>[c??f,a??r],[c,a,f,r]),d=c!==void 0||a!==void 0,[p,S]=l.useState(d),v=l.useCallback(()=>{S(g=>!g)},[]),m=l.useCallback(([g,b])=>{if(!n)return;const y=$(g,b,f,r);s(n.field,y)},[f,r,s,n]);return R.useEventBusSubscribe({event:"events/removeAllFilters",callback:()=>{S(!1)}}),n?{min:f,max:r,range:i,updateRange:m,active:p,toggleActive:v}:H}const H={min:0,max:0,range:[0,0],active:!1,toggleActive:()=>{},updateRange:()=>{}};function _(e){const s=e?.range?.[0];return typeof s=="object"&&("gte"in s||"lte"in s)?[F.parseNumber(s.gte),F.parseNumber(s.lte)]:[void 0,void 0]}function $(e,s,t,o){const n=e!==void 0?Math.floor(e):void 0,u=s!==void 0?Math.ceil(s):void 0,c=n!==void 0,a=u!==void 0;if((t===n||!c)&&(o===u||!a))return;const f={};return c&&n!==t&&(f.gte=n.toString()),a&&u!==o&&(f.lte=u.toString()),Object.keys(f).length>0?f:void 0}function U(e,s){const{min:t,max:o,range:n,updateRange:u}=T(e),{filters:c}=L(),a=l.useMemo(()=>{const d=c.find(m=>m?.filter?.range);let p=null;if(d){const m=d.filter.range?.[0];p=[F.parseNumber(m?.gte),F.parseNumber(m?.lte)]}const S=[];let v=Math.floor(t/s)*s;for(;v<o;){const m=v+s,g=p&&p[0]===v&&p[1]===m;S.push({min:v,max:m,selected:g}),v=m}return S},[c,t,o,s]),f=l.useCallback(d=>{u([d,n[1]])},[n,u]),r=l.useCallback(d=>{u([n[0],d])},[n,u]),i=t!==n[0]||o!==n[1];return{min:t,max:o,range:n,updateRange:u,ranges:a,handleMinChange:f,handleMaxChange:r,isSelected:i}}function I(){const{products:e,keywords:s}=h.useNostoAppState(t=>({products:t.response.products??{hits:[],total:0},keywords:t.response.keywords??{hits:[],total:0}}));return{products:e,keywords:s}}function K(){const e=h.useNostoAppState(t=>t.query.products?.filter);return l.useMemo(()=>e?e.reduce((t,o)=>t+(Array.isArray(o.value)?o.value.length:1),0):0,[e])}const Z=5*60*1e3,N=new Map;function G(e){const[s,t]=l.useState({product:null,loading:!0,error:null});return l.useEffect(()=>{if(!e){t({product:null,loading:!1,error:"Product handle is required"});return}t(n=>({...n,loading:!0,error:null}));const o=Q(e);if(o){t({product:o,loading:!1,error:null});return}J(e).then(n=>{W(e,n),t({product:n,loading:!1,error:null})}).catch(n=>{t({product:null,loading:!1,error:n.message||"Failed to fetch product"})})},[e]),s}async function J(e){const s=await fetch(`/products/${e}.js`);if(!s.ok)throw new Error(`Failed to fetch product: ${s.status} ${s.statusText}`);return s.json()}function Q(e){const s=N.get(e);return s?Date.now()-s.created>Z?(N.delete(e),null):s.product:null}function W(e,s){N.set(e,{product:s,created:Date.now()})}function k(e){return e&&!Number.isNaN(e)?e:0}function Y(e,s){const{from:t,size:o,total:n}=h.useNostoAppState(r=>({from:k(r.query.products?.from??0),size:k(r.response?.products?.size??s),total:k(r.response?.products?.total??0)})),{updateSearch:u}=A.useActions(),c=t+o,a=l.useMemo(()=>[...e].reverse().filter(r=>r<n),[e,n]),f=l.useCallback(r=>{u({products:{size:F.parseNumber(r)}})},[u]);return{from:t,to:c,total:n,size:o,sizeOptions:a,handleSizeChange:f}}function ee(e,s){return e.length!==s.length?!1:e.every(t=>s.find(o=>t.field===o.field&&t.order===o.order))}function te(e){const s=h.useNostoAppState(u=>u.query),{updateSearch:t}=A.useActions(),o=e.find(u=>ee(u.value.sort,s.products?.sort||[]))?.id??e[0]?.id,n=l.useCallback(u=>{const c=e.find(a=>a.id===u);c&&t({products:{sort:c.value.sort}})},[e,t]);return{activeSort:o,setSort:n}}const w=window.SpeechRecognition||window.webkitSpeechRecognition,x=!!(w&&typeof w=="function");function se(){return{listening:!1,startListening:()=>{},stopListening:()=>{}}}function ne({language:e="en-US",interimResults:s=!1,onResult:t,onError:o}={}){const[n,u]=l.useState(!1),c=l.useRef(null),a=l.useCallback(()=>{const r=new w;r.lang=e,r.interimResults=s,r.onstart=()=>u(!0),t&&(r.onresult=i=>{const{transcript:d}=i.results?.[0]?.[0];t(d)}),o&&(r.onerror=i=>o(i.error)),r.onend=()=>u(!1),c.current=r,r.start()},[e,s,o,t]),f=l.useCallback(()=>{c.current?.stop()},[c]);return{listening:n,startListening:a,stopListening:f}}const oe=x?ne:se;function re(e,s){if(!e.length||!s.length)return[];const t=s.reduce((o,n)=>(o[n]={},o),{});return e.forEach(o=>{o.customFields?.forEach(({key:n,value:u})=>{const c=n.toLowerCase();s.includes(c)&&(t[c][u]=t[c][u]||[],t[c][u].push(o))})}),Object.entries(t).filter(o=>Object.keys(o[1]).length).map(([o,n])=>({field:o,options:Object.entries(n).map(([u,c])=>({value:u,skus:c,unavailable:!1,selected:!1}))}))}function ue(e,s){return e.length?e.map(({field:t,options:o})=>({field:t,options:o.map(n=>{const u=!n.skus?.some(a=>Object.entries(s).every(([f,r])=>f===t?!0:a.customFields?.find(d=>d.key.toLowerCase()===f)?.value===r)),c=s[t]===n.value;return{...n,unavailable:u,selected:c}})})):[]}const M=["4XS","3XS","2XS","XXS","XS","S","M","L","XL","XXL","2XL","XXXL","3XL","4XL"];function ce(e){if(M.includes(e))return 1e3+M.indexOf(e);const s=parseFloat(e);return isNaN(s)?e:s}function ie(e,s){return[...s].sort((t,o)=>{const[n,u]=[t.value,o.value].map(ce);return n<u?-1:1})}function ae(e=[],s=[]){const[t,o]=l.useState({}),n=l.useMemo(()=>re(e,s).map(({field:r,options:i})=>({field:r,options:ie(r,i)})),[e,s]),u=l.useMemo(()=>ue(n,t),[n,t]),c=l.useCallback((f,r)=>{o(i=>{const d={...i};return d[f]===r?delete d[f]:d[f]=r,d})},[]),a=l.useMemo(()=>Object.keys(t).filter(i=>t[i]).length===0?[]:u.filter(({field:i})=>t[i]).map(({field:i,options:d})=>{const p=t[i];return d.find(v=>v.value===p)?.skus??[]}).reduce((i,d)=>i.filter(p=>d.includes(p))),[u,t]);return{swatches:u,toggleOption:c,matchedSkus:a}}exports.useActions=A.useActions;exports.useLoadMore=h.useLoadMore;exports.useNostoAppState=h.useNostoAppState;exports.addToHistory=C.addToHistory;exports.getSavedHistory=C.getSavedHistory;exports.useHistory=C.useHistory;exports.speechToTextSupported=x;exports.useDecoratedSearchResults=O;exports.useFacet=X;exports.useFacets=E;exports.usePagination=B;exports.usePersonalization=V;exports.useProductFilters=L;exports.useRange=T;exports.useRangeSelector=U;exports.useResponse=I;exports.useSelectedFiltersCount=K;exports.useShopifyProduct=G;exports.useSizeOptions=Y;exports.useSort=te;exports.useSpeechToText=oe;exports.useSwatches=ae;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("../../useActions-CY9uts_o.cjs"),P=require("../../logger-Boh_C6Bz.cjs"),h=require("../../useLoadMore-CBshMpps.cjs"),R=require("../../eventBusSubscribe-oONOUGH8.cjs"),l=require("preact/hooks"),C=require("../../useHistory-rc2PvSkv.cjs"),q=require("../../index.es-Dp6Iaxz3.cjs"),z=require("../../eventBusDispatch-BKQcSHAB.cjs"),F=require("../../parseNumber-FsZ8w61u.cjs");function O(e){const s=h.useNostoAppState(t=>t.response);return e&&Array.isArray(e)||e&&P.isPlainObject(e)?e:s}function X(e,s){const t=e.data?.filter(f=>f.selected).length??0,{active:o}={active:t>0,...s},[n,c]=l.useState(o),{toggleProductFilter:u}=A.useActions(),a=l.useCallback(()=>{c(!n)},[n]);return R.useEventBusSubscribe({event:"events/removeAllFilters",callback:()=>{c(!1)}}),{active:n,selectedFiltersCount:t,toggleActive:a,toggleProductFilter:u}}function E(){const{loading:e,facets:s}=h.useNostoAppState(t=>({loading:t.loading,facets:t.response?.products?.facets??[]}));return{loading:e,facets:s}}function j(e,s){const t=s-e;return!isNaN(t)&&t>0?new Array(s-e).fill(void 0).map((o,n)=>n+e):[]}function B(e){const{query:s,products:t}=h.useNostoAppState(o=>({query:o.query,products:o.response.products}));return l.useMemo(()=>{if(!t)return{totalPages:0,resultsFrom:0,resultsTo:0,pages:[]};const o=s.products?.from??0,n=e?.width??1/0,c=Math.max(Math.floor(n-1)/2,1),u=t.size>0?Math.floor(o/t.size)+1:1,a=t.size>0?Math.ceil(t.total/t.size):0,f=y=>y>=u-c&&y<=u+c,r=o+1,i=Math.min(o+t.total,t.total),d={from:o,page:u,current:!0},p=y=>({from:(y-1)*t.size,page:y,current:y===u}),S=u>1?p(u-1):void 0,v=u<a?p(u+1):void 0,m=u-c-1>1?p(1):void 0,g=u+c+1<a?p(a):void 0,b=j(1,a+1).filter(f).map(p);return!m&&b[0]?.page===2&&b.unshift(p(1)),!g&&b[b.length-1]?.page===a-1&&b.push(p(a)),{totalPages:a,resultsFrom:r,resultsTo:i,current:d,prev:S,next:v,first:m,last:g,pages:b}},[s,t,e?.width])}function V(){const[e,s]=l.useState([]),[t,o]=l.useState([]);return l.useEffect(()=>{q.s(async n=>{const{products:c,segments:u}=await n.getSearchSessionParams();s(u??[]),o(c?.personalizationBoost??[])})},[]),{segments:e,boost:t}}function D(){const{facets:e}=h.useNostoAppState(r=>({facets:r.response.products?.facets??[]})),{replaceFilter:s,toggleProductFilter:t}=A.useActions(),o=l.useCallback(r=>{const i=e?.find(d=>d.type==="stats"&&d.field===r);if(i&&"min"in i&&"max"in i)return i},[e]),n=l.useCallback(r=>e?.find(i=>i.field===r)?.name??r,[e]),c=l.useCallback(r=>"field"in r&&(r.value instanceof Array||r.range instanceof Array),[]),u=l.useCallback(r=>({...r,range:r.range?.map(i=>({gt:i.gt?Number(i.gt):i.gt,gte:i.gte?Number(i.gte):i.gte,lt:i.lt?Number(i.lt):i.lt,lte:i.lte?Number(i.lte):i.lte}))}),[]),a=l.useCallback(r=>(r.value??[]).map(d=>({value:d,field:r.field,name:n(r.field),filter:u(r),remove:()=>{t(r.field,d,!1)}})),[u,n,t]),f=l.useCallback(r=>(r.range??[]).map(d=>{const p=d.gte??d.gt??o(r.field)?.min,S=d.lte??d.lt??o(r.field)?.max;if(p!==void 0&&S!==void 0)return{value:`${p} - ${S}`,field:r.field,name:n(r.field),filter:u(r),remove:()=>{s(r.field,void 0)}}}).filter(Boolean),[u,o,n,s]);return{selectFilters:c,toValueFilter:a,toRangeFilter:f}}function L(){const{filter:e}=h.useNostoAppState(a=>({filter:a.query.products?.filter??[]})),{updateSearch:s}=A.useActions(),{selectFilters:t,toValueFilter:o,toRangeFilter:n}=D(),c=l.useMemo(()=>e?e.filter(t).flatMap(a=>"value"in a?o(a):"range"in a?n(a):[]).filter(Boolean):[],[e,t,n,o]),u=l.useCallback(()=>{s({products:{filter:[]}}),z.dispatchNostoEvent({event:"events/removeAllFilters",params:null})},[s]);return{filters:c,removeAll:u}}function T(e){const{replaceFilter:s}=A.useActions(),{query:t,products:o}=h.useNostoAppState(g=>({query:g.query,products:g.response.products})),n=o?.facets?.find(g=>g.id===e),c=t.products?.filter?.find(g=>g.field===n?.field),[u,a]=H(c),f=n&&"min"in n?Math.floor(n.min??0):0,r=n&&"max"in n?Math.ceil(n.max??0):0,i=l.useMemo(()=>[u??f,a??r],[u,a,f,r]),d=u!==void 0||a!==void 0,[p,S]=l.useState(d),v=l.useCallback(()=>{S(g=>!g)},[]),m=l.useCallback(([g,b])=>{if(!n)return;const y=U(g,b,f,r);s(n.field,y)},[f,r,s,n]);return R.useEventBusSubscribe({event:"events/removeAllFilters",callback:()=>{S(!1)}}),n?{min:f,max:r,range:i,updateRange:m,active:p,toggleActive:v}:$}const $={min:0,max:0,range:[0,0],active:!1,toggleActive:()=>{},updateRange:()=>{}};function H(e){const s=e?.range?.[0];return typeof s=="object"&&("gte"in s||"lte"in s)?[F.parseNumber(s.gte),F.parseNumber(s.lte)]:[void 0,void 0]}function U(e,s,t,o){const n=e!==void 0?Math.floor(e):void 0,c=s!==void 0?Math.ceil(s):void 0,u=n!==void 0,a=c!==void 0;if((t===n||!u)&&(o===c||!a))return;const f={};return u&&n!==t&&(f.gte=n.toString()),a&&c!==o&&(f.lte=c.toString()),Object.keys(f).length>0?f:void 0}function _(e,s){const{min:t,max:o,range:n,updateRange:c}=T(e),{filters:u}=L(),a=l.useMemo(()=>{const d=u.find(m=>m?.filter?.range);let p=null;if(d){const m=d.filter.range?.[0];p=[F.parseNumber(m?.gte),F.parseNumber(m?.lte)]}const S=[];let v=Math.floor(t/s)*s;for(;v<o;){const m=v+s,g=p&&p[0]===v&&p[1]===m;S.push({min:v,max:m,selected:g}),v=m}return S},[u,t,o,s]),f=l.useCallback(d=>{c([d,n[1]])},[n,c]),r=l.useCallback(d=>{c([n[0],d])},[n,c]),i=t!==n[0]||o!==n[1];return{min:t,max:o,range:n,updateRange:c,ranges:a,handleMinChange:f,handleMaxChange:r,isSelected:i}}function I(){const{products:e,keywords:s}=h.useNostoAppState(t=>({products:t.response.products??{hits:[],total:0},keywords:t.response.keywords??{hits:[],total:0}}));return{products:e,keywords:s}}function K(){const e=h.useNostoAppState(t=>t.query.products?.filter);return l.useMemo(()=>e?e.reduce((t,o)=>t+(Array.isArray(o.value)?o.value.length:1),0):0,[e])}const Z=5*60*1e3,k=new Map;function G(e){const[s,t]=l.useState({product:null,loading:!0,error:null});return l.useEffect(()=>{if(!e){t({product:null,loading:!1,error:"Product handle is required"});return}t(n=>({...n,loading:!0,error:null}));const o=W(e);if(o){t({product:o,loading:!1,error:null});return}Q(e).then(n=>{Y(e,n),t({product:n,loading:!1,error:null})}).catch(n=>{t({product:null,loading:!1,error:n.message||"Failed to fetch product"})})},[e]),s}function J(e){const s=window.Shopify?.routes?.root;return s?new URL(`${s}products/${e}`,window.location.href):e}async function Q(e){const s=await fetch(J(`/products/${e}.js`));if(!s.ok)throw new Error(`Failed to fetch product: ${s.status} ${s.statusText}`);return s.json()}function W(e){const s=k.get(e);return s?Date.now()-s.created>Z?(k.delete(e),null):s.product:null}function Y(e,s){k.set(e,{product:s,created:Date.now()})}function w(e){return e&&!Number.isNaN(e)?e:0}function ee(e,s){const{from:t,size:o,total:n}=h.useNostoAppState(r=>({from:w(r.query.products?.from??0),size:w(r.response?.products?.size??s),total:w(r.response?.products?.total??0)})),{updateSearch:c}=A.useActions(),u=t+o,a=l.useMemo(()=>[...e].reverse().filter(r=>r<n),[e,n]),f=l.useCallback(r=>{c({products:{size:F.parseNumber(r)}})},[c]);return{from:t,to:u,total:n,size:o,sizeOptions:a,handleSizeChange:f}}function te(e,s){return e.length!==s.length?!1:e.every(t=>s.find(o=>t.field===o.field&&t.order===o.order))}function se(e){const s=h.useNostoAppState(c=>c.query),{updateSearch:t}=A.useActions(),o=e.find(c=>te(c.value.sort,s.products?.sort||[]))?.id??e[0]?.id,n=l.useCallback(c=>{const u=e.find(a=>a.id===c);u&&t({products:{sort:u.value.sort}})},[e,t]);return{activeSort:o,setSort:n}}const N=window.SpeechRecognition||window.webkitSpeechRecognition,x=!!(N&&typeof N=="function");function ne(){return{listening:!1,startListening:()=>{},stopListening:()=>{}}}function oe({language:e="en-US",interimResults:s=!1,onResult:t,onError:o}={}){const[n,c]=l.useState(!1),u=l.useRef(null),a=l.useCallback(()=>{const r=new N;r.lang=e,r.interimResults=s,r.onstart=()=>c(!0),t&&(r.onresult=i=>{const{transcript:d}=i.results?.[0]?.[0];t(d)}),o&&(r.onerror=i=>o(i.error)),r.onend=()=>c(!1),u.current=r,r.start()},[e,s,o,t]),f=l.useCallback(()=>{u.current?.stop()},[u]);return{listening:n,startListening:a,stopListening:f}}const re=x?oe:ne;function ce(e,s){if(!e.length||!s.length)return[];const t=s.reduce((o,n)=>(o[n]={},o),{});return e.forEach(o=>{o.customFields?.forEach(({key:n,value:c})=>{const u=n.toLowerCase();s.includes(u)&&(t[u][c]=t[u][c]||[],t[u][c].push(o))})}),Object.entries(t).filter(o=>Object.keys(o[1]).length).map(([o,n])=>({field:o,options:Object.entries(n).map(([c,u])=>({value:c,skus:u,unavailable:!1,selected:!1}))}))}function ue(e,s){return e.length?e.map(({field:t,options:o})=>({field:t,options:o.map(n=>{const c=!n.skus?.some(a=>Object.entries(s).every(([f,r])=>f===t?!0:a.customFields?.find(d=>d.key.toLowerCase()===f)?.value===r)),u=s[t]===n.value;return{...n,unavailable:c,selected:u}})})):[]}const M=["4XS","3XS","2XS","XXS","XS","S","M","L","XL","XXL","2XL","XXXL","3XL","4XL"];function ie(e){if(M.includes(e))return 1e3+M.indexOf(e);const s=parseFloat(e);return isNaN(s)?e:s}function ae(e,s){return[...s].sort((t,o)=>{const[n,c]=[t.value,o.value].map(ie);return n<c?-1:1})}function le(e=[],s=[]){const[t,o]=l.useState({}),n=l.useMemo(()=>ce(e,s).map(({field:r,options:i})=>({field:r,options:ae(r,i)})),[e,s]),c=l.useMemo(()=>ue(n,t),[n,t]),u=l.useCallback((f,r)=>{o(i=>{const d={...i};return d[f]===r?delete d[f]:d[f]=r,d})},[]),a=l.useMemo(()=>Object.keys(t).filter(i=>t[i]).length===0?[]:c.filter(({field:i})=>t[i]).map(({field:i,options:d})=>{const p=t[i];return d.find(v=>v.value===p)?.skus??[]}).reduce((i,d)=>i.filter(p=>d.includes(p))),[c,t]);return{swatches:c,toggleOption:u,matchedSkus:a}}exports.useActions=A.useActions;exports.useLoadMore=h.useLoadMore;exports.useNostoAppState=h.useNostoAppState;exports.addToHistory=C.addToHistory;exports.getSavedHistory=C.getSavedHistory;exports.useHistory=C.useHistory;exports.speechToTextSupported=x;exports.useDecoratedSearchResults=O;exports.useFacet=X;exports.useFacets=E;exports.usePagination=B;exports.usePersonalization=V;exports.useProductFilters=L;exports.useRange=T;exports.useRangeSelector=_;exports.useResponse=I;exports.useSelectedFiltersCount=K;exports.useShopifyProduct=G;exports.useSizeOptions=ee;exports.useSort=se;exports.useSpeechToText=re;exports.useSwatches=le;
@@ -1,18 +1,18 @@
1
1
  import { h as A } from "../../useActions-CSNwQtT1.js";
2
2
  import { a as k } from "../../logger-_fg_Za9y.js";
3
3
  import { a as S } from "../../useLoadMore-2OmOqicJ.js";
4
- import { u as Ae } from "../../useLoadMore-2OmOqicJ.js";
4
+ import { u as Re } from "../../useLoadMore-2OmOqicJ.js";
5
5
  import { u as N } from "../../eventBusSubscribe-CzlS132j.js";
6
6
  import { useState as b, useCallback as g, useMemo as y, useEffect as P, useRef as X } from "preact/hooks";
7
- import { a as xe, g as Le, u as Me } from "../../useHistory-joVBx1r2.js";
7
+ import { a as xe, g as Me, u as Te } from "../../useHistory-joVBx1r2.js";
8
8
  import { s as z } from "../../index.es-XNBESE3P.js";
9
9
  import { d as C } from "../../eventBusDispatch-DPR2Vwd4.js";
10
10
  import { p as R } from "../../parseNumber-QA48nJLp.js";
11
- function ae(e) {
11
+ function ue(e) {
12
12
  const n = S((t) => t.response);
13
13
  return e && Array.isArray(e) || e && k(e) ? e : n;
14
14
  }
15
- function ue(e, n) {
15
+ function le(e, n) {
16
16
  const t = e.data?.filter((d) => d.selected).length ?? 0, { active: o } = {
17
17
  active: t > 0,
18
18
  ...n
@@ -35,7 +35,7 @@ function ue(e, n) {
35
35
  toggleProductFilter: i
36
36
  };
37
37
  }
38
- function le() {
38
+ function de() {
39
39
  const { loading: e, facets: n } = S((t) => ({
40
40
  loading: t.loading,
41
41
  facets: t.response?.products?.facets ?? []
@@ -51,7 +51,7 @@ function O(e, n) {
51
51
  const t = n - e;
52
52
  return !isNaN(t) && t > 0 ? new Array(n - e).fill(void 0).map((o, r) => r + e) : [];
53
53
  }
54
- function de(e) {
54
+ function fe(e) {
55
55
  const { query: n, products: t } = S((o) => ({
56
56
  query: o.query,
57
57
  products: o.response.products
@@ -86,7 +86,7 @@ function de(e) {
86
86
  };
87
87
  }, [n, t, e?.width]);
88
88
  }
89
- function fe() {
89
+ function ge() {
90
90
  const [e, n] = b([]), [t, o] = b([]);
91
91
  return P(() => {
92
92
  z(async (r) => {
@@ -176,13 +176,13 @@ function E(e) {
176
176
  const { replaceFilter: n } = A(), { query: t, products: o } = S((p) => ({
177
177
  query: p.query,
178
178
  products: p.response.products
179
- })), r = o?.facets?.find((p) => p.id === e), c = t.products?.filter?.find((p) => p.field === r?.field), [i, u] = B(c), d = r && "min" in r ? Math.floor(r.min ?? 0) : 0, s = r && "max" in r ? Math.ceil(r.max ?? 0) : 0, a = y(() => [i ?? d, u ?? s], [i, u, d, s]), l = i !== void 0 || u !== void 0, [f, h] = b(l), v = g(() => {
179
+ })), r = o?.facets?.find((p) => p.id === e), c = t.products?.filter?.find((p) => p.field === r?.field), [i, u] = $(c), d = r && "min" in r ? Math.floor(r.min ?? 0) : 0, s = r && "max" in r ? Math.ceil(r.max ?? 0) : 0, a = y(() => [i ?? d, u ?? s], [i, u, d, s]), l = i !== void 0 || u !== void 0, [f, h] = b(l), v = g(() => {
180
180
  h((p) => !p);
181
181
  }, []), m = g(
182
182
  ([p, F]) => {
183
183
  if (!r)
184
184
  return;
185
- const w = D(p, F, d, s);
185
+ const w = U(p, F, d, s);
186
186
  n(r.field, w);
187
187
  },
188
188
  [d, s, n, r]
@@ -217,18 +217,18 @@ const V = {
217
217
  updateRange: () => {
218
218
  }
219
219
  };
220
- function B(e) {
220
+ function $(e) {
221
221
  const n = e?.range?.[0];
222
222
  return typeof n == "object" && ("gte" in n || "lte" in n) ? [R(n.gte), R(n.lte)] : [void 0, void 0];
223
223
  }
224
- function D(e, n, t, o) {
224
+ function U(e, n, t, o) {
225
225
  const r = e !== void 0 ? Math.floor(e) : void 0, c = n !== void 0 ? Math.ceil(n) : void 0, i = r !== void 0, u = c !== void 0;
226
226
  if ((t === r || !i) && (o === c || !u))
227
227
  return;
228
228
  const d = {};
229
229
  return i && r !== t && (d.gte = r.toString()), u && c !== o && (d.lte = c.toString()), Object.keys(d).length > 0 ? d : void 0;
230
230
  }
231
- function ge(e, n) {
231
+ function pe(e, n) {
232
232
  const { min: t, max: o, range: r, updateRange: c } = E(e), { filters: i } = q(), u = y(() => {
233
233
  const l = i.find((m) => m?.filter?.range);
234
234
  let f = null;
@@ -277,7 +277,7 @@ function ge(e, n) {
277
277
  isSelected: a
278
278
  };
279
279
  }
280
- function pe() {
280
+ function me() {
281
281
  const { products: e, keywords: n } = S((t) => ({
282
282
  products: t.response.products ?? { hits: [], total: 0 },
283
283
  keywords: t.response.keywords ?? { hits: [], total: 0 }
@@ -289,12 +289,12 @@ function pe() {
289
289
  keywords: n
290
290
  };
291
291
  }
292
- function me() {
292
+ function he() {
293
293
  const e = S((t) => t.query.products?.filter);
294
294
  return y(() => e ? e.reduce((t, o) => t + (Array.isArray(o.value) ? o.value.length : 1), 0) : 0, [e]);
295
295
  }
296
- const $ = 5 * 60 * 1e3, L = /* @__PURE__ */ new Map();
297
- function he(e) {
296
+ const B = 5 * 60 * 1e3, x = /* @__PURE__ */ new Map();
297
+ function ve(e) {
298
298
  const [n, t] = b({
299
299
  product: null,
300
300
  loading: !0,
@@ -314,7 +314,7 @@ function he(e) {
314
314
  loading: !0,
315
315
  error: null
316
316
  }));
317
- const o = _(e);
317
+ const o = H(e);
318
318
  if (o) {
319
319
  t({
320
320
  product: o,
@@ -323,8 +323,8 @@ function he(e) {
323
323
  });
324
324
  return;
325
325
  }
326
- U(e).then((r) => {
327
- H(e, r), t({
326
+ _(e).then((r) => {
327
+ I(e, r), t({
328
328
  product: r,
329
329
  loading: !1,
330
330
  error: null
@@ -338,30 +338,34 @@ function he(e) {
338
338
  });
339
339
  }, [e]), n;
340
340
  }
341
- async function U(e) {
342
- const n = await fetch(`/products/${e}.js`);
341
+ function D(e) {
342
+ const n = window.Shopify?.routes?.root;
343
+ return n ? new URL(`${n}products/${e}`, window.location.href) : e;
344
+ }
345
+ async function _(e) {
346
+ const n = await fetch(D(`/products/${e}.js`));
343
347
  if (!n.ok)
344
348
  throw new Error(`Failed to fetch product: ${n.status} ${n.statusText}`);
345
349
  return n.json();
346
350
  }
347
- function _(e) {
348
- const n = L.get(e);
349
- return n ? Date.now() - n.created > $ ? (L.delete(e), null) : n.product : null;
351
+ function H(e) {
352
+ const n = x.get(e);
353
+ return n ? Date.now() - n.created > B ? (x.delete(e), null) : n.product : null;
350
354
  }
351
- function H(e, n) {
352
- L.set(e, {
355
+ function I(e, n) {
356
+ x.set(e, {
353
357
  product: n,
354
358
  created: Date.now()
355
359
  });
356
360
  }
357
- function x(e) {
361
+ function L(e) {
358
362
  return e && !Number.isNaN(e) ? e : 0;
359
363
  }
360
- function ve(e, n) {
364
+ function Se(e, n) {
361
365
  const { from: t, size: o, total: r } = S((s) => ({
362
- from: x(s.query.products?.from ?? 0),
363
- size: x(s.response?.products?.size ?? n),
364
- total: x(s.response?.products?.total ?? 0)
366
+ from: L(s.query.products?.from ?? 0),
367
+ size: L(s.response?.products?.size ?? n),
368
+ total: L(s.response?.products?.total ?? 0)
365
369
  })), { updateSearch: c } = A(), i = t + o, u = y(() => [...e].reverse().filter((s) => s < r), [e, r]), d = g(
366
370
  (s) => {
367
371
  c({
@@ -387,11 +391,11 @@ function ve(e, n) {
387
391
  handleSizeChange: d
388
392
  };
389
393
  }
390
- function I(e, n) {
394
+ function K(e, n) {
391
395
  return e.length !== n.length ? !1 : e.every((t) => n.find((o) => t.field === o.field && t.order === o.order));
392
396
  }
393
- function Se(e) {
394
- const n = S((c) => c.query), { updateSearch: t } = A(), o = e.find((c) => I(c.value.sort, n.products?.sort || []))?.id ?? e[0]?.id, r = g(
397
+ function ye(e) {
398
+ const n = S((c) => c.query), { updateSearch: t } = A(), o = e.find((c) => K(c.value.sort, n.products?.sort || []))?.id ?? e[0]?.id, r = g(
395
399
  (c) => {
396
400
  const i = e.find((u) => u.id === c);
397
401
  i && t({
@@ -409,8 +413,8 @@ function Se(e) {
409
413
  setSort: r
410
414
  };
411
415
  }
412
- const M = window.SpeechRecognition || window.webkitSpeechRecognition, K = !!(M && typeof M == "function");
413
- function Z() {
416
+ const M = window.SpeechRecognition || window.webkitSpeechRecognition, Z = !!(M && typeof M == "function");
417
+ function G() {
414
418
  return {
415
419
  listening: !1,
416
420
  startListening: () => {
@@ -419,7 +423,7 @@ function Z() {
419
423
  }
420
424
  };
421
425
  }
422
- function G({
426
+ function J({
423
427
  language: e = "en-US",
424
428
  interimResults: n = !1,
425
429
  onResult: t,
@@ -440,8 +444,8 @@ function G({
440
444
  stopListening: d
441
445
  };
442
446
  }
443
- const ye = K ? G : Z;
444
- function J(e, n) {
447
+ const Fe = Z ? J : G;
448
+ function Q(e, n) {
445
449
  if (!e.length || !n.length) return [];
446
450
  const t = n.reduce((o, r) => (o[r] = {}, o), {});
447
451
  return e.forEach((o) => {
@@ -459,7 +463,7 @@ function J(e, n) {
459
463
  }))
460
464
  }));
461
465
  }
462
- function Q(e, n) {
466
+ function W(e, n) {
463
467
  return e.length ? e.map(({ field: t, options: o }) => ({
464
468
  field: t,
465
469
  options: o.map((r) => {
@@ -473,23 +477,23 @@ function Q(e, n) {
473
477
  })) : [];
474
478
  }
475
479
  const T = ["4XS", "3XS", "2XS", "XXS", "XS", "S", "M", "L", "XL", "XXL", "2XL", "XXXL", "3XL", "4XL"];
476
- function W(e) {
480
+ function Y(e) {
477
481
  if (T.includes(e))
478
482
  return 1e3 + T.indexOf(e);
479
483
  const n = parseFloat(e);
480
484
  return isNaN(n) ? e : n;
481
485
  }
482
- function Y(e, n) {
486
+ function ee(e, n) {
483
487
  return [...n].sort((t, o) => {
484
- const [r, c] = [t.value, o.value].map(W);
488
+ const [r, c] = [t.value, o.value].map(Y);
485
489
  return r < c ? -1 : 1;
486
490
  });
487
491
  }
488
- function Fe(e = [], n = []) {
489
- const [t, o] = b({}), r = y(() => J(e, n).map(({ field: s, options: a }) => ({
492
+ function we(e = [], n = []) {
493
+ const [t, o] = b({}), r = y(() => Q(e, n).map(({ field: s, options: a }) => ({
490
494
  field: s,
491
- options: Y(s, a)
492
- })), [e, n]), c = y(() => Q(r, t), [r, t]), i = g((d, s) => {
495
+ options: ee(s, a)
496
+ })), [e, n]), c = y(() => W(r, t), [r, t]), i = g((d, s) => {
493
497
  o((a) => {
494
498
  const l = { ...a };
495
499
  return l[d] === s ? delete l[d] : l[d] = s, l;
@@ -502,25 +506,25 @@ function Fe(e = [], n = []) {
502
506
  }
503
507
  export {
504
508
  xe as addToHistory,
505
- Le as getSavedHistory,
506
- K as speechToTextSupported,
509
+ Me as getSavedHistory,
510
+ Z as speechToTextSupported,
507
511
  A as useActions,
508
- ae as useDecoratedSearchResults,
509
- ue as useFacet,
510
- le as useFacets,
511
- Me as useHistory,
512
- Ae as useLoadMore,
512
+ ue as useDecoratedSearchResults,
513
+ le as useFacet,
514
+ de as useFacets,
515
+ Te as useHistory,
516
+ Re as useLoadMore,
513
517
  S as useNostoAppState,
514
- de as usePagination,
515
- fe as usePersonalization,
518
+ fe as usePagination,
519
+ ge as usePersonalization,
516
520
  q as useProductFilters,
517
521
  E as useRange,
518
- ge as useRangeSelector,
519
- pe as useResponse,
520
- me as useSelectedFiltersCount,
521
- he as useShopifyProduct,
522
- ve as useSizeOptions,
523
- Se as useSort,
524
- ye as useSpeechToText,
525
- Fe as useSwatches
522
+ pe as useRangeSelector,
523
+ me as useResponse,
524
+ he as useSelectedFiltersCount,
525
+ ve as useShopifyProduct,
526
+ Se as useSizeOptions,
527
+ ye as useSort,
528
+ Fe as useSpeechToText,
529
+ we as useSwatches
526
530
  };
@@ -31,13 +31,6 @@ type RangeProps = [number | undefined, number | undefined];
31
31
  * ```
32
32
  */
33
33
  export declare function useRange(id: string): {
34
- readonly min: 0;
35
- readonly max: 0;
36
- readonly range: readonly [0, 0];
37
- readonly active: false;
38
- readonly toggleActive: () => void;
39
- readonly updateRange: () => void;
40
- } | {
41
34
  /** Min value */
42
35
  min: number;
43
36
  /** Max value */
@@ -80,9 +80,9 @@ export declare function useRangeSelector(id: string, rangeSize: number): {
80
80
  /** Maximum value */
81
81
  max: number;
82
82
  /** Range value */
83
- range: number[] | readonly [0, 0];
83
+ range: number[];
84
84
  /** Update range function */
85
- updateRange: (([from, to]: [number | undefined, number | undefined]) => void) | (() => void);
85
+ updateRange: ([from, to]: [number | undefined, number | undefined]) => void;
86
86
  /** Ranges */
87
87
  ranges: {
88
88
  min: number;
@@ -5,5 +5,29 @@ export type Config = {
5
5
  /**
6
6
  * Replaces full size images with thumbnail sized versions.
7
7
  * Uses `shopifyThumbnailDecorator` and `nostoThumbnailDecorator` based on the platform.
8
+ *
9
+ * @param config - Configuration object specifying the desired thumbnail size.
10
+ * @returns A decorator function that transforms image URLs to thumbnail versions.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { search } from '@nosto/search-js'
15
+ * import { thumbnailDecorator } from '@nosto/search-js/thumbnails'
16
+ *
17
+ * // Use thumbnail decorator with search
18
+ * const results = await search(
19
+ * { query: 'shoes' },
20
+ * {
21
+ * hitDecorators: [
22
+ * thumbnailDecorator({ size: '200x200' })
23
+ * ]
24
+ * }
25
+ * )
26
+ * console.log(results.products.hits[0].thumb_url)
27
+ *
28
+ * // Available sizes: '100x100', '200x200', '400x400', '600x600', '800x800'
29
+ * const smallThumbs = thumbnailDecorator({ size: '100x100' })
30
+ * const largeThumbs = thumbnailDecorator({ size: '800x800' })
31
+ * ```
8
32
  */
9
33
  export declare function thumbnailDecorator({ size }: Config): (hit: import('@nosto/nosto-js/client').SearchProduct) => import('@nosto/nosto-js/client').SearchProduct;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nosto/search-js",
3
- "version": "3.21.0",
3
+ "version": "3.21.2",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "files": [
@@ -99,30 +99,30 @@
99
99
  "devDependencies": {
100
100
  "@commitlint/cli": "^20.1.0",
101
101
  "@commitlint/config-conventional": "^20.0.0",
102
- "@nosto/nosto-js": "^2.8.0",
102
+ "@nosto/nosto-js": "^2.9.0",
103
103
  "@testing-library/dom": "^10.4.1",
104
104
  "@types/dom-speech-recognition": "^0.0.7",
105
105
  "@types/eslint-config-prettier": "^6.11.3",
106
- "@types/node": "^24.7.0",
106
+ "@types/node": "^24.9.0",
107
107
  "@vitest/coverage-v8": "^3.2.4",
108
108
  "concurrently": "^9.2.1",
109
109
  "copyfiles": "^2.4.1",
110
- "eslint": "^9.37.0",
110
+ "eslint": "^9.38.0",
111
111
  "eslint-config-prettier": "^10.1.8",
112
112
  "eslint-plugin-barrel-files": "^3.0.1",
113
113
  "eslint-plugin-prettier": "^5.5.4",
114
114
  "eslint-plugin-react": "^7.37.5",
115
- "eslint-plugin-react-hooks": "^6.1.1",
115
+ "eslint-plugin-react-hooks": "^7.0.0",
116
116
  "eslint-plugin-simple-import-sort": "^12.1.1",
117
- "eslint-plugin-unused-imports": "^4.2.0",
117
+ "eslint-plugin-unused-imports": "^4.3.0",
118
118
  "husky": "^9.1.7",
119
119
  "isbot": "^5.1.31",
120
- "jsdom": "^27.0.0",
120
+ "jsdom": "^27.0.1",
121
121
  "prettier": "^3.6.2",
122
- "typedoc": "^0.28.13",
122
+ "typedoc": "^0.28.14",
123
123
  "typescript": "^5.9.3",
124
- "typescript-eslint": "^8.46.0",
125
- "vite": "^7.1.9",
124
+ "typescript-eslint": "^8.46.2",
125
+ "vite": "^7.1.11",
126
126
  "vite-plugin-dts": "^4.5.4",
127
127
  "vitest": "^3.1.3"
128
128
  },