@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,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAnalytics Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for tracking analytics events with the Seekora SDK.
|
|
5
|
+
* Supports Analytics V3 payload fields (event_ts, anonymous_id, orgcode, xstoreid);
|
|
6
|
+
* the SDK sends both legacy and v3 fields for backend compatibility.
|
|
7
|
+
*/
|
|
8
|
+
import type { SeekoraClient, SearchContext, ExtendedEventPayload, DataTypesEventPayload } from '@seekora-ai/search-sdk';
|
|
9
|
+
export interface UseAnalyticsOptions {
|
|
10
|
+
client: SeekoraClient;
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Payload for trackEvent/trackBatch: supports legacy and Analytics V3 field names */
|
|
14
|
+
export type AnalyticsEventPayload = Partial<DataTypesEventPayload> & Partial<ExtendedEventPayload>;
|
|
15
|
+
export interface UseAnalyticsReturn {
|
|
16
|
+
trackEvent: (eventType: string, payload: AnalyticsEventPayload, context?: SearchContext | Partial<SearchContext>) => Promise<void>;
|
|
17
|
+
trackClick: (resultId: string, result: any, context?: SearchContext | Partial<SearchContext>, position?: number) => Promise<void>;
|
|
18
|
+
trackConversion: (resultId: string, result: any, value?: number, currency?: string, context?: SearchContext | Partial<SearchContext>) => Promise<void>;
|
|
19
|
+
trackBatch: (events: (AnalyticsEventPayload & {
|
|
20
|
+
event_name?: string;
|
|
21
|
+
})[], context?: SearchContext) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare const useAnalytics: ({ client, enabled, }: UseAnalyticsOptions) => UseAnalyticsReturn;
|
|
24
|
+
//# sourceMappingURL=useAnalytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalytics.d.ts","sourceRoot":"","sources":["../../src/hooks/useAnalytics.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAGxH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEnG,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnI,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClI,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvJ,UAAU,EAAE,CAAC,MAAM,EAAE,CAAC,qBAAqB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrH;AAED,eAAO,MAAM,YAAY,GAAI,sBAG1B,mBAAmB,KAAG,kBA6ExB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAnalytics Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for tracking analytics events with the Seekora SDK.
|
|
5
|
+
* Supports Analytics V3 payload fields (event_ts, anonymous_id, orgcode, xstoreid);
|
|
6
|
+
* the SDK sends both legacy and v3 fields for backend compatibility.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback } from 'react';
|
|
9
|
+
import { log } from '@seekora-ai/ui-sdk-core';
|
|
10
|
+
export const useAnalytics = ({ client, enabled = true, }) => {
|
|
11
|
+
const trackEvent = useCallback(async (eventType, payload, context) => {
|
|
12
|
+
if (!enabled)
|
|
13
|
+
return;
|
|
14
|
+
try {
|
|
15
|
+
const eventPayload = {
|
|
16
|
+
event_name: eventType,
|
|
17
|
+
...payload,
|
|
18
|
+
};
|
|
19
|
+
await client.trackEvent?.(eventPayload, context);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
log.error('Failed to track event:', err);
|
|
23
|
+
}
|
|
24
|
+
}, [client, enabled]);
|
|
25
|
+
const trackClick = useCallback(async (resultId, result, context, position) => {
|
|
26
|
+
if (!enabled)
|
|
27
|
+
return;
|
|
28
|
+
const pos = position ?? 0;
|
|
29
|
+
if (client.trackClick) {
|
|
30
|
+
await client.trackClick(resultId, pos, context);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await trackEvent('product_click', {
|
|
34
|
+
clicked_item_id: resultId,
|
|
35
|
+
metadata: { result, ...(position !== undefined && { position: pos }) },
|
|
36
|
+
}, context);
|
|
37
|
+
}
|
|
38
|
+
}, [client, trackEvent, enabled]);
|
|
39
|
+
const trackConversion = useCallback(async (resultId, result, value, currency, context) => {
|
|
40
|
+
if (!enabled)
|
|
41
|
+
return;
|
|
42
|
+
await trackEvent('conversion', {
|
|
43
|
+
clicked_item_id: resultId,
|
|
44
|
+
value: value,
|
|
45
|
+
currency: currency,
|
|
46
|
+
metadata: {
|
|
47
|
+
result: result,
|
|
48
|
+
},
|
|
49
|
+
}, context);
|
|
50
|
+
}, [trackEvent, enabled]);
|
|
51
|
+
const trackBatch = useCallback(async (events, context) => {
|
|
52
|
+
if (!enabled || events.length === 0)
|
|
53
|
+
return;
|
|
54
|
+
try {
|
|
55
|
+
await client.trackEvents?.(events, context);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
log.error('Failed to track batch events:', err);
|
|
59
|
+
}
|
|
60
|
+
}, [client, enabled]);
|
|
61
|
+
return {
|
|
62
|
+
trackEvent,
|
|
63
|
+
trackClick,
|
|
64
|
+
trackConversion,
|
|
65
|
+
trackBatch,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useClickTracking Hook
|
|
3
|
+
*
|
|
4
|
+
* Wraps result link clicks with analytics fire-before-navigate.
|
|
5
|
+
* - For target="_blank" links: fires analytics normally (page stays)
|
|
6
|
+
* - For same-page navigation: uses sendBeacon + small delay before navigation
|
|
7
|
+
* - Tracks click_target: 'new_tab' | 'same_page' | 'in_page'
|
|
8
|
+
* - Includes destination_url and source_url in click event payload
|
|
9
|
+
*/
|
|
10
|
+
export type ClickTarget = 'new_tab' | 'same_page' | 'in_page';
|
|
11
|
+
export interface ClickTrackingOptions {
|
|
12
|
+
/** The destination URL the user is navigating to */
|
|
13
|
+
destinationUrl?: string;
|
|
14
|
+
/** The clicked item ID */
|
|
15
|
+
itemId: string;
|
|
16
|
+
/** Position in search results (1-based) */
|
|
17
|
+
position: number;
|
|
18
|
+
/** Click target type */
|
|
19
|
+
clickTarget?: ClickTarget;
|
|
20
|
+
/** Additional metadata */
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
export interface UseClickTrackingReturn {
|
|
24
|
+
/**
|
|
25
|
+
* Track a click event and optionally delay navigation.
|
|
26
|
+
* Returns a promise that resolves when tracking is complete.
|
|
27
|
+
*/
|
|
28
|
+
trackClick: (options: ClickTrackingOptions) => Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Create an onClick handler that tracks before navigating.
|
|
31
|
+
* Use this to wrap <a> tag clicks.
|
|
32
|
+
*/
|
|
33
|
+
createClickHandler: (options: ClickTrackingOptions, onComplete?: () => void) => (e: React.MouseEvent<HTMLAnchorElement>) => void;
|
|
34
|
+
}
|
|
35
|
+
export declare const useClickTracking: () => UseClickTrackingReturn;
|
|
36
|
+
//# sourceMappingURL=useClickTracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useClickTracking.d.ts","sourceRoot":"","sources":["../../src/hooks/useClickTracking.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D;;;OAGG;IACH,kBAAkB,EAAE,CAClB,OAAO,EAAE,oBAAoB,EAC7B,UAAU,CAAC,EAAE,MAAM,IAAI,KACpB,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;CACvD;AAED,eAAO,MAAM,gBAAgB,QAAO,sBAkFnC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useClickTracking Hook
|
|
3
|
+
*
|
|
4
|
+
* Wraps result link clicks with analytics fire-before-navigate.
|
|
5
|
+
* - For target="_blank" links: fires analytics normally (page stays)
|
|
6
|
+
* - For same-page navigation: uses sendBeacon + small delay before navigation
|
|
7
|
+
* - Tracks click_target: 'new_tab' | 'same_page' | 'in_page'
|
|
8
|
+
* - Includes destination_url and source_url in click event payload
|
|
9
|
+
*/
|
|
10
|
+
import { useCallback, useRef } from 'react';
|
|
11
|
+
import { useSearchContext } from '../components/SearchProvider';
|
|
12
|
+
import { useSearchState } from './useSearchState';
|
|
13
|
+
export const useClickTracking = () => {
|
|
14
|
+
const { client, enableAnalytics, stateManager } = useSearchContext();
|
|
15
|
+
const { results } = useSearchState();
|
|
16
|
+
const pendingRef = useRef(false);
|
|
17
|
+
const trackClick = useCallback(async (options) => {
|
|
18
|
+
if (!enableAnalytics || pendingRef.current)
|
|
19
|
+
return;
|
|
20
|
+
pendingRef.current = true;
|
|
21
|
+
try {
|
|
22
|
+
const sourceUrl = typeof window !== 'undefined' ? window.location.href : undefined;
|
|
23
|
+
const searchContext = results?.context;
|
|
24
|
+
// Include A/B test fields from state manager (beacon payloads bypass client.trackEvent)
|
|
25
|
+
const abTestId = stateManager.getAbTestId?.();
|
|
26
|
+
const abVariant = stateManager.getAbVariant?.();
|
|
27
|
+
const eventPayload = {
|
|
28
|
+
event_name: 'product_click',
|
|
29
|
+
clicked_item_id: options.itemId,
|
|
30
|
+
position: options.position,
|
|
31
|
+
destination_url: options.destinationUrl || '',
|
|
32
|
+
source_url: sourceUrl || '',
|
|
33
|
+
click_target: options.clickTarget || 'in_page',
|
|
34
|
+
...(abTestId && { ab_test_id: abTestId }),
|
|
35
|
+
...(abVariant && { ab_variant: abVariant }),
|
|
36
|
+
...options.metadata,
|
|
37
|
+
};
|
|
38
|
+
if (options.clickTarget === 'same_page') {
|
|
39
|
+
// For same_page navigation, track via SDK then flush to ensure delivery before navigation
|
|
40
|
+
if (client.trackEvent) {
|
|
41
|
+
await client.trackEvent(eventPayload, searchContext);
|
|
42
|
+
await client.flushEventQueue();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Normal tracking via client SDK
|
|
47
|
+
if (client.trackClick) {
|
|
48
|
+
await client.trackClick(options.itemId, options.position, searchContext);
|
|
49
|
+
}
|
|
50
|
+
else if (client.trackEvent) {
|
|
51
|
+
await client.trackEvent(eventPayload, searchContext);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Silently fail — analytics should never break navigation
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
pendingRef.current = false;
|
|
60
|
+
}
|
|
61
|
+
}, [client, enableAnalytics, results, stateManager]);
|
|
62
|
+
const createClickHandler = useCallback((options, onComplete) => {
|
|
63
|
+
return (e) => {
|
|
64
|
+
const anchor = e.currentTarget;
|
|
65
|
+
const href = anchor.href;
|
|
66
|
+
const target = anchor.target;
|
|
67
|
+
const isNewTab = target === '_blank' || e.metaKey || e.ctrlKey;
|
|
68
|
+
const clickTarget = isNewTab ? 'new_tab' : 'same_page';
|
|
69
|
+
const trackOptions = { ...options, destinationUrl: href, clickTarget };
|
|
70
|
+
if (isNewTab) {
|
|
71
|
+
// New tab: page stays, track normally
|
|
72
|
+
trackClick(trackOptions);
|
|
73
|
+
onComplete?.();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Same page: prevent default, track with beacon, then navigate
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
trackClick(trackOptions).then(() => {
|
|
79
|
+
// Small delay to ensure beacon fires
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
onComplete?.();
|
|
82
|
+
window.location.href = href;
|
|
83
|
+
}, 50);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}, [trackClick]);
|
|
88
|
+
return { trackClick, createClickHandler };
|
|
89
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useExperiment Hook
|
|
3
|
+
*
|
|
4
|
+
* Fetches experiment variant assignments from the backend and caches them.
|
|
5
|
+
* Auto-injects ab_test_id and ab_variant into SearchProvider context.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { experimentId, variantId, variantConfig, isLoading } = useExperiment('search-ranking-v2');
|
|
9
|
+
*/
|
|
10
|
+
export interface ExperimentAssignment {
|
|
11
|
+
experiment_id: string;
|
|
12
|
+
variant_id: string;
|
|
13
|
+
variant_config?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export interface UseExperimentReturn {
|
|
16
|
+
experimentId: string | null;
|
|
17
|
+
variantId: string | null;
|
|
18
|
+
variantConfig: Record<string, unknown> | null;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
error: Error | null;
|
|
21
|
+
/** All active assignments for the current user */
|
|
22
|
+
allAssignments: ExperimentAssignment[];
|
|
23
|
+
}
|
|
24
|
+
export declare const useExperiment: (experimentId?: string) => UseExperimentReturn;
|
|
25
|
+
//# sourceMappingURL=useExperiment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useExperiment.d.ts","sourceRoot":"","sources":["../../src/hooks/useExperiment.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kDAAkD;IAClD,cAAc,EAAE,oBAAoB,EAAE,CAAC;CACxC;AAsCD,eAAO,MAAM,aAAa,GAAI,eAAe,MAAM,KAAG,mBAuFrD,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useExperiment Hook
|
|
3
|
+
*
|
|
4
|
+
* Fetches experiment variant assignments from the backend and caches them.
|
|
5
|
+
* Auto-injects ab_test_id and ab_variant into SearchProvider context.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { experimentId, variantId, variantConfig, isLoading } = useExperiment('search-ranking-v2');
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
11
|
+
import { useSearchContext } from '../components/SearchProvider';
|
|
12
|
+
const CACHE_PREFIX = 'seekora_experiment_';
|
|
13
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
14
|
+
function getCachedAssignment(userKey, experimentId) {
|
|
15
|
+
if (typeof localStorage === 'undefined')
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const key = `${CACHE_PREFIX}${userKey}_${experimentId}`;
|
|
19
|
+
const raw = localStorage.getItem(key);
|
|
20
|
+
if (!raw)
|
|
21
|
+
return null;
|
|
22
|
+
const cached = JSON.parse(raw);
|
|
23
|
+
if (Date.now() - cached.timestamp > CACHE_TTL_MS) {
|
|
24
|
+
localStorage.removeItem(key);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return cached.assignment;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function setCachedAssignment(userKey, assignment) {
|
|
34
|
+
if (typeof localStorage === 'undefined')
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
const key = `${CACHE_PREFIX}${userKey}_${assignment.experiment_id}`;
|
|
38
|
+
const cached = { assignment, timestamp: Date.now() };
|
|
39
|
+
localStorage.setItem(key, JSON.stringify(cached));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Silently fail — localStorage may be full or unavailable
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export const useExperiment = (experimentId) => {
|
|
46
|
+
const { client, stateManager } = useSearchContext();
|
|
47
|
+
const [allAssignments, setAllAssignments] = useState([]);
|
|
48
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
49
|
+
const [error, setError] = useState(null);
|
|
50
|
+
const fetchedRef = useRef(false);
|
|
51
|
+
const fetchAssignments = useCallback(async () => {
|
|
52
|
+
if (fetchedRef.current)
|
|
53
|
+
return;
|
|
54
|
+
fetchedRef.current = true;
|
|
55
|
+
setIsLoading(true);
|
|
56
|
+
try {
|
|
57
|
+
// Try to determine user key for caching
|
|
58
|
+
const clientAny = client;
|
|
59
|
+
const userKey = clientAny.userId || clientAny.anonymousId || clientAny.anonId || '';
|
|
60
|
+
// Check cache first for specific experiment
|
|
61
|
+
if (experimentId && userKey) {
|
|
62
|
+
const cached = getCachedAssignment(userKey, experimentId);
|
|
63
|
+
if (cached) {
|
|
64
|
+
setAllAssignments([cached]);
|
|
65
|
+
// Update state manager and SDK client with cached assignment
|
|
66
|
+
stateManager.setAbTest(cached.experiment_id, cached.variant_id);
|
|
67
|
+
if (typeof clientAny.setAbTest === 'function') {
|
|
68
|
+
clientAny.setAbTest(cached.experiment_id, cached.variant_id);
|
|
69
|
+
}
|
|
70
|
+
setIsLoading(false);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Fetch from backend via SDK client (handles auth, baseUrl, headers internally)
|
|
75
|
+
if (typeof clientAny.getExperimentAssignment !== 'function') {
|
|
76
|
+
setIsLoading(false);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const data = await client.getExperimentAssignment();
|
|
80
|
+
const assignments = data.assignments || [];
|
|
81
|
+
// Cache all assignments
|
|
82
|
+
assignments.forEach(a => setCachedAssignment(userKey, a));
|
|
83
|
+
setAllAssignments(assignments);
|
|
84
|
+
// If a specific experiment was requested, set it on the state manager and SDK client
|
|
85
|
+
const setAbFields = (expId, varId) => {
|
|
86
|
+
stateManager.setAbTest(expId, varId);
|
|
87
|
+
client.setAbTest(expId, varId);
|
|
88
|
+
};
|
|
89
|
+
if (experimentId) {
|
|
90
|
+
const match = assignments.find(a => a.experiment_id === experimentId);
|
|
91
|
+
if (match) {
|
|
92
|
+
setAbFields(match.experiment_id, match.variant_id);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (assignments.length > 0) {
|
|
96
|
+
// Use the first assignment by default
|
|
97
|
+
setAbFields(assignments[0].experiment_id, assignments[0].variant_id);
|
|
98
|
+
}
|
|
99
|
+
setError(null);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
setIsLoading(false);
|
|
106
|
+
}
|
|
107
|
+
}, [client, stateManager, experimentId]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
fetchAssignments();
|
|
110
|
+
}, [fetchAssignments]);
|
|
111
|
+
// Find the specific experiment assignment
|
|
112
|
+
const assignment = experimentId
|
|
113
|
+
? allAssignments.find(a => a.experiment_id === experimentId)
|
|
114
|
+
: allAssignments[0] || null;
|
|
115
|
+
return {
|
|
116
|
+
experimentId: assignment?.experiment_id || null,
|
|
117
|
+
variantId: assignment?.variant_id || null,
|
|
118
|
+
variantConfig: assignment?.variant_config || null,
|
|
119
|
+
isLoading,
|
|
120
|
+
error,
|
|
121
|
+
allAssignments,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFilters Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for fetching filter values, searching facet values,
|
|
5
|
+
* and retrieving filter schema via the dedicated Filters API.
|
|
6
|
+
*/
|
|
7
|
+
import type { FilterOptions, FilterField, FiltersSchemaResponse, FacetValuesSearchResponse } from '@seekora-ai/search-sdk';
|
|
8
|
+
export interface UseFiltersOptions extends FilterOptions {
|
|
9
|
+
/** Whether to automatically refetch filters when query or refinements change (default: true) */
|
|
10
|
+
autoFetch?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface UseFiltersReturn {
|
|
13
|
+
/** Filter fields with values and counts */
|
|
14
|
+
filters: FilterField[];
|
|
15
|
+
/** Filter schema metadata (fetched once on mount) */
|
|
16
|
+
schema: FiltersSchemaResponse | null;
|
|
17
|
+
/** Whether filters are currently loading */
|
|
18
|
+
loading: boolean;
|
|
19
|
+
/** Error from the last fetch, if any */
|
|
20
|
+
error: Error | null;
|
|
21
|
+
/** Search within a facet's values (for typeahead/autocomplete) */
|
|
22
|
+
searchFacetValues: (facetName: string, query: string) => Promise<FacetValuesSearchResponse>;
|
|
23
|
+
/** Manually refetch filters */
|
|
24
|
+
refetch: () => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare const useFilters: (options?: UseFiltersOptions) => UseFiltersReturn;
|
|
27
|
+
//# sourceMappingURL=useFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFilters.d.ts","sourceRoot":"","sources":["../../src/hooks/useFilters.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,wBAAwB,CAAC;AAIhC,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,gGAAgG;IAChG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,qDAAqD;IACrD,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kEAAkE;IAClE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5F,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,UAAU,GAAI,UAAU,iBAAiB,KAAG,gBA2FxD,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFilters Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for fetching filter values, searching facet values,
|
|
5
|
+
* and retrieving filter schema via the dedicated Filters API.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
8
|
+
import { useSearchContext } from '../components/SearchProvider';
|
|
9
|
+
export const useFilters = (options) => {
|
|
10
|
+
const { stateManager } = useSearchContext();
|
|
11
|
+
const [filters, setFilters] = useState([]);
|
|
12
|
+
const [schema, setSchema] = useState(null);
|
|
13
|
+
const [loading, setLoading] = useState(false);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const mountedRef = useRef(true);
|
|
16
|
+
const autoFetch = options?.autoFetch !== false;
|
|
17
|
+
// Track whether we've completed the first fetch (to avoid skeleton flash on refetches)
|
|
18
|
+
const hasDataRef = useRef(false);
|
|
19
|
+
// Extract non-autoFetch options to pass to fetchFilters
|
|
20
|
+
const fetchFilters = useCallback(async () => {
|
|
21
|
+
// Only show loading spinner on the very first fetch; subsequent refetches
|
|
22
|
+
// keep previous data visible to avoid skeleton/flash on facet changes.
|
|
23
|
+
if (!hasDataRef.current) {
|
|
24
|
+
setLoading(true);
|
|
25
|
+
}
|
|
26
|
+
setError(null);
|
|
27
|
+
try {
|
|
28
|
+
const { autoFetch: _, ...filterOptions } = options || {};
|
|
29
|
+
const response = await stateManager.fetchFilters(filterOptions);
|
|
30
|
+
if (mountedRef.current) {
|
|
31
|
+
setFilters(response?.filters || []);
|
|
32
|
+
hasDataRef.current = true;
|
|
33
|
+
setLoading(false);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (mountedRef.current) {
|
|
38
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
39
|
+
setLoading(false);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, [stateManager, options?.facetBy, options?.maxFacetValues, options?.disjunctiveFacets?.join(',')]);
|
|
43
|
+
// Track query to only refetch filters when query actually changes.
|
|
44
|
+
// Sentinel ensures the first subscribe callback always triggers a fetch.
|
|
45
|
+
const prevKeyRef = useRef(null);
|
|
46
|
+
// Refetch when query or refinements change (not on every state update)
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!autoFetch)
|
|
49
|
+
return;
|
|
50
|
+
const unsubscribe = stateManager.subscribe((state) => {
|
|
51
|
+
// Only track query changes — refinements are NOT passed to the Filters API
|
|
52
|
+
// (facets are generated from search query only, not narrowed by active filters).
|
|
53
|
+
// This prevents redundant filters refetches on every facet toggle.
|
|
54
|
+
const key = state.query;
|
|
55
|
+
if (key === prevKeyRef.current)
|
|
56
|
+
return;
|
|
57
|
+
prevKeyRef.current = key;
|
|
58
|
+
fetchFilters();
|
|
59
|
+
});
|
|
60
|
+
// subscribe() immediately invokes the listener with current state,
|
|
61
|
+
// which handles the initial fetch (prevKeyRef starts as '' so key
|
|
62
|
+
// will differ). No explicit fetchFilters() call needed here.
|
|
63
|
+
return unsubscribe;
|
|
64
|
+
}, [stateManager, autoFetch, fetchFilters]);
|
|
65
|
+
// Fetch schema once on mount
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
stateManager.getFiltersSchema().then((response) => {
|
|
68
|
+
if (mountedRef.current) {
|
|
69
|
+
setSchema(response);
|
|
70
|
+
}
|
|
71
|
+
}).catch(() => {
|
|
72
|
+
// Schema fetch failure is non-critical
|
|
73
|
+
});
|
|
74
|
+
}, [stateManager]);
|
|
75
|
+
// Cleanup
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
return () => {
|
|
78
|
+
mountedRef.current = false;
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
const searchFacetValues = useCallback((facetName, query) => stateManager.searchFacetValues(facetName, query), [stateManager]);
|
|
82
|
+
const refetch = useCallback(async () => {
|
|
83
|
+
await fetchFilters();
|
|
84
|
+
}, [fetchFilters]);
|
|
85
|
+
return { filters, schema, loading, error, searchFacetValues, refetch };
|
|
86
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useKeyboardNavigation Hook
|
|
3
|
+
*
|
|
4
|
+
* Shared focus management for navigable component lists.
|
|
5
|
+
* Handles arrow keys, Enter/Space, Escape, Home/End.
|
|
6
|
+
* Provides visible focus indicators via CSS variables.
|
|
7
|
+
*/
|
|
8
|
+
export interface KeyboardNavigationOptions {
|
|
9
|
+
/** Total number of items in the list */
|
|
10
|
+
itemCount: number;
|
|
11
|
+
/** Orientation: 'vertical' for up/down, 'horizontal' for left/right */
|
|
12
|
+
orientation?: 'vertical' | 'horizontal';
|
|
13
|
+
/** Whether navigation wraps around at boundaries */
|
|
14
|
+
wrap?: boolean;
|
|
15
|
+
/** Callback when an item is selected (Enter/Space) */
|
|
16
|
+
onSelect?: (index: number) => void;
|
|
17
|
+
/** Callback when Escape is pressed */
|
|
18
|
+
onEscape?: () => void;
|
|
19
|
+
/** Callback when Delete/Backspace is pressed on focused item */
|
|
20
|
+
onDelete?: (index: number) => void;
|
|
21
|
+
/** Whether keyboard navigation is enabled */
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface UseKeyboardNavigationReturn {
|
|
25
|
+
/** Currently focused item index (-1 = none) */
|
|
26
|
+
activeIndex: number;
|
|
27
|
+
/** Set active index programmatically */
|
|
28
|
+
setActiveIndex: (index: number) => void;
|
|
29
|
+
/** Props to spread onto the container element */
|
|
30
|
+
containerProps: {
|
|
31
|
+
tabIndex: number;
|
|
32
|
+
role: string;
|
|
33
|
+
'aria-activedescendant': string | undefined;
|
|
34
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
35
|
+
onBlur: () => void;
|
|
36
|
+
};
|
|
37
|
+
/** Get props for an individual item */
|
|
38
|
+
getItemProps: (index: number) => {
|
|
39
|
+
id: string;
|
|
40
|
+
role: string;
|
|
41
|
+
tabIndex: number;
|
|
42
|
+
'aria-selected': boolean;
|
|
43
|
+
onMouseEnter: () => void;
|
|
44
|
+
onFocus: () => void;
|
|
45
|
+
style: React.CSSProperties;
|
|
46
|
+
};
|
|
47
|
+
/** Whether any item is currently focused */
|
|
48
|
+
hasFocus: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare const useKeyboardNavigation: (options: KeyboardNavigationOptions) => UseKeyboardNavigationReturn;
|
|
51
|
+
//# sourceMappingURL=useKeyboardNavigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyboardNavigation.d.ts","sourceRoot":"","sources":["../../src/hooks/useKeyboardNavigation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,yBAAyB;IACxC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,2BAA2B;IAC1C,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iDAAiD;IACjD,cAAc,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5C,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;QAC5C,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IACF,uCAAuC;IACvC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK;QAC/B,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,OAAO,CAAC;QACzB,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC;KAC5B,CAAC;IACF,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,CAAC;CACnB;AAaD,eAAO,MAAM,qBAAqB,GAAI,SAAS,yBAAyB,KAAG,2BAkH1E,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useKeyboardNavigation Hook
|
|
3
|
+
*
|
|
4
|
+
* Shared focus management for navigable component lists.
|
|
5
|
+
* Handles arrow keys, Enter/Space, Escape, Home/End.
|
|
6
|
+
* Provides visible focus indicators via CSS variables.
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
9
|
+
const FOCUS_RING_STYLE = {
|
|
10
|
+
outline: '2px solid var(--seekora-focus-color, #2563eb)',
|
|
11
|
+
outlineOffset: '2px',
|
|
12
|
+
};
|
|
13
|
+
const NO_FOCUS_STYLE = {
|
|
14
|
+
outline: 'none',
|
|
15
|
+
};
|
|
16
|
+
let idCounter = 0;
|
|
17
|
+
export const useKeyboardNavigation = (options) => {
|
|
18
|
+
const { itemCount, orientation = 'vertical', wrap = false, onSelect, onEscape, onDelete, enabled = true, } = options;
|
|
19
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
20
|
+
const idPrefixRef = useRef(`seekora-nav-${++idCounter}`);
|
|
21
|
+
// Reset active index when item count changes
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (activeIndex >= itemCount) {
|
|
24
|
+
setActiveIndex(itemCount > 0 ? itemCount - 1 : -1);
|
|
25
|
+
}
|
|
26
|
+
}, [itemCount, activeIndex]);
|
|
27
|
+
const moveNext = useCallback(() => {
|
|
28
|
+
setActiveIndex(prev => {
|
|
29
|
+
if (prev >= itemCount - 1) {
|
|
30
|
+
return wrap ? 0 : prev;
|
|
31
|
+
}
|
|
32
|
+
return prev + 1;
|
|
33
|
+
});
|
|
34
|
+
}, [itemCount, wrap]);
|
|
35
|
+
const movePrev = useCallback(() => {
|
|
36
|
+
setActiveIndex(prev => {
|
|
37
|
+
if (prev <= 0) {
|
|
38
|
+
return wrap ? itemCount - 1 : (prev === -1 ? 0 : prev);
|
|
39
|
+
}
|
|
40
|
+
return prev - 1;
|
|
41
|
+
});
|
|
42
|
+
}, [itemCount, wrap]);
|
|
43
|
+
const handleKeyDown = useCallback((e) => {
|
|
44
|
+
if (!enabled || itemCount === 0)
|
|
45
|
+
return;
|
|
46
|
+
const nextKey = orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight';
|
|
47
|
+
const prevKey = orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft';
|
|
48
|
+
switch (e.key) {
|
|
49
|
+
case nextKey:
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
moveNext();
|
|
52
|
+
break;
|
|
53
|
+
case prevKey:
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
movePrev();
|
|
56
|
+
break;
|
|
57
|
+
case 'Enter':
|
|
58
|
+
case ' ':
|
|
59
|
+
if (activeIndex >= 0) {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
onSelect?.(activeIndex);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
case 'Escape':
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
setActiveIndex(-1);
|
|
67
|
+
onEscape?.();
|
|
68
|
+
break;
|
|
69
|
+
case 'Home':
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
setActiveIndex(0);
|
|
72
|
+
break;
|
|
73
|
+
case 'End':
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
setActiveIndex(itemCount - 1);
|
|
76
|
+
break;
|
|
77
|
+
case 'Delete':
|
|
78
|
+
case 'Backspace':
|
|
79
|
+
if (activeIndex >= 0) {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
onDelete?.(activeIndex);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}, [enabled, itemCount, orientation, activeIndex, moveNext, movePrev, onSelect, onEscape, onDelete]);
|
|
86
|
+
const handleBlur = useCallback(() => {
|
|
87
|
+
// Delay reset to allow click events to fire
|
|
88
|
+
setTimeout(() => setActiveIndex(-1), 150);
|
|
89
|
+
}, []);
|
|
90
|
+
const containerProps = {
|
|
91
|
+
tabIndex: enabled ? 0 : -1,
|
|
92
|
+
role: orientation === 'vertical' ? 'listbox' : 'list',
|
|
93
|
+
'aria-activedescendant': activeIndex >= 0 ? `${idPrefixRef.current}-${activeIndex}` : undefined,
|
|
94
|
+
onKeyDown: handleKeyDown,
|
|
95
|
+
onBlur: handleBlur,
|
|
96
|
+
};
|
|
97
|
+
const getItemProps = useCallback((index) => ({
|
|
98
|
+
id: `${idPrefixRef.current}-${index}`,
|
|
99
|
+
role: 'option',
|
|
100
|
+
tabIndex: -1,
|
|
101
|
+
'aria-selected': index === activeIndex,
|
|
102
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
103
|
+
onFocus: () => setActiveIndex(index),
|
|
104
|
+
style: index === activeIndex ? FOCUS_RING_STYLE : NO_FOCUS_STYLE,
|
|
105
|
+
}), [activeIndex]);
|
|
106
|
+
return {
|
|
107
|
+
activeIndex,
|
|
108
|
+
setActiveIndex,
|
|
109
|
+
containerProps,
|
|
110
|
+
getItemProps,
|
|
111
|
+
hasFocus: activeIndex >= 0,
|
|
112
|
+
};
|
|
113
|
+
};
|