@seekora-ai/ui-sdk-react 0.2.22 → 0.2.23

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.
@@ -481,6 +481,10 @@ interface FacetsProps {
481
481
  useFiltersApi?: boolean;
482
482
  /** Fields that should use disjunctive (OR) faceting (only with useFiltersApi) */
483
483
  disjunctiveFacets?: string[];
484
+ /** Hide facets that have no selectable values (default: true) */
485
+ hideEmptyFacets?: boolean;
486
+ /** Fields that should start collapsed (collapsible variant only). Overrides defaultCollapsed for listed fields. */
487
+ defaultCollapsedFields?: string[];
484
488
  }
485
489
  declare const Facets: React__default.FC<FacetsProps>;
486
490
 
@@ -2914,6 +2918,46 @@ interface AnalyticsContextValue {
2914
2918
  declare const useAnalyticsProvider: () => AnalyticsContextValue | null;
2915
2919
  declare function AnalyticsProvider({ client, context, children }: AnalyticsProviderProps): React__default.JSX.Element;
2916
2920
 
2921
+ /**
2922
+ * CustomSelect — lightweight, accessible custom dropdown replacement for native <select>.
2923
+ *
2924
+ * CSS Variables (apply on a parent element to customize):
2925
+ * --seekora-select-bg — background color (default: #fff)
2926
+ * --seekora-select-color — text color (default: inherit)
2927
+ * --seekora-select-border — border color (default: rgba(128,128,128,0.3))
2928
+ * --seekora-select-hover-bg — option hover background (default: #f3f4f6)
2929
+ * --seekora-select-active-bg — selected option background (default: #eff6ff)
2930
+ * --seekora-select-active-color — selected option text color (default: inherit)
2931
+ * --seekora-select-radius — border radius (default: 6px)
2932
+ * --seekora-select-font-size — font size (default: 0.875rem)
2933
+ */
2934
+
2935
+ interface CustomSelectOption {
2936
+ value: string;
2937
+ label: string;
2938
+ disabled?: boolean;
2939
+ }
2940
+ interface CustomSelectTheme {
2941
+ trigger?: string;
2942
+ menu?: string;
2943
+ option?: string;
2944
+ optionActive?: string;
2945
+ optionDisabled?: string;
2946
+ }
2947
+ interface CustomSelectProps {
2948
+ value: string;
2949
+ onChange: (value: string) => void;
2950
+ options: CustomSelectOption[];
2951
+ placeholder?: string;
2952
+ className?: string;
2953
+ style?: React__default.CSSProperties;
2954
+ theme?: CustomSelectTheme;
2955
+ /** aria-label for the trigger button */
2956
+ 'aria-label'?: string;
2957
+ disabled?: boolean;
2958
+ }
2959
+ declare const CustomSelect: React__default.FC<CustomSelectProps>;
2960
+
2917
2961
  /**
2918
2962
  * SectionSearchProvider – preset query + filter section
2919
2963
  *
@@ -4411,5 +4455,5 @@ declare function updateSuggestionsStyles(theme: SuggestionsThemeVariables): void
4411
4455
 
4412
4456
  declare const createTheme: (config: ThemeConfig) => _seekora_ai_ui_sdk_types.Theme;
4413
4457
 
4414
- export { ActionButtons, AmazonDropdown, AnalyticsProvider, BadgeList, Breadcrumb, CategoriesTabs, ClearRefinements, CurrentRefinements, DocSearch, DocSearchButton, DropdownPanel, FacetDropdown, Facets, FederatedDropdown, FrequentlyBoughtTogether, GoogleDropdown, HierarchicalMenu, Highlight, HitsPerPage, ImageDisplay, ImageZoom, InfiniteHits, ItemCard, ItemGrid, MinimalDropdown, MobileFilters, MobileFiltersButton, MobileSheetDropdown, Pagination, PinterestDropdown, PriceDisplay, ProductCard, ProductGallery, ProductGrid, ProductInfo, ProductRecommendations, QuerySuggestions, QuerySuggestionsDropdown, RangeInput, RangeSlider, RatingDisplay, RecentSearchesList, RecentlyViewed, RelatedProducts, RichQuerySuggestions, SearchBar, SearchBarWithSuggestions, SearchInput, SearchLayout, SearchProvider, SearchResults, SectionError, SectionItemGrid, SectionSearchProvider, ShopifyDropdown, Snippet, SortBy, SpotlightDropdown, Stats, SuggestionDropdownVariants, SuggestionItem$1 as SuggestionItem, SuggestionList, SuggestionSearchBar, SuggestionsCache, SuggestionsDropdownComposition, SuggestionsError, SuggestionsProvider, TrendingItems, TrendingList, VariantSelector, VariantSwatches, addRecentSearch, addToRecentlyViewed, brandPresets, breakpoints, clearRecentSearches, clearSuggestionsCache, createSuggestionsCache, createSuggestionsTheme, createTheme, darkTheme, darkThemeVariables, defaultTheme, extractBadges, extractBrand, extractCategory, extractProduct, extractSuggestion, findVariantBySelections, formatParsedFilters, formatPriceRange, formatPrice as formatSuggestionPrice, generateSuggestionsStylesheet, getAvailableValuesForOption, getPriceRange, getRecentSearches, getShortcutText, getSuggestionsCache, highlightText, injectGlobalResponsiveStyles, injectSuggestionsStyles, lightThemeVariables, mediaQueries, minimalTheme, minimalThemeVariables, parseHighlightMarkup, removeRecentSearch, touchTargets, updateSuggestionsStyles, useAnalytics, useAnalyticsProvider, useDocSearch, useSeekoraSearch$1 as useDocSearchSeekoraSearch, useFilters, useInjectResponsiveStyles, useKeyboard, useNaturalLanguageFilters, useProductAnalytics, useQuerySuggestions, useQuerySuggestionsEnhanced, useResponsive, useSearchContext, useSearchState, useSectionSearchContext, useSeekoraSearch, useSmartSuggestions, useSuggestionsAnalytics, useSuggestionsContext, useVariantSelection, withAnalytics };
4415
- export type { ActionButton, ActionButtonType, ActionButtonsProps, AnalyticsConfig, AnalyticsEventPayload, AnalyticsProviderProps, BadgeListProps, BaseDropdownProps, BrandFieldMapping, BreadcrumbItem, BreadcrumbProps, BreadcrumbTheme, CategoriesTabsProps, CategoryFieldMapping, ClearRefinementsProps, ClearRefinementsTheme, DocSearchAction, DocSearchButtonProps, DocSearchHit, DocSearchProps, DocSearchResponse, DocSearchState, DocSearchSuggestion, DocSearchSuggestionsResponse, DocSearchTranslations, DropdownClassNames, DropdownEventHandlers, DropdownPanelProps, DropdownRef, DropdownThemeConfig, Facet, FacetDropdownOption, FacetDropdownProps, FacetDropdownTheme, FacetItem, FacetRangeConfig, FacetRangeItem, FacetSize, FacetStats, FacetVariant, FacetsProps, FacetsTheme, FederatedDropdownProps, FederatedDropdownRef, FrequentlyBoughtTogetherProps, GenericItem, HierarchicalMenuItem, HierarchicalMenuProps, HierarchicalMenuTheme, HighlightMarkupOptions, HighlightProps, HighlightTheme, HitsPerPageItem, HitsPerPageProps, HitsPerPageTheme, ImageDisplayProps, ImageDisplayVariant, ImageZoomMode, ImageZoomProps, InfiniteHitsProps, InfiniteHitsTheme, ImageDisplayVariant$1 as ItemCardImageVariant, ItemCardProps, ItemGridProps, MobileFiltersButtonProps, MobileFiltersProps, MobileFiltersTheme, NaturalLanguageFiltersOptions, NaturalLanguageResult, NavigableItem, PaginationProps, PaginationTheme, ParsedFilter, PriceDisplayProps, ProductCardImageVariant, ProductCardProps, ProductClickEventData, ProductDisplayConfig, ProductFieldMapping, ProductGalleryProps, ProductGridProps, ProductInfoProps, ProductRecommendationsProps, QuerySuggestionsDropdownProps, QuerySuggestionsDropdownRef, QuerySuggestionsProps, QuerySuggestionsTheme, RangeSliderProps, RangeSliderTheme, RatingDisplayProps, RatingSize, RatingVariant, RecentSearchesListProps, RecentlyViewedProps, RecommendationItem, RecommendationTheme, RefinementInput, RelatedProductsProps, ResponsiveState, RichQuerySuggestionsProps, RichQuerySuggestionsRef, SearchBarProps, SearchBarSize, SearchBarTheme, SearchBarWithSuggestionsProps, SearchBarWithSuggestionsRef, SearchInputProps, SearchProviderProps, SearchResultsProps, SearchResultsTheme, SearchSource, SectionConfig, SectionErrorProps, SectionItemGridProps, SectionSearchContextValue, SectionSearchProviderProps, SmartSuggestion, SmartSuggestionsOptions, SnippetProps, SnippetTheme, SortByProps, SortBySize, SortByTheme, SortByVariant, SortOption, SuggestionClickEventData, SuggestionDisplayConfig, SuggestionDropdownVariant, SuggestionFieldMapping, SuggestionImpressionEventData, SuggestionItemProps, SuggestionListProps, SuggestionSearchBarProps, SuggestionSearchBarRef, SuggestionsContextValue, SuggestionsDropdownCompositionProps, SuggestionsErrorProps, SuggestionsProviderProps, SuggestionsThemeVariables, TrendingItemsProps, TrendingListProps, UseAnalyticsOptions, UseAnalyticsReturn, UseSeekoraSearchOptions$1 as UseDocSearchSeekoraSearchOptions, UseSeekoraSearchResult as UseDocSearchSeekoraSearchResult, UseFiltersOptions, UseFiltersReturn, UseProductAnalyticsOptions, UseProductAnalyticsReturn, UseQuerySuggestionsEnhancedOptions, UseQuerySuggestionsEnhancedReturn, UseSmartSuggestionsReturn, UseSuggestionsAnalyticsOptions, UseSuggestionsAnalyticsReturn, UseVariantSelectionOptions, UseVariantSelectionReturn, VariantSelectorProps, VariantSwatchesProps, WithAnalyticsConfig, WithAnalyticsInjectedProps };
4458
+ export { ActionButtons, AmazonDropdown, AnalyticsProvider, BadgeList, Breadcrumb, CategoriesTabs, ClearRefinements, CurrentRefinements, CustomSelect, DocSearch, DocSearchButton, DropdownPanel, FacetDropdown, Facets, FederatedDropdown, FrequentlyBoughtTogether, GoogleDropdown, HierarchicalMenu, Highlight, HitsPerPage, ImageDisplay, ImageZoom, InfiniteHits, ItemCard, ItemGrid, MinimalDropdown, MobileFilters, MobileFiltersButton, MobileSheetDropdown, Pagination, PinterestDropdown, PriceDisplay, ProductCard, ProductGallery, ProductGrid, ProductInfo, ProductRecommendations, QuerySuggestions, QuerySuggestionsDropdown, RangeInput, RangeSlider, RatingDisplay, RecentSearchesList, RecentlyViewed, RelatedProducts, RichQuerySuggestions, SearchBar, SearchBarWithSuggestions, SearchInput, SearchLayout, SearchProvider, SearchResults, SectionError, SectionItemGrid, SectionSearchProvider, ShopifyDropdown, Snippet, SortBy, SpotlightDropdown, Stats, SuggestionDropdownVariants, SuggestionItem$1 as SuggestionItem, SuggestionList, SuggestionSearchBar, SuggestionsCache, SuggestionsDropdownComposition, SuggestionsError, SuggestionsProvider, TrendingItems, TrendingList, VariantSelector, VariantSwatches, addRecentSearch, addToRecentlyViewed, brandPresets, breakpoints, clearRecentSearches, clearSuggestionsCache, createSuggestionsCache, createSuggestionsTheme, createTheme, darkTheme, darkThemeVariables, defaultTheme, extractBadges, extractBrand, extractCategory, extractProduct, extractSuggestion, findVariantBySelections, formatParsedFilters, formatPriceRange, formatPrice as formatSuggestionPrice, generateSuggestionsStylesheet, getAvailableValuesForOption, getPriceRange, getRecentSearches, getShortcutText, getSuggestionsCache, highlightText, injectGlobalResponsiveStyles, injectSuggestionsStyles, lightThemeVariables, mediaQueries, minimalTheme, minimalThemeVariables, parseHighlightMarkup, removeRecentSearch, touchTargets, updateSuggestionsStyles, useAnalytics, useAnalyticsProvider, useDocSearch, useSeekoraSearch$1 as useDocSearchSeekoraSearch, useFilters, useInjectResponsiveStyles, useKeyboard, useNaturalLanguageFilters, useProductAnalytics, useQuerySuggestions, useQuerySuggestionsEnhanced, useResponsive, useSearchContext, useSearchState, useSectionSearchContext, useSeekoraSearch, useSmartSuggestions, useSuggestionsAnalytics, useSuggestionsContext, useVariantSelection, withAnalytics };
4459
+ export type { ActionButton, ActionButtonType, ActionButtonsProps, AnalyticsConfig, AnalyticsEventPayload, AnalyticsProviderProps, BadgeListProps, BaseDropdownProps, BrandFieldMapping, BreadcrumbItem, BreadcrumbProps, BreadcrumbTheme, CategoriesTabsProps, CategoryFieldMapping, ClearRefinementsProps, ClearRefinementsTheme, CustomSelectOption, CustomSelectProps, CustomSelectTheme, DocSearchAction, DocSearchButtonProps, DocSearchHit, DocSearchProps, DocSearchResponse, DocSearchState, DocSearchSuggestion, DocSearchSuggestionsResponse, DocSearchTranslations, DropdownClassNames, DropdownEventHandlers, DropdownPanelProps, DropdownRef, DropdownThemeConfig, Facet, FacetDropdownOption, FacetDropdownProps, FacetDropdownTheme, FacetItem, FacetRangeConfig, FacetRangeItem, FacetSize, FacetStats, FacetVariant, FacetsProps, FacetsTheme, FederatedDropdownProps, FederatedDropdownRef, FrequentlyBoughtTogetherProps, GenericItem, HierarchicalMenuItem, HierarchicalMenuProps, HierarchicalMenuTheme, HighlightMarkupOptions, HighlightProps, HighlightTheme, HitsPerPageItem, HitsPerPageProps, HitsPerPageTheme, ImageDisplayProps, ImageDisplayVariant, ImageZoomMode, ImageZoomProps, InfiniteHitsProps, InfiniteHitsTheme, ImageDisplayVariant$1 as ItemCardImageVariant, ItemCardProps, ItemGridProps, MobileFiltersButtonProps, MobileFiltersProps, MobileFiltersTheme, NaturalLanguageFiltersOptions, NaturalLanguageResult, NavigableItem, PaginationProps, PaginationTheme, ParsedFilter, PriceDisplayProps, ProductCardImageVariant, ProductCardProps, ProductClickEventData, ProductDisplayConfig, ProductFieldMapping, ProductGalleryProps, ProductGridProps, ProductInfoProps, ProductRecommendationsProps, QuerySuggestionsDropdownProps, QuerySuggestionsDropdownRef, QuerySuggestionsProps, QuerySuggestionsTheme, RangeSliderProps, RangeSliderTheme, RatingDisplayProps, RatingSize, RatingVariant, RecentSearchesListProps, RecentlyViewedProps, RecommendationItem, RecommendationTheme, RefinementInput, RelatedProductsProps, ResponsiveState, RichQuerySuggestionsProps, RichQuerySuggestionsRef, SearchBarProps, SearchBarSize, SearchBarTheme, SearchBarWithSuggestionsProps, SearchBarWithSuggestionsRef, SearchInputProps, SearchProviderProps, SearchResultsProps, SearchResultsTheme, SearchSource, SectionConfig, SectionErrorProps, SectionItemGridProps, SectionSearchContextValue, SectionSearchProviderProps, SmartSuggestion, SmartSuggestionsOptions, SnippetProps, SnippetTheme, SortByProps, SortBySize, SortByTheme, SortByVariant, SortOption, SuggestionClickEventData, SuggestionDisplayConfig, SuggestionDropdownVariant, SuggestionFieldMapping, SuggestionImpressionEventData, SuggestionItemProps, SuggestionListProps, SuggestionSearchBarProps, SuggestionSearchBarRef, SuggestionsContextValue, SuggestionsDropdownCompositionProps, SuggestionsErrorProps, SuggestionsProviderProps, SuggestionsThemeVariables, TrendingItemsProps, TrendingListProps, UseAnalyticsOptions, UseAnalyticsReturn, UseSeekoraSearchOptions$1 as UseDocSearchSeekoraSearchOptions, UseSeekoraSearchResult as UseDocSearchSeekoraSearchResult, UseFiltersOptions, UseFiltersReturn, UseProductAnalyticsOptions, UseProductAnalyticsReturn, UseQuerySuggestionsEnhancedOptions, UseQuerySuggestionsEnhancedReturn, UseSmartSuggestionsReturn, UseSuggestionsAnalyticsOptions, UseSuggestionsAnalyticsReturn, UseVariantSelectionOptions, UseVariantSelectionReturn, VariantSelectorProps, VariantSwatchesProps, WithAnalyticsConfig, WithAnalyticsInjectedProps };
@@ -3112,6 +3112,201 @@ const Pagination = ({ results: resultsProp, currentPage: currentPageProp, itemsP
3112
3112
  resolvedShowPageInfo && (React.createElement("li", { style: { marginLeft: theme.spacing.small } }, pageInfoElement)))));
3113
3113
  };
3114
3114
 
3115
+ /**
3116
+ * CustomSelect — lightweight, accessible custom dropdown replacement for native <select>.
3117
+ *
3118
+ * CSS Variables (apply on a parent element to customize):
3119
+ * --seekora-select-bg — background color (default: #fff)
3120
+ * --seekora-select-color — text color (default: inherit)
3121
+ * --seekora-select-border — border color (default: rgba(128,128,128,0.3))
3122
+ * --seekora-select-hover-bg — option hover background (default: #f3f4f6)
3123
+ * --seekora-select-active-bg — selected option background (default: #eff6ff)
3124
+ * --seekora-select-active-color — selected option text color (default: inherit)
3125
+ * --seekora-select-radius — border radius (default: 6px)
3126
+ * --seekora-select-font-size — font size (default: 0.875rem)
3127
+ */
3128
+ // ---------------------------------------------------------------------------
3129
+ // Component
3130
+ // ---------------------------------------------------------------------------
3131
+ const CustomSelect = ({ value, onChange, options, placeholder = 'Select...', className, style, theme: customTheme, 'aria-label': ariaLabel, disabled = false, }) => {
3132
+ const [isOpen, setIsOpen] = useState(false);
3133
+ const [activeIndex, setActiveIndex] = useState(-1);
3134
+ const containerRef = useRef(null);
3135
+ const menuRef = useRef(null);
3136
+ const instanceId = useId();
3137
+ const t = customTheme || {};
3138
+ const selectedOption = options.find((o) => o.value === value);
3139
+ const displayLabel = selectedOption?.label ?? placeholder;
3140
+ // Close on click outside
3141
+ useEffect(() => {
3142
+ if (!isOpen)
3143
+ return;
3144
+ const handleMouseDown = (e) => {
3145
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
3146
+ setIsOpen(false);
3147
+ setActiveIndex(-1);
3148
+ }
3149
+ };
3150
+ document.addEventListener('mousedown', handleMouseDown);
3151
+ return () => document.removeEventListener('mousedown', handleMouseDown);
3152
+ }, [isOpen]);
3153
+ // Scroll active item into view
3154
+ useEffect(() => {
3155
+ if (!isOpen || activeIndex < 0 || !menuRef.current)
3156
+ return;
3157
+ const item = menuRef.current.children[activeIndex];
3158
+ item?.scrollIntoView?.({ block: 'nearest' });
3159
+ }, [activeIndex, isOpen]);
3160
+ const toggle = useCallback(() => {
3161
+ if (disabled)
3162
+ return;
3163
+ setIsOpen((prev) => {
3164
+ if (!prev) {
3165
+ // Opening — highlight current selection
3166
+ const idx = options.findIndex((o) => o.value === value);
3167
+ setActiveIndex(idx >= 0 ? idx : 0);
3168
+ }
3169
+ return !prev;
3170
+ });
3171
+ }, [disabled, options, value]);
3172
+ const selectOption = useCallback((opt) => {
3173
+ if (opt.disabled)
3174
+ return;
3175
+ onChange(opt.value);
3176
+ setIsOpen(false);
3177
+ setActiveIndex(-1);
3178
+ }, [onChange]);
3179
+ // Find next non-disabled index in given direction
3180
+ const findNextEnabled = (from, dir) => {
3181
+ let idx = from;
3182
+ for (let i = 0; i < options.length; i++) {
3183
+ idx += dir;
3184
+ if (idx < 0)
3185
+ idx = options.length - 1;
3186
+ if (idx >= options.length)
3187
+ idx = 0;
3188
+ if (!options[idx].disabled)
3189
+ return idx;
3190
+ }
3191
+ return from;
3192
+ };
3193
+ const handleKeyDown = useCallback((e) => {
3194
+ if (disabled)
3195
+ return;
3196
+ if (!isOpen) {
3197
+ if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {
3198
+ e.preventDefault();
3199
+ toggle();
3200
+ }
3201
+ return;
3202
+ }
3203
+ switch (e.key) {
3204
+ case 'ArrowDown':
3205
+ e.preventDefault();
3206
+ setActiveIndex((prev) => findNextEnabled(prev, 1));
3207
+ break;
3208
+ case 'ArrowUp':
3209
+ e.preventDefault();
3210
+ setActiveIndex((prev) => findNextEnabled(prev, -1));
3211
+ break;
3212
+ case 'Enter':
3213
+ case ' ':
3214
+ e.preventDefault();
3215
+ if (activeIndex >= 0 && !options[activeIndex].disabled) {
3216
+ selectOption(options[activeIndex]);
3217
+ }
3218
+ break;
3219
+ case 'Escape':
3220
+ e.preventDefault();
3221
+ setIsOpen(false);
3222
+ setActiveIndex(-1);
3223
+ break;
3224
+ case 'Home':
3225
+ e.preventDefault();
3226
+ setActiveIndex(findNextEnabled(-1, 1));
3227
+ break;
3228
+ case 'End':
3229
+ e.preventDefault();
3230
+ setActiveIndex(findNextEnabled(options.length, -1));
3231
+ break;
3232
+ case 'Tab':
3233
+ setIsOpen(false);
3234
+ setActiveIndex(-1);
3235
+ break;
3236
+ }
3237
+ }, [disabled, isOpen, activeIndex, options, toggle, selectOption]);
3238
+ const menuId = `seekora-select-menu-${instanceId}`;
3239
+ return (React.createElement("div", { ref: containerRef, className: clsx('seekora-select', className), style: { position: 'relative', display: 'inline-block', ...style }, onKeyDown: handleKeyDown },
3240
+ React.createElement("button", { type: "button", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": ariaLabel, "aria-activedescendant": isOpen && activeIndex >= 0
3241
+ ? `${menuId}-opt-${activeIndex}`
3242
+ : undefined, disabled: disabled, onClick: toggle, className: clsx('seekora-select__trigger', t.trigger), style: {
3243
+ display: 'flex',
3244
+ alignItems: 'center',
3245
+ justifyContent: 'space-between',
3246
+ gap: 8,
3247
+ width: '100%',
3248
+ padding: '8px 12px',
3249
+ fontSize: 'var(--seekora-select-font-size, 0.875rem)',
3250
+ lineHeight: 1.4,
3251
+ border: '1px solid var(--seekora-select-border, rgba(128,128,128,0.3))',
3252
+ borderRadius: 'var(--seekora-select-radius, 6px)',
3253
+ backgroundColor: 'var(--seekora-select-bg, #fff)',
3254
+ color: 'var(--seekora-select-color, inherit)',
3255
+ cursor: disabled ? 'not-allowed' : 'pointer',
3256
+ outline: 'none',
3257
+ textAlign: 'left',
3258
+ fontFamily: 'inherit',
3259
+ opacity: disabled ? 0.5 : 1,
3260
+ } },
3261
+ React.createElement("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, displayLabel),
3262
+ React.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: {
3263
+ flexShrink: 0,
3264
+ transition: 'transform 0.15s ease',
3265
+ transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
3266
+ } },
3267
+ React.createElement("path", { d: "M2.5 4.5L6 8L9.5 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }))),
3268
+ isOpen && (React.createElement("div", { ref: menuRef, id: menuId, role: "listbox", className: clsx('seekora-select__menu', t.menu), style: {
3269
+ position: 'absolute',
3270
+ top: '100%',
3271
+ left: 0,
3272
+ right: 0,
3273
+ zIndex: 9999,
3274
+ marginTop: 4,
3275
+ padding: '4px 0',
3276
+ border: '1px solid var(--seekora-select-border, rgba(128,128,128,0.3))',
3277
+ borderRadius: 'var(--seekora-select-radius, 6px)',
3278
+ backgroundColor: 'var(--seekora-select-bg, #fff)',
3279
+ boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
3280
+ maxHeight: 220,
3281
+ overflowY: 'auto',
3282
+ } }, options.map((opt, idx) => {
3283
+ const isSelected = opt.value === value;
3284
+ const isHighlighted = idx === activeIndex;
3285
+ return (React.createElement("div", { key: opt.value, id: `${menuId}-opt-${idx}`, role: "option", "aria-selected": isSelected, "aria-disabled": opt.disabled || undefined, className: clsx('seekora-select__option', t.option, isSelected && 'seekora-select__option--selected', isHighlighted && (t.optionActive || 'seekora-select__option--highlighted'), opt.disabled && (t.optionDisabled || 'seekora-select__option--disabled')), onMouseEnter: () => !opt.disabled && setActiveIndex(idx), onMouseDown: (e) => {
3286
+ e.preventDefault(); // Prevent blur
3287
+ if (!opt.disabled)
3288
+ selectOption(opt);
3289
+ }, style: {
3290
+ padding: '6px 12px',
3291
+ fontSize: 'var(--seekora-select-font-size, 0.875rem)',
3292
+ cursor: opt.disabled ? 'not-allowed' : 'pointer',
3293
+ backgroundColor: isHighlighted
3294
+ ? 'var(--seekora-select-hover-bg, #f3f4f6)'
3295
+ : isSelected
3296
+ ? 'var(--seekora-select-active-bg, #eff6ff)'
3297
+ : 'transparent',
3298
+ color: opt.disabled
3299
+ ? 'rgba(128,128,128,0.5)'
3300
+ : isSelected
3301
+ ? 'var(--seekora-select-active-color, inherit)'
3302
+ : 'var(--seekora-select-color, inherit)',
3303
+ fontWeight: isSelected ? 500 : 400,
3304
+ opacity: opt.disabled ? 0.5 : 1,
3305
+ transition: 'background-color 0.1s ease',
3306
+ } }, opt.label));
3307
+ })))));
3308
+ };
3309
+
3115
3310
  /**
3116
3311
  * SortBy Component
3117
3312
  *
@@ -3215,18 +3410,14 @@ const SortBy = ({ options, value: valueProp, defaultValue, onSortChange, renderS
3215
3410
  }
3216
3411
  return (React.createElement("div", { className: clsx(sortByTheme.container, className), style: { ...cssVarStyle, ...style } },
3217
3412
  labelElement,
3218
- React.createElement("select", { value: value, onChange: handleChange, className: clsx(sortByTheme.select), style: {
3219
- padding,
3220
- paddingRight: theme.spacing.medium,
3221
- fontSize,
3222
- border: '1px solid var(--seekora-sort-border)',
3223
- borderRadius,
3224
- backgroundColor: 'var(--seekora-sort-bg)',
3225
- color: 'var(--seekora-sort-color)',
3226
- cursor: 'pointer',
3227
- outline: 'none',
3413
+ React.createElement(CustomSelect, { value: value, onChange: applyValue, options: options, placeholder: placeholder, "aria-label": label || 'Sort results', className: clsx(sortByTheme.select), style: {
3228
3414
  width: '100%',
3229
- }, "aria-label": label || 'Sort results' }, options.map((option) => (React.createElement("option", { key: option.value, value: option.value, className: sortByTheme.option }, option.label))))));
3415
+ '--seekora-select-font-size': fontSize,
3416
+ '--seekora-select-border': 'var(--seekora-sort-border)',
3417
+ '--seekora-select-radius': borderRadius,
3418
+ '--seekora-select-bg': 'var(--seekora-sort-bg)',
3419
+ '--seekora-select-color': 'var(--seekora-sort-color)',
3420
+ } })));
3230
3421
  }
3231
3422
  // ------ Button group variant -------------------------------------------
3232
3423
  if (variant === 'button-group') {
@@ -3676,7 +3867,7 @@ const CSS_VAR_DEFAULTS = {
3676
3867
  // ---------------------------------------------------------------------------
3677
3868
  // Component
3678
3869
  // ---------------------------------------------------------------------------
3679
- const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, renderFacet, renderFacetItem, maxItems = 10, showMore = true, className, style, theme: customTheme, variant = 'checkbox', searchable = false, showCounts = true, colorMap, defaultCollapsed = false, size = 'medium', facetRanges, useFiltersApi = false, disjunctiveFacets, }) => {
3870
+ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, renderFacet, renderFacetItem, maxItems = 10, showMore = true, className, style, theme: customTheme, variant = 'checkbox', searchable = false, showCounts = true, colorMap, defaultCollapsed = false, size = 'medium', facetRanges, useFiltersApi = false, disjunctiveFacets, hideEmptyFacets = true, defaultCollapsedFields, }) => {
3680
3871
  const { theme } = useSearchContext();
3681
3872
  const { results: stateResults, refinements, addRefinement, removeRefinement } = useSearchState();
3682
3873
  const facetsTheme = customTheme || {};
@@ -3753,7 +3944,10 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3753
3944
  });
3754
3945
  return extracted;
3755
3946
  };
3756
- const facets = extractFacets();
3947
+ const rawFacetList = extractFacets();
3948
+ const facets = hideEmptyFacets
3949
+ ? rawFacetList.filter(f => f.items.length > 0 || f.stats != null)
3950
+ : rawFacetList;
3757
3951
  // -------------------------------------------------------------------
3758
3952
  // Handlers
3759
3953
  // -------------------------------------------------------------------
@@ -3790,17 +3984,21 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3790
3984
  }));
3791
3985
  };
3792
3986
  /** For collapsible variant — determine if a facet group is open. */
3987
+ const isFieldDefaultCollapsed = (field) => {
3988
+ if (defaultCollapsedFields?.includes(field))
3989
+ return true;
3990
+ return defaultCollapsed;
3991
+ };
3793
3992
  const isFacetGroupOpen = (field) => {
3794
3993
  if (field in expandedFacets) {
3795
3994
  return expandedFacets[field];
3796
3995
  }
3797
- // Default based on defaultCollapsed prop
3798
- return !defaultCollapsed;
3996
+ return !isFieldDefaultCollapsed(field);
3799
3997
  };
3800
3998
  const toggleCollapsible = (field) => {
3801
3999
  setExpandedFacets((prev) => ({
3802
4000
  ...prev,
3803
- [field]: !(prev[field] ?? !defaultCollapsed),
4001
+ [field]: !(prev[field] ?? !isFieldDefaultCollapsed(field)),
3804
4002
  }));
3805
4003
  };
3806
4004
  const getSearchTerm = (field) => searchTerms[field] || '';
@@ -5437,19 +5635,28 @@ const HitsPerPage = ({ items, onHitsPerPageChange, renderSelect, className, styl
5437
5635
  fontSize: theme.typography.fontSize.medium,
5438
5636
  color: theme.colors.text,
5439
5637
  } }, label)),
5440
- React.createElement("select", { value: value, onChange: handleChange, className: hitsPerPageTheme.select, style: {
5441
- padding: theme.spacing.small,
5442
- paddingRight: theme.spacing.medium,
5443
- fontSize: theme.typography.fontSize.medium,
5444
- border: `1px solid ${theme.colors.border}`,
5445
- borderRadius: typeof theme.borderRadius === 'string'
5638
+ React.createElement(CustomSelect, { value: String(value), onChange: (val) => {
5639
+ const newValue = parseInt(val, 10);
5640
+ setInternalValue(newValue);
5641
+ if (syncWithState) {
5642
+ stateManager.setItemsPerPage(newValue, false);
5643
+ setPage(1, true);
5644
+ }
5645
+ if (onHitsPerPageChange) {
5646
+ onHitsPerPageChange(newValue);
5647
+ }
5648
+ }, options: items.map((item) => ({
5649
+ value: String(item.value),
5650
+ label: item.label,
5651
+ })), "aria-label": "Results per page", className: hitsPerPageTheme.select, style: {
5652
+ '--seekora-select-font-size': theme.typography.fontSize.medium,
5653
+ '--seekora-select-border': theme.colors.border,
5654
+ '--seekora-select-radius': typeof theme.borderRadius === 'string'
5446
5655
  ? theme.borderRadius
5447
5656
  : theme.borderRadius.medium,
5448
- backgroundColor: theme.colors.background,
5449
- color: theme.colors.text,
5450
- cursor: 'pointer',
5451
- outline: 'none',
5452
- }, "aria-label": "Results per page" }, items.map((item) => (React.createElement("option", { key: item.value, value: item.value, className: hitsPerPageTheme.option }, item.label))))));
5657
+ '--seekora-select-bg': theme.colors.background,
5658
+ '--seekora-select-color': theme.colors.text,
5659
+ } })));
5453
5660
  };
