@nosto/search-js 3.21.1 → 3.22.0
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.
- package/dist/core/src/addToCart.d.ts +17 -0
- package/dist/core/src/search.d.ts +28 -0
- package/dist/currencies/src/getCurrencyFormatting.d.ts +37 -0
- package/dist/currencies/src/priceDecorator.d.ts +44 -3
- package/dist/preact/common/src/actions/withDefaultQuery.d.ts +7 -0
- package/dist/preact/hooks/hooks.cjs.js +1 -1
- package/dist/preact/hooks/hooks.es.js +42 -36
- package/dist/preact/hooks/src/useRange.d.ts +0 -7
- package/dist/preact/hooks/src/useRangeSelector.d.ts +2 -2
- package/dist/preact/hooks/src/useResponse.d.ts +32 -2
- package/dist/thumbnails/src/thumbnailDecorator.d.ts +24 -0
- package/package.json +5 -5
|
@@ -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;
|
|
@@ -27,11 +27,18 @@ export declare function withDefaultQuery(pageType: PageType, query: SearchQuery)
|
|
|
27
27
|
size?: number;
|
|
28
28
|
sort?: import('@nosto/nosto-js/client').InputSearchSort[];
|
|
29
29
|
variationId?: string;
|
|
30
|
+
currency?: string;
|
|
30
31
|
fields: string[];
|
|
31
32
|
};
|
|
32
33
|
accountId?: string | undefined;
|
|
33
34
|
customRules?: import('@nosto/nosto-js/client').InputSearchRule[] | undefined;
|
|
34
35
|
explain?: boolean | undefined;
|
|
36
|
+
popularSearches?: import('@nosto/nosto-js/client').InputSearchQuery["popularSearches"] & {
|
|
37
|
+
fields?: string[];
|
|
38
|
+
};
|
|
39
|
+
categories?: import('@nosto/nosto-js/client').InputSearchQuery["categories"] & {
|
|
40
|
+
fields?: string[];
|
|
41
|
+
};
|
|
35
42
|
query?: string | undefined;
|
|
36
43
|
redirect?: string | undefined;
|
|
37
44
|
rules?: string[] | undefined;
|
|
@@ -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,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
|
+
"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,popularSearches:t,categories:o}=h.useNostoAppState(n=>({products:n.response.products??{hits:[],total:0},keywords:n.response.keywords??{hits:[],total:0},popularSearches:n.response.popularSearches??{hits:[],total:0},categories:n.response.categories??{hits:[],total:0}}));return{products:e,keywords:s,popularSearches:t,categories:o}}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;
|
|
@@ -3,7 +3,7 @@ import { a as k } from "../../logger-_fg_Za9y.js";
|
|
|
3
3
|
import { a as S } from "../../useLoadMore-2OmOqicJ.js";
|
|
4
4
|
import { u as Re } from "../../useLoadMore-2OmOqicJ.js";
|
|
5
5
|
import { u as N } from "../../eventBusSubscribe-CzlS132j.js";
|
|
6
|
-
import { useState as b, useCallback as
|
|
6
|
+
import { useState as b, useCallback as p, useMemo as y, useEffect as P, useRef as X } from "preact/hooks";
|
|
7
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";
|
|
@@ -16,7 +16,7 @@ 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
|
|
19
|
-
}, [r, c] = b(o), { toggleProductFilter: i } = A(), u =
|
|
19
|
+
}, [r, c] = b(o), { toggleProductFilter: i } = A(), u = p(() => {
|
|
20
20
|
c(!r);
|
|
21
21
|
}, [r]);
|
|
22
22
|
return N({
|
|
@@ -72,8 +72,8 @@ function fe(e) {
|
|
|
72
72
|
from: (w - 1) * t.size,
|
|
73
73
|
page: w,
|
|
74
74
|
current: w === i
|
|
75
|
-
}), h = i > 1 ? f(i - 1) : void 0, v = i < u ? f(i + 1) : void 0, m = i - c - 1 > 1 ? f(1) : void 0,
|
|
76
|
-
return !m && F[0]?.page === 2 && F.unshift(f(1)), !
|
|
75
|
+
}), h = i > 1 ? f(i - 1) : void 0, v = i < u ? f(i + 1) : void 0, m = i - c - 1 > 1 ? f(1) : void 0, g = i + c + 1 < u ? f(u) : void 0, F = O(1, u + 1).filter(d).map(f);
|
|
76
|
+
return !m && F[0]?.page === 2 && F.unshift(f(1)), !g && F[F.length - 1]?.page === u - 1 && F.push(f(u)), {
|
|
77
77
|
totalPages: u,
|
|
78
78
|
resultsFrom: s,
|
|
79
79
|
resultsTo: a,
|
|
@@ -81,12 +81,12 @@ function fe(e) {
|
|
|
81
81
|
prev: h,
|
|
82
82
|
next: v,
|
|
83
83
|
first: m,
|
|
84
|
-
last:
|
|
84
|
+
last: g,
|
|
85
85
|
pages: F
|
|
86
86
|
};
|
|
87
87
|
}, [n, t, e?.width]);
|
|
88
88
|
}
|
|
89
|
-
function
|
|
89
|
+
function pe() {
|
|
90
90
|
const [e, n] = b([]), [t, o] = b([]);
|
|
91
91
|
return P(() => {
|
|
92
92
|
z(async (r) => {
|
|
@@ -101,17 +101,17 @@ function ge() {
|
|
|
101
101
|
function j() {
|
|
102
102
|
const { facets: e } = S((s) => ({
|
|
103
103
|
facets: s.response.products?.facets ?? []
|
|
104
|
-
})), { replaceFilter: n, toggleProductFilter: t } = A(), o =
|
|
104
|
+
})), { replaceFilter: n, toggleProductFilter: t } = A(), o = p(
|
|
105
105
|
(s) => {
|
|
106
106
|
const a = e?.find((l) => l.type === "stats" && l.field === s);
|
|
107
107
|
if (a && "min" in a && "max" in a)
|
|
108
108
|
return a;
|
|
109
109
|
},
|
|
110
110
|
[e]
|
|
111
|
-
), r =
|
|
111
|
+
), r = p(
|
|
112
112
|
(s) => e?.find((a) => a.field === s)?.name ?? s,
|
|
113
113
|
[e]
|
|
114
|
-
), c =
|
|
114
|
+
), c = p((s) => "field" in s && (s.value instanceof Array || s.range instanceof Array), []), i = p((s) => ({
|
|
115
115
|
...s,
|
|
116
116
|
range: s.range?.map((a) => ({
|
|
117
117
|
gt: a.gt ? Number(a.gt) : a.gt,
|
|
@@ -119,7 +119,7 @@ function j() {
|
|
|
119
119
|
lt: a.lt ? Number(a.lt) : a.lt,
|
|
120
120
|
lte: a.lte ? Number(a.lte) : a.lte
|
|
121
121
|
}))
|
|
122
|
-
}), []), u =
|
|
122
|
+
}), []), u = p(
|
|
123
123
|
(s) => (s.value ?? []).map((l) => ({
|
|
124
124
|
value: l,
|
|
125
125
|
field: s.field,
|
|
@@ -130,7 +130,7 @@ function j() {
|
|
|
130
130
|
}
|
|
131
131
|
})),
|
|
132
132
|
[i, r, t]
|
|
133
|
-
), d =
|
|
133
|
+
), d = p(
|
|
134
134
|
(s) => (s.range ?? []).map((l) => {
|
|
135
135
|
const f = l.gte ?? l.gt ?? o(s.field)?.min, h = l.lte ?? l.lt ?? o(s.field)?.max;
|
|
136
136
|
if (f !== void 0 && h !== void 0)
|
|
@@ -155,7 +155,7 @@ function j() {
|
|
|
155
155
|
function q() {
|
|
156
156
|
const { filter: e } = S((u) => ({
|
|
157
157
|
filter: u.query.products?.filter ?? []
|
|
158
|
-
})), { updateSearch: n } = A(), { selectFilters: t, toValueFilter: o, toRangeFilter: r } = j(), c = y(() => e ? e.filter(t).flatMap((u) => "value" in u ? o(u) : "range" in u ? r(u) : []).filter(Boolean) : [], [e, t, r, o]), i =
|
|
158
|
+
})), { updateSearch: n } = A(), { selectFilters: t, toValueFilter: o, toRangeFilter: r } = j(), c = y(() => e ? e.filter(t).flatMap((u) => "value" in u ? o(u) : "range" in u ? r(u) : []).filter(Boolean) : [], [e, t, r, o]), i = p(() => {
|
|
159
159
|
n({
|
|
160
160
|
products: {
|
|
161
161
|
filter: []
|
|
@@ -173,16 +173,16 @@ function q() {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
function E(e) {
|
|
176
|
-
const { replaceFilter: n } = A(), { query: t, products: o } = S((
|
|
177
|
-
query:
|
|
178
|
-
products:
|
|
179
|
-
})), r = o?.facets?.find((
|
|
180
|
-
h((
|
|
181
|
-
}, []), m =
|
|
182
|
-
([
|
|
176
|
+
const { replaceFilter: n } = A(), { query: t, products: o } = S((g) => ({
|
|
177
|
+
query: g.query,
|
|
178
|
+
products: g.response.products
|
|
179
|
+
})), r = o?.facets?.find((g) => g.id === e), c = t.products?.filter?.find((g) => g.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 = p(() => {
|
|
180
|
+
h((g) => !g);
|
|
181
|
+
}, []), m = p(
|
|
182
|
+
([g, F]) => {
|
|
183
183
|
if (!r)
|
|
184
184
|
return;
|
|
185
|
-
const w = U(
|
|
185
|
+
const w = U(g, F, d, s);
|
|
186
186
|
n(r.field, w);
|
|
187
187
|
},
|
|
188
188
|
[d, s, n, r]
|
|
@@ -228,7 +228,7 @@ function U(e, n, t, o) {
|
|
|
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
|
|
231
|
+
function ge(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;
|
|
@@ -239,20 +239,20 @@ function pe(e, n) {
|
|
|
239
239
|
const h = [];
|
|
240
240
|
let v = Math.floor(t / n) * n;
|
|
241
241
|
for (; v < o; ) {
|
|
242
|
-
const m = v + n,
|
|
242
|
+
const m = v + n, g = f && f[0] === v && f[1] === m;
|
|
243
243
|
h.push({
|
|
244
244
|
min: v,
|
|
245
245
|
max: m,
|
|
246
|
-
selected:
|
|
246
|
+
selected: g
|
|
247
247
|
}), v = m;
|
|
248
248
|
}
|
|
249
249
|
return h;
|
|
250
|
-
}, [i, t, o, n]), d =
|
|
250
|
+
}, [i, t, o, n]), d = p(
|
|
251
251
|
(l) => {
|
|
252
252
|
c([l, r[1]]);
|
|
253
253
|
},
|
|
254
254
|
[r, c]
|
|
255
|
-
), s =
|
|
255
|
+
), s = p(
|
|
256
256
|
(l) => {
|
|
257
257
|
c([r[0], l]);
|
|
258
258
|
},
|
|
@@ -278,15 +278,21 @@ function pe(e, n) {
|
|
|
278
278
|
};
|
|
279
279
|
}
|
|
280
280
|
function me() {
|
|
281
|
-
const { products: e, keywords: n } = S((
|
|
282
|
-
products:
|
|
283
|
-
keywords:
|
|
281
|
+
const { products: e, keywords: n, popularSearches: t, categories: o } = S((r) => ({
|
|
282
|
+
products: r.response.products ?? { hits: [], total: 0 },
|
|
283
|
+
keywords: r.response.keywords ?? { hits: [], total: 0 },
|
|
284
|
+
popularSearches: r.response.popularSearches ?? { hits: [], total: 0 },
|
|
285
|
+
categories: r.response.categories ?? { hits: [], total: 0 }
|
|
284
286
|
}));
|
|
285
287
|
return {
|
|
286
288
|
/** Array of products */
|
|
287
289
|
products: e,
|
|
288
290
|
/** Array of keywords */
|
|
289
|
-
keywords: n
|
|
291
|
+
keywords: n,
|
|
292
|
+
/** Array of popular searches */
|
|
293
|
+
popularSearches: t,
|
|
294
|
+
/** Array of categories */
|
|
295
|
+
categories: o
|
|
290
296
|
};
|
|
291
297
|
}
|
|
292
298
|
function he() {
|
|
@@ -366,7 +372,7 @@ function Se(e, n) {
|
|
|
366
372
|
from: L(s.query.products?.from ?? 0),
|
|
367
373
|
size: L(s.response?.products?.size ?? n),
|
|
368
374
|
total: L(s.response?.products?.total ?? 0)
|
|
369
|
-
})), { updateSearch: c } = A(), i = t + o, u = y(() => [...e].reverse().filter((s) => s < r), [e, r]), d =
|
|
375
|
+
})), { updateSearch: c } = A(), i = t + o, u = y(() => [...e].reverse().filter((s) => s < r), [e, r]), d = p(
|
|
370
376
|
(s) => {
|
|
371
377
|
c({
|
|
372
378
|
products: {
|
|
@@ -395,7 +401,7 @@ function K(e, n) {
|
|
|
395
401
|
return e.length !== n.length ? !1 : e.every((t) => n.find((o) => t.field === o.field && t.order === o.order));
|
|
396
402
|
}
|
|
397
403
|
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 =
|
|
404
|
+
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 = p(
|
|
399
405
|
(c) => {
|
|
400
406
|
const i = e.find((u) => u.id === c);
|
|
401
407
|
i && t({
|
|
@@ -429,13 +435,13 @@ function J({
|
|
|
429
435
|
onResult: t,
|
|
430
436
|
onError: o
|
|
431
437
|
} = {}) {
|
|
432
|
-
const [r, c] = b(!1), i = X(null), u =
|
|
438
|
+
const [r, c] = b(!1), i = X(null), u = p(() => {
|
|
433
439
|
const s = new M();
|
|
434
440
|
s.lang = e, s.interimResults = n, s.onstart = () => c(!0), t && (s.onresult = (a) => {
|
|
435
441
|
const { transcript: l } = a.results?.[0]?.[0];
|
|
436
442
|
t(l);
|
|
437
443
|
}), o && (s.onerror = (a) => o(a.error)), s.onend = () => c(!1), i.current = s, s.start();
|
|
438
|
-
}, [e, n, o, t]), d =
|
|
444
|
+
}, [e, n, o, t]), d = p(() => {
|
|
439
445
|
i.current?.stop();
|
|
440
446
|
}, [i]);
|
|
441
447
|
return {
|
|
@@ -493,7 +499,7 @@ function we(e = [], n = []) {
|
|
|
493
499
|
const [t, o] = b({}), r = y(() => Q(e, n).map(({ field: s, options: a }) => ({
|
|
494
500
|
field: s,
|
|
495
501
|
options: ee(s, a)
|
|
496
|
-
})), [e, n]), c = y(() => W(r, t), [r, t]), i =
|
|
502
|
+
})), [e, n]), c = y(() => W(r, t), [r, t]), i = p((d, s) => {
|
|
497
503
|
o((a) => {
|
|
498
504
|
const l = { ...a };
|
|
499
505
|
return l[d] === s ? delete l[d] : l[d] = s, l;
|
|
@@ -516,10 +522,10 @@ export {
|
|
|
516
522
|
Re as useLoadMore,
|
|
517
523
|
S as useNostoAppState,
|
|
518
524
|
fe as usePagination,
|
|
519
|
-
|
|
525
|
+
pe as usePersonalization,
|
|
520
526
|
q as useProductFilters,
|
|
521
527
|
E as useRange,
|
|
522
|
-
|
|
528
|
+
ge as useRangeSelector,
|
|
523
529
|
me as useResponse,
|
|
524
530
|
he as useSelectedFiltersCount,
|
|
525
531
|
ve as useShopifyProduct,
|
|
@@ -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[]
|
|
83
|
+
range: number[];
|
|
84
84
|
/** Update range function */
|
|
85
|
-
updateRange: (
|
|
85
|
+
updateRange: ([from, to]: [number | undefined, number | undefined]) => void;
|
|
86
86
|
/** Ranges */
|
|
87
87
|
ranges: {
|
|
88
88
|
min: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SearchKeywords, SearchProducts } from '@nosto/nosto-js/client';
|
|
1
|
+
import { SearchCategories, SearchKeywords, SearchPopularSearches, SearchProducts } from '@nosto/nosto-js/client';
|
|
2
2
|
/**
|
|
3
3
|
* Preact hook that imports response data to the component.
|
|
4
4
|
* @example
|
|
@@ -7,7 +7,7 @@ import { SearchKeywords, SearchProducts } from '@nosto/nosto-js/client';
|
|
|
7
7
|
* import { defaultConfig } from "../config"
|
|
8
8
|
*
|
|
9
9
|
* export default () => {
|
|
10
|
-
* const { products, keywords } = useResponse()
|
|
10
|
+
* const { products, keywords, popularSearches, categories } = useResponse()
|
|
11
11
|
* return (
|
|
12
12
|
* <div>
|
|
13
13
|
* <div>
|
|
@@ -68,6 +68,34 @@ import { SearchKeywords, SearchProducts } from '@nosto/nosto-js/client';
|
|
|
68
68
|
* <SubmitButton />
|
|
69
69
|
* </div>
|
|
70
70
|
* )}
|
|
71
|
+
* {popularSearches.hits.length > 0 && (
|
|
72
|
+
* <div>
|
|
73
|
+
* <div>
|
|
74
|
+
* Popular Searches
|
|
75
|
+
* </div>
|
|
76
|
+
* <div>
|
|
77
|
+
* {popularSearches.hits.map(hit => (
|
|
78
|
+
* <div key={hit.query}>
|
|
79
|
+
* {hit.query} ({hit.total} results)
|
|
80
|
+
* </div>
|
|
81
|
+
* ))}
|
|
82
|
+
* </div>
|
|
83
|
+
* </div>
|
|
84
|
+
* )}
|
|
85
|
+
* {categories.hits.length > 0 && (
|
|
86
|
+
* <div>
|
|
87
|
+
* <div>
|
|
88
|
+
* Categories
|
|
89
|
+
* </div>
|
|
90
|
+
* <div>
|
|
91
|
+
* {categories.hits.map(hit => (
|
|
92
|
+
* <div key={hit.externalId}>
|
|
93
|
+
* {hit.name}
|
|
94
|
+
* </div>
|
|
95
|
+
* ))}
|
|
96
|
+
* </div>
|
|
97
|
+
* </div>
|
|
98
|
+
* )}
|
|
71
99
|
* </div>
|
|
72
100
|
* </div>
|
|
73
101
|
* )
|
|
@@ -79,4 +107,6 @@ import { SearchKeywords, SearchProducts } from '@nosto/nosto-js/client';
|
|
|
79
107
|
export declare function useResponse(): {
|
|
80
108
|
products: SearchProducts;
|
|
81
109
|
keywords: SearchKeywords;
|
|
110
|
+
popularSearches: SearchPopularSearches;
|
|
111
|
+
categories: SearchCategories;
|
|
82
112
|
};
|
|
@@ -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.
|
|
3
|
+
"version": "3.22.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -99,11 +99,11 @@
|
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"@commitlint/cli": "^20.1.0",
|
|
101
101
|
"@commitlint/config-conventional": "^20.0.0",
|
|
102
|
-
"@nosto/nosto-js": "^2.9.
|
|
102
|
+
"@nosto/nosto-js": "^2.9.2",
|
|
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.9.
|
|
106
|
+
"@types/node": "^24.9.1",
|
|
107
107
|
"@vitest/coverage-v8": "^3.2.4",
|
|
108
108
|
"concurrently": "^9.2.1",
|
|
109
109
|
"copyfiles": "^2.4.1",
|
|
@@ -112,7 +112,7 @@
|
|
|
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": "^7.0.
|
|
115
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
116
116
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
117
117
|
"eslint-plugin-unused-imports": "^4.3.0",
|
|
118
118
|
"husky": "^9.1.7",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"typedoc": "^0.28.14",
|
|
123
123
|
"typescript": "^5.9.3",
|
|
124
124
|
"typescript-eslint": "^8.46.2",
|
|
125
|
-
"vite": "^7.1.
|
|
125
|
+
"vite": "^7.1.12",
|
|
126
126
|
"vite-plugin-dts": "^4.5.4",
|
|
127
127
|
"vitest": "^3.1.3"
|
|
128
128
|
},
|