@seekora-ai/ui-sdk-react 0.2.7 → 0.2.9
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/RichQuerySuggestions.d.ts +4 -0
- package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
- package/dist/components/RichQuerySuggestions.js +3 -1
- package/dist/components/suggestions/SuggestionSearchBar.d.ts +4 -0
- package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -1
- package/dist/components/suggestions/SuggestionSearchBar.js +6 -2
- 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 +4 -0
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestionsEnhanced.js +35 -9
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +17 -1
- package/dist/src/index.esm.js +49 -14
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +49 -14
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -3
package/dist/src/index.js
CHANGED
|
@@ -4536,15 +4536,16 @@ function parseHighlight(highlighted) {
|
|
|
4536
4536
|
.replace(/__\/ais-highlight__/g, '</mark>');
|
|
4537
4537
|
}
|
|
4538
4538
|
function transformProduct(raw) {
|
|
4539
|
+
const meta = raw.metadata || {};
|
|
4539
4540
|
return {
|
|
4540
4541
|
id: raw.id || raw.objectID,
|
|
4541
4542
|
objectID: raw.objectID || raw.id,
|
|
4542
|
-
title: raw.title || raw.name || raw.productName,
|
|
4543
|
-
name: raw.name || raw.title,
|
|
4544
|
-
image: raw.image || raw.imageUrl ||
|
|
4545
|
-
price: raw.price
|
|
4546
|
-
currency: raw.currency ||
|
|
4547
|
-
url: raw.url || raw.productId ||
|
|
4543
|
+
title: raw.title || raw.name || raw.productName || meta.name || meta.productName || '',
|
|
4544
|
+
name: raw.name || raw.title || meta.name || meta.productName || '',
|
|
4545
|
+
image: raw.image || raw.imageUrl || meta.image || meta.image_url || meta.images?.[0] || '',
|
|
4546
|
+
price: raw.price ?? raw.sellPrice ?? meta.sellPrice ?? meta.price,
|
|
4547
|
+
currency: raw.currency || meta.currency || '',
|
|
4548
|
+
url: raw.url || raw.productId || meta.url || meta.productId || '',
|
|
4548
4549
|
clicks: raw.clicks,
|
|
4549
4550
|
conversions: raw.conversions,
|
|
4550
4551
|
revenue: raw.revenue,
|
|
@@ -4566,7 +4567,7 @@ function transformFilteredTab(raw) {
|
|
|
4566
4567
|
// Main Hook
|
|
4567
4568
|
// ============================================================================
|
|
4568
4569
|
function useQuerySuggestionsEnhanced(options) {
|
|
4569
|
-
const { client, query, enabled = true, debounceMs = 200, maxSuggestions = 10, minQueryLength = 1, includeDropdownRecommendations = false, includeCategories = true, includeFacets = false, maxCategories = 3, maxFacets = 5, filteredTabs, minPopularity, timeRange, disableTypoTolerance, analyticsTags, enableRecentSearches = true, maxRecentSearches = MAX_RECENT_SEARCHES_DEFAULT, recentSearchesKey = RECENT_SEARCHES_DEFAULT_KEY, onSuggestionsLoaded, onError, } = options;
|
|
4570
|
+
const { client, query, enabled = true, debounceMs = 200, maxSuggestions = 10, minQueryLength = 1, includeDropdownRecommendations = false, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, includeFacets = false, maxCategories = 3, maxFacets = 5, filteredTabs, minPopularity, timeRange, disableTypoTolerance, analyticsTags, enableRecentSearches = true, maxRecentSearches = MAX_RECENT_SEARCHES_DEFAULT, recentSearchesKey = RECENT_SEARCHES_DEFAULT_KEY, onSuggestionsLoaded, onError, } = options;
|
|
4570
4571
|
// State
|
|
4571
4572
|
const [suggestions, setSuggestions] = React.useState([]);
|
|
4572
4573
|
const [loading, setLoading] = React.useState(false);
|
|
@@ -4594,7 +4595,10 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4594
4595
|
}, [enableRecentSearches, recentSearchesKey, maxRecentSearches]);
|
|
4595
4596
|
// Fetch suggestions
|
|
4596
4597
|
const fetchSuggestions = React.useCallback(async (searchQuery) => {
|
|
4597
|
-
if (!client
|
|
4598
|
+
if (!client)
|
|
4599
|
+
return;
|
|
4600
|
+
// When minQueryLength is 0, allow empty query so overlay can show default/trending recommendations on open
|
|
4601
|
+
if (!searchQuery.trim() && minQueryLength > 0) {
|
|
4598
4602
|
setSuggestions([]);
|
|
4599
4603
|
setDropdownRecommendations(null);
|
|
4600
4604
|
return;
|
|
@@ -4610,6 +4614,8 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4610
4614
|
const response = await client.getSuggestions?.(searchQuery, {
|
|
4611
4615
|
hitsPerPage: maxSuggestions,
|
|
4612
4616
|
include_dropdown_recommendations: includeDropdownRecommendations || (filteredTabs && filteredTabs.length > 0),
|
|
4617
|
+
include_dropdown_product_list: includeDropdownProductList,
|
|
4618
|
+
include_filtered_tabs: includeFilteredTabs,
|
|
4613
4619
|
include_categories: includeCategories,
|
|
4614
4620
|
include_facets: includeFacets,
|
|
4615
4621
|
max_categories: maxCategories,
|
|
@@ -4629,12 +4635,17 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4629
4635
|
setSuggestions(transformedSuggestions);
|
|
4630
4636
|
// Extract dropdown recommendations from extensions
|
|
4631
4637
|
const extensions = (response.extensions || {});
|
|
4638
|
+
const rawResults = response.results;
|
|
4639
|
+
const secondResultHits = Array.isArray(rawResults?.[1]?.hits) ? rawResults[1].hits : [];
|
|
4640
|
+
// Multi-index response: results[0]=suggestions, results[1]=product hits; expose results[1].hits as product_hits for fallback when extensions have no products
|
|
4641
|
+
const productHits = secondResultHits.length > 0 ? secondResultHits.map((h) => transformProduct(h)) : [];
|
|
4632
4642
|
const recommendations = {
|
|
4633
4643
|
trending_searches: Array.isArray(extensions.trending_searches) ? extensions.trending_searches : [],
|
|
4634
4644
|
top_searches: Array.isArray(extensions.top_searches) ? extensions.top_searches : [],
|
|
4635
4645
|
related_searches: Array.isArray(extensions.related_searches) ? extensions.related_searches : [],
|
|
4636
4646
|
trending_products: Array.isArray(extensions.trending_products) ? extensions.trending_products.map(transformProduct) : [],
|
|
4637
4647
|
item_recommendations: Array.isArray(extensions.item_recommendations) ? extensions.item_recommendations.map(transformProduct) : [],
|
|
4648
|
+
product_hits: productHits.length > 0 ? productHits : undefined,
|
|
4638
4649
|
popular_brands: Array.isArray(extensions.popular_brands) ? extensions.popular_brands : [],
|
|
4639
4650
|
filtered_tabs: Array.isArray(extensions.filtered_tabs) ? extensions.filtered_tabs.map(transformFilteredTab) : [],
|
|
4640
4651
|
processing_time_ms: typeof extensions.processing_time_ms === 'number' ? extensions.processing_time_ms : undefined,
|
|
@@ -4694,8 +4705,11 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4694
4705
|
}
|
|
4695
4706
|
}, [
|
|
4696
4707
|
client,
|
|
4708
|
+
minQueryLength,
|
|
4697
4709
|
maxSuggestions,
|
|
4698
4710
|
includeDropdownRecommendations,
|
|
4711
|
+
includeDropdownProductList,
|
|
4712
|
+
includeFilteredTabs,
|
|
4699
4713
|
includeCategories,
|
|
4700
4714
|
includeFacets,
|
|
4701
4715
|
maxCategories,
|
|
@@ -4770,7 +4784,19 @@ function useQuerySuggestionsEnhanced(options) {
|
|
|
4770
4784
|
const relatedSearches = dropdownRecommendations?.related_searches || [];
|
|
4771
4785
|
const popularBrands = dropdownRecommendations?.popular_brands || [];
|
|
4772
4786
|
const filteredTabsResult = dropdownRecommendations?.filtered_tabs || [];
|
|
4773
|
-
|
|
4787
|
+
// 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
|
|
4788
|
+
const trendingProducts = React.useMemo(() => {
|
|
4789
|
+
const fromTrending = dropdownRecommendations?.trending_products;
|
|
4790
|
+
if (fromTrending && fromTrending.length > 0)
|
|
4791
|
+
return fromTrending;
|
|
4792
|
+
const fromItemRecs = dropdownRecommendations?.item_recommendations;
|
|
4793
|
+
if (fromItemRecs && fromItemRecs.length > 0)
|
|
4794
|
+
return fromItemRecs;
|
|
4795
|
+
const firstTab = dropdownRecommendations?.filtered_tabs?.[0];
|
|
4796
|
+
if (firstTab?.products && firstTab.products.length > 0)
|
|
4797
|
+
return firstTab.products;
|
|
4798
|
+
return dropdownRecommendations?.product_hits ?? [];
|
|
4799
|
+
}, [dropdownRecommendations?.trending_products, dropdownRecommendations?.item_recommendations, dropdownRecommendations?.filtered_tabs, dropdownRecommendations?.product_hits]);
|
|
4774
4800
|
const hasContent = React.useMemo(() => {
|
|
4775
4801
|
return (suggestions.length > 0 ||
|
|
4776
4802
|
recentSearches.length > 0 ||
|
|
@@ -5453,7 +5479,7 @@ const CloseIcon = () => (React.createElement("svg", { viewBox: "0 0 20 20", fill
|
|
|
5453
5479
|
// Component
|
|
5454
5480
|
// ============================================================================
|
|
5455
5481
|
const RichQuerySuggestions = React.forwardRef(function RichQuerySuggestions(props, ref) {
|
|
5456
|
-
const { query, isOpen = true, sections = DEFAULT_SECTIONS, maxSuggestionsPerSection = 8, minQueryLength = 0, debounceMs = 200, includeDropdownRecommendations = true, includeCategories = true, maxCategories = 3, showCounts = true, showCategoryCounts = true, showSectionHeaders = true, classNames = {}, style, renderSuggestion, renderCategory, renderTrendingItem, renderRecentItem, header, footer, width = '100%', maxHeight = '480px', zIndex = 1000, ariaLabel = 'Search suggestions', analyticsTags, onSuggestionSelect, onCategoryClick, onRecentSearchClick, onRecentSearchRemove, onViewAllClick, onOpen, onClose, } = props;
|
|
5482
|
+
const { query, isOpen = true, sections = DEFAULT_SECTIONS, maxSuggestionsPerSection = 8, minQueryLength = 0, debounceMs = 200, includeDropdownRecommendations = true, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, maxCategories = 3, showCounts = true, showCategoryCounts = true, showSectionHeaders = true, classNames = {}, style, renderSuggestion, renderCategory, renderTrendingItem, renderRecentItem, header, footer, width = '100%', maxHeight = '480px', zIndex = 1000, ariaLabel = 'Search suggestions', analyticsTags, onSuggestionSelect, onCategoryClick, onRecentSearchClick, onRecentSearchRemove, onViewAllClick, onOpen, onClose, } = props;
|
|
5457
5483
|
const { client } = useSearchContext();
|
|
5458
5484
|
const containerRef = React.useRef(null);
|
|
5459
5485
|
const [activeIndex, setActiveIndex] = React.useState(-1);
|
|
@@ -5467,6 +5493,8 @@ const RichQuerySuggestions = React.forwardRef(function RichQuerySuggestions(prop
|
|
|
5467
5493
|
maxSuggestions: maxSuggestionsPerSection,
|
|
5468
5494
|
minQueryLength,
|
|
5469
5495
|
includeDropdownRecommendations,
|
|
5496
|
+
includeDropdownProductList,
|
|
5497
|
+
includeFilteredTabs,
|
|
5470
5498
|
includeCategories,
|
|
5471
5499
|
maxCategories,
|
|
5472
5500
|
analyticsTags,
|
|
@@ -6971,15 +6999,17 @@ const inputStyles = {
|
|
|
6971
6999
|
color: 'var(--seekora-text-primary, #111827)',
|
|
6972
7000
|
fontFamily: 'inherit',
|
|
6973
7001
|
};
|
|
6974
|
-
function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearButton = true, className, style, inputClassName, inputStyle, ariaLabel = 'Search', }) {
|
|
7002
|
+
function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearButton = true, closeOnBlur = true, leftIcon, className, style, inputClassName, inputStyle, ariaLabel = 'Search', }) {
|
|
6975
7003
|
const { query, setQuery, isOpen, setIsOpen, navigateNext, navigatePrev, selectActive, close, } = useSuggestionsContext();
|
|
6976
7004
|
const inputRef = React.useRef(null);
|
|
6977
7005
|
const handleFocus = React.useCallback(() => {
|
|
6978
7006
|
setIsOpen(true);
|
|
6979
7007
|
}, [setIsOpen]);
|
|
6980
7008
|
const handleBlur = React.useCallback(() => {
|
|
7009
|
+
if (!closeOnBlur)
|
|
7010
|
+
return;
|
|
6981
7011
|
setTimeout(() => close(), 200);
|
|
6982
|
-
}, [close]);
|
|
7012
|
+
}, [close, closeOnBlur]);
|
|
6983
7013
|
const handleChange = React.useCallback((e) => {
|
|
6984
7014
|
setQuery(e.target.value);
|
|
6985
7015
|
}, [setQuery]);
|
|
@@ -7012,6 +7042,7 @@ function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearBu
|
|
|
7012
7042
|
}, [setQuery]);
|
|
7013
7043
|
return (React.createElement("div", { className: clsx('seekora-suggestions-search-input-wrapper', className), style: { ...defaultStyles, ...style } },
|
|
7014
7044
|
React.createElement("div", { className: "seekora-suggestions-input-wrapper", style: inputWrapperStyles },
|
|
7045
|
+
leftIcon ? (React.createElement("span", { className: "seekora-suggestions-input-left-icon", style: { display: 'flex', flexShrink: 0, color: 'var(--seekora-text-secondary, #6b7280)' } }, leftIcon)) : null,
|
|
7015
7046
|
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 } }),
|
|
7016
7047
|
showClearButton && query ? (React.createElement("button", { type: "button", onClick: handleClear, className: "seekora-suggestions-input-clear", "aria-label": "Clear search", style: {
|
|
7017
7048
|
padding: 4,
|
|
@@ -11767,7 +11798,7 @@ const createStyles = (isMobile) => ({
|
|
|
11767
11798
|
// Component
|
|
11768
11799
|
// ============================================================================
|
|
11769
11800
|
const SuggestionSearchBar = React.forwardRef(function SuggestionSearchBar(props, ref) {
|
|
11770
|
-
const { client, variant = 'amazon', autoMobileVariant = true, placeholder = 'Search...', defaultQuery = '', value, minQueryLength = 1, maxSuggestions = 8, debounceMs = 200, includeDropdownRecommendations = true, includeCategories = true, filteredTabs, analyticsTags, enableRecentSearches = true, maxRecentSearches = 10, showProducts = true, showTrendingOnEmpty = true, enableAnalytics = true, analyticsConfig, suggestionFields, productFields, theme, onSearch, onQueryChange, onSuggestionSelect, onProductClick, onCategoryClick, onTabChange, className, style, inputClassName, dropdownWidth, dropdownMaxHeight = '500px', zIndex = 1000, enableCache = true, cacheTtlMs = 30000, cacheMaxSize = 100, } = props;
|
|
11801
|
+
const { client, variant = 'amazon', autoMobileVariant = true, placeholder = 'Search...', defaultQuery = '', value, minQueryLength = 1, maxSuggestions = 8, debounceMs = 200, includeDropdownRecommendations = true, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, filteredTabs, analyticsTags, enableRecentSearches = true, maxRecentSearches = 10, showProducts = true, showTrendingOnEmpty = true, enableAnalytics = true, analyticsConfig, suggestionFields, productFields, theme, onSearch, onQueryChange, onSuggestionSelect, onProductClick, onCategoryClick, onTabChange, className, style, inputClassName, dropdownWidth, dropdownMaxHeight = '500px', zIndex = 1000, enableCache = true, cacheTtlMs = 30000, cacheMaxSize = 100, } = props;
|
|
11771
11802
|
// Theme: prop overrides context (SearchProvider theme)
|
|
11772
11803
|
const searchContext = useSearchContext();
|
|
11773
11804
|
const effectiveTheme = theme ?? searchContext.theme;
|
|
@@ -11850,6 +11881,8 @@ const SuggestionSearchBar = React.forwardRef(function SuggestionSearchBar(props,
|
|
|
11850
11881
|
const cacheOptions = {
|
|
11851
11882
|
maxSuggestions,
|
|
11852
11883
|
includeDropdownRecommendations,
|
|
11884
|
+
includeDropdownProductList,
|
|
11885
|
+
includeFilteredTabs,
|
|
11853
11886
|
includeCategories,
|
|
11854
11887
|
filteredTabs: filteredTabs?.map(t => t.filter).join(','),
|
|
11855
11888
|
};
|
|
@@ -11870,6 +11903,8 @@ const SuggestionSearchBar = React.forwardRef(function SuggestionSearchBar(props,
|
|
|
11870
11903
|
const response = await client.getSuggestions?.(searchQuery, {
|
|
11871
11904
|
hitsPerPage: maxSuggestions,
|
|
11872
11905
|
include_dropdown_recommendations: includeDropdownRecommendations,
|
|
11906
|
+
include_dropdown_product_list: includeDropdownProductList,
|
|
11907
|
+
include_filtered_tabs: includeFilteredTabs,
|
|
11873
11908
|
include_categories: includeCategories,
|
|
11874
11909
|
filtered_tabs: filteredTabs,
|
|
11875
11910
|
analytics_tags: analyticsTags,
|
|
@@ -11908,7 +11943,7 @@ const SuggestionSearchBar = React.forwardRef(function SuggestionSearchBar(props,
|
|
|
11908
11943
|
finally {
|
|
11909
11944
|
setLoading(false);
|
|
11910
11945
|
}
|
|
11911
|
-
}, [client, minQueryLength, maxSuggestions, includeDropdownRecommendations, includeCategories, filteredTabs, analyticsTags, enableAnalytics, analytics, cache]);
|
|
11946
|
+
}, [client, minQueryLength, maxSuggestions, includeDropdownRecommendations, includeDropdownProductList, includeFilteredTabs, includeCategories, filteredTabs, analyticsTags, enableAnalytics, analytics, cache]);
|
|
11912
11947
|
// Parse API response - handles multiple response formats
|
|
11913
11948
|
const parseAndSetData = React.useCallback((response) => {
|
|
11914
11949
|
// Handle different response structures from the API/SDK
|