@seekora-ai/ui-sdk-react 0.2.7 → 0.2.8
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/components/suggestions-primitives/SearchInput.d.ts +5 -1
- package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SearchInput.js +5 -2
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestionsEnhanced.js +30 -8
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.esm.js +35 -10
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +35 -10
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -3
package/dist/src/index.d.ts
CHANGED
|
@@ -1518,13 +1518,17 @@ interface SearchInputProps {
|
|
|
1518
1518
|
placeholder?: string;
|
|
1519
1519
|
autoFocus?: boolean;
|
|
1520
1520
|
showClearButton?: boolean;
|
|
1521
|
+
/** When false, blur does not close the dropdown (e.g. for overlay mode). Default true. */
|
|
1522
|
+
closeOnBlur?: boolean;
|
|
1523
|
+
/** Optional icon (e.g. magnifying glass) rendered to the left of the input */
|
|
1524
|
+
leftIcon?: React__default.ReactNode;
|
|
1521
1525
|
className?: string;
|
|
1522
1526
|
style?: React__default.CSSProperties;
|
|
1523
1527
|
inputClassName?: string;
|
|
1524
1528
|
inputStyle?: React__default.CSSProperties;
|
|
1525
1529
|
ariaLabel?: string;
|
|
1526
1530
|
}
|
|
1527
|
-
declare function SearchInput({ placeholder, autoFocus, showClearButton, className, style, inputClassName, inputStyle, ariaLabel, }: SearchInputProps): React__default.JSX.Element;
|
|
1531
|
+
declare function SearchInput({ placeholder, autoFocus, showClearButton, closeOnBlur, leftIcon, className, style, inputClassName, inputStyle, ariaLabel, }: SearchInputProps): React__default.JSX.Element;
|
|
1528
1532
|
|
|
1529
1533
|
/**
|
|
1530
1534
|
* DropdownPanel – floating panel for suggestions (primitive)
|
package/dist/src/index.esm.js
CHANGED
|
@@ -4534,15 +4534,16 @@ function parseHighlight(highlighted) {
|
|
|
4534
4534
|
.replace(/__\/ais-highlight__/g, '</mark>');
|
|
4535
4535
|
}
|
|
4536
4536
|
function transformProduct(raw) {
|
|
4537
|
+
const meta = raw.metadata || {};
|
|
4537
4538
|
return {
|
|
4538
4539
|
id: raw.id || raw.objectID,
|
|
4539
4540
|
objectID: raw.objectID || raw.id,
|
|
4540
|
-
title: raw.title || raw.name || raw.productName,
|
|
4541
|
-
name: raw.name || raw.title,
|
|
4542
|
-
image: raw.image || raw.imageUrl ||
|
|
4543
|
-
price: raw.price
|
|
4544
|
-
currency: raw.currency ||
|
|
4545
|
-
url: raw.url || raw.productId ||
|
|
4541
|
+
title: raw.title || raw.name || raw.productName || meta.name || meta.productName || '',
|
|
4542
|
+
name: raw.name || raw.title || meta.name || meta.productName || '',
|
|
4543
|
+
image: raw.image || raw.imageUrl || meta.image || meta.image_url || meta.images?.[0] || '',
|
|
4544
|
+
price: raw.price ?? raw.sellPrice ?? meta.sellPrice ?? meta.price,
|
|
4545
|
+
currency: raw.currency || meta.currency || '',
|
|
4546
|
+
url: raw.url || raw.productId || meta.url || meta.productId || '',
|
|
4546
4547
|
clicks: raw.clicks,
|
|
4547
4548
|
conversions: raw.conversions,
|
|
4548
4549
|
revenue: raw.revenue,
|
|
@@ -4592,7 +4593,10 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4592
4593
|
}, [enableRecentSearches, recentSearchesKey, maxRecentSearches]);
|
|
4593
4594
|
// Fetch suggestions
|
|
4594
4595
|
const fetchSuggestions = useCallback(async (searchQuery) => {
|
|
4595
|
-
if (!client
|
|
4596
|
+
if (!client)
|
|
4597
|
+
return;
|
|
4598
|
+
// When minQueryLength is 0, allow empty query so overlay can show default/trending recommendations on open
|
|
4599
|
+
if (!searchQuery.trim() && minQueryLength > 0) {
|
|
4596
4600
|
setSuggestions([]);
|
|
4597
4601
|
setDropdownRecommendations(null);
|
|
4598
4602
|
return;
|
|
@@ -4627,12 +4631,17 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4627
4631
|
setSuggestions(transformedSuggestions);
|
|
4628
4632
|
// Extract dropdown recommendations from extensions
|
|
4629
4633
|
const extensions = (response.extensions || {});
|
|
4634
|
+
const rawResults = response.results;
|
|
4635
|
+
const secondResultHits = Array.isArray(rawResults?.[1]?.hits) ? rawResults[1].hits : [];
|
|
4636
|
+
// Multi-index response: results[0]=suggestions, results[1]=product hits; expose results[1].hits as product_hits for fallback when extensions have no products
|
|
4637
|
+
const productHits = secondResultHits.length > 0 ? secondResultHits.map((h) => transformProduct(h)) : [];
|
|
4630
4638
|
const recommendations = {
|
|
4631
4639
|
trending_searches: Array.isArray(extensions.trending_searches) ? extensions.trending_searches : [],
|
|
4632
4640
|
top_searches: Array.isArray(extensions.top_searches) ? extensions.top_searches : [],
|
|
4633
4641
|
related_searches: Array.isArray(extensions.related_searches) ? extensions.related_searches : [],
|
|
4634
4642
|
trending_products: Array.isArray(extensions.trending_products) ? extensions.trending_products.map(transformProduct) : [],
|
|
4635
4643
|
item_recommendations: Array.isArray(extensions.item_recommendations) ? extensions.item_recommendations.map(transformProduct) : [],
|
|
4644
|
+
product_hits: productHits.length > 0 ? productHits : undefined,
|
|
4636
4645
|
popular_brands: Array.isArray(extensions.popular_brands) ? extensions.popular_brands : [],
|
|
4637
4646
|
filtered_tabs: Array.isArray(extensions.filtered_tabs) ? extensions.filtered_tabs.map(transformFilteredTab) : [],
|
|
4638
4647
|
processing_time_ms: typeof extensions.processing_time_ms === 'number' ? extensions.processing_time_ms : undefined,
|
|
@@ -4692,6 +4701,7 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4692
4701
|
}
|
|
4693
4702
|
}, [
|
|
4694
4703
|
client,
|
|
4704
|
+
minQueryLength,
|
|
4695
4705
|
maxSuggestions,
|
|
4696
4706
|
includeDropdownRecommendations,
|
|
4697
4707
|
includeCategories,
|
|
@@ -4768,7 +4778,19 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4768
4778
|
const relatedSearches = dropdownRecommendations?.related_searches || [];
|
|
4769
4779
|
const popularBrands = dropdownRecommendations?.popular_brands || [];
|
|
4770
4780
|
const filteredTabsResult = dropdownRecommendations?.filtered_tabs || [];
|
|
4771
|
-
|
|
4781
|
+
// Use trending_products, then item_recommendations, then first filtered_tab's products, then results[1].hits (product_hits) so grid shows for any API shape
|
|
4782
|
+
const trendingProducts = useMemo(() => {
|
|
4783
|
+
const fromTrending = dropdownRecommendations?.trending_products;
|
|
4784
|
+
if (fromTrending && fromTrending.length > 0)
|
|
4785
|
+
return fromTrending;
|
|
4786
|
+
const fromItemRecs = dropdownRecommendations?.item_recommendations;
|
|
4787
|
+
if (fromItemRecs && fromItemRecs.length > 0)
|
|
4788
|
+
return fromItemRecs;
|
|
4789
|
+
const firstTab = dropdownRecommendations?.filtered_tabs?.[0];
|
|
4790
|
+
if (firstTab?.products && firstTab.products.length > 0)
|
|
4791
|
+
return firstTab.products;
|
|
4792
|
+
return dropdownRecommendations?.product_hits ?? [];
|
|
4793
|
+
}, [dropdownRecommendations?.trending_products, dropdownRecommendations?.item_recommendations, dropdownRecommendations?.filtered_tabs, dropdownRecommendations?.product_hits]);
|
|
4772
4794
|
const hasContent = useMemo(() => {
|
|
4773
4795
|
return (suggestions.length > 0 ||
|
|
4774
4796
|
recentSearches.length > 0 ||
|
|
@@ -6969,15 +6991,17 @@ const inputStyles = {
|
|
|
6969
6991
|
color: 'var(--seekora-text-primary, #111827)',
|
|
6970
6992
|
fontFamily: 'inherit',
|
|
6971
6993
|
};
|
|
6972
|
-
function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearButton = true, className, style, inputClassName, inputStyle, ariaLabel = 'Search', }) {
|
|
6994
|
+
function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearButton = true, closeOnBlur = true, leftIcon, className, style, inputClassName, inputStyle, ariaLabel = 'Search', }) {
|
|
6973
6995
|
const { query, setQuery, isOpen, setIsOpen, navigateNext, navigatePrev, selectActive, close, } = useSuggestionsContext();
|
|
6974
6996
|
const inputRef = useRef(null);
|
|
6975
6997
|
const handleFocus = useCallback(() => {
|
|
6976
6998
|
setIsOpen(true);
|
|
6977
6999
|
}, [setIsOpen]);
|
|
6978
7000
|
const handleBlur = useCallback(() => {
|
|
7001
|
+
if (!closeOnBlur)
|
|
7002
|
+
return;
|
|
6979
7003
|
setTimeout(() => close(), 200);
|
|
6980
|
-
}, [close]);
|
|
7004
|
+
}, [close, closeOnBlur]);
|
|
6981
7005
|
const handleChange = useCallback((e) => {
|
|
6982
7006
|
setQuery(e.target.value);
|
|
6983
7007
|
}, [setQuery]);
|
|
@@ -7010,6 +7034,7 @@ function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearBu
|
|
|
7010
7034
|
}, [setQuery]);
|
|
7011
7035
|
return (React.createElement("div", { className: clsx('seekora-suggestions-search-input-wrapper', className), style: { ...defaultStyles, ...style } },
|
|
7012
7036
|
React.createElement("div", { className: "seekora-suggestions-input-wrapper", style: inputWrapperStyles },
|
|
7037
|
+
leftIcon ? (React.createElement("span", { className: "seekora-suggestions-input-left-icon", style: { display: 'flex', flexShrink: 0, color: 'var(--seekora-text-secondary, #6b7280)' } }, leftIcon)) : null,
|
|
7013
7038
|
React.createElement("input", { ref: inputRef, type: "text", value: query, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, placeholder: placeholder, autoFocus: autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, "aria-label": ariaLabel, "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-autocomplete": "list", role: "combobox", className: clsx('seekora-suggestions-input', inputClassName), style: { ...inputStyles, ...inputStyle } }),
|
|
7014
7039
|
showClearButton && query ? (React.createElement("button", { type: "button", onClick: handleClear, className: "seekora-suggestions-input-clear", "aria-label": "Clear search", style: {
|
|
7015
7040
|
padding: 4,
|