@seekora-ai/ui-sdk-react 0.0.0-stage-20260517092419
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/Breadcrumb.d.ts +43 -0
- package/dist/components/Breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb.js +119 -0
- package/dist/components/ClearRefinements.d.ts +42 -0
- package/dist/components/ClearRefinements.d.ts.map +1 -0
- package/dist/components/ClearRefinements.js +81 -0
- package/dist/components/CurrentRefinements.d.ts +63 -0
- package/dist/components/CurrentRefinements.d.ts.map +1 -0
- package/dist/components/CurrentRefinements.js +302 -0
- package/dist/components/FacetDropdown.d.ts +94 -0
- package/dist/components/FacetDropdown.d.ts.map +1 -0
- package/dist/components/FacetDropdown.js +396 -0
- package/dist/components/Facets.d.ts +118 -0
- package/dist/components/Facets.d.ts.map +1 -0
- package/dist/components/Facets.js +785 -0
- package/dist/components/FederatedDropdown.d.ts +98 -0
- package/dist/components/FederatedDropdown.d.ts.map +1 -0
- package/dist/components/FederatedDropdown.js +526 -0
- package/dist/components/HierarchicalMenu.d.ts +55 -0
- package/dist/components/HierarchicalMenu.d.ts.map +1 -0
- package/dist/components/HierarchicalMenu.js +276 -0
- package/dist/components/Highlight.d.ts +51 -0
- package/dist/components/Highlight.d.ts.map +1 -0
- package/dist/components/Highlight.js +155 -0
- package/dist/components/HitsPerPage.d.ts +41 -0
- package/dist/components/HitsPerPage.d.ts.map +1 -0
- package/dist/components/HitsPerPage.js +82 -0
- package/dist/components/InfiniteHits.d.ts +51 -0
- package/dist/components/InfiniteHits.d.ts.map +1 -0
- package/dist/components/InfiniteHits.js +173 -0
- package/dist/components/MobileFilters.d.ts +71 -0
- package/dist/components/MobileFilters.d.ts.map +1 -0
- package/dist/components/MobileFilters.js +242 -0
- package/dist/components/Pagination.d.ts +90 -0
- package/dist/components/Pagination.d.ts.map +1 -0
- package/dist/components/Pagination.js +298 -0
- package/dist/components/QuerySuggestions.d.ts +36 -0
- package/dist/components/QuerySuggestions.d.ts.map +1 -0
- package/dist/components/QuerySuggestions.js +71 -0
- package/dist/components/QuerySuggestionsDropdown.d.ts +82 -0
- package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -0
- package/dist/components/QuerySuggestionsDropdown.js +394 -0
- package/dist/components/RangeInput.d.ts +58 -0
- package/dist/components/RangeInput.d.ts.map +1 -0
- package/dist/components/RangeInput.js +203 -0
- package/dist/components/RangeSlider.d.ts +51 -0
- package/dist/components/RangeSlider.d.ts.map +1 -0
- package/dist/components/RangeSlider.js +262 -0
- package/dist/components/Recommendations.d.ts +89 -0
- package/dist/components/Recommendations.d.ts.map +1 -0
- package/dist/components/Recommendations.js +256 -0
- package/dist/components/RichQuerySuggestions.d.ts +88 -0
- package/dist/components/RichQuerySuggestions.d.ts.map +1 -0
- package/dist/components/RichQuerySuggestions.js +498 -0
- package/dist/components/SearchBar.d.ts +57 -0
- package/dist/components/SearchBar.d.ts.map +1 -0
- package/dist/components/SearchBar.js +361 -0
- package/dist/components/SearchBarWithSuggestions.d.ts +105 -0
- package/dist/components/SearchBarWithSuggestions.d.ts.map +1 -0
- package/dist/components/SearchBarWithSuggestions.js +275 -0
- package/dist/components/SearchLayout.d.ts +35 -0
- package/dist/components/SearchLayout.d.ts.map +1 -0
- package/dist/components/SearchLayout.js +61 -0
- package/dist/components/SearchProvider.d.ts +35 -0
- package/dist/components/SearchProvider.d.ts.map +1 -0
- package/dist/components/SearchProvider.js +53 -0
- package/dist/components/SearchResults.d.ts +57 -0
- package/dist/components/SearchResults.d.ts.map +1 -0
- package/dist/components/SearchResults.js +456 -0
- package/dist/components/SortBy.d.ts +84 -0
- package/dist/components/SortBy.d.ts.map +1 -0
- package/dist/components/SortBy.js +183 -0
- package/dist/components/Stats.d.ts +51 -0
- package/dist/components/Stats.d.ts.map +1 -0
- package/dist/components/Stats.js +201 -0
- package/dist/components/primitives/ActionButtons.d.ts +27 -0
- package/dist/components/primitives/ActionButtons.d.ts.map +1 -0
- package/dist/components/primitives/ActionButtons.js +102 -0
- package/dist/components/primitives/AnalyticsProvider.d.ts +22 -0
- package/dist/components/primitives/AnalyticsProvider.d.ts.map +1 -0
- package/dist/components/primitives/AnalyticsProvider.js +87 -0
- package/dist/components/primitives/BadgeList.d.ts +14 -0
- package/dist/components/primitives/BadgeList.d.ts.map +1 -0
- package/dist/components/primitives/BadgeList.js +65 -0
- package/dist/components/primitives/CustomSelect.d.ts +40 -0
- package/dist/components/primitives/CustomSelect.d.ts.map +1 -0
- package/dist/components/primitives/CustomSelect.js +196 -0
- package/dist/components/primitives/ImageDisplay.d.ts +28 -0
- package/dist/components/primitives/ImageDisplay.d.ts.map +1 -0
- package/dist/components/primitives/ImageDisplay.js +127 -0
- package/dist/components/primitives/ImageZoom.d.ts +33 -0
- package/dist/components/primitives/ImageZoom.d.ts.map +1 -0
- package/dist/components/primitives/ImageZoom.js +433 -0
- package/dist/components/primitives/PriceDisplay.d.ts +21 -0
- package/dist/components/primitives/PriceDisplay.d.ts.map +1 -0
- package/dist/components/primitives/PriceDisplay.js +44 -0
- package/dist/components/primitives/RatingDisplay.d.ts +43 -0
- package/dist/components/primitives/RatingDisplay.d.ts.map +1 -0
- package/dist/components/primitives/RatingDisplay.js +114 -0
- package/dist/components/primitives/VariantSelector.d.ts +30 -0
- package/dist/components/primitives/VariantSelector.d.ts.map +1 -0
- package/dist/components/primitives/VariantSelector.js +155 -0
- package/dist/components/primitives/VariantSwatches.d.ts +28 -0
- package/dist/components/primitives/VariantSwatches.d.ts.map +1 -0
- package/dist/components/primitives/VariantSwatches.js +188 -0
- package/dist/components/primitives/index.d.ts +12 -0
- package/dist/components/primitives/index.d.ts.map +1 -0
- package/dist/components/primitives/index.js +11 -0
- package/dist/components/primitives/withAnalytics.d.ts +24 -0
- package/dist/components/primitives/withAnalytics.d.ts.map +1 -0
- package/dist/components/primitives/withAnalytics.js +73 -0
- package/dist/components/product-page/ProductGallery.d.ts +26 -0
- package/dist/components/product-page/ProductGallery.d.ts.map +1 -0
- package/dist/components/product-page/ProductGallery.js +13 -0
- package/dist/components/product-page/ProductInfo.d.ts +44 -0
- package/dist/components/product-page/ProductInfo.d.ts.map +1 -0
- package/dist/components/product-page/ProductInfo.js +34 -0
- package/dist/components/product-page/ProductRecommendations.d.ts +21 -0
- package/dist/components/product-page/ProductRecommendations.d.ts.map +1 -0
- package/dist/components/product-page/ProductRecommendations.js +17 -0
- package/dist/components/product-page/index.d.ts +4 -0
- package/dist/components/product-page/index.d.ts.map +1 -0
- package/dist/components/product-page/index.js +3 -0
- package/dist/components/section-primitives/SectionError.d.ts +11 -0
- package/dist/components/section-primitives/SectionError.d.ts.map +1 -0
- package/dist/components/section-primitives/SectionError.js +13 -0
- package/dist/components/section-primitives/SectionItemGrid.d.ts +18 -0
- package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -0
- package/dist/components/section-primitives/SectionItemGrid.js +14 -0
- package/dist/components/section-primitives/SectionLoading.d.ts +11 -0
- package/dist/components/section-primitives/SectionLoading.d.ts.map +1 -0
- package/dist/components/section-primitives/SectionLoading.js +11 -0
- package/dist/components/section-primitives/SectionSearchContext.d.ts +17 -0
- package/dist/components/section-primitives/SectionSearchContext.d.ts.map +1 -0
- package/dist/components/section-primitives/SectionSearchContext.js +17 -0
- package/dist/components/section-primitives/SectionSearchProvider.d.ts +25 -0
- package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -0
- package/dist/components/section-primitives/SectionSearchProvider.js +106 -0
- package/dist/components/section-primitives/index.d.ts +5 -0
- package/dist/components/section-primitives/index.d.ts.map +1 -0
- package/dist/components/section-primitives/index.js +4 -0
- package/dist/components/suggestions/AmazonDropdown.d.ts +30 -0
- package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/AmazonDropdown.js +509 -0
- package/dist/components/suggestions/GoogleDropdown.d.ts +31 -0
- package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/GoogleDropdown.js +349 -0
- package/dist/components/suggestions/MinimalDropdown.d.ts +24 -0
- package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/MinimalDropdown.js +312 -0
- package/dist/components/suggestions/MobileSheetDropdown.d.ts +31 -0
- package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/MobileSheetDropdown.js +483 -0
- package/dist/components/suggestions/PinterestDropdown.d.ts +29 -0
- package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/PinterestDropdown.js +446 -0
- package/dist/components/suggestions/ShopifyDropdown.d.ts +27 -0
- package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/ShopifyDropdown.js +448 -0
- package/dist/components/suggestions/SpotlightDropdown.d.ts +33 -0
- package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -0
- package/dist/components/suggestions/SpotlightDropdown.js +544 -0
- package/dist/components/suggestions/SuggestionSearchBar.d.ts +127 -0
- package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -0
- package/dist/components/suggestions/SuggestionSearchBar.js +644 -0
- package/dist/components/suggestions/index.d.ts +37 -0
- package/dist/components/suggestions/index.d.ts.map +1 -0
- package/dist/components/suggestions/index.js +59 -0
- package/dist/components/suggestions/styles/index.d.ts +11 -0
- package/dist/components/suggestions/styles/index.d.ts.map +1 -0
- package/dist/components/suggestions/styles/index.js +289 -0
- package/dist/components/suggestions/styles/responsive.d.ts +107 -0
- package/dist/components/suggestions/styles/responsive.d.ts.map +1 -0
- package/dist/components/suggestions/styles/responsive.js +237 -0
- package/dist/components/suggestions/types.d.ts +511 -0
- package/dist/components/suggestions/types.d.ts.map +1 -0
- package/dist/components/suggestions/types.js +6 -0
- package/dist/components/suggestions/utils.d.ts +259 -0
- package/dist/components/suggestions/utils.d.ts.map +1 -0
- package/dist/components/suggestions/utils.js +668 -0
- package/dist/components/suggestions-primitives/CategoriesTabs.d.ts +13 -0
- package/dist/components/suggestions-primitives/CategoriesTabs.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/CategoriesTabs.js +35 -0
- package/dist/components/suggestions-primitives/DropdownPanel.d.ts +24 -0
- package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/DropdownPanel.js +67 -0
- package/dist/components/suggestions-primitives/ItemCard.d.ts +48 -0
- package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/ItemCard.js +103 -0
- package/dist/components/suggestions-primitives/ItemGrid.d.ts +28 -0
- package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/ItemGrid.js +55 -0
- package/dist/components/suggestions-primitives/ProductCard.d.ts +45 -0
- package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/ProductCard.js +177 -0
- package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts +44 -0
- package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/ProductCardLayouts.js +137 -0
- package/dist/components/suggestions-primitives/ProductGrid.d.ts +22 -0
- package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/ProductGrid.js +41 -0
- package/dist/components/suggestions-primitives/RecentSearchesList.d.ts +17 -0
- package/dist/components/suggestions-primitives/RecentSearchesList.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/RecentSearchesList.js +46 -0
- package/dist/components/suggestions-primitives/SearchInput.d.ts +23 -0
- package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SearchInput.js +114 -0
- package/dist/components/suggestions-primitives/SuggestionItem.d.ts +31 -0
- package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionItem.js +47 -0
- package/dist/components/suggestions-primitives/SuggestionList.d.ts +26 -0
- package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionList.js +35 -0
- package/dist/components/suggestions-primitives/SuggestionsContext.d.ts +44 -0
- package/dist/components/suggestions-primitives/SuggestionsContext.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionsContext.js +18 -0
- package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts +24 -0
- package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.js +30 -0
- package/dist/components/suggestions-primitives/SuggestionsError.d.ts +11 -0
- package/dist/components/suggestions-primitives/SuggestionsError.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionsError.js +19 -0
- package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts +11 -0
- package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionsLoading.js +17 -0
- package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts +38 -0
- package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/SuggestionsProvider.js +259 -0
- package/dist/components/suggestions-primitives/TrendingList.d.ts +17 -0
- package/dist/components/suggestions-primitives/TrendingList.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/TrendingList.js +48 -0
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts +31 -0
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/highlightMarkup.js +70 -0
- package/dist/components/suggestions-primitives/index.d.ts +39 -0
- package/dist/components/suggestions-primitives/index.d.ts.map +1 -0
- package/dist/components/suggestions-primitives/index.js +24 -0
- package/dist/docsearch/components/DocSearch.d.ts +4 -0
- package/dist/docsearch/components/DocSearch.d.ts.map +1 -0
- package/dist/docsearch/components/DocSearch.js +93 -0
- package/dist/docsearch/components/DocSearchButton.d.ts +4 -0
- package/dist/docsearch/components/DocSearchButton.d.ts.map +1 -0
- package/dist/docsearch/components/DocSearchButton.js +12 -0
- package/dist/docsearch/components/Footer.d.ts +8 -0
- package/dist/docsearch/components/Footer.d.ts.map +1 -0
- package/dist/docsearch/components/Footer.js +40 -0
- package/dist/docsearch/components/Highlight.d.ts +9 -0
- package/dist/docsearch/components/Highlight.d.ts.map +1 -0
- package/dist/docsearch/components/Highlight.js +48 -0
- package/dist/docsearch/components/Hit.d.ts +15 -0
- package/dist/docsearch/components/Hit.d.ts.map +1 -0
- package/dist/docsearch/components/Hit.js +96 -0
- package/dist/docsearch/components/Modal.d.ts +10 -0
- package/dist/docsearch/components/Modal.d.ts.map +1 -0
- package/dist/docsearch/components/Modal.js +57 -0
- package/dist/docsearch/components/Results.d.ts +23 -0
- package/dist/docsearch/components/Results.d.ts.map +1 -0
- package/dist/docsearch/components/Results.js +141 -0
- package/dist/docsearch/components/SearchBox.d.ts +11 -0
- package/dist/docsearch/components/SearchBox.d.ts.map +1 -0
- package/dist/docsearch/components/SearchBox.js +16 -0
- package/dist/docsearch/hooks/useDocSearch.d.ts +33 -0
- package/dist/docsearch/hooks/useDocSearch.d.ts.map +1 -0
- package/dist/docsearch/hooks/useDocSearch.js +224 -0
- package/dist/docsearch/hooks/useKeyboard.d.ts +17 -0
- package/dist/docsearch/hooks/useKeyboard.d.ts.map +1 -0
- package/dist/docsearch/hooks/useKeyboard.js +71 -0
- package/dist/docsearch/hooks/useSeekoraSearch.d.ts +27 -0
- package/dist/docsearch/hooks/useSeekoraSearch.d.ts.map +1 -0
- package/dist/docsearch/hooks/useSeekoraSearch.js +213 -0
- package/dist/docsearch/index.d.ts +13 -0
- package/dist/docsearch/index.d.ts.map +1 -0
- package/dist/docsearch/index.js +11 -0
- package/dist/docsearch/types.d.ts +175 -0
- package/dist/docsearch/types.d.ts.map +1 -0
- package/dist/docsearch/types.js +4 -0
- package/dist/docsearch.css +234 -0
- package/dist/hooks/useAnalytics.d.ts +24 -0
- package/dist/hooks/useAnalytics.d.ts.map +1 -0
- package/dist/hooks/useAnalytics.js +67 -0
- package/dist/hooks/useClickTracking.d.ts +36 -0
- package/dist/hooks/useClickTracking.d.ts.map +1 -0
- package/dist/hooks/useClickTracking.js +89 -0
- package/dist/hooks/useExperiment.d.ts +25 -0
- package/dist/hooks/useExperiment.d.ts.map +1 -0
- package/dist/hooks/useExperiment.js +123 -0
- package/dist/hooks/useFilters.d.ts +27 -0
- package/dist/hooks/useFilters.d.ts.map +1 -0
- package/dist/hooks/useFilters.js +86 -0
- package/dist/hooks/useKeyboardNavigation.d.ts +51 -0
- package/dist/hooks/useKeyboardNavigation.d.ts.map +1 -0
- package/dist/hooks/useKeyboardNavigation.js +113 -0
- package/dist/hooks/useNaturalLanguageFilters.d.ts +48 -0
- package/dist/hooks/useNaturalLanguageFilters.d.ts.map +1 -0
- package/dist/hooks/useNaturalLanguageFilters.js +221 -0
- package/dist/hooks/useProductAnalytics.d.ts +49 -0
- package/dist/hooks/useProductAnalytics.d.ts.map +1 -0
- package/dist/hooks/useProductAnalytics.js +116 -0
- package/dist/hooks/useQuerySuggestions.d.ts +21 -0
- package/dist/hooks/useQuerySuggestions.d.ts.map +1 -0
- package/dist/hooks/useQuerySuggestions.js +84 -0
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts +120 -0
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -0
- package/dist/hooks/useQuerySuggestionsEnhanced.js +444 -0
- package/dist/hooks/useSearchState.d.ts +35 -0
- package/dist/hooks/useSearchState.d.ts.map +1 -0
- package/dist/hooks/useSearchState.js +68 -0
- package/dist/hooks/useSeekoraSearch.d.ts +20 -0
- package/dist/hooks/useSeekoraSearch.d.ts.map +1 -0
- package/dist/hooks/useSeekoraSearch.js +63 -0
- package/dist/hooks/useSmartSuggestions.d.ts +55 -0
- package/dist/hooks/useSmartSuggestions.d.ts.map +1 -0
- package/dist/hooks/useSmartSuggestions.js +236 -0
- package/dist/hooks/useSuggestionsAnalytics.d.ts +93 -0
- package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -0
- package/dist/hooks/useSuggestionsAnalytics.js +239 -0
- package/dist/hooks/useVariantSelection.d.ts +28 -0
- package/dist/hooks/useVariantSelection.d.ts.map +1 -0
- package/dist/hooks/useVariantSelection.js +44 -0
- package/dist/index.d.ts +105 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.umd.js +1 -0
- package/dist/src/index.d.ts +4469 -0
- package/dist/src/index.esm.js +18952 -0
- package/dist/src/index.esm.js.map +1 -0
- package/dist/src/index.js +19086 -0
- package/dist/src/index.js.map +1 -0
- package/dist/themes/createTheme.d.ts +8 -0
- package/dist/themes/createTheme.d.ts.map +1 -0
- package/dist/themes/createTheme.js +10 -0
- package/dist/themes/dark.d.ts +6 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +34 -0
- package/dist/themes/default.d.ts +6 -0
- package/dist/themes/default.d.ts.map +1 -0
- package/dist/themes/default.js +71 -0
- package/dist/themes/mergeThemes.d.ts +7 -0
- package/dist/themes/mergeThemes.d.ts.map +1 -0
- package/dist/themes/mergeThemes.js +6 -0
- package/dist/themes/minimal.d.ts +6 -0
- package/dist/themes/minimal.d.ts.map +1 -0
- package/dist/themes/minimal.js +34 -0
- package/dist/themes/suggestions.d.ts +216 -0
- package/dist/themes/suggestions.d.ts.map +1 -0
- package/dist/themes/suggestions.js +546 -0
- package/dist/themes/types.d.ts +7 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/themes/types.js +6 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/responsive.d.ts +130 -0
- package/dist/utils/responsive.d.ts.map +1 -0
- package/dist/utils/responsive.js +225 -0
- package/package.json +68 -0
- package/src/docsearch/docsearch.css +234 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RangeSlider Component
|
|
3
|
+
*
|
|
4
|
+
* Visual slider for numeric range filtering
|
|
5
|
+
* Alternative to RangeInput for a more interactive UX
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export interface RangeSliderTheme {
|
|
9
|
+
root?: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
slider?: string;
|
|
12
|
+
track?: string;
|
|
13
|
+
trackFilled?: string;
|
|
14
|
+
thumb?: string;
|
|
15
|
+
values?: string;
|
|
16
|
+
value?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RangeSliderProps {
|
|
19
|
+
/** Field name for the range filter */
|
|
20
|
+
field: string;
|
|
21
|
+
/** Label for the slider */
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Minimum value */
|
|
24
|
+
min: number;
|
|
25
|
+
/** Maximum value */
|
|
26
|
+
max: number;
|
|
27
|
+
/** Step value (default: 1) */
|
|
28
|
+
step?: number;
|
|
29
|
+
/** Current minimum value */
|
|
30
|
+
currentMin?: number;
|
|
31
|
+
/** Current maximum value */
|
|
32
|
+
currentMax?: number;
|
|
33
|
+
/** Callback when range changes */
|
|
34
|
+
onRangeChange?: (min: number, max: number) => void;
|
|
35
|
+
/** Format value for display (default: (v) => v.toString()) */
|
|
36
|
+
formatValue?: (value: number) => string;
|
|
37
|
+
/** Custom className */
|
|
38
|
+
className?: string;
|
|
39
|
+
/** Custom styles */
|
|
40
|
+
style?: React.CSSProperties;
|
|
41
|
+
/** Custom theme */
|
|
42
|
+
theme?: RangeSliderTheme;
|
|
43
|
+
/** Show current values (default: true) */
|
|
44
|
+
showValues?: boolean;
|
|
45
|
+
/** Whether to sync with SearchStateManager (default: true) */
|
|
46
|
+
syncWithState?: boolean;
|
|
47
|
+
/** Debounce delay for updates (default: 300ms) */
|
|
48
|
+
debounceMs?: number;
|
|
49
|
+
}
|
|
50
|
+
export declare const RangeSlider: React.FC<RangeSliderProps>;
|
|
51
|
+
//# sourceMappingURL=RangeSlider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/components/RangeSlider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAYxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAsVlD,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RangeSlider Component
|
|
3
|
+
*
|
|
4
|
+
* Visual slider for numeric range filtering
|
|
5
|
+
* Alternative to RangeInput for a more interactive UX
|
|
6
|
+
*/
|
|
7
|
+
import React, { useState, useCallback, useEffect, useRef } from 'react';
|
|
8
|
+
import { useSearchContext } from './SearchProvider';
|
|
9
|
+
import { useSearchState } from '../hooks/useSearchState';
|
|
10
|
+
import { clsx } from 'clsx';
|
|
11
|
+
const SHADOWS = {
|
|
12
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
13
|
+
md: '0 2px 4px rgba(0,0,0,0.1)',
|
|
14
|
+
lg: '0 4px 6px rgba(0,0,0,0.1)',
|
|
15
|
+
xl: '0 10px 15px rgba(0,0,0,0.1)',
|
|
16
|
+
};
|
|
17
|
+
export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: currentMinProp, currentMax: currentMaxProp, onRangeChange, formatValue = (v) => v.toString(), className, style, theme: customTheme, showValues = true, syncWithState = true, debounceMs = 300, }) => {
|
|
18
|
+
const { theme } = useSearchContext();
|
|
19
|
+
const { refinements, addRefinement, removeRefinement } = useSearchState();
|
|
20
|
+
const rangeSliderTheme = customTheme || {};
|
|
21
|
+
const thumbClass = rangeSliderTheme.thumb || 'seekora-range-slider__thumb';
|
|
22
|
+
// Parse current range from StateManager
|
|
23
|
+
// NOTE: computed every render (no useMemo) because the state manager mutates
|
|
24
|
+
// the refinements array in place — the reference never changes.
|
|
25
|
+
let stateRange;
|
|
26
|
+
if (!syncWithState) {
|
|
27
|
+
stateRange = { min: undefined, max: undefined };
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
let minVal;
|
|
31
|
+
let maxVal;
|
|
32
|
+
refinements.forEach(r => {
|
|
33
|
+
if (r.field === field) {
|
|
34
|
+
const minMatch = r.value.match(/^>=(\d+(?:\.\d+)?)$/);
|
|
35
|
+
if (minMatch)
|
|
36
|
+
minVal = parseFloat(minMatch[1]);
|
|
37
|
+
const maxMatch = r.value.match(/^<=(\d+(?:\.\d+)?)$/);
|
|
38
|
+
if (maxMatch)
|
|
39
|
+
maxVal = parseFloat(maxMatch[1]);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
stateRange = { min: minVal, max: maxVal };
|
|
43
|
+
}
|
|
44
|
+
const [internalMin, setInternalMin] = useState(currentMinProp ?? stateRange.min ?? min);
|
|
45
|
+
const [internalMax, setInternalMax] = useState(currentMaxProp ?? stateRange.max ?? max);
|
|
46
|
+
const isDraggingRef = useRef(false);
|
|
47
|
+
const debounceRef = useRef(null);
|
|
48
|
+
const pendingMinRef = useRef(internalMin);
|
|
49
|
+
const pendingMaxRef = useRef(internalMax);
|
|
50
|
+
// Sync with StateManager changes (only when stateRange actually changes, not on drag)
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (syncWithState && !isDraggingRef.current) {
|
|
53
|
+
if (stateRange.min !== undefined)
|
|
54
|
+
setInternalMin(stateRange.min);
|
|
55
|
+
else
|
|
56
|
+
setInternalMin(min);
|
|
57
|
+
if (stateRange.max !== undefined)
|
|
58
|
+
setInternalMax(stateRange.max);
|
|
59
|
+
else
|
|
60
|
+
setInternalMax(max);
|
|
61
|
+
}
|
|
62
|
+
}, [syncWithState, stateRange.min, stateRange.max, min, max]);
|
|
63
|
+
// Update StateManager with range refinements
|
|
64
|
+
const updateStateManager = useCallback((minVal, maxVal) => {
|
|
65
|
+
if (!syncWithState)
|
|
66
|
+
return;
|
|
67
|
+
// Remove existing range refinements for this field
|
|
68
|
+
refinements.forEach(r => {
|
|
69
|
+
if (r.field === field) {
|
|
70
|
+
removeRefinement(field, r.value, false);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// Add new range refinements — trigger search on the last one added
|
|
74
|
+
const setMin = minVal > min;
|
|
75
|
+
const setMax = maxVal < max;
|
|
76
|
+
if (setMin && setMax) {
|
|
77
|
+
addRefinement(field, `>=${minVal}`, false);
|
|
78
|
+
addRefinement(field, `<=${maxVal}`, true);
|
|
79
|
+
}
|
|
80
|
+
else if (setMin) {
|
|
81
|
+
addRefinement(field, `>=${minVal}`, true);
|
|
82
|
+
}
|
|
83
|
+
else if (setMax) {
|
|
84
|
+
addRefinement(field, `<=${maxVal}`, true);
|
|
85
|
+
}
|
|
86
|
+
}, [syncWithState, field, refinements, addRefinement, removeRefinement, min, max]);
|
|
87
|
+
// Debounced update (during drag only)
|
|
88
|
+
const debouncedUpdate = useCallback((minVal, maxVal) => {
|
|
89
|
+
pendingMinRef.current = minVal;
|
|
90
|
+
pendingMaxRef.current = maxVal;
|
|
91
|
+
if (debounceRef.current) {
|
|
92
|
+
clearTimeout(debounceRef.current);
|
|
93
|
+
}
|
|
94
|
+
debounceRef.current = setTimeout(() => {
|
|
95
|
+
updateStateManager(minVal, maxVal);
|
|
96
|
+
if (onRangeChange) {
|
|
97
|
+
onRangeChange(minVal, maxVal);
|
|
98
|
+
}
|
|
99
|
+
}, debounceMs);
|
|
100
|
+
}, [updateStateManager, onRangeChange, debounceMs]);
|
|
101
|
+
// Handle min slider change
|
|
102
|
+
const handleMinChange = (e) => {
|
|
103
|
+
const value = Math.min(Number(e.target.value), internalMax - step);
|
|
104
|
+
setInternalMin(value);
|
|
105
|
+
isDraggingRef.current = true;
|
|
106
|
+
debouncedUpdate(value, internalMax);
|
|
107
|
+
};
|
|
108
|
+
// Handle max slider change
|
|
109
|
+
const handleMaxChange = (e) => {
|
|
110
|
+
const value = Math.max(Number(e.target.value), internalMin + step);
|
|
111
|
+
setInternalMax(value);
|
|
112
|
+
isDraggingRef.current = true;
|
|
113
|
+
debouncedUpdate(internalMin, value);
|
|
114
|
+
};
|
|
115
|
+
// Handle drag end — flush pending update immediately
|
|
116
|
+
const handleDragEnd = () => {
|
|
117
|
+
isDraggingRef.current = false;
|
|
118
|
+
// Cancel the debounce and commit immediately
|
|
119
|
+
if (debounceRef.current) {
|
|
120
|
+
clearTimeout(debounceRef.current);
|
|
121
|
+
debounceRef.current = null;
|
|
122
|
+
}
|
|
123
|
+
updateStateManager(pendingMinRef.current, pendingMaxRef.current);
|
|
124
|
+
if (onRangeChange) {
|
|
125
|
+
onRangeChange(pendingMinRef.current, pendingMaxRef.current);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
// Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
|
|
129
|
+
const handleMinKeyDown = (e) => {
|
|
130
|
+
let newValue = null;
|
|
131
|
+
if (e.key === 'Home') {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
newValue = min;
|
|
134
|
+
}
|
|
135
|
+
else if (e.key === 'End') {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
newValue = internalMax - step;
|
|
138
|
+
}
|
|
139
|
+
else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
newValue = Math.max(min, internalMin - step * 10);
|
|
142
|
+
}
|
|
143
|
+
else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
newValue = Math.min(internalMax - step, internalMin + step * 10);
|
|
146
|
+
}
|
|
147
|
+
if (newValue !== null) {
|
|
148
|
+
setInternalMin(newValue);
|
|
149
|
+
debouncedUpdate(newValue, internalMax);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const handleMaxKeyDown = (e) => {
|
|
153
|
+
let newValue = null;
|
|
154
|
+
if (e.key === 'Home') {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
newValue = internalMin + step;
|
|
157
|
+
}
|
|
158
|
+
else if (e.key === 'End') {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
newValue = max;
|
|
161
|
+
}
|
|
162
|
+
else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
newValue = Math.max(internalMin + step, internalMax - step * 10);
|
|
165
|
+
}
|
|
166
|
+
else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
newValue = Math.min(max, internalMax + step * 10);
|
|
169
|
+
}
|
|
170
|
+
if (newValue !== null) {
|
|
171
|
+
setInternalMax(newValue);
|
|
172
|
+
debouncedUpdate(internalMin, newValue);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
// Calculate filled track position
|
|
176
|
+
const minPercent = ((internalMin - min) / (max - min)) * 100;
|
|
177
|
+
const maxPercent = ((internalMax - min) / (max - min)) * 100;
|
|
178
|
+
return (React.createElement("div", { className: clsx(rangeSliderTheme.root, className), style: {
|
|
179
|
+
fontFamily: 'inherit',
|
|
180
|
+
...style,
|
|
181
|
+
} },
|
|
182
|
+
label && (React.createElement("label", { className: rangeSliderTheme.label, style: {
|
|
183
|
+
display: 'block',
|
|
184
|
+
marginBottom: theme.spacing.small,
|
|
185
|
+
fontSize: theme.typography.fontSize.medium,
|
|
186
|
+
fontWeight: theme.typography.fontWeight?.medium || 500,
|
|
187
|
+
color: theme.colors.text,
|
|
188
|
+
} }, label)),
|
|
189
|
+
React.createElement("div", { className: rangeSliderTheme.slider, style: {
|
|
190
|
+
position: 'relative',
|
|
191
|
+
minHeight: '40px',
|
|
192
|
+
display: 'flex',
|
|
193
|
+
alignItems: 'center',
|
|
194
|
+
} },
|
|
195
|
+
React.createElement("div", { className: rangeSliderTheme.track, style: {
|
|
196
|
+
position: 'absolute',
|
|
197
|
+
width: '100%',
|
|
198
|
+
height: '4px',
|
|
199
|
+
backgroundColor: theme.colors.border,
|
|
200
|
+
borderRadius: '2px',
|
|
201
|
+
} }),
|
|
202
|
+
React.createElement("div", { className: rangeSliderTheme.trackFilled, style: {
|
|
203
|
+
position: 'absolute',
|
|
204
|
+
left: `${minPercent}%`,
|
|
205
|
+
width: `${maxPercent - minPercent}%`,
|
|
206
|
+
height: '4px',
|
|
207
|
+
backgroundColor: theme.colors.primary,
|
|
208
|
+
borderRadius: '2px',
|
|
209
|
+
} }),
|
|
210
|
+
React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMinKeyDown, tabIndex: 0, "aria-valuenow": internalMin, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
|
|
211
|
+
position: 'absolute',
|
|
212
|
+
width: '100%',
|
|
213
|
+
height: '4px',
|
|
214
|
+
background: 'transparent',
|
|
215
|
+
WebkitAppearance: 'none',
|
|
216
|
+
appearance: 'none',
|
|
217
|
+
cursor: 'pointer',
|
|
218
|
+
pointerEvents: 'none',
|
|
219
|
+
}, "aria-label": `Minimum ${label || field}` }),
|
|
220
|
+
React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMaxKeyDown, tabIndex: 0, "aria-valuenow": internalMax, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
|
|
221
|
+
position: 'absolute',
|
|
222
|
+
width: '100%',
|
|
223
|
+
height: '4px',
|
|
224
|
+
background: 'transparent',
|
|
225
|
+
WebkitAppearance: 'none',
|
|
226
|
+
appearance: 'none',
|
|
227
|
+
cursor: 'pointer',
|
|
228
|
+
pointerEvents: 'none',
|
|
229
|
+
}, "aria-label": `Maximum ${label || field}` })),
|
|
230
|
+
showValues && (React.createElement("div", { className: rangeSliderTheme.values, style: {
|
|
231
|
+
display: 'flex',
|
|
232
|
+
justifyContent: 'space-between',
|
|
233
|
+
marginTop: theme.spacing.small,
|
|
234
|
+
fontSize: theme.typography.fontSize.small,
|
|
235
|
+
color: theme.colors.textSecondary,
|
|
236
|
+
} },
|
|
237
|
+
React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMin)),
|
|
238
|
+
React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMax)))),
|
|
239
|
+
React.createElement("style", null, `
|
|
240
|
+
.${thumbClass}::-webkit-slider-thumb {
|
|
241
|
+
-webkit-appearance: none;
|
|
242
|
+
appearance: none;
|
|
243
|
+
width: 20px;
|
|
244
|
+
height: 20px;
|
|
245
|
+
background: ${theme.colors.primary};
|
|
246
|
+
border-radius: 50%;
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
pointer-events: all;
|
|
249
|
+
box-shadow: ${SHADOWS.md};
|
|
250
|
+
}
|
|
251
|
+
.${thumbClass}::-moz-range-thumb {
|
|
252
|
+
width: 20px;
|
|
253
|
+
height: 20px;
|
|
254
|
+
background: ${theme.colors.primary};
|
|
255
|
+
border-radius: 50%;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
pointer-events: all;
|
|
258
|
+
border: none;
|
|
259
|
+
box-shadow: ${SHADOWS.md};
|
|
260
|
+
}
|
|
261
|
+
`)));
|
|
262
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recommendation Components
|
|
3
|
+
*
|
|
4
|
+
* Components for displaying product recommendations:
|
|
5
|
+
* - RelatedProducts: Show related items based on a product
|
|
6
|
+
* - TrendingItems: Display trending/popular products
|
|
7
|
+
* - FrequentlyBoughtTogether: Bundle recommendations
|
|
8
|
+
* - RecentlyViewed: User's recently viewed items
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import type { ResultItem } from '@seekora-ai/ui-sdk-types';
|
|
12
|
+
export interface RecommendationItem extends ResultItem {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}
|
|
15
|
+
export interface RecommendationTheme {
|
|
16
|
+
root?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
list?: string;
|
|
19
|
+
item?: string;
|
|
20
|
+
image?: string;
|
|
21
|
+
content?: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
price?: string;
|
|
24
|
+
empty?: string;
|
|
25
|
+
}
|
|
26
|
+
interface BaseRecommendationProps {
|
|
27
|
+
/** Title for the section */
|
|
28
|
+
title?: string;
|
|
29
|
+
/** Maximum items to show */
|
|
30
|
+
maxItems?: number;
|
|
31
|
+
/** Custom render function for items */
|
|
32
|
+
renderItem?: (item: RecommendationItem, index: number) => React.ReactNode;
|
|
33
|
+
/** Callback when item is clicked */
|
|
34
|
+
onItemClick?: (item: RecommendationItem, index: number) => void;
|
|
35
|
+
/** Custom className */
|
|
36
|
+
className?: string;
|
|
37
|
+
/** Custom styles */
|
|
38
|
+
style?: React.CSSProperties;
|
|
39
|
+
/** Custom theme */
|
|
40
|
+
theme?: RecommendationTheme;
|
|
41
|
+
/** Layout mode */
|
|
42
|
+
layout?: 'horizontal' | 'grid' | 'list';
|
|
43
|
+
/** Currency symbol for prices */
|
|
44
|
+
currencySymbol?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface RelatedProductsProps extends BaseRecommendationProps {
|
|
47
|
+
/** Product ID to get related products for */
|
|
48
|
+
productId: string;
|
|
49
|
+
/** Custom items (if not using API) */
|
|
50
|
+
items?: RecommendationItem[];
|
|
51
|
+
/** Loading state */
|
|
52
|
+
loading?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export declare const RelatedProducts: React.FC<RelatedProductsProps>;
|
|
55
|
+
export interface TrendingItemsProps extends BaseRecommendationProps {
|
|
56
|
+
/** Custom items (if not using API) */
|
|
57
|
+
items?: RecommendationItem[];
|
|
58
|
+
/** Loading state */
|
|
59
|
+
loading?: boolean;
|
|
60
|
+
/** Facet name for trending (if using facet data) */
|
|
61
|
+
facetName?: string;
|
|
62
|
+
}
|
|
63
|
+
export declare const TrendingItems: React.FC<TrendingItemsProps>;
|
|
64
|
+
export interface FrequentlyBoughtTogetherProps extends BaseRecommendationProps {
|
|
65
|
+
/** Product ID to get frequently bought together items for */
|
|
66
|
+
productId: string;
|
|
67
|
+
/** Custom items (if not using API) */
|
|
68
|
+
items?: RecommendationItem[];
|
|
69
|
+
/** Loading state */
|
|
70
|
+
loading?: boolean;
|
|
71
|
+
/** Show "Add all to cart" button */
|
|
72
|
+
showAddAllButton?: boolean;
|
|
73
|
+
/** Callback when "Add all" is clicked */
|
|
74
|
+
onAddAll?: (items: RecommendationItem[]) => void;
|
|
75
|
+
}
|
|
76
|
+
export declare const FrequentlyBoughtTogether: React.FC<FrequentlyBoughtTogetherProps>;
|
|
77
|
+
export interface RecentlyViewedProps extends BaseRecommendationProps {
|
|
78
|
+
/** Storage key for localStorage */
|
|
79
|
+
storageKey?: string;
|
|
80
|
+
/** Custom items (overrides localStorage) */
|
|
81
|
+
items?: RecommendationItem[];
|
|
82
|
+
}
|
|
83
|
+
export declare const RecentlyViewed: React.FC<RecentlyViewedProps>;
|
|
84
|
+
/**
|
|
85
|
+
* Add item to recently viewed (utility function)
|
|
86
|
+
*/
|
|
87
|
+
export declare function addToRecentlyViewed(item: RecommendationItem, storageKey?: string, maxItems?: number): void;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=Recommendations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Recommendations.d.ts","sourceRoot":"","sources":["../../src/components/Recommendations.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAG5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E,oCAAoC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,kBAAkB;IAClB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD,MAAM,WAAW,oBAAqB,SAAQ,uBAAuB;IACnE,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwC1D,CAAC;AAMF,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IACjE,sCAAsC;IACtC,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsCtD,CAAC;AAMF,MAAM,WAAW,6BAA8B,SAAQ,uBAAuB;IAC5E,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,IAAI,CAAC;CAClD;AAED,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC,6BAA6B,CAiJ5E,CAAC;AAMF,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+CxD,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,UAAU,GAAE,MAAkC,EAC9C,QAAQ,GAAE,MAAW,GACpB,IAAI,CAoBN"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recommendation Components
|
|
3
|
+
*
|
|
4
|
+
* Components for displaying product recommendations:
|
|
5
|
+
* - RelatedProducts: Show related items based on a product
|
|
6
|
+
* - TrendingItems: Display trending/popular products
|
|
7
|
+
* - FrequentlyBoughtTogether: Bundle recommendations
|
|
8
|
+
* - RecentlyViewed: User's recently viewed items
|
|
9
|
+
*/
|
|
10
|
+
import React, { useEffect, useState, useMemo } from 'react';
|
|
11
|
+
import { useSearchContext } from './SearchProvider';
|
|
12
|
+
import { clsx } from 'clsx';
|
|
13
|
+
export const RelatedProducts = ({ productId, items: itemsProp, loading: loadingProp = false, title = 'Related Products', maxItems = 6, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
14
|
+
const { theme } = useSearchContext();
|
|
15
|
+
const recommendationTheme = customTheme || {};
|
|
16
|
+
// If items are provided, use them directly
|
|
17
|
+
const items = itemsProp?.slice(0, maxItems) || [];
|
|
18
|
+
const loading = loadingProp;
|
|
19
|
+
if (loading && items.length === 0)
|
|
20
|
+
return null;
|
|
21
|
+
if (items.length === 0) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return (React.createElement(RecommendationSection, { title: title, items: items, renderItem: renderItem, onItemClick: onItemClick, className: className, style: style, theme: customTheme, layout: layout, currencySymbol: currencySymbol }));
|
|
25
|
+
};
|
|
26
|
+
export const TrendingItems = ({ items: itemsProp, loading: loadingProp = false, title = 'Trending Now', maxItems = 8, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
27
|
+
const { theme } = useSearchContext();
|
|
28
|
+
const recommendationTheme = customTheme || {};
|
|
29
|
+
const items = itemsProp?.slice(0, maxItems) || [];
|
|
30
|
+
const loading = loadingProp;
|
|
31
|
+
if (loading && items.length === 0)
|
|
32
|
+
return null;
|
|
33
|
+
if (items.length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return (React.createElement(RecommendationSection, { title: title, items: items, renderItem: renderItem, onItemClick: onItemClick, className: className, style: style, theme: customTheme, layout: layout, currencySymbol: currencySymbol }));
|
|
37
|
+
};
|
|
38
|
+
export const FrequentlyBoughtTogether = ({ productId, items: itemsProp, loading: loadingProp = false, title = 'Frequently Bought Together', maxItems = 4, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', showAddAllButton = true, onAddAll, }) => {
|
|
39
|
+
const { theme } = useSearchContext();
|
|
40
|
+
const recommendationTheme = customTheme || {};
|
|
41
|
+
const items = itemsProp?.slice(0, maxItems) || [];
|
|
42
|
+
const loading = loadingProp;
|
|
43
|
+
// Calculate total price
|
|
44
|
+
const totalPrice = useMemo(() => {
|
|
45
|
+
return items.reduce((sum, item) => {
|
|
46
|
+
const itemPrice = item.price;
|
|
47
|
+
const price = typeof itemPrice === 'number' ? itemPrice : parseFloat(String(itemPrice)) || 0;
|
|
48
|
+
return sum + price;
|
|
49
|
+
}, 0);
|
|
50
|
+
}, [items]);
|
|
51
|
+
if (loading && items.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
if (items.length === 0) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return (React.createElement("div", { className: clsx(recommendationTheme.root, className), style: style },
|
|
57
|
+
title && (React.createElement("h3", { className: recommendationTheme.title, style: {
|
|
58
|
+
margin: `0 0 ${theme.spacing.medium} 0`,
|
|
59
|
+
fontSize: theme.typography.fontSize.large,
|
|
60
|
+
fontWeight: theme.typography.fontWeight?.semibold || 600,
|
|
61
|
+
color: theme.colors.text,
|
|
62
|
+
} }, title)),
|
|
63
|
+
React.createElement("div", { style: {
|
|
64
|
+
display: 'flex',
|
|
65
|
+
alignItems: 'center',
|
|
66
|
+
gap: theme.spacing.medium,
|
|
67
|
+
flexWrap: 'wrap',
|
|
68
|
+
} },
|
|
69
|
+
items.map((item, index) => (React.createElement(React.Fragment, { key: item.id || index },
|
|
70
|
+
index > 0 && (React.createElement("span", { style: { fontSize: '1.5rem', color: theme.colors.textSecondary } }, "+")),
|
|
71
|
+
React.createElement("div", { onClick: () => onItemClick?.(item, index), style: {
|
|
72
|
+
cursor: onItemClick ? 'pointer' : 'default',
|
|
73
|
+
textAlign: 'center',
|
|
74
|
+
} }, renderItem ? (renderItem(item, index)) : (React.createElement(React.Fragment, null,
|
|
75
|
+
React.createElement("img", { src: item.image || item.imageUrl || '', alt: item.title || item.name || '', style: {
|
|
76
|
+
width: '80px',
|
|
77
|
+
height: '80px',
|
|
78
|
+
objectFit: 'cover',
|
|
79
|
+
borderRadius: typeof theme.borderRadius === 'string'
|
|
80
|
+
? theme.borderRadius
|
|
81
|
+
: theme.borderRadius.small,
|
|
82
|
+
border: `1px solid ${theme.colors.border}`,
|
|
83
|
+
} }),
|
|
84
|
+
React.createElement("div", { style: {
|
|
85
|
+
marginTop: theme.spacing.small,
|
|
86
|
+
fontSize: theme.typography.fontSize.small,
|
|
87
|
+
color: theme.colors.text,
|
|
88
|
+
} },
|
|
89
|
+
currencySymbol,
|
|
90
|
+
typeof item.price === 'number' ? item.price.toFixed(2) : item.price))))))),
|
|
91
|
+
showAddAllButton && items.length > 0 && (React.createElement("div", { style: {
|
|
92
|
+
marginLeft: 'auto',
|
|
93
|
+
textAlign: 'center',
|
|
94
|
+
} },
|
|
95
|
+
React.createElement("div", { style: {
|
|
96
|
+
fontSize: theme.typography.fontSize.large,
|
|
97
|
+
fontWeight: theme.typography.fontWeight?.bold || 700,
|
|
98
|
+
color: theme.colors.text,
|
|
99
|
+
marginBottom: theme.spacing.small,
|
|
100
|
+
} },
|
|
101
|
+
"Total: ",
|
|
102
|
+
currencySymbol,
|
|
103
|
+
totalPrice.toFixed(2)),
|
|
104
|
+
React.createElement("button", { type: "button", onClick: () => onAddAll?.(items), style: {
|
|
105
|
+
padding: `${theme.spacing.small} ${theme.spacing.medium}`,
|
|
106
|
+
fontSize: theme.typography.fontSize.medium,
|
|
107
|
+
fontWeight: theme.typography.fontWeight?.medium || 500,
|
|
108
|
+
color: '#ffffff',
|
|
109
|
+
backgroundColor: theme.colors.primary,
|
|
110
|
+
border: 'none',
|
|
111
|
+
borderRadius: typeof theme.borderRadius === 'string'
|
|
112
|
+
? theme.borderRadius
|
|
113
|
+
: theme.borderRadius.medium,
|
|
114
|
+
cursor: 'pointer',
|
|
115
|
+
} }, "Add all to cart"))))));
|
|
116
|
+
};
|
|
117
|
+
export const RecentlyViewed = ({ storageKey = 'seekora_recently_viewed', items: itemsProp, title = 'Recently Viewed', maxItems = 6, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
118
|
+
const [storedItems, setStoredItems] = useState([]);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (itemsProp)
|
|
121
|
+
return;
|
|
122
|
+
try {
|
|
123
|
+
const stored = localStorage.getItem(storageKey);
|
|
124
|
+
if (stored) {
|
|
125
|
+
setStoredItems(JSON.parse(stored));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
// Ignore localStorage errors
|
|
130
|
+
}
|
|
131
|
+
}, [storageKey, itemsProp]);
|
|
132
|
+
const items = (itemsProp || storedItems).slice(0, maxItems);
|
|
133
|
+
if (items.length === 0) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return (React.createElement(RecommendationSection, { title: title, items: items, renderItem: renderItem, onItemClick: onItemClick, className: className, style: style, theme: customTheme, layout: layout, currencySymbol: currencySymbol }));
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Add item to recently viewed (utility function)
|
|
140
|
+
*/
|
|
141
|
+
export function addToRecentlyViewed(item, storageKey = 'seekora_recently_viewed', maxItems = 20) {
|
|
142
|
+
if (typeof localStorage === 'undefined')
|
|
143
|
+
return;
|
|
144
|
+
try {
|
|
145
|
+
const stored = localStorage.getItem(storageKey);
|
|
146
|
+
let items = stored ? JSON.parse(stored) : [];
|
|
147
|
+
// Remove if already exists
|
|
148
|
+
items = items.filter(i => i.id !== item.id);
|
|
149
|
+
// Add to beginning
|
|
150
|
+
items.unshift(item);
|
|
151
|
+
// Limit
|
|
152
|
+
items = items.slice(0, maxItems);
|
|
153
|
+
localStorage.setItem(storageKey, JSON.stringify(items));
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
// Ignore localStorage errors
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const RecommendationSection = ({ title, items, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
160
|
+
const { theme } = useSearchContext();
|
|
161
|
+
const recommendationTheme = customTheme || {};
|
|
162
|
+
const getListStyle = () => {
|
|
163
|
+
switch (layout) {
|
|
164
|
+
case 'horizontal':
|
|
165
|
+
return {
|
|
166
|
+
display: 'flex',
|
|
167
|
+
gap: theme.spacing.medium,
|
|
168
|
+
overflowX: 'auto',
|
|
169
|
+
scrollSnapType: 'x mandatory',
|
|
170
|
+
paddingBottom: theme.spacing.small,
|
|
171
|
+
};
|
|
172
|
+
case 'grid':
|
|
173
|
+
return {
|
|
174
|
+
display: 'grid',
|
|
175
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
|
|
176
|
+
gap: theme.spacing.medium,
|
|
177
|
+
};
|
|
178
|
+
case 'list':
|
|
179
|
+
return {
|
|
180
|
+
display: 'flex',
|
|
181
|
+
flexDirection: 'column',
|
|
182
|
+
gap: theme.spacing.small,
|
|
183
|
+
};
|
|
184
|
+
default:
|
|
185
|
+
return {};
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const getItemStyle = () => {
|
|
189
|
+
switch (layout) {
|
|
190
|
+
case 'horizontal':
|
|
191
|
+
return {
|
|
192
|
+
flexShrink: 0,
|
|
193
|
+
width: '150px',
|
|
194
|
+
scrollSnapAlign: 'start',
|
|
195
|
+
};
|
|
196
|
+
case 'grid':
|
|
197
|
+
return {};
|
|
198
|
+
case 'list':
|
|
199
|
+
return {
|
|
200
|
+
display: 'flex',
|
|
201
|
+
gap: theme.spacing.medium,
|
|
202
|
+
padding: theme.spacing.small,
|
|
203
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
204
|
+
};
|
|
205
|
+
default:
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
return (React.createElement("div", { className: clsx(recommendationTheme.root, className), style: style },
|
|
210
|
+
title && (React.createElement("h3", { className: recommendationTheme.title, style: {
|
|
211
|
+
margin: `0 0 ${theme.spacing.medium} 0`,
|
|
212
|
+
fontSize: theme.typography.fontSize.large,
|
|
213
|
+
fontWeight: theme.typography.fontWeight?.semibold || 600,
|
|
214
|
+
color: theme.colors.text,
|
|
215
|
+
} }, title)),
|
|
216
|
+
React.createElement("div", { className: recommendationTheme.list, style: getListStyle() }, items.map((item, index) => (React.createElement("div", { key: item.id || index, className: recommendationTheme.item, onClick: () => onItemClick?.(item, index), style: {
|
|
217
|
+
...getItemStyle(),
|
|
218
|
+
cursor: onItemClick ? 'pointer' : 'default',
|
|
219
|
+
} }, renderItem ? (renderItem(item, index)) : (React.createElement(DefaultRecommendationItem, { item: item, theme: recommendationTheme, currencySymbol: currencySymbol, layout: layout }))))))));
|
|
220
|
+
};
|
|
221
|
+
const DefaultRecommendationItem = ({ item, theme: recommendationTheme, currencySymbol, layout, }) => {
|
|
222
|
+
const { theme } = useSearchContext();
|
|
223
|
+
const image = item.image || item.imageUrl || '';
|
|
224
|
+
const title = item.title || item.name || '';
|
|
225
|
+
const price = item.price;
|
|
226
|
+
const imageSize = layout === 'list' ? '60px' : '100%';
|
|
227
|
+
return (React.createElement(React.Fragment, null,
|
|
228
|
+
image && (React.createElement("img", { src: image, alt: title, className: recommendationTheme.image, style: {
|
|
229
|
+
width: imageSize,
|
|
230
|
+
height: layout === 'list' ? '60px' : '120px',
|
|
231
|
+
objectFit: 'cover',
|
|
232
|
+
borderRadius: typeof theme.borderRadius === 'string'
|
|
233
|
+
? theme.borderRadius
|
|
234
|
+
: theme.borderRadius.small,
|
|
235
|
+
} })),
|
|
236
|
+
React.createElement("div", { className: recommendationTheme.content, style: { flex: layout === 'list' ? 1 : undefined } },
|
|
237
|
+
React.createElement("div", { className: recommendationTheme.name, style: {
|
|
238
|
+
marginTop: layout === 'list' ? 0 : theme.spacing.small,
|
|
239
|
+
fontSize: theme.typography.fontSize.small,
|
|
240
|
+
fontWeight: theme.typography.fontWeight?.medium || 500,
|
|
241
|
+
color: theme.colors.text,
|
|
242
|
+
overflow: 'hidden',
|
|
243
|
+
textOverflow: 'ellipsis',
|
|
244
|
+
display: '-webkit-box',
|
|
245
|
+
WebkitLineClamp: 2,
|
|
246
|
+
WebkitBoxOrient: 'vertical',
|
|
247
|
+
} }, title),
|
|
248
|
+
price !== undefined && (React.createElement("div", { className: recommendationTheme.price, style: {
|
|
249
|
+
marginTop: theme.spacing.small,
|
|
250
|
+
fontSize: theme.typography.fontSize.small,
|
|
251
|
+
fontWeight: theme.typography.fontWeight?.bold || 700,
|
|
252
|
+
color: theme.colors.primary,
|
|
253
|
+
} },
|
|
254
|
+
currencySymbol,
|
|
255
|
+
typeof price === 'number' ? price.toFixed(2) : price)))));
|
|
256
|
+
};
|