5454
5661
 
5455
5662
  /**
@@ -9718,13 +9925,30 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
9718
9925
  objectFit: 'cover',
9719
9926
  display: 'block',
9720
9927
  };
9928
+ // Compute the indicator rectangle (what portion of the image the zoom panel shows).
9929
+ // indW / containerW = 1 / zoomLevel (the panel shows 1/zoomLevel of the image width).
9930
+ // indH is derived from the zoom panel's aspect ratio so it's consistent with what the
9931
+ // panel actually renders — no need for the image's natural dimensions.
9932
+ const getIndicatorRect = useCallback(() => {
9933
+ if (!containerRef.current)
9934
+ return { indL: 0, indT: 0, indW: 0, indH: 0 };
9935
+ const rect = containerRef.current.getBoundingClientRect();
9936
+ const indW = rect.width / zoomLevel;
9937
+ const indH = (zoomPanelSize.height / zoomPanelSize.width) * rect.width / zoomLevel;
9938
+ const indL = Math.max(0, Math.min(rect.width - indW, cursorPos.x - indW / 2));
9939
+ const indT = Math.max(0, Math.min(rect.height - indH, cursorPos.y - indH / 2));
9940
+ return { indL, indT, indW, indH };
9941
+ }, [cursorPos, zoomLevel, zoomPanelSize]);
9721
9942
  // Calculate zoom panel background position (Amazon-style)
9722
9943
  const getZoomPanelStyle = () => {
9723
9944
  if (!containerRef.current || !imageLoaded)
9724
9945
  return { display: 'none' };
9725
9946
  const rect = containerRef.current.getBoundingClientRect();
9726
- const bgPosX = (cursorPos.x / rect.width) * 100;
9727
- const bgPosY = (cursorPos.y / rect.height) * 100;
9947
+ const { indL, indT, indW, indH } = getIndicatorRect();
9948
+ // bgPos is derived from the clamped indicator position, not the raw cursor.
9949
+ // At indL=0 → bgPosX=0% (show left), at indL=containerW-indW → bgPosX=100% (show right).
9950
+ const bgPosX = (rect.width - indW) > 0 ? (indL / (rect.width - indW)) * 100 : 0;
9951
+ const bgPosY = (rect.height - indH) > 0 ? (indT / (rect.height - indH)) * 100 : 0;
9728
9952
  // Calculate available space in all directions
9729
9953
  const viewportWidth = window.innerWidth;
9730
9954
  const viewportHeight = window.innerHeight;
@@ -9852,19 +10076,22 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
9852
10076
  } }, "\uD83D\uDD0D")),
9853
10077
  supportsLens && isHovering && imageLoaded && (React.createElement("div", { style: getLensStyle() },
9854
10078
  React.createElement("img", { src: src, alt: "", style: getLensImageStyle() }))),
9855
- supportsHover && isHovering && imageLoaded && containerRef.current && (React.createElement("div", { style: {
9856
- position: 'absolute',
9857
- left: cursorPos.x - 75,
9858
- top: cursorPos.y - 75,
9859
- width: 150,
9860
- height: 150,
9861
- border: 'var(--seekora-hover-area-border, 2px solid rgba(0,0,0,0.3))',
9862
- backgroundColor: 'var(--seekora-hover-area-bg, rgba(255,255,255,0.1))',
9863
- pointerEvents: 'none',
9864
- zIndex: 50,
9865
- } })),
9866
- supportsHover && isHovering && imageLoaded && (React.createElement("div", { style: getZoomPanelStyle() }))),
9867
- isLightboxOpen && (React.createElement("div", { className: "seekora-image-zoom-lightbox", style: {
10079
+ supportsHover && isHovering && imageLoaded && containerRef.current && (() => {
10080
+ const { indL, indT, indW, indH } = getIndicatorRect();
10081
+ return (React.createElement("div", { style: {
10082
+ position: 'absolute',
10083
+ left: indL,
10084
+ top: indT,
10085
+ width: indW,
10086
+ height: indH,
10087
+ border: 'var(--seekora-hover-area-border, 2px solid rgba(0,0,0,0.3))',
10088
+ backgroundColor: 'var(--seekora-hover-area-bg, rgba(255,255,255,0.1))',
10089
+ pointerEvents: 'none',
10090
+ zIndex: 50,
10091
+ } }));
10092
+ })()),
10093
+ supportsHover && isHovering && imageLoaded && typeof document !== 'undefined' && createPortal(React.createElement("div", { style: getZoomPanelStyle() }), document.body),
10094
+ isLightboxOpen && typeof document !== 'undefined' && createPortal(React.createElement("div", { className: "seekora-image-zoom-lightbox", style: {
9868
10095
  position: 'fixed',
9869
10096
  top: 0,
9870
10097
  left: 0,
@@ -10019,7 +10246,7 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
10019
10246
  backgroundColor: 'var(--seekora-lightbox-instructions-bg, rgba(0,0,0,0.5))',
10020
10247
  padding: '8px 16px',
10021
10248
  borderRadius: 12,
10022
- } }, hasMultipleImages ? 'Use arrow keys or click thumbnails to navigate • ESC to close' : 'Click outside or press ESC to close')))));
10249
+ } }, hasMultipleImages ? 'Use arrow keys or click thumbnails to navigate • ESC to close' : 'Click outside or press ESC to close')), document.body)));
10023
10250
  }
10024
10251
 
10025
10252
  /**
@@ -11850,30 +12077,22 @@ function VariantSelector({ options, variants, selections, onSelectionChange, opt
11850
12077
  } },
11851
12078
  option.name,
11852
12079
  selected && (React.createElement("span", { style: { fontWeight: 400, marginLeft: 6, color: 'var(--seekora-text-secondary, inherit)' } }, selected))),
11853
- mode === 'dropdown' ? (React.createElement("select", { className: "seekora-variant-dropdown", value: selected ?? '', onChange: (e) => {
11854
- e.stopPropagation();
11855
- onSelectionChange(option.name, e.target.value);
11856
- }, onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), style: {
11857
- padding: '8px 12px',
11858
- fontSize: '0.875rem',
11859
- borderRadius: 6,
11860
- border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
11861
- backgroundColor: 'var(--seekora-bg-surface, transparent)',
11862
- color: 'var(--seekora-text-primary, inherit)',
11863
- cursor: 'pointer',
11864
- minWidth: 120,
11865
- } },
11866
- React.createElement("option", { value: "" },
11867
- "Select ",
11868
- option.name),
11869
- option.values.map((value) => {
11870
- const available = showAvailability
11871
- ? getAvailability(option.name, value, options, variants, selections)
11872
- : true;
11873
- return (React.createElement("option", { key: value, value: value, disabled: !available },
11874
- value,
11875
- !available ? ' (Unavailable)' : ''));
11876
- }))) : (React.createElement("div", { className: "seekora-variant-buttons", style: { display: 'flex', flexWrap: 'wrap', gap: 8 } }, option.values.map((value) => {
12080
+ mode === 'dropdown' ? (React.createElement("div", { onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation() },
12081
+ React.createElement(CustomSelect, { className: "seekora-variant-dropdown", value: selected ?? '', onChange: (val) => onSelectionChange(option.name, val), placeholder: `Select ${option.name}`, "aria-label": `Select ${option.name}`, options: option.values.map((val) => {
12082
+ const available = showAvailability
12083
+ ? getAvailability(option.name, val, options, variants, selections)
12084
+ : true;
12085
+ return {
12086
+ value: val,
12087
+ label: available ? val : `${val} (Unavailable)`,
12088
+ disabled: !available,
12089
+ };
12090
+ }), style: {
12091
+ minWidth: 120,
12092
+ '--seekora-select-border': 'var(--seekora-border-color, rgba(128,128,128,0.2))',
12093
+ '--seekora-select-bg': 'var(--seekora-bg-surface, transparent)',
12094
+ '--seekora-select-color': 'var(--seekora-text-primary, inherit)',
12095
+ } }))) : (React.createElement("div", { className: "seekora-variant-buttons", style: { display: 'flex', flexWrap: 'wrap', gap: 8 } }, option.values.map((value) => {
11877
12096
  const isActive = selected === value;
11878
12097
  const available = showAvailability
11879
12098
  ? getAvailability(option.name, value, options, variants, selections)
@@ -18637,5 +18856,5 @@ function updateSuggestionsStyles(theme) {
18637
18856
  injectSuggestionsStyles(theme, true);
18638
18857
  }
18639
18858
 
18640
- export { ActionButtons, AmazonDropdown, AnalyticsProvider, BadgeList, Breadcrumb, CategoriesTabs, ClearRefinements, CurrentRefinements, DocSearch, DocSearchButton, DropdownPanel, FacetDropdown, Facets, FederatedDropdown, Fingerprint, FrequentlyBoughtTogether, GoogleDropdown, HierarchicalMenu, Highlight$1 as Highlight, HitsPerPage, ImageDisplay, ImageZoom, InfiniteHits, ItemCard, ItemGrid, MinimalDropdown, MobileFilters, MobileFiltersButton, MobileSheetDropdown, Pagination, PinterestDropdown, PriceDisplay, ProductCard, ProductGallery, ProductGrid, ProductInfo, ProductRecommendations, QuerySuggestions, QuerySuggestionsDropdown, RangeInput, RangeSlider, RatingDisplay, RecentSearchesList, RecentlyViewed, RelatedProducts, RichQuerySuggestions, SearchBar, SearchBarWithSuggestions, SearchInput, SearchLayout, SearchProvider, SearchResults, SectionError, SectionItemGrid, SectionSearchProvider, ShopifyDropdown, Snippet, SortBy, SpotlightDropdown, Stats, SuggestionDropdownVariants, SuggestionItem, SuggestionList, SuggestionSearchBar, SuggestionsDropdownComposition, SuggestionsError, SuggestionsProvider, TrendingItems, TrendingList, VariantSelector, VariantSwatches, addRecentSearch, addToRecentlyViewed, brandPresets, breakpoints, clearRecentSearches, clearSuggestionsCache, createSuggestionsCache, createSuggestionsTheme, createTheme, darkTheme, darkThemeVariables, defaultTheme, extractBadges, extractBrand, extractCategory, extractProduct, extractSuggestion, findVariantBySelections, formatParsedFilters, formatPriceRange, formatPrice as formatSuggestionPrice, generateSuggestionsStylesheet, getAvailableValuesForOption, getFingerprint, getPriceRange, getRecentSearches, getShortcutText, getSuggestionsCache, highlightText, injectGlobalResponsiveStyles, injectSuggestionsStyles, lightThemeVariables, mediaQueries, mergeThemes, minimalTheme, minimalThemeVariables, parseHighlightMarkup, removeRecentSearch, touchTargets, updateSuggestionsStyles, useAnalytics, useAnalyticsProvider, useDocSearch, useSeekoraSearch$1 as useDocSearchSeekoraSearch, useFilters, useInjectResponsiveStyles, useKeyboard, useNaturalLanguageFilters, useProductAnalytics, useQuerySuggestions, useQuerySuggestionsEnhanced, useResponsive, useSearchContext, useSearchState, useSectionSearchContext, useSeekoraSearch, useSmartSuggestions, useSuggestionsAnalytics, useSuggestionsContext, useVariantSelection, withAnalytics };
18859
+ export { ActionButtons, AmazonDropdown, AnalyticsProvider, BadgeList, Breadcrumb, CategoriesTabs, ClearRefinements, CurrentRefinements, CustomSelect, DocSearch, DocSearchButton, DropdownPanel, FacetDropdown, Facets, FederatedDropdown, Fingerprint, FrequentlyBoughtTogether, GoogleDropdown, HierarchicalMenu, Highlight$1 as Highlight, HitsPerPage, ImageDisplay, ImageZoom, InfiniteHits, ItemCard, ItemGrid, MinimalDropdown, MobileFilters, MobileFiltersButton, MobileSheetDropdown, Pagination, PinterestDropdown, PriceDisplay, ProductCard, ProductGallery, ProductGrid, ProductInfo, ProductRecommendations, QuerySuggestions, QuerySuggestionsDropdown, RangeInput, RangeSlider, RatingDisplay, RecentSearchesList, RecentlyViewed, RelatedProducts, RichQuerySuggestions, SearchBar, SearchBarWithSuggestions, SearchInput, SearchLayout, SearchProvider, SearchResults, SectionError, SectionItemGrid, SectionSearchProvider, ShopifyDropdown, Snippet, SortBy, SpotlightDropdown, Stats, SuggestionDropdownVariants, SuggestionItem, SuggestionList, SuggestionSearchBar, SuggestionsDropdownComposition, SuggestionsError, SuggestionsProvider, TrendingItems, TrendingList, VariantSelector, VariantSwatches, addRecentSearch, addToRecentlyViewed, brandPresets, breakpoints, clearRecentSearches, clearSuggestionsCache, createSuggestionsCache, createSuggestionsTheme, createTheme, darkTheme, darkThemeVariables, defaultTheme, extractBadges, extractBrand, extractCategory, extractProduct, extractSuggestion, findVariantBySelections, formatParsedFilters, formatPriceRange, formatPrice as formatSuggestionPrice, generateSuggestionsStylesheet, getAvailableValuesForOption, getFingerprint, getPriceRange, getRecentSearches, getShortcutText, getSuggestionsCache, highlightText, injectGlobalResponsiveStyles, injectSuggestionsStyles, lightThemeVariables, mediaQueries, mergeThemes, minimalTheme, minimalThemeVariables, parseHighlightMarkup, removeRecentSearch, touchTargets, updateSuggestionsStyles, useAnalytics, useAnalyticsProvider, useDocSearch, useSeekoraSearch$1 as useDocSearchSeekoraSearch, useFilters, useInjectResponsiveStyles, useKeyboard, useNaturalLanguageFilters, useProductAnalytics, useQuerySuggestions, useQuerySuggestionsEnhanced, useResponsive, useSearchContext, useSearchState, useSectionSearchContext, useSeekoraSearch, useSmartSuggestions, useSuggestionsAnalytics, useSuggestionsContext, useVariantSelection, withAnalytics };
18641
18860
  //# sourceMappingURL=index.esm.js.map