@nosto/search-js 3.4.1 → 3.6.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/AutocompletePageProvider-BoV4iLil.js +29 -0
- package/dist/AutocompletePageProvider-DPTHPXyz.cjs +1 -0
- package/dist/BaseElement-DgwqyaY8.cjs +1 -0
- package/dist/BaseElement-iXMoOyxY.js +23 -0
- package/dist/CategoryPageProvider-CkeR1heA.cjs +1 -0
- package/dist/CategoryPageProvider-Dzcbnz1W.js +26 -0
- package/dist/{InfiniteScrollWithObserver-DfQ4cqvs.js → InfiniteScrollWithObserver-Dh_gZaQ6.js} +1 -1
- package/dist/{InfiniteScrollWithObserver-DEmjpb8o.cjs → InfiniteScrollWithObserver-MCgxQ06X.cjs} +1 -1
- package/dist/SerpPageProvider-CCPCHjKU.cjs +1 -0
- package/dist/SerpPageProvider-Ca6ZoAOq.js +26 -0
- package/dist/{baseConfig-CR4INhSV.cjs → baseConfig-0GdMC5Qa.cjs} +1 -1
- package/dist/{baseConfig-BG_h7eA6.js → baseConfig-CvAG6x_p.js} +3 -3
- package/dist/bindInput-BnKvCky1.cjs +1 -0
- package/dist/bindInput-CCx0Fhsg.js +27 -0
- package/dist/core/core.cjs.js +1 -1
- package/dist/core/core.es.js +1 -1
- package/dist/isBot-Lnmft0Z0.js +20 -0
- package/dist/isBot-iyBlT_oq.cjs +1 -0
- package/dist/preact/autocomplete/autocomplete.cjs.js +1 -1
- package/dist/preact/autocomplete/autocomplete.d.ts +1 -0
- package/dist/preact/autocomplete/autocomplete.es.js +37 -42
- package/dist/preact/autocomplete/src/AutocompleteConfig.d.ts +25 -1
- package/dist/preact/autocomplete/src/components/HistoryElement.d.ts +23 -0
- package/dist/preact/category/category.cjs.js +1 -1
- package/dist/preact/category/category.es.js +2 -23
- package/dist/preact/common/common.cjs.js +1 -1
- package/dist/preact/common/common.es.js +4 -4
- package/dist/preact/common/src/components/BaseElement.d.ts +2 -1
- package/dist/preact/common/src/store/store.d.ts +1 -0
- package/dist/preact/common/src/store/storeContext.d.ts +1 -0
- package/dist/preact/common/src/store/storeExtensions.d.ts +1 -0
- package/dist/preact/hooks/hooks.cjs.js +1 -1
- package/dist/preact/hooks/hooks.es.js +3 -3
- package/dist/preact/inject/inject.cjs.js +1 -0
- package/dist/preact/inject/inject.d.ts +3 -0
- package/dist/preact/inject/inject.es.js +350 -0
- package/dist/preact/inject/src/components/ErrorBoundary.d.ts +8 -0
- package/dist/preact/inject/src/config.d.ts +117 -0
- package/dist/preact/inject/src/helpers/dom.d.ts +12 -0
- package/dist/preact/inject/src/init/autocomplete/AutocompleteContext.d.ts +12 -0
- package/dist/preact/inject/src/init/autocomplete/components/AutocompleteDropdown.d.ts +14 -0
- package/dist/preact/inject/src/init/autocomplete/components/AutocompleteHistory.d.ts +16 -0
- package/dist/preact/inject/src/init/autocomplete/components/createComponent.d.ts +13 -0
- package/dist/preact/inject/src/init/autocomplete/events/onClick.d.ts +2 -0
- package/dist/preact/inject/src/init/autocomplete/events/onFocus.d.ts +2 -0
- package/dist/preact/inject/src/init/autocomplete/events/onInput.d.ts +2 -0
- package/dist/preact/inject/src/init/autocomplete/events/onKeyDown.d.ts +5 -0
- package/dist/preact/inject/src/init/autocomplete/events/onSubmit.d.ts +2 -0
- package/dist/preact/inject/src/init/injectAutocomplete.d.ts +15 -0
- package/dist/preact/inject/src/init/injectCategory.d.ts +3 -0
- package/dist/preact/inject/src/init/injectComponent.d.ts +9 -0
- package/dist/preact/inject/src/init/injectSerp.d.ts +3 -0
- package/dist/preact/inject/src/init.d.ts +2 -0
- package/dist/preact/inject/src/resolveCssSelector.d.ts +8 -0
- package/dist/preact/inject/src/wait.d.ts +32 -0
- package/dist/preact/legacy/legacy.cjs.js +1 -1
- package/dist/preact/legacy/legacy.es.js +3 -3
- package/dist/preact/serp/serp.cjs.js +1 -1
- package/dist/preact/serp/serp.es.js +15 -34
- package/dist/search-DTqo1D6Y.cjs +1 -0
- package/dist/search-sC5QgJmw.js +170 -0
- package/dist/{useActions-BOhorGOy.js → useActions-Cd7V2qfb.js} +51 -42
- package/dist/useActions-yB4RkNMW.cjs +1 -0
- package/dist/{useLoadMore-D0TMnfNk.cjs → useLoadMore-DMhtg639.cjs} +1 -1
- package/dist/{useLoadMore-DGGR76Vv.js → useLoadMore-vgH5ApBL.js} +2 -2
- package/dist/utils/src/debounce.d.ts +1 -0
- package/dist/utils/utils.cjs.js +1 -1
- package/dist/utils/utils.es.js +18 -39
- package/package.json +21 -15
- package/dist/BaseElement-Ds4INJSy.cjs +0 -1
- package/dist/BaseElement-fZSwbg09.js +0 -17
- package/dist/isBot-CLCqH-df.cjs +0 -1
- package/dist/isBot-DfEzHKzJ.js +0 -20
- package/dist/search-DTLQih9k.cjs +0 -1
- package/dist/search-Iwwxc0Yj.js +0 -162
- package/dist/useActions-CDUotElR.cjs +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("../../AutocompletePageProvider-DPTHPXyz.cjs"),L=require("../../CategoryPageProvider-CkeR1heA.cjs"),m=require("../../useActions-yB4RkNMW.cjs"),x=require("../../SerpPageProvider-CCPCHjKU.cjs"),u=require("../../jsxRuntime.module-B3sGoTIU.cjs"),A=require("../../bindInput-BnKvCky1.cjs"),P=require("../../unique-BXXNictB.cjs"),g=require("preact"),b=require("../../logger-Boh_C6Bz.cjs"),O=require("preact/hooks"),B=require("../../index.es-Dp6Iaxz3.cjs"),y=require("../../search-DTqo1D6Y.cjs");function F(e){let t;return n=>{t&&clearTimeout(t),t=setTimeout(n,e)}}function p({children:e}){const[t]=O.useErrorBoundary();return t&&b.logger.error("Error caught in ErrorBoundary",t),u.u(g.Fragment,{children:e})}function C(e,t){return(typeof e=="string"?Array.from(document.querySelectorAll(e)):[e]).filter(o=>!0)}function H(e,t){let n=[];return C(e).forEach(o=>{const r=o.parentNode;r!==document&&r instanceof Element&&(n.push(r),n=n.concat(H(r)))}),n.filter(o=>t===void 0)}function I([e,t],n){const o=r=>{const s=r.target;s instanceof HTMLElement&&e&&s!==e&&s!==t&&!H(s).includes(e)&&n()};return document.addEventListener("click",o),{destroy:()=>{document.removeEventListener("click",o)}}}function T(e,t){e.tabIndex=0,e.addEventListener("blur",t)}function E(e){return typeof e=="string"?{selector:e,position:"last"}:{position:"last",...e}}function N({selector:e,timeout:t=500}){return new Promise(n=>{const o=C(e);if(o.length>0)return n(o);const r=new MutationObserver(()=>{const i=C(e);i.length>0&&(r.disconnect(),clearTimeout(s),n(i))}),s=setTimeout(()=>{r.disconnect(),b.logger.warn(`Timed out (${t}) while waiting for element ${e}`),n([])},t);r.observe(document.body,{childList:!0,subtree:!0})})}const k=g.createContext({reportProductClick:()=>{},reportKeywordClick:()=>{},handleSubmit:()=>{},highlightedElementIndex:-1});function $(e,t){const{dropdown:n,history:o,store:r,input:s,onNavigateToSearch:i}=e,a=(c,h)=>{n.hide(),o.hide(),c&&(o.add(c),r.updateState({historyItems:o.get()}),h&&B.s(l=>l.recordSearchSubmit(c)),s.value=c)};return{reportProductClick:c=>{a(c.name,!1)},reportKeywordClick:c=>{a(c.keyword,!0)},handleSubmit:c=>{a(c.query,!1),i?.(c)},highlightedElementIndex:t.highlightedIndex()}}function v(e,t,n){t.style.display="none";const o=(()=>{if(e.parentElement&&e.parentElement.classList.contains("nosto-autocomplete-wrapper"))return e.parentElement;const l=document.createElement("div");return l.className="nosto-autocomplete-wrapper",e.parentNode?.insertBefore(l,e.nextSibling),l.appendChild(e),l})(),r=E(n),s=r&&document.querySelector(r.selector);if(s){const l=document.createElement("form");l.className="nosto-dropdown-form",l.appendChild(t),r.position==="first"?s.prepend(l):s.appendChild(l)}else o.appendChild(t);const i={index:-1,onChangeListeners:[]},a=(l,d)=>{const f=l.length;f===0&&(d=-1),i.index=d>=0?d%f:f-1,i.onChangeListeners.forEach(D=>D())},c=()=>{i.index=-1,i.onChangeListeners.forEach(l=>l())},h=()=>i.index;return{element:t,hide:()=>{t.style.display="none",c()},show:()=>{t.style.display="inherit"},isOpen:()=>t.style.display!=="none",goDown:()=>{const l=Array.from(t.getElementsByClassName("ns-autocomplete-element")),d=h();a(l,d+1)},goUp:()=>{const l=Array.from(t.getElementsByClassName("ns-autocomplete-element")),d=h();a(l,d-1)},highlight:a,highlightedIndex:h,submitHighlightedItem:l=>{Array.from(t.querySelectorAll(".ns-autocomplete-element"))[l]?.click()},onHighlightChange:l=>{i.onChangeListeners.push(l)}}}function K(e,t){const n=document.createElement("div");return n.className="nosto-autocomplete-dropdown",{...v(e,n,t),element:n}}const w="nosto:search-js:history";function Q(e,t,n){const o=document.createElement("div");return o.className="nosto-autocomplete-history",{...v(e,o,t),element:o,add:s=>{const a=(y.getLocalStorageItem(w)??[]).filter(c=>c!==s).slice(n?-n:0);a.push(s),y.setLocalStorageItem(w,a)},get:()=>(y.getLocalStorageItem(w)??[]).reverse().filter(i=>!!i)}}async function M(e,{config:t,dropdown:n,history:o,renderHistory:r,store:s}){const{historyEnabled:i,minQueryLength:a}=t;if(e.length<a&&i&&r&&!o.isOpen()){o.show();return}if(e.length<a)return;n.hide();const c=s.getState()?.query?.query;c&&c!==e&&await m.newSearch({config:t,store:s},{query:e}),n.show()}async function U(e,t){const{config:n,renderHistory:o,history:r}=t,{historyEnabled:s,minQueryLength:i}=n;if(!o||e.length>=i||!s||r.isOpen())return;const a=R(t,r);r.onHighlightChange(()=>{a(o,r.element)}),r.show();const c=P.measure("renderHistory");a(o,r.element),c()}async function _(e,{config:t,dropdown:n,history:o,store:r,debouncer:s}){const{minQueryLength:i,historyEnabled:a}=t;if(e.length<i&&!a){n.hide(),o.hide();return}if(e.length<i&&a){n.hide(),o.show();return}o.hide(),s(async()=>{m.newSearch({config:t,store:r},{query:e}),n.show()})}function z(e,t,n){const{config:o,debouncer:r}=n;if(r(()=>{}),e.length>=o.minQueryLength)return q(t,n.dropdown,n.history);if(o.historyEnabled)return q(t,n.history,n.dropdown)}function q(e,t,n){if(!t.isOpen()&&e==="ArrowDown"){t.show(),n.hide();return}if(e==="Escape"&&t.hide(),!!t.isOpen()){if(e==="ArrowDown")t.goDown();else if(e==="ArrowUp")t.goUp();else if(e==="Enter"){const o=t.highlightedIndex();return o>=0&&t.submitHighlightedItem(o),t.hide(),o>=0}}}function G(e,{config:t,dropdown:n,history:o,onNavigateToSearch:r,store:s}){n.hide(),o.hide(),!(e.length<t.minQueryLength)&&(o.add(e),s.updateState({historyItems:o.get()}),r?.({query:e}))}async function J(e,t){const{inputCssSelector:n,timeout:o}=e,r=E(n).selector,s=await N({selector:r,timeout:o});if(s.length===0)throw new Error(`No elements found for selector: ${r}`);s.forEach(i=>{V(i,e,t)})}async function V(e,t,n){const{config:o,dropdownCssSelector:r}=t,s=K(e,r),i=Q(e,r,o.historySize),a={...t,input:e,dropdown:s,history:i,store:n,debouncer:F(o.debounceDelay)};X(a),e.setAttribute("data-nosto-element","search-input"),n.updateState({historyItems:i.get()}),A.disableNativeAutocomplete(e),n.onInit(()=>{W(a)}),A.bindInput(e,{onInput:c=>_(c,a),onFocus:c=>U(c,a),onClick:c=>M(c,a),onSubmit:c=>G(c,a),onKeyDown:(c,h)=>z(c,h,a)}),T(i.element,i.hide),T(s.element,s.hide),I([i.element,e],i.hide),I([s.element,e],s.hide)}function W(e){const{dropdown:t,renderAutocomplete:n}=e;if(!n)return;const o=R(e,t);t.onHighlightChange(()=>{o(n,t.element)});const r=P.measure("renderAutocomplete");o(n,t.element),r()}async function X(e){const{input:t,renderSpeechToText:n,config:o,store:r}=e;if(!n)return;const s="ns-autocomplete-voice-position";if(!!t.parentElement?.querySelector(`.${s}`))return;const a=document.createElement("div");a.className=s,t.insertAdjacentElement("afterend",a);const c=await n();g.render(u.u(p,{children:u.u(S.AutocompletePageProvider,{config:o,store:r,children:c})}),a)}function R(e,t){const{config:n,store:o}=e,r=$(e,t);return t.onHighlightChange(()=>{r.highlightedElementIndex=t.highlightedIndex()}),(s,i)=>g.render(u.u(p,{children:u.u(S.AutocompletePageProvider,{config:n,store:o,children:u.u(k,{value:r,children:s()})})}),i)}async function j({cssSelector:e,timeout:t,renderComponent:n}){const o=E(e).selector,r=await N({selector:o,timeout:t??100});if(r.length===0)throw new Error(`No elements found for selector: ${o}`);r.length>1&&b.logger.warn(`Multiple (${r.length}) elements found for selector: ${o}`),g.render(n(),r[0])}async function Y(e,t){const{render:n}=e,o=await n();j({...e,renderComponent:()=>u.u(p,{children:u.u(L.CategoryPageProvider,{store:t,config:e.config,children:o})})})}async function Z(e,t){const{render:n}=e,o=await n();j({...e,renderComponent:()=>u.u(p,{children:u.u(x.SearchPageProvider,{store:t,config:e.config,children:o})})})}async function ee(e){e.autocomplete&&await J({...e.autocomplete,config:S.makeAutocompleteConfig(e.autocomplete.config)},m.createStore({query:e.autocomplete.query})),e.category&&await Y({...e.category,config:L.makeCategoryConfig(e.category.config)},m.createStore()),e.serp&&await Z({...e.serp,config:x.makeSerpConfig(e.serp.config)},m.createStore())}exports.AutocompleteContext=k;exports.init=ee;
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { A as T, m as R } from "../../AutocompletePageProvider-BoV4iLil.js";
|
|
2
|
+
import { C as B, m as F } from "../../CategoryPageProvider-Dzcbnz1W.js";
|
|
3
|
+
import { n as L, c as f } from "../../useActions-Cd7V2qfb.js";
|
|
4
|
+
import { S as O, m as $ } from "../../SerpPageProvider-Ca6ZoAOq.js";
|
|
5
|
+
import { u as d } from "../../jsxRuntime.module-Bzuv3cXw.js";
|
|
6
|
+
import { d as j, b as v } from "../../bindInput-CCx0Fhsg.js";
|
|
7
|
+
import { a as x } from "../../unique-Cv2g464w.js";
|
|
8
|
+
import { Fragment as K, createContext as Q, render as w } from "preact";
|
|
9
|
+
import { l as C } from "../../logger-_fg_Za9y.js";
|
|
10
|
+
import { useErrorBoundary as U } from "preact/hooks";
|
|
11
|
+
import { s as M } from "../../index.es-XNBESE3P.js";
|
|
12
|
+
import { g as b, a as z } from "../../search-sC5QgJmw.js";
|
|
13
|
+
function G(e) {
|
|
14
|
+
let t;
|
|
15
|
+
return (n) => {
|
|
16
|
+
t && clearTimeout(t), t = setTimeout(n, e);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function h({ children: e }) {
|
|
20
|
+
const [t] = U();
|
|
21
|
+
return t && C.error("Error caught in ErrorBoundary", t), /* @__PURE__ */ d(K, { children: e });
|
|
22
|
+
}
|
|
23
|
+
function y(e, t) {
|
|
24
|
+
return (typeof e == "string" ? Array.from(document.querySelectorAll(e)) : [e]).filter((o) => !0);
|
|
25
|
+
}
|
|
26
|
+
function H(e, t) {
|
|
27
|
+
let n = [];
|
|
28
|
+
return y(e).forEach((o) => {
|
|
29
|
+
const r = o.parentNode;
|
|
30
|
+
r !== document && r instanceof Element && (n.push(r), n = n.concat(H(r)));
|
|
31
|
+
}), n.filter((o) => t === void 0);
|
|
32
|
+
}
|
|
33
|
+
function E([e, t], n) {
|
|
34
|
+
const o = (r) => {
|
|
35
|
+
const s = r.target;
|
|
36
|
+
s instanceof HTMLElement && e && s !== e && s !== t && !H(s).includes(e) && n();
|
|
37
|
+
};
|
|
38
|
+
return document.addEventListener("click", o), {
|
|
39
|
+
destroy: () => {
|
|
40
|
+
document.removeEventListener("click", o);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function A(e, t) {
|
|
45
|
+
e.tabIndex = 0, e.addEventListener("blur", t);
|
|
46
|
+
}
|
|
47
|
+
function S(e) {
|
|
48
|
+
return typeof e == "string" ? {
|
|
49
|
+
selector: e,
|
|
50
|
+
position: "last"
|
|
51
|
+
} : {
|
|
52
|
+
position: "last",
|
|
53
|
+
...e
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function N({ selector: e, timeout: t = 500 }) {
|
|
57
|
+
return new Promise((n) => {
|
|
58
|
+
const o = y(e);
|
|
59
|
+
if (o.length > 0)
|
|
60
|
+
return n(o);
|
|
61
|
+
const r = new MutationObserver(() => {
|
|
62
|
+
const i = y(e);
|
|
63
|
+
i.length > 0 && (r.disconnect(), clearTimeout(s), n(i));
|
|
64
|
+
}), s = setTimeout(() => {
|
|
65
|
+
r.disconnect(), C.warn(`Timed out (${t}) while waiting for element ${e}`), n([]);
|
|
66
|
+
}, t);
|
|
67
|
+
r.observe(document.body, {
|
|
68
|
+
childList: !0,
|
|
69
|
+
subtree: !0
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const J = Q({
|
|
74
|
+
reportProductClick: () => {
|
|
75
|
+
},
|
|
76
|
+
reportKeywordClick: () => {
|
|
77
|
+
},
|
|
78
|
+
handleSubmit: () => {
|
|
79
|
+
},
|
|
80
|
+
highlightedElementIndex: -1
|
|
81
|
+
});
|
|
82
|
+
function V(e, t) {
|
|
83
|
+
const { dropdown: n, history: o, store: r, input: s, onNavigateToSearch: i } = e, a = (c, u) => {
|
|
84
|
+
n.hide(), o.hide(), c && (o.add(c), r.updateState({
|
|
85
|
+
historyItems: o.get()
|
|
86
|
+
}), u && M((l) => l.recordSearchSubmit(c)), s.value = c);
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
reportProductClick: (c) => {
|
|
90
|
+
a(c.name, !1);
|
|
91
|
+
},
|
|
92
|
+
reportKeywordClick: (c) => {
|
|
93
|
+
a(c.keyword, !0);
|
|
94
|
+
},
|
|
95
|
+
handleSubmit: (c) => {
|
|
96
|
+
a(c.query, !1), i?.(c);
|
|
97
|
+
},
|
|
98
|
+
highlightedElementIndex: t.highlightedIndex()
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function k(e, t, n) {
|
|
102
|
+
t.style.display = "none";
|
|
103
|
+
const o = (() => {
|
|
104
|
+
if (e.parentElement && e.parentElement.classList.contains("nosto-autocomplete-wrapper"))
|
|
105
|
+
return e.parentElement;
|
|
106
|
+
const l = document.createElement("div");
|
|
107
|
+
return l.className = "nosto-autocomplete-wrapper", e.parentNode?.insertBefore(l, e.nextSibling), l.appendChild(e), l;
|
|
108
|
+
})(), r = S(n), s = r && document.querySelector(r.selector);
|
|
109
|
+
if (s) {
|
|
110
|
+
const l = document.createElement("form");
|
|
111
|
+
l.className = "nosto-dropdown-form", l.appendChild(t), r.position === "first" ? s.prepend(l) : s.appendChild(l);
|
|
112
|
+
} else
|
|
113
|
+
o.appendChild(t);
|
|
114
|
+
const i = {
|
|
115
|
+
index: -1,
|
|
116
|
+
onChangeListeners: []
|
|
117
|
+
}, a = (l, m) => {
|
|
118
|
+
const p = l.length;
|
|
119
|
+
p === 0 && (m = -1), i.index = m >= 0 ? m % p : p - 1, i.onChangeListeners.forEach((D) => D());
|
|
120
|
+
}, c = () => {
|
|
121
|
+
i.index = -1, i.onChangeListeners.forEach((l) => l());
|
|
122
|
+
}, u = () => i.index;
|
|
123
|
+
return {
|
|
124
|
+
element: t,
|
|
125
|
+
hide: () => {
|
|
126
|
+
t.style.display = "none", c();
|
|
127
|
+
},
|
|
128
|
+
show: () => {
|
|
129
|
+
t.style.display = "inherit";
|
|
130
|
+
},
|
|
131
|
+
isOpen: () => t.style.display !== "none",
|
|
132
|
+
goDown: () => {
|
|
133
|
+
const l = Array.from(t.getElementsByClassName("ns-autocomplete-element")), m = u();
|
|
134
|
+
a(l, m + 1);
|
|
135
|
+
},
|
|
136
|
+
goUp: () => {
|
|
137
|
+
const l = Array.from(t.getElementsByClassName("ns-autocomplete-element")), m = u();
|
|
138
|
+
a(l, m - 1);
|
|
139
|
+
},
|
|
140
|
+
highlight: a,
|
|
141
|
+
highlightedIndex: u,
|
|
142
|
+
submitHighlightedItem: (l) => {
|
|
143
|
+
Array.from(t.querySelectorAll(".ns-autocomplete-element"))[l]?.click();
|
|
144
|
+
},
|
|
145
|
+
onHighlightChange: (l) => {
|
|
146
|
+
i.onChangeListeners.push(l);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function W(e, t) {
|
|
151
|
+
const n = document.createElement("div");
|
|
152
|
+
return n.className = "nosto-autocomplete-dropdown", {
|
|
153
|
+
...k(e, n, t),
|
|
154
|
+
element: n
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const g = "nosto:search-js:history";
|
|
158
|
+
function X(e, t, n) {
|
|
159
|
+
const o = document.createElement("div");
|
|
160
|
+
return o.className = "nosto-autocomplete-history", {
|
|
161
|
+
...k(e, o, t),
|
|
162
|
+
element: o,
|
|
163
|
+
add: (s) => {
|
|
164
|
+
const a = (b(g) ?? []).filter((c) => c !== s).slice(n ? -n : 0);
|
|
165
|
+
a.push(s), z(g, a);
|
|
166
|
+
},
|
|
167
|
+
get: () => (b(g) ?? []).reverse().filter((i) => !!i)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function Y(e, { config: t, dropdown: n, history: o, renderHistory: r, store: s }) {
|
|
171
|
+
const { historyEnabled: i, minQueryLength: a } = t;
|
|
172
|
+
if (e.length < a && i && r && !o.isOpen()) {
|
|
173
|
+
o.show();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (e.length < a)
|
|
177
|
+
return;
|
|
178
|
+
n.hide();
|
|
179
|
+
const c = s.getState()?.query?.query;
|
|
180
|
+
c && c !== e && await L({ config: t, store: s }, { query: e }), n.show();
|
|
181
|
+
}
|
|
182
|
+
async function Z(e, t) {
|
|
183
|
+
const { config: n, renderHistory: o, history: r } = t, { historyEnabled: s, minQueryLength: i } = n;
|
|
184
|
+
if (!o || e.length >= i || !s || r.isOpen())
|
|
185
|
+
return;
|
|
186
|
+
const a = P(t, r);
|
|
187
|
+
r.onHighlightChange(() => {
|
|
188
|
+
a(o, r.element);
|
|
189
|
+
}), r.show();
|
|
190
|
+
const c = x("renderHistory");
|
|
191
|
+
a(o, r.element), c();
|
|
192
|
+
}
|
|
193
|
+
async function _(e, { config: t, dropdown: n, history: o, store: r, debouncer: s }) {
|
|
194
|
+
const { minQueryLength: i, historyEnabled: a } = t;
|
|
195
|
+
if (e.length < i && !a) {
|
|
196
|
+
n.hide(), o.hide();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (e.length < i && a) {
|
|
200
|
+
n.hide(), o.show();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
o.hide(), s(async () => {
|
|
204
|
+
L({ config: t, store: r }, { query: e }), n.show();
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function ee(e, t, n) {
|
|
208
|
+
const { config: o, debouncer: r } = n;
|
|
209
|
+
if (r(() => {
|
|
210
|
+
}), e.length >= o.minQueryLength)
|
|
211
|
+
return I(t, n.dropdown, n.history);
|
|
212
|
+
if (o.historyEnabled)
|
|
213
|
+
return I(t, n.history, n.dropdown);
|
|
214
|
+
}
|
|
215
|
+
function I(e, t, n) {
|
|
216
|
+
if (!t.isOpen() && e === "ArrowDown") {
|
|
217
|
+
t.show(), n.hide();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (e === "Escape" && t.hide(), !!t.isOpen()) {
|
|
221
|
+
if (e === "ArrowDown")
|
|
222
|
+
t.goDown();
|
|
223
|
+
else if (e === "ArrowUp")
|
|
224
|
+
t.goUp();
|
|
225
|
+
else if (e === "Enter") {
|
|
226
|
+
const o = t.highlightedIndex();
|
|
227
|
+
return o >= 0 && t.submitHighlightedItem(o), t.hide(), o >= 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function te(e, { config: t, dropdown: n, history: o, onNavigateToSearch: r, store: s }) {
|
|
232
|
+
n.hide(), o.hide(), !(e.length < t.minQueryLength) && (o.add(e), s.updateState({
|
|
233
|
+
historyItems: o.get()
|
|
234
|
+
}), r?.({
|
|
235
|
+
query: e
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
async function ne(e, t) {
|
|
239
|
+
const { inputCssSelector: n, timeout: o } = e, r = S(n).selector, s = await N({
|
|
240
|
+
selector: r,
|
|
241
|
+
timeout: o
|
|
242
|
+
});
|
|
243
|
+
if (s.length === 0)
|
|
244
|
+
throw new Error(`No elements found for selector: ${r}`);
|
|
245
|
+
s.forEach((i) => {
|
|
246
|
+
oe(i, e, t);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async function oe(e, t, n) {
|
|
250
|
+
const { config: o, dropdownCssSelector: r } = t, s = W(e, r), i = X(e, r, o.historySize), a = {
|
|
251
|
+
...t,
|
|
252
|
+
input: e,
|
|
253
|
+
dropdown: s,
|
|
254
|
+
history: i,
|
|
255
|
+
store: n,
|
|
256
|
+
debouncer: G(o.debounceDelay)
|
|
257
|
+
};
|
|
258
|
+
se(a), e.setAttribute("data-nosto-element", "search-input"), n.updateState({
|
|
259
|
+
historyItems: i.get()
|
|
260
|
+
}), j(e), n.onInit(() => {
|
|
261
|
+
re(a);
|
|
262
|
+
}), v(e, {
|
|
263
|
+
onInput: (c) => _(c, a),
|
|
264
|
+
onFocus: (c) => Z(c, a),
|
|
265
|
+
onClick: (c) => Y(c, a),
|
|
266
|
+
onSubmit: (c) => te(c, a),
|
|
267
|
+
onKeyDown: (c, u) => ee(c, u, a)
|
|
268
|
+
}), A(i.element, i.hide), A(s.element, s.hide), E([i.element, e], i.hide), E([s.element, e], s.hide);
|
|
269
|
+
}
|
|
270
|
+
function re(e) {
|
|
271
|
+
const { dropdown: t, renderAutocomplete: n } = e;
|
|
272
|
+
if (!n)
|
|
273
|
+
return;
|
|
274
|
+
const o = P(e, t);
|
|
275
|
+
t.onHighlightChange(() => {
|
|
276
|
+
o(n, t.element);
|
|
277
|
+
});
|
|
278
|
+
const r = x("renderAutocomplete");
|
|
279
|
+
o(n, t.element), r();
|
|
280
|
+
}
|
|
281
|
+
async function se(e) {
|
|
282
|
+
const { input: t, renderSpeechToText: n, config: o, store: r } = e;
|
|
283
|
+
if (!n) return;
|
|
284
|
+
const s = "ns-autocomplete-voice-position";
|
|
285
|
+
if (!!t.parentElement?.querySelector(`.${s}`)) return;
|
|
286
|
+
const a = document.createElement("div");
|
|
287
|
+
a.className = s, t.insertAdjacentElement("afterend", a);
|
|
288
|
+
const c = await n();
|
|
289
|
+
w(
|
|
290
|
+
/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(T, { config: o, store: r, children: c }) }),
|
|
291
|
+
a
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
function P(e, t) {
|
|
295
|
+
const { config: n, store: o } = e, r = V(e, t);
|
|
296
|
+
return t.onHighlightChange(() => {
|
|
297
|
+
r.highlightedElementIndex = t.highlightedIndex();
|
|
298
|
+
}), (s, i) => w(
|
|
299
|
+
/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(T, { config: n, store: o, children: /* @__PURE__ */ d(J, { value: r, children: s() }) }) }),
|
|
300
|
+
i
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
async function q({ cssSelector: e, timeout: t, renderComponent: n }) {
|
|
304
|
+
const o = S(e).selector, r = await N({
|
|
305
|
+
selector: o,
|
|
306
|
+
timeout: t ?? 100
|
|
307
|
+
});
|
|
308
|
+
if (r.length === 0)
|
|
309
|
+
throw new Error(`No elements found for selector: ${o}`);
|
|
310
|
+
r.length > 1 && C.warn(`Multiple (${r.length}) elements found for selector: ${o}`), w(n(), r[0]);
|
|
311
|
+
}
|
|
312
|
+
async function ie(e, t) {
|
|
313
|
+
const { render: n } = e, o = await n();
|
|
314
|
+
q({
|
|
315
|
+
...e,
|
|
316
|
+
renderComponent: () => /* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(B, { store: t, config: e.config, children: o }) })
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
async function ce(e, t) {
|
|
320
|
+
const { render: n } = e, o = await n();
|
|
321
|
+
q({
|
|
322
|
+
...e,
|
|
323
|
+
renderComponent: () => /* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(O, { store: t, config: e.config, children: o }) })
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
async function Se(e) {
|
|
327
|
+
e.autocomplete && await ne(
|
|
328
|
+
{
|
|
329
|
+
...e.autocomplete,
|
|
330
|
+
config: R(e.autocomplete.config)
|
|
331
|
+
},
|
|
332
|
+
f({ query: e.autocomplete.query })
|
|
333
|
+
), e.category && await ie(
|
|
334
|
+
{
|
|
335
|
+
...e.category,
|
|
336
|
+
config: F(e.category.config)
|
|
337
|
+
},
|
|
338
|
+
f()
|
|
339
|
+
), e.serp && await ce(
|
|
340
|
+
{
|
|
341
|
+
...e.serp,
|
|
342
|
+
config: $(e.serp.config)
|
|
343
|
+
},
|
|
344
|
+
f()
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
export {
|
|
348
|
+
J as AutocompleteContext,
|
|
349
|
+
Se as init
|
|
350
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { SearchQuery } from '@nosto/nosto-js/client';
|
|
2
|
+
import { AutocompleteConfig, PublicAutocompleteConfig } from '../../autocomplete/src/AutocompleteConfig';
|
|
3
|
+
import { CategoryConfig, PublicCategoryConfig } from '../../category/src/CategoryConfig';
|
|
4
|
+
import { PublicSerpConfig, SerpConfig } from '../../serp/src/SerpConfig';
|
|
5
|
+
import { VNode } from 'preact';
|
|
6
|
+
import { CssSelector } from './resolveCssSelector';
|
|
7
|
+
export type PublicAutocompleteInjectConfig = {
|
|
8
|
+
/**
|
|
9
|
+
* Configuration passthrough.
|
|
10
|
+
*/
|
|
11
|
+
config: PublicAutocompleteConfig;
|
|
12
|
+
/**
|
|
13
|
+
* Query to be used for autocomplete.
|
|
14
|
+
*/
|
|
15
|
+
query?: SearchQuery;
|
|
16
|
+
/**
|
|
17
|
+
* Maximum time (in milliseconds) to wait for the DOM to be available.
|
|
18
|
+
* If a selector is unable to find any elements after the timeout, an error will be thrown.
|
|
19
|
+
* @default 100
|
|
20
|
+
*/
|
|
21
|
+
timeout?: number;
|
|
22
|
+
/**
|
|
23
|
+
* CSS selector for the form element to bind search events like form submit.
|
|
24
|
+
*/
|
|
25
|
+
formCssSelector: CssSelector;
|
|
26
|
+
/**
|
|
27
|
+
* CSS selector for each input element to bind search events like input change and form submit.
|
|
28
|
+
*/
|
|
29
|
+
inputCssSelector: CssSelector;
|
|
30
|
+
/**
|
|
31
|
+
* CSS selector for autocomplete dropdown render.
|
|
32
|
+
* Leave undefined for default use (After input element)
|
|
33
|
+
*/
|
|
34
|
+
dropdownCssSelector: CssSelector;
|
|
35
|
+
/**
|
|
36
|
+
* Render function for autocomplete component.
|
|
37
|
+
*/
|
|
38
|
+
renderAutocomplete?: () => VNode | Promise<VNode>;
|
|
39
|
+
/**
|
|
40
|
+
* Render function for autocomplete history component.
|
|
41
|
+
*/
|
|
42
|
+
renderHistory?: () => VNode | Promise<VNode>;
|
|
43
|
+
/**
|
|
44
|
+
* Render function for speech to text component.
|
|
45
|
+
*/
|
|
46
|
+
renderSpeechToText?: () => VNode | Promise<VNode>;
|
|
47
|
+
/**
|
|
48
|
+
* If provided, will be called on search submit or "show all products" click.
|
|
49
|
+
*/
|
|
50
|
+
onNavigateToSearch?: (query: SearchQuery) => void;
|
|
51
|
+
};
|
|
52
|
+
export type AutocompleteInjectConfig = PublicAutocompleteInjectConfig & {
|
|
53
|
+
config: AutocompleteConfig;
|
|
54
|
+
};
|
|
55
|
+
export type PublicCategoryInjectConfig = {
|
|
56
|
+
/**
|
|
57
|
+
* Configuration passthrough.
|
|
58
|
+
*/
|
|
59
|
+
config: PublicCategoryConfig;
|
|
60
|
+
/**
|
|
61
|
+
* Maximum time (in milliseconds) to wait for the DOM to be available.
|
|
62
|
+
* If a selector is unable to find any elements after the timeout, an error will be thrown.
|
|
63
|
+
* @default 100
|
|
64
|
+
*/
|
|
65
|
+
timeout?: number;
|
|
66
|
+
/**
|
|
67
|
+
* CSS selector for category content rendering.
|
|
68
|
+
*/
|
|
69
|
+
cssSelector: CssSelector;
|
|
70
|
+
/**
|
|
71
|
+
* Render function for category content.
|
|
72
|
+
*/
|
|
73
|
+
render: () => VNode | Promise<VNode>;
|
|
74
|
+
};
|
|
75
|
+
export type CategoryInjectConfig = PublicCategoryInjectConfig & {
|
|
76
|
+
config: CategoryConfig;
|
|
77
|
+
};
|
|
78
|
+
export type PublicSerpInjectConfig = {
|
|
79
|
+
/**
|
|
80
|
+
* Configuration passthrough.
|
|
81
|
+
*/
|
|
82
|
+
config: PublicSerpConfig;
|
|
83
|
+
/**
|
|
84
|
+
* Maximum time (in milliseconds) to wait for the DOM to be available.
|
|
85
|
+
* If a selector is unable to find any elements after the timeout, an error will be thrown.
|
|
86
|
+
* @default 100
|
|
87
|
+
*/
|
|
88
|
+
timeout?: number;
|
|
89
|
+
/**
|
|
90
|
+
* CSS selector for search page rendering.
|
|
91
|
+
*/
|
|
92
|
+
cssSelector: CssSelector;
|
|
93
|
+
/**
|
|
94
|
+
* Render function for search page content.
|
|
95
|
+
*/
|
|
96
|
+
render: () => VNode | Promise<VNode>;
|
|
97
|
+
};
|
|
98
|
+
export type SerpInjectConfig = PublicSerpInjectConfig & {
|
|
99
|
+
config: SerpConfig;
|
|
100
|
+
};
|
|
101
|
+
export type InitConfig = {
|
|
102
|
+
/**
|
|
103
|
+
* Autocomplete injection config.
|
|
104
|
+
* If present, the autocomplete dropdown will be injected into the page.
|
|
105
|
+
*/
|
|
106
|
+
autocomplete?: PublicAutocompleteInjectConfig;
|
|
107
|
+
/**
|
|
108
|
+
* Category injection config.
|
|
109
|
+
* If present, the category page will be injected.
|
|
110
|
+
*/
|
|
111
|
+
category?: PublicCategoryInjectConfig;
|
|
112
|
+
/**
|
|
113
|
+
* Serp injection config.
|
|
114
|
+
* If present, the search result page will be injected.
|
|
115
|
+
*/
|
|
116
|
+
serp?: PublicSerpInjectConfig;
|
|
117
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type DOMTarget = string | Element;
|
|
2
|
+
export declare function findAll<T extends Element>(selector: DOMTarget, filterType?: {
|
|
3
|
+
new (): T;
|
|
4
|
+
}): T[];
|
|
5
|
+
export declare function DOMReady(): Promise<void>;
|
|
6
|
+
export declare function cloneNode<T extends Node>(node: T, deep: boolean): T;
|
|
7
|
+
export declare function parents(target: DOMTarget, selector?: string): Element[];
|
|
8
|
+
export declare function matches(target: DOMTarget, selector: string): boolean;
|
|
9
|
+
export declare function bindClickOutside([element, input]: HTMLElement[], callback: () => void): {
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
};
|
|
12
|
+
export declare function bindBlur(element: HTMLElement, callback: () => void): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SearchKeyword, SearchProduct, SearchQuery } from '@nosto/nosto-js/client';
|
|
2
|
+
import { AutocompleteInjectContext } from '../injectAutocomplete';
|
|
3
|
+
import { AutocompleteDropdown } from './components/AutocompleteDropdown';
|
|
4
|
+
import { AutocompleteHistory } from './components/AutocompleteHistory';
|
|
5
|
+
export type AutocompleteUserContext = {
|
|
6
|
+
reportProductClick: (product: SearchProduct) => void;
|
|
7
|
+
reportKeywordClick: (keyword: SearchKeyword) => void;
|
|
8
|
+
handleSubmit: (query: SearchQuery) => void;
|
|
9
|
+
highlightedElementIndex: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const AutocompleteContext: import('preact').Context<AutocompleteUserContext>;
|
|
12
|
+
export declare function createContextHandle(context: AutocompleteInjectContext, element: AutocompleteDropdown | AutocompleteHistory): AutocompleteUserContext;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CssSelector } from '../../../resolveCssSelector';
|
|
2
|
+
export type AutocompleteDropdown = ReturnType<typeof createDropdownComponent>;
|
|
3
|
+
export declare function createDropdownComponent(input: HTMLInputElement, dropdownSelector: CssSelector): {
|
|
4
|
+
element: HTMLDivElement;
|
|
5
|
+
hide: () => void;
|
|
6
|
+
show: () => void;
|
|
7
|
+
isOpen: () => boolean;
|
|
8
|
+
goDown: () => void;
|
|
9
|
+
goUp: () => void;
|
|
10
|
+
highlight: (elements: Element[], highlightIndex: number) => void;
|
|
11
|
+
highlightedIndex: () => number;
|
|
12
|
+
submitHighlightedItem: (highlightedIndex: number) => void;
|
|
13
|
+
onHighlightChange: (callback: () => void) => void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CssSelector } from '../../../resolveCssSelector';
|
|
2
|
+
export type AutocompleteHistory = ReturnType<typeof createHistoryComponent>;
|
|
3
|
+
export declare function createHistoryComponent(input: HTMLInputElement, dropdownSelector: CssSelector, historySize: number): {
|
|
4
|
+
element: HTMLDivElement;
|
|
5
|
+
add: (value: string) => void;
|
|
6
|
+
get: () => string[];
|
|
7
|
+
hide: () => void;
|
|
8
|
+
show: () => void;
|
|
9
|
+
isOpen: () => boolean;
|
|
10
|
+
goDown: () => void;
|
|
11
|
+
goUp: () => void;
|
|
12
|
+
highlight: (elements: Element[], highlightIndex: number) => void;
|
|
13
|
+
highlightedIndex: () => number;
|
|
14
|
+
submitHighlightedItem: (highlightedIndex: number) => void;
|
|
15
|
+
onHighlightChange: (callback: () => void) => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CssSelector } from '../../../resolveCssSelector';
|
|
2
|
+
export declare function createComponent(input: HTMLInputElement, dropdown: HTMLDivElement, dropdownSelector: CssSelector): {
|
|
3
|
+
element: HTMLDivElement;
|
|
4
|
+
hide: () => void;
|
|
5
|
+
show: () => void;
|
|
6
|
+
isOpen: () => boolean;
|
|
7
|
+
goDown: () => void;
|
|
8
|
+
goUp: () => void;
|
|
9
|
+
highlight: (elements: Element[], highlightIndex: number) => void;
|
|
10
|
+
highlightedIndex: () => number;
|
|
11
|
+
submitHighlightedItem: (highlightedIndex: number) => void;
|
|
12
|
+
onHighlightChange: (callback: () => void) => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AutocompleteInjectContext } from '../../injectAutocomplete';
|
|
2
|
+
import { AutocompleteDropdown } from '../components/AutocompleteDropdown';
|
|
3
|
+
import { AutocompleteHistory } from '../components/AutocompleteHistory';
|
|
4
|
+
export declare function onKeyDown(value: string, key: string, context: AutocompleteInjectContext): boolean | undefined;
|
|
5
|
+
export declare function elementControls(key: string, activeElement: AutocompleteDropdown | AutocompleteHistory, inactiveElement: AutocompleteDropdown | AutocompleteHistory): boolean | undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Store } from '../../../common/src/store/store';
|
|
2
|
+
import { debounce } from '../../../../utils/src/debounce';
|
|
3
|
+
import { VNode } from 'preact';
|
|
4
|
+
import { AutocompleteInjectConfig } from '../config';
|
|
5
|
+
import { AutocompleteDropdown } from './autocomplete/components/AutocompleteDropdown';
|
|
6
|
+
import { AutocompleteHistory } from './autocomplete/components/AutocompleteHistory';
|
|
7
|
+
export declare function injectAutocomplete(config: AutocompleteInjectConfig, store: Store): Promise<void>;
|
|
8
|
+
export type AutocompleteInjectContext = AutocompleteInjectConfig & {
|
|
9
|
+
input: HTMLInputElement;
|
|
10
|
+
dropdown: AutocompleteDropdown;
|
|
11
|
+
history: AutocompleteHistory;
|
|
12
|
+
store: Store;
|
|
13
|
+
debouncer: ReturnType<typeof debounce>;
|
|
14
|
+
};
|
|
15
|
+
export declare function createUserComponentRenderer(injectContext: AutocompleteInjectContext, element: AutocompleteDropdown | AutocompleteHistory): (renderer: () => VNode | Promise<VNode>, target: HTMLDivElement) => void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { JSX } from 'preact/jsx-runtime';
|
|
2
|
+
import { CssSelector } from '../resolveCssSelector';
|
|
3
|
+
type Props = {
|
|
4
|
+
cssSelector: CssSelector;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
renderComponent: () => JSX.Element;
|
|
7
|
+
};
|
|
8
|
+
export declare function injectComponent({ cssSelector, timeout, renderComponent }: Props): Promise<void>;
|
|
9
|
+
export {};
|