@seekora-ai/ui-sdk-react 0.2.14 → 0.2.15

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.
Files changed (66) hide show
  1. package/dist/components/CurrentRefinements.d.ts.map +1 -1
  2. package/dist/components/CurrentRefinements.js +69 -9
  3. package/dist/components/FacetDropdown.d.ts +92 -0
  4. package/dist/components/FacetDropdown.d.ts.map +1 -0
  5. package/dist/components/FacetDropdown.js +374 -0
  6. package/dist/components/Facets.d.ts +26 -0
  7. package/dist/components/Facets.d.ts.map +1 -1
  8. package/dist/components/Facets.js +195 -6
  9. package/dist/components/FederatedDropdown.d.ts.map +1 -1
  10. package/dist/components/FederatedDropdown.js +45 -31
  11. package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
  12. package/dist/components/QuerySuggestionsDropdown.js +32 -18
  13. package/dist/components/RangeInput.d.ts.map +1 -1
  14. package/dist/components/RangeInput.js +6 -6
  15. package/dist/components/RangeSlider.d.ts.map +1 -1
  16. package/dist/components/RangeSlider.js +54 -32
  17. package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
  18. package/dist/components/RichQuerySuggestions.js +40 -26
  19. package/dist/components/SearchBar.d.ts.map +1 -1
  20. package/dist/components/SearchBar.js +15 -7
  21. package/dist/components/SearchBarWithSuggestions.js +3 -3
  22. package/dist/components/SearchLayout.d.ts.map +1 -1
  23. package/dist/components/SearchLayout.js +10 -1
  24. package/dist/components/SearchResults.d.ts.map +1 -1
  25. package/dist/components/SearchResults.js +37 -25
  26. package/dist/components/primitives/ActionButtons.d.ts.map +1 -1
  27. package/dist/components/primitives/ActionButtons.js +34 -10
  28. package/dist/components/primitives/BadgeList.d.ts.map +1 -1
  29. package/dist/components/primitives/BadgeList.js +33 -13
  30. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -1
  31. package/dist/components/primitives/ImageDisplay.js +11 -8
  32. package/dist/components/primitives/ImageZoom.js +26 -26
  33. package/dist/components/primitives/VariantSelector.js +10 -10
  34. package/dist/components/primitives/VariantSwatches.js +3 -3
  35. package/dist/components/product-page/ProductGallery.d.ts +8 -1
  36. package/dist/components/product-page/ProductGallery.d.ts.map +1 -1
  37. package/dist/components/product-page/ProductGallery.js +2 -2
  38. package/dist/components/section-primitives/SectionSearchProvider.d.ts +3 -1
  39. package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -1
  40. package/dist/components/section-primitives/SectionSearchProvider.js +3 -2
  41. package/dist/components/suggestions/MobileSheetDropdown.js +18 -18
  42. package/dist/components/suggestions/ShopifyDropdown.js +37 -37
  43. package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -1
  44. package/dist/components/suggestions-primitives/DropdownPanel.js +15 -2
  45. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -1
  46. package/dist/components/suggestions-primitives/ItemCard.js +21 -8
  47. package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -1
  48. package/dist/components/suggestions-primitives/ItemGrid.js +9 -3
  49. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -1
  50. package/dist/components/suggestions-primitives/ProductCard.js +25 -10
  51. package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -1
  52. package/dist/components/suggestions-primitives/ProductCardLayouts.js +24 -12
  53. package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -1
  54. package/dist/components/suggestions-primitives/SearchInput.js +28 -9
  55. package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -1
  56. package/dist/components/suggestions-primitives/SuggestionItem.js +3 -0
  57. package/dist/index.d.ts +3 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +1 -0
  60. package/dist/index.umd.js +1 -1
  61. package/dist/src/index.d.ts +129 -4
  62. package/dist/src/index.esm.js +1361 -616
  63. package/dist/src/index.esm.js.map +1 -1
  64. package/dist/src/index.js +1361 -615
  65. package/dist/src/index.js.map +1 -1
  66. package/package.json +6 -6
package/dist/src/index.js CHANGED
@@ -1570,6 +1570,9 @@ function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else i
1570
1570
  *
1571
1571
  * Interactive search input component with query suggestions support
1572
1572
  */
1573
+ // Z-index scale for consistent layering
1574
+ const Z_INDEX$2 = {
1575
+ dropdown: 100};
1573
1576
  const SIZE_CONFIG = {
1574
1577
  small: {
1575
1578
  padding: '0.375rem 0.5rem',
@@ -1753,9 +1756,9 @@ const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounce
1753
1756
  const inputPaddingLeft = sizeConfig.iconPaddingLeft ;
1754
1757
  const inputPaddingRight = hasClearBtn ? sizeConfig.iconPaddingRight : sizeConfig.padding.split(' ')[1] || sizeConfig.padding;
1755
1758
  const borderRadius = typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium;
1756
- const focusBorderColor = isFocused ? theme.colors.focus : theme.colors.border;
1759
+ const focusBorderColor = isFocused ? `var(--seekora-border-focus, ${theme.colors.focus})` : `var(--seekora-border, ${theme.colors.border})`;
1757
1760
  const focusRingShadow = isFocused
1758
- ? `0 0 0 3px ${theme.colors.focus}33`
1761
+ ? `0 0 0 3px var(--seekora-border-focus-alpha, ${theme.colors.focus}33)`
1759
1762
  : undefined;
1760
1763
  const handleClear = React.useCallback(() => {
1761
1764
  setQuery('', false);
@@ -1789,7 +1792,7 @@ const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounce
1789
1792
  justifyContent: 'center',
1790
1793
  pointerEvents: 'none',
1791
1794
  color: 'var(--seekora-searchbar-icon-color)',
1792
- zIndex: 1,
1795
+ zIndex: 2,
1793
1796
  } }, renderSearchIcon ? renderSearchIcon() : React.createElement(DefaultSearchIcon, { size: sizeConfig.iconSize }))),
1794
1797
  React.createElement("input", { ref: inputRef, type: "text", value: query, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder, className: clsx(searchBarTheme.input, isFocused && searchBarTheme.inputFocused), style: {
1795
1798
  width: '100%',
@@ -1825,7 +1828,7 @@ const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounce
1825
1828
  borderRadius: '50%',
1826
1829
  color: 'var(--seekora-searchbar-icon-color)',
1827
1830
  transition: theme.transitions?.fast || '150ms ease-in-out',
1828
- zIndex: 1,
1831
+ zIndex: 2,
1829
1832
  }, onMouseDown: (e) => {
1830
1833
  // Prevent input blur so the clear action doesn't race with blur handler
1831
1834
  e.preventDefault();
@@ -1836,8 +1839,8 @@ const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounce
1836
1839
  fontSize: sizeConfig.fontSize,
1837
1840
  fontFamily: theme.typography.fontFamily,
1838
1841
  fontWeight: theme.typography.fontWeight?.medium ?? 500,
1839
- backgroundColor: theme.colors.primary,
1840
- color: '#ffffff',
1842
+ backgroundColor: `var(--seekora-primary, ${theme.colors.primary})`,
1843
+ color: 'var(--seekora-primary-text, #ffffff)',
1841
1844
  border: 'none',
1842
1845
  borderRadius: 'var(--seekora-searchbar-radius)',
1843
1846
  cursor: 'pointer',
@@ -1865,7 +1868,8 @@ const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounce
1865
1868
  boxShadow: theme.shadows.medium,
1866
1869
  maxHeight: '400px',
1867
1870
  overflowY: 'auto',
1868
- zIndex: 1000,
1871
+ zIndex: Z_INDEX$2.dropdown,
1872
+ boxSizing: 'border-box',
1869
1873
  } },
1870
1874
  isLoading && displayedSuggestions.length === 0 && showLoadingState && (renderLoading ? renderLoading() : defaultRenderLoading()),
1871
1875
  displayedSuggestions.length > 0 && (React.createElement(React.Fragment, null, displayedSuggestions.map((suggestion, index) => {
@@ -1934,6 +1938,43 @@ const SearchResults = ({ results: resultsProp, loading: loadingProp, error: erro
1934
1938
  }
1935
1939
  }
1936
1940
  }, [activeIndex, enableKeyboardNavigation]);
1941
+ // Global keyboard listener for seamless navigation from search box to results
1942
+ React.useEffect(() => {
1943
+ if (!enableKeyboardNavigation)
1944
+ return;
1945
+ const handleGlobalKeyDown = (e) => {
1946
+ // Only handle if we have results and the container exists
1947
+ if (!containerRef.current)
1948
+ return;
1949
+ const resultElements = containerRef.current.querySelectorAll('[data-result-index]');
1950
+ const maxIndex = resultElements.length - 1;
1951
+ if (maxIndex < 0)
1952
+ return;
1953
+ // Check if focus is on an input/textarea (search box)
1954
+ const activeElement = document.activeElement;
1955
+ const isInputFocused = activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA';
1956
+ if (e.key === 'ArrowDown') {
1957
+ // If in search box or no result selected, select first result
1958
+ if (isInputFocused || activeIndex === -1) {
1959
+ e.preventDefault();
1960
+ setActiveIndex(0);
1961
+ containerRef.current?.focus();
1962
+ }
1963
+ }
1964
+ else if (e.key === 'ArrowUp') {
1965
+ // If first result is selected, go back to search box
1966
+ if (activeIndex === 0) {
1967
+ e.preventDefault();
1968
+ setActiveIndex(-1);
1969
+ // Find and focus the search input
1970
+ const searchInput = document.querySelector('input[type="text"], input[type="search"]');
1971
+ searchInput?.focus();
1972
+ }
1973
+ }
1974
+ };
1975
+ document.addEventListener('keydown', handleGlobalKeyDown);
1976
+ return () => document.removeEventListener('keydown', handleGlobalKeyDown);
1977
+ }, [enableKeyboardNavigation, activeIndex]);
1937
1978
  // Keyboard navigation handler
1938
1979
  const handleKeyDown = React.useCallback((e) => {
1939
1980
  if (!enableKeyboardNavigation)
@@ -2309,31 +2350,6 @@ const SearchResults = ({ results: resultsProp, loading: loadingProp, error: erro
2309
2350
  results?.totalResults || results?.data?.total_results || 0,
2310
2351
  " result",
2311
2352
  (results?.totalResults || results?.data?.total_results || 0) !== 1 ? 's' : '')),
2312
- enableKeyboardNavigation && resultItems.length > 0 && (React.createElement("div", { style: {
2313
- fontSize: '12px',
2314
- color: theme.colors.text,
2315
- opacity: 0.6,
2316
- marginBottom: theme.spacing.small,
2317
- display: 'flex',
2318
- gap: '8px',
2319
- alignItems: 'center',
2320
- } },
2321
- React.createElement("span", { style: {
2322
- display: 'inline-flex',
2323
- gap: '4px',
2324
- padding: '2px 6px',
2325
- backgroundColor: theme.colors.hover,
2326
- borderRadius: '4px',
2327
- fontSize: '11px',
2328
- } }, "\u2191\u2193 navigate"),
2329
- React.createElement("span", { style: {
2330
- display: 'inline-flex',
2331
- gap: '4px',
2332
- padding: '2px 6px',
2333
- backgroundColor: theme.colors.hover,
2334
- borderRadius: '4px',
2335
- fontSize: '11px',
2336
- } }, "\u21B5 select"))),
2337
2353
  React.createElement("div", { className: searchResultsTheme.resultsList, style: resultsListStyle }, resultItems.map((result, index) => renderFn(result, index, index === activeIndex)))));
2338
2354
  };
2339
2355
 
@@ -2995,6 +3011,261 @@ const SortBy = ({ options, value: valueProp, defaultValue, onSortChange, renderS
2995
3011
  return null;
2996
3012
  };
2997
3013
 
3014
+ /**
3015
+ * RangeSlider Component
3016
+ *
3017
+ * Visual slider for numeric range filtering
3018
+ * Alternative to RangeInput for a more interactive UX
3019
+ */
3020
+ const SHADOWS$1 = {
3021
+ md: '0 2px 4px rgba(0,0,0,0.1)'};
3022
+ const RangeSlider = ({ field, label, min, max, step = 1, currentMin: currentMinProp, currentMax: currentMaxProp, onRangeChange, formatValue = (v) => v.toString(), className, style, theme: customTheme, showValues = true, syncWithState = true, debounceMs = 300, }) => {
3023
+ const { theme } = useSearchContext();
3024
+ const { refinements, addRefinement, removeRefinement } = useSearchState();
3025
+ const rangeSliderTheme = customTheme || {};
3026
+ const thumbClass = rangeSliderTheme.thumb || 'seekora-range-slider__thumb';
3027
+ // Parse current range from StateManager
3028
+ // NOTE: computed every render (no useMemo) because the state manager mutates
3029
+ // the refinements array in place — the reference never changes.
3030
+ let stateRange;
3031
+ if (!syncWithState) {
3032
+ stateRange = { min: undefined, max: undefined };
3033
+ }
3034
+ else {
3035
+ let minVal;
3036
+ let maxVal;
3037
+ refinements.forEach(r => {
3038
+ if (r.field === field) {
3039
+ const minMatch = r.value.match(/^>=(\d+(?:\.\d+)?)$/);
3040
+ if (minMatch)
3041
+ minVal = parseFloat(minMatch[1]);
3042
+ const maxMatch = r.value.match(/^<=(\d+(?:\.\d+)?)$/);
3043
+ if (maxMatch)
3044
+ maxVal = parseFloat(maxMatch[1]);
3045
+ }
3046
+ });
3047
+ stateRange = { min: minVal, max: maxVal };
3048
+ }
3049
+ const [internalMin, setInternalMin] = React.useState(currentMinProp ?? stateRange.min ?? min);
3050
+ const [internalMax, setInternalMax] = React.useState(currentMaxProp ?? stateRange.max ?? max);
3051
+ const isDraggingRef = React.useRef(false);
3052
+ const debounceRef = React.useRef(null);
3053
+ const pendingMinRef = React.useRef(internalMin);
3054
+ const pendingMaxRef = React.useRef(internalMax);
3055
+ // Sync with StateManager changes (only when stateRange actually changes, not on drag)
3056
+ React.useEffect(() => {
3057
+ if (syncWithState && !isDraggingRef.current) {
3058
+ if (stateRange.min !== undefined)
3059
+ setInternalMin(stateRange.min);
3060
+ else
3061
+ setInternalMin(min);
3062
+ if (stateRange.max !== undefined)
3063
+ setInternalMax(stateRange.max);
3064
+ else
3065
+ setInternalMax(max);
3066
+ }
3067
+ }, [syncWithState, stateRange.min, stateRange.max, min, max]);
3068
+ // Update StateManager with range refinements
3069
+ const updateStateManager = React.useCallback((minVal, maxVal) => {
3070
+ if (!syncWithState)
3071
+ return;
3072
+ // Remove existing range refinements for this field
3073
+ refinements.forEach(r => {
3074
+ if (r.field === field) {
3075
+ removeRefinement(field, r.value, false);
3076
+ }
3077
+ });
3078
+ // Add new range refinements — trigger search on the last one added
3079
+ const setMin = minVal > min;
3080
+ const setMax = maxVal < max;
3081
+ if (setMin && setMax) {
3082
+ addRefinement(field, `>=${minVal}`, false);
3083
+ addRefinement(field, `<=${maxVal}`, true);
3084
+ }
3085
+ else if (setMin) {
3086
+ addRefinement(field, `>=${minVal}`, true);
3087
+ }
3088
+ else if (setMax) {
3089
+ addRefinement(field, `<=${maxVal}`, true);
3090
+ }
3091
+ }, [syncWithState, field, refinements, addRefinement, removeRefinement, min, max]);
3092
+ // Debounced update (during drag only)
3093
+ const debouncedUpdate = React.useCallback((minVal, maxVal) => {
3094
+ pendingMinRef.current = minVal;
3095
+ pendingMaxRef.current = maxVal;
3096
+ if (debounceRef.current) {
3097
+ clearTimeout(debounceRef.current);
3098
+ }
3099
+ debounceRef.current = setTimeout(() => {
3100
+ updateStateManager(minVal, maxVal);
3101
+ if (onRangeChange) {
3102
+ onRangeChange(minVal, maxVal);
3103
+ }
3104
+ }, debounceMs);
3105
+ }, [updateStateManager, onRangeChange, debounceMs]);
3106
+ // Handle min slider change
3107
+ const handleMinChange = (e) => {
3108
+ const value = Math.min(Number(e.target.value), internalMax - step);
3109
+ setInternalMin(value);
3110
+ isDraggingRef.current = true;
3111
+ debouncedUpdate(value, internalMax);
3112
+ };
3113
+ // Handle max slider change
3114
+ const handleMaxChange = (e) => {
3115
+ const value = Math.max(Number(e.target.value), internalMin + step);
3116
+ setInternalMax(value);
3117
+ isDraggingRef.current = true;
3118
+ debouncedUpdate(internalMin, value);
3119
+ };
3120
+ // Handle drag end — flush pending update immediately
3121
+ const handleDragEnd = () => {
3122
+ isDraggingRef.current = false;
3123
+ // Cancel the debounce and commit immediately
3124
+ if (debounceRef.current) {
3125
+ clearTimeout(debounceRef.current);
3126
+ debounceRef.current = null;
3127
+ }
3128
+ updateStateManager(pendingMinRef.current, pendingMaxRef.current);
3129
+ if (onRangeChange) {
3130
+ onRangeChange(pendingMinRef.current, pendingMaxRef.current);
3131
+ }
3132
+ };
3133
+ // Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
3134
+ const handleMinKeyDown = (e) => {
3135
+ let newValue = null;
3136
+ if (e.key === 'Home') {
3137
+ e.preventDefault();
3138
+ newValue = min;
3139
+ }
3140
+ else if (e.key === 'End') {
3141
+ e.preventDefault();
3142
+ newValue = internalMax - step;
3143
+ }
3144
+ else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
3145
+ e.preventDefault();
3146
+ newValue = Math.max(min, internalMin - step * 10);
3147
+ }
3148
+ else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
3149
+ e.preventDefault();
3150
+ newValue = Math.min(internalMax - step, internalMin + step * 10);
3151
+ }
3152
+ if (newValue !== null) {
3153
+ setInternalMin(newValue);
3154
+ debouncedUpdate(newValue, internalMax);
3155
+ }
3156
+ };
3157
+ const handleMaxKeyDown = (e) => {
3158
+ let newValue = null;
3159
+ if (e.key === 'Home') {
3160
+ e.preventDefault();
3161
+ newValue = internalMin + step;
3162
+ }
3163
+ else if (e.key === 'End') {
3164
+ e.preventDefault();
3165
+ newValue = max;
3166
+ }
3167
+ else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
3168
+ e.preventDefault();
3169
+ newValue = Math.max(internalMin + step, internalMax - step * 10);
3170
+ }
3171
+ else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
3172
+ e.preventDefault();
3173
+ newValue = Math.min(max, internalMax + step * 10);
3174
+ }
3175
+ if (newValue !== null) {
3176
+ setInternalMax(newValue);
3177
+ debouncedUpdate(internalMin, newValue);
3178
+ }
3179
+ };
3180
+ // Calculate filled track position
3181
+ const minPercent = ((internalMin - min) / (max - min)) * 100;
3182
+ const maxPercent = ((internalMax - min) / (max - min)) * 100;
3183
+ return (React.createElement("div", { className: clsx(rangeSliderTheme.root, className), style: {
3184
+ fontFamily: 'inherit',
3185
+ ...style,
3186
+ } },
3187
+ label && (React.createElement("label", { className: rangeSliderTheme.label, style: {
3188
+ display: 'block',
3189
+ marginBottom: theme.spacing.small,
3190
+ fontSize: theme.typography.fontSize.medium,
3191
+ fontWeight: theme.typography.fontWeight?.medium || 500,
3192
+ color: theme.colors.text,
3193
+ } }, label)),
3194
+ React.createElement("div", { className: rangeSliderTheme.slider, style: {
3195
+ position: 'relative',
3196
+ minHeight: '40px',
3197
+ display: 'flex',
3198
+ alignItems: 'center',
3199
+ } },
3200
+ React.createElement("div", { className: rangeSliderTheme.track, style: {
3201
+ position: 'absolute',
3202
+ width: '100%',
3203
+ height: '4px',
3204
+ backgroundColor: theme.colors.border,
3205
+ borderRadius: '2px',
3206
+ } }),
3207
+ React.createElement("div", { className: rangeSliderTheme.trackFilled, style: {
3208
+ position: 'absolute',
3209
+ left: `${minPercent}%`,
3210
+ width: `${maxPercent - minPercent}%`,
3211
+ height: '4px',
3212
+ backgroundColor: theme.colors.primary,
3213
+ borderRadius: '2px',
3214
+ } }),
3215
+ React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMinKeyDown, tabIndex: 0, "aria-valuenow": internalMin, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
3216
+ position: 'absolute',
3217
+ width: '100%',
3218
+ height: '4px',
3219
+ background: 'transparent',
3220
+ WebkitAppearance: 'none',
3221
+ appearance: 'none',
3222
+ cursor: 'pointer',
3223
+ pointerEvents: 'none',
3224
+ }, "aria-label": `Minimum ${label || field}` }),
3225
+ React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMaxKeyDown, tabIndex: 0, "aria-valuenow": internalMax, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
3226
+ position: 'absolute',
3227
+ width: '100%',
3228
+ height: '4px',
3229
+ background: 'transparent',
3230
+ WebkitAppearance: 'none',
3231
+ appearance: 'none',
3232
+ cursor: 'pointer',
3233
+ pointerEvents: 'none',
3234
+ }, "aria-label": `Maximum ${label || field}` })),
3235
+ showValues && (React.createElement("div", { className: rangeSliderTheme.values, style: {
3236
+ display: 'flex',
3237
+ justifyContent: 'space-between',
3238
+ marginTop: theme.spacing.small,
3239
+ fontSize: theme.typography.fontSize.small,
3240
+ color: theme.colors.textSecondary,
3241
+ } },
3242
+ React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMin)),
3243
+ React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMax)))),
3244
+ React.createElement("style", null, `
3245
+ .${thumbClass}::-webkit-slider-thumb {
3246
+ -webkit-appearance: none;
3247
+ appearance: none;
3248
+ width: 20px;
3249
+ height: 20px;
3250
+ background: ${theme.colors.primary};
3251
+ border-radius: 50%;
3252
+ cursor: pointer;
3253
+ pointer-events: all;
3254
+ box-shadow: ${SHADOWS$1.md};
3255
+ }
3256
+ .${thumbClass}::-moz-range-thumb {
3257
+ width: 20px;
3258
+ height: 20px;
3259
+ background: ${theme.colors.primary};
3260
+ border-radius: 50%;
3261
+ cursor: pointer;
3262
+ pointer-events: all;
3263
+ border: none;
3264
+ box-shadow: ${SHADOWS$1.md};
3265
+ }
3266
+ `)));
3267
+ };
3268
+
2998
3269
  /**
2999
3270
  * Facets Component
3000
3271
  *
@@ -3044,17 +3315,19 @@ const CheckmarkIcon = ({ size = 16 }) => (React.createElement("svg", { width: si
3044
3315
  // CSS variable defaults
3045
3316
  // ---------------------------------------------------------------------------
3046
3317
  const CSS_VAR_DEFAULTS = {
3047
- '--seekora-facet-bg': '#ffffff',
3318
+ '--seekora-facet-bg': 'transparent',
3048
3319
  '--seekora-facet-border': '#dee2e6',
3049
- '--seekora-facet-active-bg': '#f0f7ff',
3320
+ '--seekora-facet-active-bg': 'rgba(0, 0, 0, 0.05)',
3050
3321
  '--seekora-facet-swatch-size': '32px',
3051
3322
  '--seekora-facet-count-bg': '#e9ecef',
3052
3323
  '--seekora-facet-count-color': '#495057',
3324
+ '--seekora-primary': '#3b82f6',
3325
+ '--seekora-primary-text': '#ffffff',
3053
3326
  };
3054
3327
  // ---------------------------------------------------------------------------
3055
3328
  // Component
3056
3329
  // ---------------------------------------------------------------------------
3057
- 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', }) => {
3330
+ 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, }) => {
3058
3331
  const { theme } = useSearchContext();
3059
3332
  const { results: stateResults, refinements, addRefinement, removeRefinement } = useSearchState();
3060
3333
  const facetsTheme = customTheme || {};
@@ -3104,6 +3377,7 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3104
3377
  count: count.count,
3105
3378
  selected: refinements.some(r => r.field === fieldName && r.value === count.value),
3106
3379
  })) : [],
3380
+ stats: facet.stats || undefined,
3107
3381
  };
3108
3382
  });
3109
3383
  log.verbose('Facets: Extracted facets', {
@@ -3181,7 +3455,7 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3181
3455
  const sizeScale = React.useMemo(() => {
3182
3456
  switch (size) {
3183
3457
  case 'small':
3184
- return { font: theme.typography.fontSize.small, padding: '0.25rem', gap: '0.25rem' };
3458
+ return { font: theme.typography.fontSize.small, padding: '0.5rem', gap: '0.5rem' };
3185
3459
  case 'large':
3186
3460
  return { font: theme.typography.fontSize.large, padding: '0.75rem', gap: '0.75rem' };
3187
3461
  case 'medium':
@@ -3250,6 +3524,7 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3250
3524
  ? 'var(--seekora-facet-active-bg, ' + theme.colors.hover + ')'
3251
3525
  : 'transparent',
3252
3526
  transition: 'background-color 0.2s ease',
3527
+ boxSizing: 'border-box',
3253
3528
  } },
3254
3529
  React.createElement("input", { type: "checkbox", checked: refinements.some(r => r.field === facet.field && r.value === item.value) || item.selected || false, onChange: () => handleFacetToggle(facet.field, item.value, item.selected || false), className: facetsTheme.checkbox, style: {
3255
3530
  marginRight: sizeScale.gap,
@@ -3258,6 +3533,7 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3258
3533
  React.createElement("span", { className: facetsTheme.facetItemLabel, style: {
3259
3534
  flex: 1,
3260
3535
  fontSize: sizeScale.font,
3536
+ lineHeight: 1.5,
3261
3537
  color: theme.colors.text,
3262
3538
  } }, item.value),
3263
3539
  renderCountBadge(item.count)));
@@ -3286,13 +3562,13 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3286
3562
  borderRadius: '50%',
3287
3563
  backgroundColor: color,
3288
3564
  border: isChecked
3289
- ? `3px solid ${theme.colors.primary}`
3565
+ ? `3px solid var(--seekora-primary, ${theme.colors.primary})`
3290
3566
  : `2px solid var(--seekora-facet-border, ${theme.colors.border})`,
3291
3567
  display: 'flex',
3292
3568
  alignItems: 'center',
3293
3569
  justifyContent: 'center',
3294
3570
  transition: 'border 0.2s ease, box-shadow 0.2s ease',
3295
- boxShadow: isChecked ? `0 0 0 2px ${theme.colors.primary}33` : 'none',
3571
+ boxShadow: isChecked ? `0 0 0 2px var(--seekora-primary-alpha, ${theme.colors.primary}33)` : 'none',
3296
3572
  position: 'relative',
3297
3573
  } }, isChecked && (React.createElement("span", { className: clsx(facetsTheme.colorSwatchInner), style: {
3298
3574
  display: 'flex',
@@ -3518,21 +3794,204 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3518
3794
  } }, "Show less"))))));
3519
3795
  };
3520
3796
  // -------------------------------------------------------------------
3521
- // Default facet renderer dispatcher
3797
+ // Render-type detection for numeric / range facets
3522
3798
  // -------------------------------------------------------------------
3523
- const defaultRenderFacet = (facet, index) => {
3524
- switch (variant) {
3525
- case 'color-swatch':
3526
- return renderColorSwatchFacet(facet);
3527
- case 'collapsible':
3528
- return renderCollapsibleFacet(facet);
3529
- case 'checkbox':
3530
- default:
3531
- return renderCheckboxFacet(facet);
3799
+ const determineFacetRenderType = (fieldName, stats) => {
3800
+ // If explicit range config exists for this field → range buttons
3801
+ if (facetRanges?.some((rc) => rc.field === fieldName)) {
3802
+ return 'range-buttons';
3532
3803
  }
3804
+ // If stats with valid min/max → range slider
3805
+ if (stats && typeof stats.min === 'number' && typeof stats.max === 'number' && stats.min !== stats.max) {
3806
+ return 'range-slider';
3807
+ }
3808
+ return 'list';
3533
3809
  };
3534
3810
  // -------------------------------------------------------------------
3535
- // Empty state
3811
+ // Range button facet renderer
3812
+ // -------------------------------------------------------------------
3813
+ const renderRangeButtonFacet = (facet, _index) => {
3814
+ const rangeConfig = facetRanges?.find((rc) => rc.field === facet.field);
3815
+ if (!rangeConfig)
3816
+ return null;
3817
+ // Build a lookup from item value → count
3818
+ const countMap = new Map();
3819
+ facet.items.forEach((item) => countMap.set(item.value, item.count));
3820
+ // Detect currently active range from refinements
3821
+ const activeMin = refinements.find((r) => r.field === facet.field && r.value.startsWith('>='));
3822
+ const activeMax = refinements.find((r) => r.field === facet.field && r.value.startsWith('<='));
3823
+ const activeFromVal = activeMin ? parseFloat(activeMin.value.slice(2)) : undefined;
3824
+ const activeToVal = activeMax ? parseFloat(activeMax.value.slice(2)) : undefined;
3825
+ const isRangeActive = (range) => {
3826
+ const fromMatch = range.from === undefined
3827
+ ? activeFromVal === undefined
3828
+ : activeFromVal === range.from;
3829
+ const toMatch = range.to === undefined
3830
+ ? activeToVal === undefined
3831
+ : activeToVal === range.to;
3832
+ return fromMatch && toMatch;
3833
+ };
3834
+ const handleRangeClick = (range) => {
3835
+ // Clear existing range refinements for this field
3836
+ refinements
3837
+ .filter((r) => r.field === facet.field)
3838
+ .forEach((r) => removeRefinement(facet.field, r.value, false));
3839
+ if (isRangeActive(range)) {
3840
+ // Was active → just clear (already removed above), trigger search
3841
+ addRefinement(facet.field, '__noop__', false);
3842
+ removeRefinement(facet.field, '__noop__', true);
3843
+ return;
3844
+ }
3845
+ // Set new range
3846
+ if (range.from !== undefined) {
3847
+ addRefinement(facet.field, `>=${range.from}`, false);
3848
+ }
3849
+ if (range.to !== undefined) {
3850
+ addRefinement(facet.field, `<=${range.to}`, true);
3851
+ }
3852
+ else if (range.from !== undefined) {
3853
+ // Only "from" set — trigger search
3854
+ addRefinement(facet.field, `>=${range.from}`, true);
3855
+ }
3856
+ };
3857
+ const hasActiveRange = activeMin !== undefined || activeMax !== undefined;
3858
+ const handleClear = () => {
3859
+ refinements
3860
+ .filter((r) => r.field === facet.field)
3861
+ .forEach((r) => removeRefinement(facet.field, r.value, false));
3862
+ // Trigger search after clearing
3863
+ addRefinement(facet.field, '__noop__', false);
3864
+ removeRefinement(facet.field, '__noop__', true);
3865
+ };
3866
+ return (React.createElement("div", { key: facet.field, className: facetsTheme.facet, style: {
3867
+ marginBottom: theme.spacing.large,
3868
+ padding: theme.spacing.medium,
3869
+ backgroundColor: 'var(--seekora-facet-bg, ' + theme.colors.background + ')',
3870
+ border: `1px solid var(--seekora-facet-border, ${theme.colors.border})`,
3871
+ borderRadius: typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium,
3872
+ } },
3873
+ React.createElement("h3", { className: facetsTheme.facetTitle, style: {
3874
+ fontSize: theme.typography.fontSize.large,
3875
+ fontWeight: 'bold',
3876
+ margin: 0,
3877
+ marginBottom: theme.spacing.medium,
3878
+ color: theme.colors.text,
3879
+ } }, facet.label || facet.field),
3880
+ React.createElement("div", { style: {
3881
+ display: 'flex',
3882
+ flexWrap: 'wrap',
3883
+ gap: sizeScale.gap,
3884
+ } }, rangeConfig.ranges.map((range) => {
3885
+ const count = countMap.get(range.label) ?? 0;
3886
+ const active = isRangeActive(range);
3887
+ return (React.createElement("button", { key: range.label, type: "button", className: clsx(facetsTheme.rangeButton, active && facetsTheme.rangeButtonActive), disabled: count === 0 && !active, onClick: () => handleRangeClick(range), style: {
3888
+ display: 'inline-flex',
3889
+ alignItems: 'center',
3890
+ gap: '0.35em',
3891
+ padding: `${sizeScale.padding} 0.75em`,
3892
+ fontSize: sizeScale.font,
3893
+ border: `1px solid ${active ? 'var(--seekora-primary, ' + theme.colors.primary + ')' : 'var(--seekora-facet-border, ' + theme.colors.border + ')'}`,
3894
+ borderRadius: typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.full,
3895
+ backgroundColor: active ? 'var(--seekora-primary, ' + theme.colors.primary + ')' : 'var(--seekora-facet-bg, ' + theme.colors.background + ')',
3896
+ color: active ? 'var(--seekora-primary-text, #fff)' : theme.colors.text,
3897
+ cursor: count === 0 && !active ? 'not-allowed' : 'pointer',
3898
+ opacity: count === 0 && !active ? 0.5 : 1,
3899
+ transition: 'all 0.2s ease',
3900
+ } },
3901
+ range.label,
3902
+ showCounts && (React.createElement("span", { className: clsx(facetsTheme.rangeButtonCount), style: {
3903
+ fontSize: theme.typography.fontSize.small,
3904
+ opacity: 0.8,
3905
+ } },
3906
+ "(",
3907
+ count,
3908
+ ")"))));
3909
+ })),
3910
+ hasActiveRange && (React.createElement("button", { type: "button", className: clsx(facetsTheme.rangeClear), onClick: handleClear, style: {
3911
+ marginTop: sizeScale.gap,
3912
+ padding: sizeScale.padding,
3913
+ border: 'none',
3914
+ backgroundColor: 'transparent',
3915
+ color: theme.colors.primary,
3916
+ cursor: 'pointer',
3917
+ fontSize: theme.typography.fontSize.small,
3918
+ textDecoration: 'underline',
3919
+ } }, "Clear"))));
3920
+ };
3921
+ // -------------------------------------------------------------------
3922
+ // Range slider facet renderer
3923
+ // -------------------------------------------------------------------
3924
+ const renderRangeSliderFacet = (facet, _index) => {
3925
+ if (!facet.stats)
3926
+ return null;
3927
+ const { min: statsMin, max: statsMax } = facet.stats;
3928
+ // Auto-detect formatting for common field names
3929
+ const fieldLower = facet.field.toLowerCase();
3930
+ const isPriceField = fieldLower.includes('price') || fieldLower.includes('cost') || fieldLower.includes('amount');
3931
+ const formatValue = isPriceField
3932
+ ? (v) => `$${v.toFixed(2)}`
3933
+ : (v) => v.toString();
3934
+ // Determine step: use 0.01 for price, 1 for integer ranges, 0.1 otherwise
3935
+ const range = statsMax - statsMin;
3936
+ const step = isPriceField ? 0.01 : range > 10 ? 1 : 0.1;
3937
+ // Check if there's an active range refinement
3938
+ const hasActiveRange = refinements.some((r) => r.field === facet.field && (r.value.startsWith('>=') || r.value.startsWith('<=')));
3939
+ const handleClear = () => {
3940
+ refinements
3941
+ .filter((r) => r.field === facet.field && (r.value.startsWith('>=') || r.value.startsWith('<=')))
3942
+ .forEach((r) => removeRefinement(facet.field, r.value, false));
3943
+ // Trigger search after clearing
3944
+ addRefinement(facet.field, '__noop__', false);
3945
+ removeRefinement(facet.field, '__noop__', true);
3946
+ };
3947
+ return (React.createElement("div", { key: facet.field, className: facetsTheme.facet, style: {
3948
+ marginBottom: theme.spacing.large,
3949
+ padding: theme.spacing.medium,
3950
+ backgroundColor: 'var(--seekora-facet-bg, ' + theme.colors.background + ')',
3951
+ border: `1px solid var(--seekora-facet-border, ${theme.colors.border})`,
3952
+ borderRadius: typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium,
3953
+ } },
3954
+ React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.small } },
3955
+ React.createElement("h3", { className: facetsTheme.facetTitle, style: {
3956
+ fontSize: theme.typography.fontSize.large,
3957
+ fontWeight: 'bold',
3958
+ margin: 0,
3959
+ color: theme.colors.text,
3960
+ } }, facet.label || facet.field),
3961
+ hasActiveRange && (React.createElement("button", { type: "button", className: clsx(facetsTheme.rangeClear), onClick: handleClear, style: {
3962
+ padding: '0.15em 0.5em',
3963
+ border: 'none',
3964
+ backgroundColor: 'transparent',
3965
+ color: theme.colors.primary,
3966
+ cursor: 'pointer',
3967
+ fontSize: theme.typography.fontSize.small,
3968
+ textDecoration: 'underline',
3969
+ } }, "Clear"))),
3970
+ React.createElement(RangeSlider, { field: facet.field, min: statsMin, max: statsMax, step: step, formatValue: formatValue, syncWithState: true })));
3971
+ };
3972
+ // -------------------------------------------------------------------
3973
+ // Default facet renderer dispatcher
3974
+ // -------------------------------------------------------------------
3975
+ const defaultRenderFacet = (facet, index) => {
3976
+ const renderType = determineFacetRenderType(facet.field, facet.stats);
3977
+ if (renderType === 'range-buttons') {
3978
+ return renderRangeButtonFacet(facet);
3979
+ }
3980
+ if (renderType === 'range-slider') {
3981
+ return renderRangeSliderFacet(facet);
3982
+ }
3983
+ switch (variant) {
3984
+ case 'color-swatch':
3985
+ return renderColorSwatchFacet(facet);
3986
+ case 'collapsible':
3987
+ return renderCollapsibleFacet(facet);
3988
+ case 'checkbox':
3989
+ default:
3990
+ return renderCheckboxFacet(facet);
3991
+ }
3992
+ };
3993
+ // -------------------------------------------------------------------
3994
+ // Empty state
3536
3995
  // -------------------------------------------------------------------
3537
3996
  if (facets.length === 0) {
3538
3997
  log.verbose('Facets: No facets to display', {
@@ -3554,12 +4013,381 @@ const Facets = ({ results: resultsProp, facets: facetsProp, onFacetChange, rende
3554
4013
  })));
3555
4014
  };
3556
4015
 
4016
+ /**
4017
+ * FacetDropdown Component
4018
+ *
4019
+ * A dropdown component that displays facet values from a specific field
4020
+ * and allows users to filter search results by selecting values.
4021
+ *
4022
+ * Can be used standalone (fetches its own data) or integrated with SearchProvider.
4023
+ *
4024
+ * @cssVariables
4025
+ * Customize the dropdown appearance using CSS variables:
4026
+ *
4027
+ * Button:
4028
+ * - `--facet-dropdown-button-bg`: Button background color
4029
+ * - `--facet-dropdown-text`: Button text color
4030
+ * - `--facet-dropdown-border`: Button and panel border color
4031
+ * - `--facet-dropdown-font-size`: Button font size (default: 0.875rem)
4032
+ * - `--facet-dropdown-font-weight`: Button font weight (default: 500)
4033
+ *
4034
+ * Dropdown Panel:
4035
+ * - `--facet-dropdown-bg`: Panel background color
4036
+ * - `--facet-dropdown-shadow`: Panel box shadow
4037
+ *
4038
+ * Options:
4039
+ * - `--facet-dropdown-option-text`: Option text color
4040
+ * - `--facet-dropdown-option-font-size`: Option font size (default: 0.875rem)
4041
+ * - `--facet-dropdown-option-font-weight-active`: Active option font weight (default: 500)
4042
+ * - `--facet-dropdown-option-active-bg`: Active option background color
4043
+ *
4044
+ * Count Badge:
4045
+ * - `--facet-dropdown-count-text`: Count text color
4046
+ * - `--facet-dropdown-count-font-size`: Count font size (default: 0.75rem)
4047
+ *
4048
+ * Scrollbar:
4049
+ * - `--facet-dropdown-scrollbar-thumb`: Scrollbar thumb color
4050
+ * - `--facet-dropdown-scrollbar-thumb-hover`: Scrollbar thumb hover color
4051
+ *
4052
+ * @example
4053
+ * ```tsx
4054
+ * <FacetDropdown
4055
+ * field="category"
4056
+ * placeholder="All Categories"
4057
+ * applyFilter={true}
4058
+ * showCounts={true}
4059
+ * />
4060
+ * ```
4061
+ */
4062
+ // Z-index scale for consistent layering
4063
+ // SearchOverlay uses z-100, so dropdown must be higher
4064
+ const Z_INDEX$1 = {
4065
+ dropdown: 150};
4066
+ // ---------------------------------------------------------------------------
4067
+ // Component
4068
+ // ---------------------------------------------------------------------------
4069
+ const FacetDropdown = ({ field, placeholder = 'All Categories', className, theme: customTheme = {}, onChange, value: controlledValue, maxOptions = 10, showCounts = true, options: providedOptions, client: providedClient, applyFilter = true, navigateOnSelect = false, searchPageUrl = '/search', }) => {
4070
+ const { client: contextClient, theme } = useSearchContext();
4071
+ const { addRefinement, removeRefinement, refinements, search } = useSearchState();
4072
+ const client = providedClient || contextClient;
4073
+ const [open, setOpen] = React.useState(false);
4074
+ const [facetOptions, setFacetOptions] = React.useState(providedOptions || []);
4075
+ const [internalValue, setInternalValue] = React.useState(controlledValue || '');
4076
+ const [dropdownPosition, setDropdownPosition] = React.useState(null);
4077
+ const dropdownRef = React.useRef(null);
4078
+ const buttonRef = React.useRef(null);
4079
+ // Determine the current value (controlled or uncontrolled)
4080
+ const currentValue = controlledValue !== undefined ? controlledValue : internalValue;
4081
+ // ---------------------------------------------------------------------------
4082
+ // Fetch facet values
4083
+ // ---------------------------------------------------------------------------
4084
+ const fetchFacetValues = React.useCallback(async () => {
4085
+ if (providedOptions || !client)
4086
+ return;
4087
+ try {
4088
+ log.verbose('FacetDropdown: Fetching facet values', { field });
4089
+ // Perform a search with facet_by parameter to get facet counts
4090
+ const response = await client.search('*', {
4091
+ facet_by: field,
4092
+ max_facet_values: 100,
4093
+ per_page: 0, // We only need facets, not results
4094
+ });
4095
+ log.verbose('FacetDropdown: Search response', { response });
4096
+ // Extract facet counts from the response
4097
+ const facetsData = response?.data?.facets || response?.facets;
4098
+ const facets = Array.isArray(facetsData) ? facetsData : [];
4099
+ const targetFacet = facets.find((f) => f.field_name === field || f.field === field);
4100
+ if (targetFacet && targetFacet.counts) {
4101
+ const options = targetFacet.counts.map((count) => ({
4102
+ value: count.value,
4103
+ count: count.count,
4104
+ label: count.value,
4105
+ }));
4106
+ setFacetOptions(options);
4107
+ log.verbose('FacetDropdown: Facet options loaded', { field, count: options.length });
4108
+ }
4109
+ else {
4110
+ log.verbose('FacetDropdown: No facet data found', { field, facets });
4111
+ setFacetOptions([]);
4112
+ }
4113
+ }
4114
+ catch (error) {
4115
+ const err = error instanceof Error ? error : new Error(String(error));
4116
+ log.error('FacetDropdown: Error fetching facet values', {
4117
+ field,
4118
+ error: err.message,
4119
+ });
4120
+ setFacetOptions([]);
4121
+ }
4122
+ }, [field, client, providedOptions]);
4123
+ React.useEffect(() => {
4124
+ if (!providedOptions && client) {
4125
+ fetchFacetValues();
4126
+ }
4127
+ }, [fetchFacetValues, providedOptions, client]);
4128
+ // ---------------------------------------------------------------------------
4129
+ // Calculate dropdown position when opened
4130
+ // ---------------------------------------------------------------------------
4131
+ React.useEffect(() => {
4132
+ if (!open || !buttonRef.current)
4133
+ return;
4134
+ const updatePosition = () => {
4135
+ if (!buttonRef.current)
4136
+ return;
4137
+ const rect = buttonRef.current.getBoundingClientRect();
4138
+ setDropdownPosition({
4139
+ top: rect.bottom + window.scrollY + 4,
4140
+ left: rect.left + window.scrollX,
4141
+ width: rect.width,
4142
+ });
4143
+ };
4144
+ updatePosition();
4145
+ window.addEventListener('scroll', updatePosition, true);
4146
+ window.addEventListener('resize', updatePosition);
4147
+ return () => {
4148
+ window.removeEventListener('scroll', updatePosition, true);
4149
+ window.removeEventListener('resize', updatePosition);
4150
+ };
4151
+ }, [open]);
4152
+ // ---------------------------------------------------------------------------
4153
+ // Click outside handler
4154
+ // ---------------------------------------------------------------------------
4155
+ React.useEffect(() => {
4156
+ if (!open)
4157
+ return;
4158
+ const handleClickOutside = (e) => {
4159
+ if (dropdownRef.current &&
4160
+ !dropdownRef.current.contains(e.target) &&
4161
+ buttonRef.current &&
4162
+ !buttonRef.current.contains(e.target)) {
4163
+ setOpen(false);
4164
+ }
4165
+ };
4166
+ const handleEscape = (e) => {
4167
+ if (e.key === 'Escape') {
4168
+ setOpen(false);
4169
+ }
4170
+ };
4171
+ document.addEventListener('mousedown', handleClickOutside);
4172
+ document.addEventListener('keydown', handleEscape);
4173
+ return () => {
4174
+ document.removeEventListener('mousedown', handleClickOutside);
4175
+ document.removeEventListener('keydown', handleEscape);
4176
+ };
4177
+ }, [open]);
4178
+ // ---------------------------------------------------------------------------
4179
+ // Selection handler
4180
+ // ---------------------------------------------------------------------------
4181
+ const handleSelect = React.useCallback((value) => {
4182
+ log.verbose('FacetDropdown: Value selected', { field, value });
4183
+ // Update internal state
4184
+ setInternalValue(value);
4185
+ setOpen(false);
4186
+ // Call onChange callback
4187
+ if (onChange) {
4188
+ onChange(value);
4189
+ }
4190
+ // Apply filter if enabled and we have search state
4191
+ if (applyFilter && addRefinement && removeRefinement) {
4192
+ // Remove any existing refinement for this field
4193
+ const existingRefinement = refinements.find(r => r.field === field);
4194
+ if (existingRefinement) {
4195
+ removeRefinement(field, existingRefinement.value, false);
4196
+ }
4197
+ // Add new refinement if value is not empty
4198
+ if (value) {
4199
+ addRefinement(field, value, true); // true = trigger search
4200
+ }
4201
+ else if (search) {
4202
+ // If clearing the filter, trigger search manually
4203
+ search();
4204
+ }
4205
+ }
4206
+ // Navigate to search page if enabled
4207
+ if (navigateOnSelect && value && typeof window !== 'undefined') {
4208
+ const url = new URL(window.location.origin + searchPageUrl);
4209
+ url.searchParams.set(field, value);
4210
+ window.location.href = url.toString();
4211
+ }
4212
+ }, [field, onChange, applyFilter, addRefinement, removeRefinement, refinements, search, navigateOnSelect, searchPageUrl]);
4213
+ // ---------------------------------------------------------------------------
4214
+ // Render
4215
+ // ---------------------------------------------------------------------------
4216
+ const displayLabel = currentValue || placeholder;
4217
+ const hasOptions = facetOptions.length > 0;
4218
+ const buttonClass = [
4219
+ 'facet-dropdown-button',
4220
+ customTheme.button,
4221
+ className,
4222
+ open && customTheme.buttonOpen,
4223
+ ]
4224
+ .filter(Boolean)
4225
+ .join(' ');
4226
+ // Render dropdown panel via portal
4227
+ const renderDropdown = () => {
4228
+ if (!open || !hasOptions || !dropdownPosition || typeof document === 'undefined') {
4229
+ return null;
4230
+ }
4231
+ const dropdown = (React.createElement("div", { ref: dropdownRef, className: customTheme.panel || 'facet-dropdown-panel', role: "listbox", "aria-label": `${field} options`, style: {
4232
+ position: 'absolute',
4233
+ top: `${dropdownPosition.top}px`,
4234
+ left: `${dropdownPosition.left}px`,
4235
+ minWidth: `${dropdownPosition.width}px`,
4236
+ width: 'max-content',
4237
+ maxWidth: 'min(24rem, 90vw)',
4238
+ maxHeight: `calc(100vh - 100px)`,
4239
+ overflowY: 'auto',
4240
+ overflowX: 'hidden',
4241
+ backgroundColor: 'var(--facet-dropdown-bg, var(--background))',
4242
+ border: '1px solid var(--facet-dropdown-border, var(--border-color))',
4243
+ borderRadius: theme?.borderRadius && typeof theme.borderRadius !== 'string'
4244
+ ? theme.borderRadius.medium
4245
+ : '0.5rem',
4246
+ boxShadow: 'var(--facet-dropdown-shadow, var(--shadow-lg))',
4247
+ zIndex: Z_INDEX$1.dropdown,
4248
+ padding: '0.25rem',
4249
+ } },
4250
+ React.createElement("button", { type: "button", role: "option", "aria-selected": !currentValue, onClick: (e) => {
4251
+ e.preventDefault();
4252
+ e.stopPropagation();
4253
+ handleSelect('');
4254
+ }, className: [
4255
+ customTheme.option,
4256
+ !currentValue && customTheme.optionActive,
4257
+ ]
4258
+ .filter(Boolean)
4259
+ .join(' '), style: {
4260
+ width: '100%',
4261
+ textAlign: 'left',
4262
+ padding: '0.5rem 0.75rem',
4263
+ fontSize: 'var(--facet-dropdown-option-font-size, 0.875rem)',
4264
+ fontWeight: !currentValue ? 'var(--facet-dropdown-option-font-weight-active, 500)' : 'normal',
4265
+ color: 'var(--facet-dropdown-option-text, var(--text-color, currentColor))',
4266
+ backgroundColor: !currentValue ? 'var(--facet-dropdown-option-active-bg, var(--hover-color))' : 'transparent',
4267
+ border: 'none',
4268
+ borderRadius: theme?.borderRadius && typeof theme.borderRadius !== 'string'
4269
+ ? theme.borderRadius.small
4270
+ : '0.25rem',
4271
+ cursor: 'pointer',
4272
+ transition: 'background-color 0.15s ease',
4273
+ display: 'flex',
4274
+ alignItems: 'center',
4275
+ justifyContent: 'space-between',
4276
+ } },
4277
+ React.createElement("span", null, placeholder)),
4278
+ facetOptions.map((option) => {
4279
+ const isActive = currentValue === option.value;
4280
+ return (React.createElement("button", { key: option.value, type: "button", role: "option", "aria-selected": isActive, onClick: (e) => {
4281
+ e.preventDefault();
4282
+ e.stopPropagation();
4283
+ handleSelect(option.value);
4284
+ }, className: [
4285
+ customTheme.option,
4286
+ isActive && customTheme.optionActive,
4287
+ ]
4288
+ .filter(Boolean)
4289
+ .join(' '), style: {
4290
+ width: '100%',
4291
+ textAlign: 'left',
4292
+ padding: '0.5rem 0.75rem',
4293
+ fontSize: 'var(--facet-dropdown-option-font-size, 0.875rem)',
4294
+ fontWeight: isActive ? 'var(--facet-dropdown-option-font-weight-active, 500)' : 'normal',
4295
+ color: 'var(--facet-dropdown-option-text, var(--text-color, currentColor))',
4296
+ backgroundColor: isActive ? 'var(--facet-dropdown-option-active-bg, var(--hover-color))' : 'transparent',
4297
+ border: 'none',
4298
+ borderRadius: theme?.borderRadius && typeof theme.borderRadius !== 'string'
4299
+ ? theme.borderRadius.small
4300
+ : '0.25rem',
4301
+ cursor: 'pointer',
4302
+ transition: 'background-color 0.15s ease',
4303
+ display: 'flex',
4304
+ alignItems: 'center',
4305
+ justifyContent: 'space-between',
4306
+ } },
4307
+ React.createElement("span", { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' } }, option.label || option.value),
4308
+ showCounts && (React.createElement("span", { style: {
4309
+ fontSize: 'var(--facet-dropdown-count-font-size, 0.75rem)',
4310
+ color: 'var(--facet-dropdown-count-text, var(--text-secondary, currentColor))',
4311
+ opacity: 0.7,
4312
+ marginLeft: '0.5rem',
4313
+ flexShrink: 0,
4314
+ } },
4315
+ "(",
4316
+ option.count,
4317
+ ")"))));
4318
+ })));
4319
+ return reactDom.createPortal(dropdown, document.body);
4320
+ };
4321
+ return (React.createElement("div", { className: "facet-dropdown-container", style: { position: 'relative' } },
4322
+ React.createElement("style", { dangerouslySetInnerHTML: {
4323
+ __html: `
4324
+ .facet-dropdown-panel {
4325
+ --scrollbar-track: transparent;
4326
+ --scrollbar-thumb: var(--facet-dropdown-scrollbar-thumb, var(--border-color));
4327
+ --scrollbar-thumb-hover: var(--facet-dropdown-scrollbar-thumb-hover, var(--text-secondary));
4328
+ }
4329
+ .facet-dropdown-panel::-webkit-scrollbar {
4330
+ width: 6px;
4331
+ }
4332
+ .facet-dropdown-panel::-webkit-scrollbar-track {
4333
+ background: var(--scrollbar-track);
4334
+ }
4335
+ .facet-dropdown-panel::-webkit-scrollbar-thumb {
4336
+ background: var(--scrollbar-thumb);
4337
+ border-radius: 3px;
4338
+ }
4339
+ .facet-dropdown-panel::-webkit-scrollbar-thumb:hover {
4340
+ background: var(--scrollbar-thumb-hover);
4341
+ }
4342
+ .facet-dropdown-panel {
4343
+ scrollbar-width: thin;
4344
+ scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
4345
+ }
4346
+ `
4347
+ } }),
4348
+ React.createElement("button", { ref: buttonRef, type: "button", onClick: (e) => {
4349
+ e.preventDefault();
4350
+ e.stopPropagation();
4351
+ setOpen(prev => !prev);
4352
+ }, className: buttonClass, "aria-label": `Filter by ${field}`, "aria-expanded": open, "aria-haspopup": "listbox", style: {
4353
+ display: 'flex',
4354
+ alignItems: 'center',
4355
+ gap: '0.375rem',
4356
+ padding: '0.625rem 0.75rem',
4357
+ fontSize: 'var(--facet-dropdown-font-size, 0.875rem)',
4358
+ fontWeight: 'var(--facet-dropdown-font-weight, 500)',
4359
+ color: 'var(--facet-dropdown-text, var(--text-color, currentColor))',
4360
+ backgroundColor: 'var(--facet-dropdown-button-bg, var(--background, transparent))',
4361
+ border: '1px solid var(--facet-dropdown-border, var(--border-color))',
4362
+ borderRadius: theme?.borderRadius && typeof theme.borderRadius !== 'string'
4363
+ ? theme.borderRadius.medium
4364
+ : '0.5rem',
4365
+ cursor: 'pointer',
4366
+ transition: 'all 0.2s ease',
4367
+ outline: 'none',
4368
+ whiteSpace: 'nowrap',
4369
+ minWidth: '8rem',
4370
+ ...(!hasOptions && { opacity: 0.6, cursor: 'not-allowed' }),
4371
+ }, disabled: !hasOptions },
4372
+ React.createElement("span", { style: { flex: 1, textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis' } }, displayLabel),
4373
+ React.createElement("svg", { className: customTheme.caretIcon, width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", style: {
4374
+ transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
4375
+ transition: 'transform 0.2s ease',
4376
+ flexShrink: 0,
4377
+ }, "aria-hidden": "true" },
4378
+ React.createElement("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }))),
4379
+ renderDropdown()));
4380
+ };
4381
+
3557
4382
  /**
3558
4383
  * CurrentRefinements Component
3559
4384
  *
3560
4385
  * Displays currently active filters/refinements with ability to clear them.
3561
4386
  * Supports StateManager auto-sync, display variants, layout modes, and animations.
3562
4387
  */
4388
+ const TRANSITIONS$7 = {
4389
+ fast: '150ms ease-in-out',
4390
+ normal: '200ms ease-in-out'};
3563
4391
  /** Get variant-specific styles */
3564
4392
  const getVariantStyles = (variant, themeColors, themeSpacing, themeBorderRadius, fieldColor) => {
3565
4393
  const baseBg = fieldColor || `var(--seekora-refinement-bg, ${themeColors.hover})`;
@@ -3643,10 +4471,59 @@ const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, o
3643
4471
  const { theme } = useSearchContext();
3644
4472
  const { refinements: stateRefinements, removeRefinement, clearRefinements } = useSearchState();
3645
4473
  const refinementsTheme = customTheme || {};
4474
+ // Format a numeric value for display (auto-detect price fields)
4475
+ const formatRangeValue = (field, val) => {
4476
+ const f = field.toLowerCase();
4477
+ if (f.includes('price') || f.includes('cost') || f.includes('amount')) {
4478
+ return `$${val.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
4479
+ }
4480
+ return val.toLocaleString();
4481
+ };
4482
+ // Create a stable serialized key from stateRefinements to detect actual changes
4483
+ // (needed because state manager mutates the array in place)
4484
+ const stateRefinementsKey = React.useMemo(() => stateRefinements.map(r => `${r.field}:${r.value}`).sort().join('|'), [stateRefinements.map(r => `${r.field}:${r.value}`).sort().join('|')]);
3646
4485
  // Use props if provided, otherwise auto-read from StateManager
3647
- const refinements = refinementsProp !== undefined
3648
- ? refinementsProp
3649
- : stateRefinements.map(r => ({ field: r.field, value: r.value }));
4486
+ // Combines >= / <= range refinements into single formatted pills
4487
+ const refinements = React.useMemo(() => {
4488
+ if (refinementsProp !== undefined) {
4489
+ return refinementsProp;
4490
+ }
4491
+ const rangeMap = new Map();
4492
+ const nonRange = [];
4493
+ stateRefinements.forEach(r => {
4494
+ const minMatch = r.value.match(/^>=(\d+(?:\.\d+)?)$/);
4495
+ const maxMatch = r.value.match(/^<=(\d+(?:\.\d+)?)$/);
4496
+ if (minMatch || maxMatch) {
4497
+ if (!rangeMap.has(r.field))
4498
+ rangeMap.set(r.field, {});
4499
+ const entry = rangeMap.get(r.field);
4500
+ if (minMatch)
4501
+ entry.minVal = parseFloat(minMatch[1]);
4502
+ if (maxMatch)
4503
+ entry.maxVal = parseFloat(maxMatch[1]);
4504
+ }
4505
+ else {
4506
+ nonRange.push({ field: r.field, value: r.value });
4507
+ }
4508
+ });
4509
+ rangeMap.forEach((range, field) => {
4510
+ let displayValue;
4511
+ if (range.minVal !== undefined && range.maxVal !== undefined) {
4512
+ displayValue = `${formatRangeValue(field, range.minVal)} – ${formatRangeValue(field, range.maxVal)}`;
4513
+ }
4514
+ else if (range.minVal !== undefined) {
4515
+ displayValue = `≥ ${formatRangeValue(field, range.minVal)}`;
4516
+ }
4517
+ else if (range.maxVal !== undefined) {
4518
+ displayValue = `≤ ${formatRangeValue(field, range.maxVal)}`;
4519
+ }
4520
+ else {
4521
+ return;
4522
+ }
4523
+ nonRange.push({ field, value: '__range__', displayValue });
4524
+ });
4525
+ return nonRange;
4526
+ }, [refinementsProp, stateRefinementsKey]);
3650
4527
  // Track items for entry/exit animations
3651
4528
  const [visibleItems, setVisibleItems] = React.useState(new Set());
3652
4529
  const [exitingItems, setExitingItems] = React.useState(new Set());
@@ -3670,9 +4547,15 @@ const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, o
3670
4547
  prevRefinementsRef.current = [...refinements];
3671
4548
  }, [refinements]);
3672
4549
  const handleClear = (field, value) => {
3673
- // If synced with StateManager and no prop provided, auto-clear via StateManager
3674
4550
  if (refinementsProp === undefined) {
3675
- removeRefinement(field, value);
4551
+ if (value === '__range__') {
4552
+ // Clear all range refinements for this field
4553
+ const rangeRefs = stateRefinements.filter(r => r.field === field && (/^>=/.test(r.value) || /^<=/.test(r.value)));
4554
+ rangeRefs.forEach((r, i) => removeRefinement(field, r.value, i === rangeRefs.length - 1));
4555
+ }
4556
+ else {
4557
+ removeRefinement(field, value);
4558
+ }
3676
4559
  }
3677
4560
  if (onRefinementClear) {
3678
4561
  onRefinementClear(field, value);
@@ -3699,7 +4582,7 @@ const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, o
3699
4582
  margin: layout === 'vertical'
3700
4583
  ? `0 0 ${theme.spacing.small} 0`
3701
4584
  : `0 ${theme.spacing.small} ${theme.spacing.small} 0`,
3702
- transition: 'all 200ms ease-in-out',
4585
+ transition: `all ${TRANSITIONS$7.normal}`,
3703
4586
  opacity: exitingItems.has(key) ? 0 : 1,
3704
4587
  transform: exitingItems.has(key) ? 'scale(0.8)' : 'scale(1)',
3705
4588
  animation: isEntering ? 'seekoraChipIn 200ms ease-out' : undefined,
@@ -3723,7 +4606,7 @@ const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, o
3723
4606
  alignItems: 'center',
3724
4607
  justifyContent: 'center',
3725
4608
  borderRadius: '50%',
3726
- transition: 'opacity 150ms ease-in-out',
4609
+ transition: `opacity ${TRANSITIONS$7.fast}`,
3727
4610
  opacity: 0.6,
3728
4611
  }, "aria-label": `Clear ${refinement.label || refinement.field}: ${refinement.value}`, onMouseEnter: e => (e.currentTarget.style.opacity = '1'), onMouseLeave: e => (e.currentTarget.style.opacity = '0.6') }, renderCloseIcon ? renderCloseIcon() : defaultCloseIcon())));
3729
4612
  };
@@ -3782,7 +4665,7 @@ const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, o
3782
4665
  cursor: 'pointer',
3783
4666
  fontSize: theme.typography.fontSize.small,
3784
4667
  textDecoration: 'underline',
3785
- transition: 'background-color 150ms ease-in-out',
4668
+ transition: `background-color ${TRANSITIONS$7.fast}`,
3786
4669
  } }, "Clear all filters"))));
3787
4670
  };
3788
4671
 
@@ -3884,6 +4767,8 @@ const SearchLayout = ({ sidebar, children, header, footer, sidebarWidth = '300px
3884
4767
  display: 'flex',
3885
4768
  flexDirection: 'column',
3886
4769
  minHeight: '100vh',
4770
+ width: '100%',
4771
+ maxWidth: '100%',
3887
4772
  backgroundColor: theme.colors.background,
3888
4773
  ...style,
3889
4774
  } },
@@ -3895,20 +4780,27 @@ const SearchLayout = ({ sidebar, children, header, footer, sidebarWidth = '300px
3895
4780
  React.createElement("div", { style: {
3896
4781
  display: 'flex',
3897
4782
  flex: 1,
4783
+ width: '100%',
4784
+ maxWidth: '100%',
3898
4785
  gap: theme.spacing.large,
3899
4786
  padding: theme.spacing.medium,
3900
4787
  backgroundColor: theme.colors.background,
3901
4788
  color: theme.colors.text,
4789
+ overflow: 'hidden',
3902
4790
  } },
3903
4791
  sidebar && (!isMobile || showSidebarOnMobile) && (React.createElement("aside", { className: layoutTheme.sidebar, style: {
3904
4792
  width: sidebarWidth,
3905
4793
  minWidth: sidebarWidth,
4794
+ flexShrink: 0,
3906
4795
  } }, sidebar)),
3907
4796
  React.createElement("main", { className: layoutTheme.main, style: {
3908
4797
  flex: 1,
3909
- minWidth: 0, // Prevents flex item from overflowing
4798
+ minWidth: 0,
4799
+ width: '100%',
4800
+ maxWidth: '100%',
3910
4801
  backgroundColor: theme.colors.background,
3911
4802
  color: theme.colors.text,
4803
+ overflow: 'auto',
3912
4804
  } }, children)),
3913
4805
  footer && (React.createElement("footer", { className: layoutTheme.footer, style: {
3914
4806
  padding: theme.spacing.medium,
@@ -3950,11 +4842,11 @@ const RangeInput = ({ field, label, min, max, currentMin: currentMinProp, curren
3950
4842
  const { refinements, addRefinement, removeRefinement } = useSearchState();
3951
4843
  const rangeInputTheme = customTheme || {};
3952
4844
  // Parse current range from StateManager
3953
- const stateRange = React.useMemo(() => {
3954
- if (!syncWithState)
3955
- return { min: undefined, max: undefined };
3956
- return parseRangeFromRefinements(refinements, field);
3957
- }, [syncWithState, refinements, field]);
4845
+ // NOTE: computed every render (no useMemo) because the state manager mutates
4846
+ // the refinements array in place — the reference never changes.
4847
+ const stateRange = !syncWithState
4848
+ ? { min: undefined, max: undefined }
4849
+ : parseRangeFromRefinements(refinements, field);
3958
4850
  const [internalMin, setInternalMin] = React.useState(currentMinProp ?? stateRange.min);
3959
4851
  const [internalMax, setInternalMax] = React.useState(currentMaxProp ?? stateRange.max);
3960
4852
  const [appliedMin, setAppliedMin] = React.useState(currentMinProp ?? stateRange.min);
@@ -4717,311 +5609,78 @@ const HierarchicalMenu = ({ attributes, separator = ' > ', limit = 10, showMore
4717
5609
  const button = parentItem.querySelector(':scope > button');
4718
5610
  if (button)
4719
5611
  button.focus();
4720
- else
4721
- parentItem.focus();
4722
- }
4723
- }
4724
- }
4725
- break;
4726
- }
4727
- case 'Enter': {
4728
- if (!currentItem)
4729
- break;
4730
- e.preventDefault();
4731
- const button = currentItem.querySelector('button');
4732
- if (button)
4733
- button.click();
4734
- break;
4735
- }
4736
- }
4737
- }, [getVisibleTreeItems]);
4738
- // Render a level of the hierarchy
4739
- const renderLevel = (items, level) => {
4740
- if (!items || items.length === 0)
4741
- return null;
4742
- const isExpanded = expanded[level] || false;
4743
- const displayLimit = isExpanded ? showMoreLimit : limit;
4744
- const displayItems = items.slice(0, displayLimit);
4745
- const hasMore = items.length > displayLimit;
4746
- return (React.createElement("ul", { role: level === 0 ? 'tree' : 'group', className: hierarchicalTheme.list, style: {
4747
- listStyle: 'none',
4748
- margin: 0,
4749
- padding: level > 0 ? `0 0 0 ${theme.spacing.medium}` : 0,
4750
- } },
4751
- displayItems.map((item, index) => (React.createElement("li", { key: item.value, role: "treeitem", ...(item.data && item.data.length > 0
4752
- ? { 'aria-expanded': !!item.isRefined }
4753
- : {}), className: clsx(hierarchicalTheme.item, item.isRefined && hierarchicalTheme.itemSelected, item.data && item.data.length > 0 && hierarchicalTheme.itemParent), style: {
4754
- padding: `${theme.spacing.small} 0`,
4755
- } }, renderItem ? (renderItem(item, level)) : (React.createElement(React.Fragment, null,
4756
- React.createElement("button", { type: "button", onClick: () => handleItemClick(item, level), className: hierarchicalTheme.link, style: {
4757
- display: 'flex',
4758
- alignItems: 'center',
4759
- gap: theme.spacing.small,
4760
- width: '100%',
4761
- padding: 0,
4762
- background: 'none',
4763
- border: 'none',
4764
- cursor: 'pointer',
4765
- textAlign: 'left',
4766
- fontFamily: 'inherit',
4767
- fontSize: theme.typography.fontSize.small,
4768
- color: item.isRefined ? theme.colors.primary : theme.colors.text,
4769
- fontWeight: item.isRefined ? 600 : 400,
4770
- } },
4771
- React.createElement("span", { className: hierarchicalTheme.label, style: { flex: 1 } }, item.label),
4772
- item.count !== undefined && (React.createElement("span", { className: hierarchicalTheme.count, style: {
4773
- color: theme.colors.textSecondary,
4774
- fontSize: theme.typography.fontSize.small,
4775
- } }, item.count))),
4776
- item.isRefined && item.data && item.data.length > 0 && (renderLevel(item.data, level + 1))))))),
4777
- showMore && hasMore && (React.createElement("li", null,
4778
- React.createElement("button", { type: "button", onClick: () => toggleShowMore(level), className: hierarchicalTheme.showMore, style: {
4779
- padding: `${theme.spacing.small} 0`,
4780
- background: 'none',
4781
- border: 'none',
4782
- cursor: 'pointer',
4783
- fontSize: theme.typography.fontSize.small,
4784
- color: theme.colors.primary,
4785
- textDecoration: 'underline',
4786
- } }, isExpanded ? 'Show less' : `Show ${items.length - displayLimit} more`)))));
4787
- };
4788
- if (processedItems.length === 0) {
4789
- return null;
4790
- }
4791
- return (React.createElement("div", { ref: containerRef, className: clsx(hierarchicalTheme.root, className), style: style, tabIndex: 0, onKeyDown: handleKeyDown }, renderLevel(processedItems, 0)));
4792
- };
4793
-
4794
- /**
4795
- * RangeSlider Component
4796
- *
4797
- * Visual slider for numeric range filtering
4798
- * Alternative to RangeInput for a more interactive UX
4799
- */
4800
- const RangeSlider = ({ field, label, min, max, step = 1, currentMin: currentMinProp, currentMax: currentMaxProp, onRangeChange, formatValue = (v) => v.toString(), className, style, theme: customTheme, showValues = true, syncWithState = true, debounceMs = 300, }) => {
4801
- const { theme } = useSearchContext();
4802
- const { refinements, addRefinement, removeRefinement } = useSearchState();
4803
- const rangeSliderTheme = customTheme || {};
4804
- // Parse current range from StateManager
4805
- const stateRange = React.useMemo(() => {
4806
- if (!syncWithState)
4807
- return { min: undefined, max: undefined };
4808
- let minVal;
4809
- let maxVal;
4810
- refinements.forEach(r => {
4811
- if (r.field === field) {
4812
- const minMatch = r.value.match(/^>=(\d+(?:\.\d+)?)$/);
4813
- if (minMatch)
4814
- minVal = parseFloat(minMatch[1]);
4815
- const maxMatch = r.value.match(/^<=(\d+(?:\.\d+)?)$/);
4816
- if (maxMatch)
4817
- maxVal = parseFloat(maxMatch[1]);
4818
- }
4819
- });
4820
- return { min: minVal, max: maxVal };
4821
- }, [syncWithState, refinements, field]);
4822
- const [internalMin, setInternalMin] = React.useState(currentMinProp ?? stateRange.min ?? min);
4823
- const [internalMax, setInternalMax] = React.useState(currentMaxProp ?? stateRange.max ?? max);
4824
- const [isDragging, setIsDragging] = React.useState(false);
4825
- const debounceRef = React.useRef(null);
4826
- // Sync with StateManager changes
4827
- React.useEffect(() => {
4828
- if (syncWithState && !isDragging) {
4829
- if (stateRange.min !== undefined)
4830
- setInternalMin(stateRange.min);
4831
- else
4832
- setInternalMin(min);
4833
- if (stateRange.max !== undefined)
4834
- setInternalMax(stateRange.max);
4835
- else
4836
- setInternalMax(max);
4837
- }
4838
- }, [syncWithState, stateRange.min, stateRange.max, isDragging, min, max]);
4839
- // Update StateManager with range refinements
4840
- const updateStateManager = React.useCallback((minVal, maxVal) => {
4841
- if (!syncWithState)
4842
- return;
4843
- // Remove existing range refinements for this field
4844
- refinements.forEach(r => {
4845
- if (r.field === field) {
4846
- removeRefinement(field, r.value, false);
4847
- }
4848
- });
4849
- // Add new range refinements
4850
- if (minVal > min) {
4851
- addRefinement(field, `>=${minVal}`, false);
4852
- }
4853
- if (maxVal < max) {
4854
- addRefinement(field, `<=${maxVal}`, minVal <= min); // Trigger search if only max is set
4855
- }
4856
- if (minVal > min && maxVal >= max) {
4857
- // Trigger search after setting min
4858
- addRefinement(field, `>=${minVal}`, true);
4859
- }
4860
- }, [syncWithState, field, refinements, addRefinement, removeRefinement, min, max]);
4861
- // Debounced update
4862
- const debouncedUpdate = React.useCallback((minVal, maxVal) => {
4863
- if (debounceRef.current) {
4864
- clearTimeout(debounceRef.current);
4865
- }
4866
- debounceRef.current = setTimeout(() => {
4867
- updateStateManager(minVal, maxVal);
4868
- if (onRangeChange) {
4869
- onRangeChange(minVal, maxVal);
4870
- }
4871
- }, debounceMs);
4872
- }, [updateStateManager, onRangeChange, debounceMs]);
4873
- // Handle min slider change
4874
- const handleMinChange = (e) => {
4875
- const value = Math.min(Number(e.target.value), internalMax - step);
4876
- setInternalMin(value);
4877
- setIsDragging(true);
4878
- debouncedUpdate(value, internalMax);
4879
- };
4880
- // Handle max slider change
4881
- const handleMaxChange = (e) => {
4882
- const value = Math.max(Number(e.target.value), internalMin + step);
4883
- setInternalMax(value);
4884
- setIsDragging(true);
4885
- debouncedUpdate(internalMin, value);
4886
- };
4887
- // Handle drag end
4888
- const handleDragEnd = () => {
4889
- setIsDragging(false);
4890
- };
4891
- // Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
4892
- const handleMinKeyDown = (e) => {
4893
- let newValue = null;
4894
- if (e.key === 'Home') {
4895
- e.preventDefault();
4896
- newValue = min;
4897
- }
4898
- else if (e.key === 'End') {
4899
- e.preventDefault();
4900
- newValue = internalMax - step;
4901
- }
4902
- else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
4903
- e.preventDefault();
4904
- newValue = Math.max(min, internalMin - step * 10);
4905
- }
4906
- else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
4907
- e.preventDefault();
4908
- newValue = Math.min(internalMax - step, internalMin + step * 10);
4909
- }
4910
- if (newValue !== null) {
4911
- setInternalMin(newValue);
4912
- debouncedUpdate(newValue, internalMax);
4913
- }
4914
- };
4915
- const handleMaxKeyDown = (e) => {
4916
- let newValue = null;
4917
- if (e.key === 'Home') {
4918
- e.preventDefault();
4919
- newValue = internalMin + step;
4920
- }
4921
- else if (e.key === 'End') {
4922
- e.preventDefault();
4923
- newValue = max;
4924
- }
4925
- else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
4926
- e.preventDefault();
4927
- newValue = Math.max(internalMin + step, internalMax - step * 10);
4928
- }
4929
- else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
4930
- e.preventDefault();
4931
- newValue = Math.min(max, internalMax + step * 10);
4932
- }
4933
- if (newValue !== null) {
4934
- setInternalMax(newValue);
4935
- debouncedUpdate(internalMin, newValue);
5612
+ else
5613
+ parentItem.focus();
5614
+ }
5615
+ }
5616
+ }
5617
+ break;
5618
+ }
5619
+ case 'Enter': {
5620
+ if (!currentItem)
5621
+ break;
5622
+ e.preventDefault();
5623
+ const button = currentItem.querySelector('button');
5624
+ if (button)
5625
+ button.click();
5626
+ break;
5627
+ }
4936
5628
  }
4937
- };
4938
- // Calculate filled track position
4939
- const minPercent = ((internalMin - min) / (max - min)) * 100;
4940
- const maxPercent = ((internalMax - min) / (max - min)) * 100;
4941
- return (React.createElement("div", { className: clsx(rangeSliderTheme.root, className), style: {
4942
- fontFamily: 'inherit',
4943
- ...style,
4944
- } },
4945
- label && (React.createElement("label", { className: rangeSliderTheme.label, style: {
4946
- display: 'block',
4947
- marginBottom: theme.spacing.small,
4948
- fontSize: theme.typography.fontSize.medium,
4949
- fontWeight: theme.typography.fontWeight?.medium || 500,
4950
- color: theme.colors.text,
4951
- } }, label)),
4952
- React.createElement("div", { className: rangeSliderTheme.slider, style: {
4953
- position: 'relative',
4954
- height: '40px',
4955
- display: 'flex',
4956
- alignItems: 'center',
4957
- } },
4958
- React.createElement("div", { className: rangeSliderTheme.track, style: {
4959
- position: 'absolute',
4960
- width: '100%',
4961
- height: '4px',
4962
- backgroundColor: theme.colors.border,
4963
- borderRadius: '2px',
4964
- } }),
4965
- React.createElement("div", { className: rangeSliderTheme.trackFilled, style: {
4966
- position: 'absolute',
4967
- left: `${minPercent}%`,
4968
- width: `${maxPercent - minPercent}%`,
4969
- height: '4px',
4970
- backgroundColor: theme.colors.primary,
4971
- borderRadius: '2px',
4972
- } }),
4973
- React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMinKeyDown, tabIndex: 0, "aria-valuenow": internalMin, "aria-valuemin": min, "aria-valuemax": max, className: rangeSliderTheme.thumb, style: {
4974
- position: 'absolute',
4975
- width: '100%',
4976
- height: '4px',
4977
- background: 'transparent',
4978
- WebkitAppearance: 'none',
4979
- appearance: 'none',
4980
- cursor: 'pointer',
4981
- pointerEvents: 'none',
4982
- }, "aria-label": `Minimum ${label || field}` }),
4983
- React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMaxKeyDown, tabIndex: 0, "aria-valuenow": internalMax, "aria-valuemin": min, "aria-valuemax": max, className: rangeSliderTheme.thumb, style: {
4984
- position: 'absolute',
4985
- width: '100%',
4986
- height: '4px',
4987
- background: 'transparent',
4988
- WebkitAppearance: 'none',
4989
- appearance: 'none',
4990
- cursor: 'pointer',
4991
- pointerEvents: 'none',
4992
- }, "aria-label": `Maximum ${label || field}` })),
4993
- showValues && (React.createElement("div", { className: rangeSliderTheme.values, style: {
4994
- display: 'flex',
4995
- justifyContent: 'space-between',
4996
- marginTop: theme.spacing.small,
4997
- fontSize: theme.typography.fontSize.small,
4998
- color: theme.colors.textSecondary,
5629
+ }, [getVisibleTreeItems]);
5630
+ // Render a level of the hierarchy
5631
+ const renderLevel = (items, level) => {
5632
+ if (!items || items.length === 0)
5633
+ return null;
5634
+ const isExpanded = expanded[level] || false;
5635
+ const displayLimit = isExpanded ? showMoreLimit : limit;
5636
+ const displayItems = items.slice(0, displayLimit);
5637
+ const hasMore = items.length > displayLimit;
5638
+ return (React.createElement("ul", { role: level === 0 ? 'tree' : 'group', className: hierarchicalTheme.list, style: {
5639
+ listStyle: 'none',
5640
+ margin: 0,
5641
+ padding: level > 0 ? `0 0 0 ${theme.spacing.medium}` : 0,
4999
5642
  } },
5000
- React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMin)),
5001
- React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMax)))),
5002
- React.createElement("style", null, `
5003
- .${rangeSliderTheme.thumb || 'seekora-range-slider__thumb'}::-webkit-slider-thumb {
5004
- -webkit-appearance: none;
5005
- appearance: none;
5006
- width: 20px;
5007
- height: 20px;
5008
- background: ${theme.colors.primary};
5009
- border-radius: 50%;
5010
- cursor: pointer;
5011
- pointer-events: all;
5012
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
5013
- }
5014
- .${rangeSliderTheme.thumb || 'seekora-range-slider__thumb'}::-moz-range-thumb {
5015
- width: 20px;
5016
- height: 20px;
5017
- background: ${theme.colors.primary};
5018
- border-radius: 50%;
5019
- cursor: pointer;
5020
- pointer-events: all;
5021
- border: none;
5022
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
5023
- }
5024
- `)));
5643
+ displayItems.map((item, index) => (React.createElement("li", { key: item.value, role: "treeitem", ...(item.data && item.data.length > 0
5644
+ ? { 'aria-expanded': !!item.isRefined }
5645
+ : {}), className: clsx(hierarchicalTheme.item, item.isRefined && hierarchicalTheme.itemSelected, item.data && item.data.length > 0 && hierarchicalTheme.itemParent), style: {
5646
+ padding: `${theme.spacing.small} 0`,
5647
+ } }, renderItem ? (renderItem(item, level)) : (React.createElement(React.Fragment, null,
5648
+ React.createElement("button", { type: "button", onClick: () => handleItemClick(item, level), className: hierarchicalTheme.link, style: {
5649
+ display: 'flex',
5650
+ alignItems: 'center',
5651
+ gap: theme.spacing.small,
5652
+ width: '100%',
5653
+ padding: 0,
5654
+ background: 'none',
5655
+ border: 'none',
5656
+ cursor: 'pointer',
5657
+ textAlign: 'left',
5658
+ fontFamily: 'inherit',
5659
+ fontSize: theme.typography.fontSize.small,
5660
+ color: item.isRefined ? theme.colors.primary : theme.colors.text,
5661
+ fontWeight: item.isRefined ? 600 : 400,
5662
+ } },
5663
+ React.createElement("span", { className: hierarchicalTheme.label, style: { flex: 1 } }, item.label),
5664
+ item.count !== undefined && (React.createElement("span", { className: hierarchicalTheme.count, style: {
5665
+ color: theme.colors.textSecondary,
5666
+ fontSize: theme.typography.fontSize.small,
5667
+ } }, item.count))),
5668
+ item.isRefined && item.data && item.data.length > 0 && (renderLevel(item.data, level + 1))))))),
5669
+ showMore && hasMore && (React.createElement("li", null,
5670
+ React.createElement("button", { type: "button", onClick: () => toggleShowMore(level), className: hierarchicalTheme.showMore, style: {
5671
+ padding: `${theme.spacing.small} 0`,
5672
+ background: 'none',
5673
+ border: 'none',
5674
+ cursor: 'pointer',
5675
+ fontSize: theme.typography.fontSize.small,
5676
+ color: theme.colors.primary,
5677
+ textDecoration: 'underline',
5678
+ } }, isExpanded ? 'Show less' : `Show ${items.length - displayLimit} more`)))));
5679
+ };
5680
+ if (processedItems.length === 0) {
5681
+ return null;
5682
+ }
5683
+ return (React.createElement("div", { ref: containerRef, className: clsx(hierarchicalTheme.root, className), style: style, tabIndex: 0, onKeyDown: handleKeyDown }, renderLevel(processedItems, 0)));
5025
5684
  };
5026
5685
 
5027
5686
  /**
@@ -6167,13 +6826,21 @@ function useQuerySuggestionsEnhanced(options) {
6167
6826
  * - Accessibility support
6168
6827
  */
6169
6828
  // ============================================================================
6829
+ // Constants
6830
+ // ============================================================================
6831
+ const TRANSITIONS$6 = {
6832
+ fast: '150ms ease-in-out'};
6833
+ const BORDER_RADIUS$9 = {
6834
+ sm: 4,
6835
+ lg: 8};
6836
+ // ============================================================================
6170
6837
  // Styles
6171
6838
  // ============================================================================
6172
6839
  const defaultStyles$1 = {
6173
6840
  container: {
6174
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
6175
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
6176
- borderRadius: 'var(--seekora-border-radius, 8px)',
6841
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
6842
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
6843
+ borderRadius: `var(--seekora-border-radius, ${BORDER_RADIUS$9.lg}px)`,
6177
6844
  boxShadow: 'var(--seekora-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05))',
6178
6845
  maxHeight: '400px',
6179
6846
  overflowY: 'auto',
@@ -6182,7 +6849,7 @@ const defaultStyles$1 = {
6182
6849
  sectionTitle: {
6183
6850
  fontSize: '12px',
6184
6851
  fontWeight: 600,
6185
- color: 'var(--seekora-text-secondary, #6b7280)',
6852
+ color: 'var(--seekora-text-secondary, inherit)',
6186
6853
  textTransform: 'uppercase',
6187
6854
  letterSpacing: '0.05em',
6188
6855
  padding: '8px 16px 4px',
@@ -6193,9 +6860,9 @@ const defaultStyles$1 = {
6193
6860
  alignItems: 'center',
6194
6861
  padding: '10px 16px',
6195
6862
  cursor: 'pointer',
6196
- transition: 'background-color 150ms ease',
6863
+ transition: `background-color ${TRANSITIONS$6.fast}`,
6197
6864
  fontSize: '14px',
6198
- color: 'var(--seekora-text-primary, #111827)',
6865
+ color: 'var(--seekora-text-primary, inherit)',
6199
6866
  gap: '12px',
6200
6867
  },
6201
6868
  suggestionItemActive: {
@@ -6215,10 +6882,10 @@ const defaultStyles$1 = {
6215
6882
  },
6216
6883
  highlight: {
6217
6884
  fontWeight: 600,
6218
- color: 'var(--seekora-text-primary, #111827)',
6885
+ color: 'var(--seekora-text-primary, inherit)',
6219
6886
  backgroundColor: 'var(--seekora-highlight-bg, #fef3c7)',
6220
6887
  padding: '0 2px',
6221
- borderRadius: '2px',
6888
+ borderRadius: `${BORDER_RADIUS$9.sm / 2}px`,
6222
6889
  },
6223
6890
  recentIcon: {
6224
6891
  width: '16px',
@@ -6228,13 +6895,13 @@ const defaultStyles$1 = {
6228
6895
  },
6229
6896
  removeButton: {
6230
6897
  padding: '4px',
6231
- borderRadius: '4px',
6898
+ borderRadius: `${BORDER_RADIUS$9.sm}px`,
6232
6899
  border: 'none',
6233
6900
  background: 'transparent',
6234
6901
  cursor: 'pointer',
6235
6902
  color: 'var(--seekora-text-secondary, #9ca3af)',
6236
6903
  opacity: 0,
6237
- transition: 'opacity 150ms ease, color 150ms ease',
6904
+ transition: `opacity ${TRANSITIONS$6.fast}, color ${TRANSITIONS$6.fast}`,
6238
6905
  },
6239
6906
  removeButtonVisible: {
6240
6907
  opacity: 1,
@@ -6244,7 +6911,7 @@ const defaultStyles$1 = {
6244
6911
  alignItems: 'center',
6245
6912
  justifyContent: 'center',
6246
6913
  padding: '24px 16px',
6247
- color: 'var(--seekora-text-secondary, #6b7280)',
6914
+ color: 'var(--seekora-text-secondary, inherit)',
6248
6915
  fontSize: '14px',
6249
6916
  gap: '8px',
6250
6917
  },
@@ -6254,20 +6921,20 @@ const defaultStyles$1 = {
6254
6921
  alignItems: 'center',
6255
6922
  justifyContent: 'center',
6256
6923
  padding: '24px 16px',
6257
- color: 'var(--seekora-text-secondary, #6b7280)',
6924
+ color: 'var(--seekora-text-secondary, inherit)',
6258
6925
  fontSize: '14px',
6259
6926
  textAlign: 'center',
6260
6927
  },
6261
6928
  divider: {
6262
6929
  height: '1px',
6263
- backgroundColor: 'var(--seekora-border-color, #e5e7eb)',
6930
+ backgroundColor: 'var(--seekora-border-color, rgba(128,128,128,0.2))',
6264
6931
  margin: '4px 0',
6265
6932
  },
6266
6933
  footer: {
6267
- borderTop: '1px solid var(--seekora-border-color, #e5e7eb)',
6934
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
6268
6935
  padding: '8px 16px',
6269
6936
  fontSize: '12px',
6270
- color: 'var(--seekora-text-secondary, #6b7280)',
6937
+ color: 'var(--seekora-text-secondary, inherit)',
6271
6938
  display: 'flex',
6272
6939
  alignItems: 'center',
6273
6940
  justifyContent: 'space-between',
@@ -6285,9 +6952,9 @@ const defaultStyles$1 = {
6285
6952
  minWidth: '20px',
6286
6953
  height: '18px',
6287
6954
  padding: '0 4px',
6288
- borderRadius: '3px',
6289
- backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
6290
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
6955
+ borderRadius: `${BORDER_RADIUS$9.sm - 1}px`,
6956
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
6957
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
6291
6958
  fontSize: '10px',
6292
6959
  fontWeight: 500,
6293
6960
  },
@@ -6555,6 +7222,16 @@ const QuerySuggestionsDropdown = React.forwardRef(function QuerySuggestionsDropd
6555
7222
  * - Configurable sections
6556
7223
  * - Rich styling options
6557
7224
  */
7225
+ // ============================================================================
7226
+ // Constants
7227
+ // ============================================================================
7228
+ const TRANSITIONS$5 = {
7229
+ fast: '150ms ease-in-out'};
7230
+ const BORDER_RADIUS$8 = {
7231
+ sm: 4,
7232
+ lg: 8,
7233
+ full: 9999,
7234
+ };
6558
7235
  // Default section order
6559
7236
  const DEFAULT_SECTIONS = [
6560
7237
  { id: 'recent', title: 'Recent Searches', maxItems: 5, enabled: true, order: 1 },
@@ -6567,16 +7244,16 @@ const DEFAULT_SECTIONS = [
6567
7244
  // ============================================================================
6568
7245
  const styles$2 = {
6569
7246
  container: {
6570
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
6571
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
6572
- borderRadius: 'var(--seekora-border-radius-lg, 12px)',
7247
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
7248
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7249
+ borderRadius: `var(--seekora-border-radius-lg, ${BORDER_RADIUS$8.lg * 1.5}px)`,
6573
7250
  boxShadow: 'var(--seekora-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04))',
6574
7251
  overflow: 'hidden',
6575
7252
  },
6576
7253
  header: {
6577
7254
  padding: '12px 16px',
6578
- borderBottom: '1px solid var(--seekora-border-color, #e5e7eb)',
6579
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
7255
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7256
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
6580
7257
  },
6581
7258
  content: {
6582
7259
  overflowY: 'auto',
@@ -6608,7 +7285,7 @@ const styles$2 = {
6608
7285
  alignItems: 'flex-start',
6609
7286
  padding: '10px 16px',
6610
7287
  cursor: 'pointer',
6611
- transition: 'background-color 100ms ease',
7288
+ transition: `background-color ${TRANSITIONS$5.fast}`,
6612
7289
  gap: '12px',
6613
7290
  },
6614
7291
  itemActive: {
@@ -6627,7 +7304,7 @@ const styles$2 = {
6627
7304
  },
6628
7305
  itemQuery: {
6629
7306
  fontSize: '14px',
6630
- color: 'var(--seekora-text-primary, #111827)',
7307
+ color: 'var(--seekora-text-primary, inherit)',
6631
7308
  fontWeight: 500,
6632
7309
  margin: 0,
6633
7310
  overflow: 'hidden',
@@ -6652,11 +7329,11 @@ const styles$2 = {
6652
7329
  padding: '3px 8px',
6653
7330
  fontSize: '11px',
6654
7331
  fontWeight: 500,
6655
- color: 'var(--seekora-text-secondary, #6b7280)',
6656
- backgroundColor: 'var(--seekora-bg-tertiary, #f3f4f6)',
6657
- borderRadius: '12px',
7332
+ color: 'var(--seekora-text-secondary, inherit)',
7333
+ backgroundColor: 'var(--seekora-bg-tertiary, rgba(255, 255, 255, 0.1))',
7334
+ borderRadius: `${BORDER_RADIUS$8.lg * 1.5}px`,
6658
7335
  cursor: 'pointer',
6659
- transition: 'all 100ms ease',
7336
+ transition: `all ${TRANSITIONS$5.fast}`,
6660
7337
  },
6661
7338
  categoryPillHover: {
6662
7339
  backgroundColor: 'var(--seekora-primary-light, #dbeafe)',
@@ -6678,12 +7355,12 @@ const styles$2 = {
6678
7355
  padding: '6px 12px',
6679
7356
  fontSize: '13px',
6680
7357
  fontWeight: 500,
6681
- color: 'var(--seekora-text-primary, #374151)',
6682
- backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
6683
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
6684
- borderRadius: '20px',
7358
+ color: 'var(--seekora-text-primary, inherit)',
7359
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
7360
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7361
+ borderRadius: `${BORDER_RADIUS$8.full}px`,
6685
7362
  cursor: 'pointer',
6686
- transition: 'all 150ms ease',
7363
+ transition: `all ${TRANSITIONS$5.fast}`,
6687
7364
  },
6688
7365
  trendingChipHover: {
6689
7366
  borderColor: 'var(--seekora-primary, #3b82f6)',
@@ -6697,7 +7374,7 @@ const styles$2 = {
6697
7374
  trendingRank: {
6698
7375
  width: '18px',
6699
7376
  height: '18px',
6700
- borderRadius: '50%',
7377
+ borderRadius: `${BORDER_RADIUS$8.full}px`,
6701
7378
  backgroundColor: 'var(--seekora-primary, #3b82f6)',
6702
7379
  color: 'white',
6703
7380
  fontSize: '10px',
@@ -6709,25 +7386,25 @@ const styles$2 = {
6709
7386
  removeButton: {
6710
7387
  padding: '4px',
6711
7388
  marginLeft: 'auto',
6712
- borderRadius: '4px',
7389
+ borderRadius: `${BORDER_RADIUS$8.sm}px`,
6713
7390
  border: 'none',
6714
7391
  background: 'transparent',
6715
7392
  cursor: 'pointer',
6716
7393
  color: 'var(--seekora-text-tertiary, #9ca3af)',
6717
7394
  opacity: 0,
6718
- transition: 'opacity 100ms ease',
7395
+ transition: `opacity ${TRANSITIONS$5.fast}`,
6719
7396
  },
6720
7397
  divider: {
6721
7398
  height: '1px',
6722
- backgroundColor: 'var(--seekora-border-color, #e5e7eb)',
7399
+ backgroundColor: 'var(--seekora-border-color, rgba(128,128,128,0.2))',
6723
7400
  margin: '4px 16px',
6724
7401
  },
6725
7402
  footer: {
6726
7403
  padding: '12px 16px',
6727
- borderTop: '1px solid var(--seekora-border-color, #e5e7eb)',
6728
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
7404
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7405
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
6729
7406
  fontSize: '12px',
6730
- color: 'var(--seekora-text-secondary, #6b7280)',
7407
+ color: 'var(--seekora-text-secondary, inherit)',
6731
7408
  },
6732
7409
  loadingOverlay: {
6733
7410
  position: 'absolute',
@@ -6735,12 +7412,12 @@ const styles$2 = {
6735
7412
  display: 'flex',
6736
7413
  alignItems: 'center',
6737
7414
  justifyContent: 'center',
6738
- backgroundColor: 'rgba(255, 255, 255, 0.8)',
7415
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
6739
7416
  },
6740
7417
  emptyState: {
6741
7418
  padding: '32px 16px',
6742
7419
  textAlign: 'center',
6743
- color: 'var(--seekora-text-secondary, #6b7280)',
7420
+ color: 'var(--seekora-text-secondary, inherit)',
6744
7421
  },
6745
7422
  highlight: {
6746
7423
  backgroundColor: 'var(--seekora-highlight-bg, #fef9c3)',
@@ -7035,20 +7712,30 @@ const RichQuerySuggestions = React.forwardRef(function RichQuerySuggestions(prop
7035
7712
  * - Rich product cards
7036
7713
  */
7037
7714
  // ============================================================================
7715
+ // Constants
7716
+ // ============================================================================
7717
+ const TRANSITIONS$4 = {
7718
+ fast: '150ms ease-in-out'};
7719
+ const BORDER_RADIUS$7 = {
7720
+ sm: 4,
7721
+ lg: 8,
7722
+ full: 9999,
7723
+ };
7724
+ // ============================================================================
7038
7725
  // Styles
7039
7726
  // ============================================================================
7040
7727
  const styles$1 = {
7041
7728
  container: {
7042
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
7043
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
7044
- borderRadius: 'var(--seekora-border-radius-lg, 12px)',
7729
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
7730
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7731
+ borderRadius: `var(--seekora-border-radius-lg, ${BORDER_RADIUS$7.lg * 1.5}px)`,
7045
7732
  boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
7046
7733
  overflow: 'hidden',
7047
7734
  },
7048
7735
  header: {
7049
7736
  padding: '12px 20px',
7050
- borderBottom: '1px solid var(--seekora-border-color, #e5e7eb)',
7051
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
7737
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7738
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
7052
7739
  },
7053
7740
  content: {
7054
7741
  display: 'flex',
@@ -7058,13 +7745,13 @@ const styles$1 = {
7058
7745
  flexDirection: 'column',
7059
7746
  },
7060
7747
  suggestionsColumn: {
7061
- borderRight: '1px solid var(--seekora-border-color, #e5e7eb)',
7748
+ borderRight: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7062
7749
  overflowY: 'auto',
7063
7750
  },
7064
7751
  productsColumn: {
7065
7752
  flex: 1,
7066
7753
  overflowY: 'auto',
7067
- backgroundColor: 'var(--seekora-bg-secondary, #fafafa)',
7754
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
7068
7755
  },
7069
7756
  section: {
7070
7757
  padding: '12px 0',
@@ -7095,7 +7782,7 @@ const styles$1 = {
7095
7782
  alignItems: 'center',
7096
7783
  padding: '10px 20px',
7097
7784
  cursor: 'pointer',
7098
- transition: 'background-color 100ms ease',
7785
+ transition: `background-color ${TRANSITIONS$4.fast}`,
7099
7786
  gap: '12px',
7100
7787
  },
7101
7788
  suggestionItemActive: {
@@ -7110,7 +7797,7 @@ const styles$1 = {
7110
7797
  suggestionText: {
7111
7798
  flex: 1,
7112
7799
  fontSize: '14px',
7113
- color: 'var(--seekora-text-primary, #111827)',
7800
+ color: 'var(--seekora-text-primary, inherit)',
7114
7801
  fontWeight: 500,
7115
7802
  overflow: 'hidden',
7116
7803
  textOverflow: 'ellipsis',
@@ -7134,7 +7821,7 @@ const styles$1 = {
7134
7821
  display: 'flex',
7135
7822
  gap: '4px',
7136
7823
  padding: '12px 20px',
7137
- borderBottom: '1px solid var(--seekora-border-color, #e5e7eb)',
7824
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7138
7825
  overflowX: 'auto',
7139
7826
  },
7140
7827
  tab: {
@@ -7144,13 +7831,13 @@ const styles$1 = {
7144
7831
  padding: '8px 16px',
7145
7832
  fontSize: '13px',
7146
7833
  fontWeight: 500,
7147
- color: 'var(--seekora-text-secondary, #6b7280)',
7834
+ color: 'var(--seekora-text-secondary, inherit)',
7148
7835
  backgroundColor: 'transparent',
7149
7836
  border: '1px solid transparent',
7150
- borderRadius: '20px',
7837
+ borderRadius: `${BORDER_RADIUS$7.full}px`,
7151
7838
  cursor: 'pointer',
7152
7839
  whiteSpace: 'nowrap',
7153
- transition: 'all 150ms ease',
7840
+ transition: `all ${TRANSITIONS$4.fast}`,
7154
7841
  },
7155
7842
  tabActive: {
7156
7843
  color: 'var(--seekora-primary, #3b82f6)',
@@ -7161,8 +7848,8 @@ const styles$1 = {
7161
7848
  fontSize: '11px',
7162
7849
  fontWeight: 600,
7163
7850
  padding: '2px 6px',
7164
- borderRadius: '10px',
7165
- backgroundColor: 'var(--seekora-bg-tertiary, #e5e7eb)',
7851
+ borderRadius: `${BORDER_RADIUS$7.lg}px`,
7852
+ backgroundColor: 'var(--seekora-bg-tertiary, rgba(255, 255, 255, 0.1))',
7166
7853
  },
7167
7854
  tabCountActive: {
7168
7855
  backgroundColor: 'var(--seekora-primary, #3b82f6)',
@@ -7177,12 +7864,12 @@ const styles$1 = {
7177
7864
  productCard: {
7178
7865
  display: 'flex',
7179
7866
  flexDirection: 'column',
7180
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
7181
- borderRadius: '8px',
7867
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
7868
+ borderRadius: `${BORDER_RADIUS$7.lg}px`,
7182
7869
  overflow: 'hidden',
7183
7870
  cursor: 'pointer',
7184
- transition: 'transform 150ms ease, box-shadow 150ms ease',
7185
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
7871
+ transition: `transform ${TRANSITIONS$4.fast}, box-shadow ${TRANSITIONS$4.fast}`,
7872
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7186
7873
  },
7187
7874
  productCardHover: {
7188
7875
  transform: 'translateY(-2px)',
@@ -7200,7 +7887,7 @@ const styles$1 = {
7200
7887
  productTitle: {
7201
7888
  fontSize: '13px',
7202
7889
  fontWeight: 500,
7203
- color: 'var(--seekora-text-primary, #111827)',
7890
+ color: 'var(--seekora-text-primary, inherit)',
7204
7891
  margin: 0,
7205
7892
  overflow: 'hidden',
7206
7893
  textOverflow: 'ellipsis',
@@ -7228,12 +7915,12 @@ const styles$1 = {
7228
7915
  padding: '8px 14px',
7229
7916
  fontSize: '13px',
7230
7917
  fontWeight: 500,
7231
- color: 'var(--seekora-text-primary, #374151)',
7232
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
7233
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
7234
- borderRadius: '8px',
7918
+ color: 'var(--seekora-text-primary, inherit)',
7919
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
7920
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7921
+ borderRadius: `${BORDER_RADIUS$7.lg}px`,
7235
7922
  cursor: 'pointer',
7236
- transition: 'all 150ms ease',
7923
+ transition: `all ${TRANSITIONS$4.fast}`,
7237
7924
  },
7238
7925
  brandChipHover: {
7239
7926
  borderColor: 'var(--seekora-primary, #3b82f6)',
@@ -7242,25 +7929,25 @@ const styles$1 = {
7242
7929
  brandLogo: {
7243
7930
  width: '20px',
7244
7931
  height: '20px',
7245
- borderRadius: '4px',
7932
+ borderRadius: `${BORDER_RADIUS$7.sm}px`,
7246
7933
  objectFit: 'contain',
7247
7934
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
7248
7935
  },
7249
7936
  footer: {
7250
7937
  padding: '12px 20px',
7251
- borderTop: '1px solid var(--seekora-border-color, #e5e7eb)',
7252
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
7938
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
7939
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
7253
7940
  display: 'flex',
7254
7941
  alignItems: 'center',
7255
7942
  justifyContent: 'space-between',
7256
7943
  fontSize: '12px',
7257
- color: 'var(--seekora-text-secondary, #6b7280)',
7944
+ color: 'var(--seekora-text-secondary, inherit)',
7258
7945
  },
7259
7946
  highlight: {
7260
7947
  backgroundColor: 'var(--seekora-highlight-bg, #fef9c3)',
7261
7948
  fontWeight: 600,
7262
7949
  padding: '0 2px',
7263
- borderRadius: '2px',
7950
+ borderRadius: `${BORDER_RADIUS$7.sm / 2}px`,
7264
7951
  },
7265
7952
  };
7266
7953
  // ============================================================================
@@ -7784,8 +8471,8 @@ const styles = {
7784
8471
  transition: 'border-color 150ms ease, box-shadow 150ms ease',
7785
8472
  },
7786
8473
  inputWrapperFocused: {
7787
- borderColor: 'var(--seekora-primary, #3b82f6)',
7788
- boxShadow: '0 0 0 3px var(--seekora-primary-light, rgba(59, 130, 246, 0.1))',
8474
+ borderColor: 'var(--seekora-border-focus, var(--seekora-primary, #3b82f6))',
8475
+ boxShadow: '0 0 0 3px var(--seekora-border-focus-alpha, var(--seekora-primary-light, rgba(59, 130, 246, 0.1)))',
7789
8476
  },
7790
8477
  input: {
7791
8478
  flex: 1,
@@ -7828,7 +8515,7 @@ const styles = {
7828
8515
  margin: '4px',
7829
8516
  border: 'none',
7830
8517
  backgroundColor: 'var(--seekora-primary, #3b82f6)',
7831
- color: 'white',
8518
+ color: 'var(--seekora-primary-text, white)',
7832
8519
  borderRadius: 'var(--seekora-border-radius, 6px)',
7833
8520
  fontSize: '14px',
7834
8521
  fontWeight: 600,
@@ -8269,6 +8956,13 @@ function SuggestionsProvider({ children, minQueryLength = 1, debounceMs = 200, m
8269
8956
  * Single input bound to suggestions context: query, setQuery, focus opens dropdown,
8270
8957
  * keydown ArrowUp/Down/Enter/Escape delegates to context. Overridable via className/style.
8271
8958
  */
8959
+ const SPACING$3 = {
8960
+ sm: 8,
8961
+ md: 12};
8962
+ const TRANSITIONS$3 = {
8963
+ fast: '150ms ease-in-out'};
8964
+ const BORDER_RADIUS$6 = {
8965
+ md: 6};
8272
8966
  const defaultStyles = {
8273
8967
  position: 'relative',
8274
8968
  width: '100%',
@@ -8276,22 +8970,23 @@ const defaultStyles = {
8276
8970
  const inputWrapperStyles = {
8277
8971
  display: 'flex',
8278
8972
  alignItems: 'center',
8279
- gap: '8px',
8280
- padding: '8px 12px',
8281
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
8282
- borderRadius: 'var(--seekora-border-radius, 6px)',
8283
- backgroundColor: 'var(--seekora-bg-surface, #fff)',
8284
- transition: 'border-color 150ms ease, box-shadow 150ms ease',
8973
+ gap: `${SPACING$3.sm}px`,
8974
+ padding: `${SPACING$3.sm}px ${SPACING$3.md}px`,
8975
+ border: '1px solid var(--seekora-border-color, rgba(0,0,0,0.1))',
8976
+ borderRadius: `var(--seekora-border-radius, ${BORDER_RADIUS$6.md}px)`,
8977
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
8978
+ transition: `border-color ${TRANSITIONS$3.fast}, box-shadow ${TRANSITIONS$3.fast}`,
8979
+ boxSizing: 'border-box',
8285
8980
  };
8286
8981
  const inputStyles = {
8287
8982
  flex: 1,
8288
8983
  minWidth: 0,
8289
- padding: '8px 0',
8984
+ padding: `${SPACING$3.sm}px 0`,
8290
8985
  border: 'none',
8291
8986
  outline: 'none',
8292
8987
  backgroundColor: 'transparent',
8293
8988
  fontSize: 'inherit',
8294
- color: 'var(--seekora-text-primary, #111827)',
8989
+ color: 'var(--seekora-text-primary, inherit)',
8295
8990
  fontFamily: 'inherit',
8296
8991
  };
8297
8992
  function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearButton = true, closeOnBlur = true, leftIcon, className, style, inputClassName, inputStyle, ariaLabel = 'Search', }) {
@@ -8340,7 +9035,7 @@ function SearchInput({ placeholder = 'Search...', autoFocus = false, showClearBu
8340
9035
  leftIcon ? (React.createElement("span", { className: "seekora-suggestions-input-left-icon", style: { display: 'flex', flexShrink: 0, color: 'var(--seekora-text-secondary, #6b7280)' } }, leftIcon)) : null,
8341
9036
  React.createElement("input", { ref: inputRef, type: "text", value: query, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, placeholder: placeholder, autoFocus: autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, "aria-label": ariaLabel, "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-autocomplete": "list", role: "combobox", className: clsx('seekora-suggestions-input', inputClassName), style: { ...inputStyles, ...inputStyle } }),
8342
9037
  showClearButton && query ? (React.createElement("button", { type: "button", onClick: handleClear, className: "seekora-suggestions-input-clear", "aria-label": "Clear search", style: {
8343
- padding: 4,
9038
+ padding: 8,
8344
9039
  border: 'none',
8345
9040
  background: 'transparent',
8346
9041
  cursor: 'pointer',
@@ -8362,7 +9057,12 @@ function ClearIcon() {
8362
9057
  * Shows when isOpen; handles click-outside and Escape to close. Children = any composition
8363
9058
  * of SuggestionList, ProductGrid, etc. Position and z-index configurable.
8364
9059
  */
8365
- function DropdownPanel({ children, position = 'absolute', top = '100%', left = 0, right, width = '100%', maxHeight = '80vh', zIndex = 1000, className, style, closeOnClickOutside = true, closeOnEscape = true, }) {
9060
+ const BORDER_RADIUS$5 = {
9061
+ md: 6};
9062
+ // Z-index scale for consistent layering
9063
+ const Z_INDEX = {
9064
+ dropdown: 100};
9065
+ function DropdownPanel({ children, position = 'absolute', top = '100%', left = 0, right, width = '100%', maxHeight = '80vh', zIndex = Z_INDEX.dropdown, className, style, closeOnClickOutside = true, closeOnEscape = true, }) {
8366
9066
  const { isOpen, close } = useSuggestionsContext();
8367
9067
  const panelRef = React.useRef(null);
8368
9068
  React.useEffect(() => {
@@ -8401,7 +9101,7 @@ function DropdownPanel({ children, position = 'absolute', top = '100%', left = 0
8401
9101
  overflow: 'auto',
8402
9102
  backgroundColor: 'var(--seekora-bg-surface, #fff)',
8403
9103
  border: '1px solid var(--seekora-border-color, #e5e7eb)',
8404
- borderRadius: 'var(--seekora-border-radius, 6px)',
9104
+ borderRadius: `var(--seekora-border-radius, ${BORDER_RADIUS$5.md}px)`,
8405
9105
  boxShadow: 'var(--seekora-shadow-lg, 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05))',
8406
9106
  marginTop: 4,
8407
9107
  };
@@ -8492,6 +9192,9 @@ const defaultItemStyle = {
8492
9192
  backgroundColor: 'transparent',
8493
9193
  color: 'var(--seekora-text-primary, #111827)',
8494
9194
  transition: 'background-color 120ms ease',
9195
+ overflow: 'hidden',
9196
+ textOverflow: 'ellipsis',
9197
+ whiteSpace: 'nowrap',
8495
9198
  };
8496
9199
  function SuggestionItem({ suggestion, index, isActive, onSelect, className, style, enableHighlightMarkup = true, highlightMarkupOptions, renderHighlight, }) {
8497
9200
  const displayText = suggestion.highlightedQuery ?? suggestion.query;
@@ -8676,8 +9379,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8676
9379
  backgroundRepeat: 'no-repeat',
8677
9380
  border: '2px solid var(--seekora-border-color, #e5e7eb)',
8678
9381
  borderRadius: 8,
8679
- boxShadow: '0 8px 24px rgba(0,0,0,0.2)',
8680
- backgroundColor: '#fff',
9382
+ boxShadow: 'var(--seekora-zoom-panel-shadow, 0 8px 24px rgba(0,0,0,0.2))',
9383
+ backgroundColor: 'var(--seekora-zoom-panel-bg, #fff)',
8681
9384
  pointerEvents: 'none',
8682
9385
  zIndex: 9998,
8683
9386
  };
@@ -8692,9 +9395,9 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8692
9395
  height: lensSize,
8693
9396
  left: cursorPos.x - lensSize / 2,
8694
9397
  top: cursorPos.y - lensSize / 2,
8695
- border: '2px solid rgba(255,255,255,0.8)',
9398
+ border: 'var(--seekora-lens-border, 2px solid rgba(255,255,255,0.8))',
8696
9399
  borderRadius: '50%',
8697
- boxShadow: '0 0 0 1px rgba(0,0,0,0.3), inset 0 0 0 1px rgba(0,0,0,0.3)',
9400
+ boxShadow: 'var(--seekora-lens-shadow, 0 0 0 1px rgba(0,0,0,0.3), inset 0 0 0 1px rgba(0,0,0,0.3))',
8698
9401
  pointerEvents: 'none',
8699
9402
  overflow: 'hidden',
8700
9403
  zIndex: 100,
@@ -8724,8 +9427,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8724
9427
  width: 32,
8725
9428
  height: 32,
8726
9429
  borderRadius: '50%',
8727
- backgroundColor: 'rgba(0,0,0,0.6)',
8728
- color: '#fff',
9430
+ backgroundColor: 'var(--seekora-zoom-indicator-bg, rgba(0,0,0,0.6))',
9431
+ color: 'var(--seekora-zoom-indicator-text, #fff)',
8729
9432
  display: 'flex',
8730
9433
  alignItems: 'center',
8731
9434
  justifyContent: 'center',
@@ -8742,8 +9445,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8742
9445
  top: cursorPos.y - 75,
8743
9446
  width: 150,
8744
9447
  height: 150,
8745
- border: '2px solid rgba(0,0,0,0.3)',
8746
- backgroundColor: 'rgba(255,255,255,0.1)',
9448
+ border: 'var(--seekora-hover-area-border, 2px solid rgba(0,0,0,0.3))',
9449
+ backgroundColor: 'var(--seekora-hover-area-bg, rgba(255,255,255,0.1))',
8747
9450
  pointerEvents: 'none',
8748
9451
  zIndex: 50,
8749
9452
  } })),
@@ -8754,7 +9457,7 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8754
9457
  left: 0,
8755
9458
  right: 0,
8756
9459
  bottom: 0,
8757
- backgroundColor: 'rgba(0,0,0,0.95)',
9460
+ backgroundColor: 'var(--seekora-lightbox-bg, rgba(0,0,0,0.95))',
8758
9461
  zIndex: 9999,
8759
9462
  display: 'flex',
8760
9463
  alignItems: 'center',
@@ -8770,8 +9473,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8770
9473
  height: 44,
8771
9474
  borderRadius: '50%',
8772
9475
  border: 'none',
8773
- backgroundColor: 'rgba(255,255,255,0.2)',
8774
- color: '#fff',
9476
+ backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
9477
+ color: 'var(--seekora-lightbox-btn-text, #fff)',
8775
9478
  fontSize: '1.5rem',
8776
9479
  cursor: 'pointer',
8777
9480
  display: 'flex',
@@ -8783,9 +9486,9 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8783
9486
  e.stopPropagation();
8784
9487
  closeLightbox();
8785
9488
  }, onMouseEnter: (e) => {
8786
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
9489
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
8787
9490
  }, onMouseLeave: (e) => {
8788
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
9491
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
8789
9492
  } }, "\u2715"),
8790
9493
  hasMultipleImages && (React.createElement(React.Fragment, null,
8791
9494
  React.createElement("button", { type: "button", "aria-label": "Previous image", style: {
@@ -8797,8 +9500,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8797
9500
  height: 56,
8798
9501
  borderRadius: '50%',
8799
9502
  border: 'none',
8800
- backgroundColor: 'rgba(255,255,255,0.2)',
8801
- color: '#fff',
9503
+ backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
9504
+ color: 'var(--seekora-lightbox-btn-text, #fff)',
8802
9505
  fontSize: '2rem',
8803
9506
  fontWeight: 'bold',
8804
9507
  cursor: 'pointer',
@@ -8811,9 +9514,9 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8811
9514
  e.stopPropagation();
8812
9515
  goToPrev();
8813
9516
  }, onMouseEnter: (e) => {
8814
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
9517
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
8815
9518
  }, onMouseLeave: (e) => {
8816
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
9519
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
8817
9520
  } }, "\u2039"),
8818
9521
  React.createElement("button", { type: "button", "aria-label": "Next image", style: {
8819
9522
  position: 'absolute',
@@ -8824,8 +9527,8 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8824
9527
  height: 56,
8825
9528
  borderRadius: '50%',
8826
9529
  border: 'none',
8827
- backgroundColor: 'rgba(255,255,255,0.2)',
8828
- color: '#fff',
9530
+ backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
9531
+ color: 'var(--seekora-lightbox-btn-text, #fff)',
8829
9532
  fontSize: '2rem',
8830
9533
  fontWeight: 'bold',
8831
9534
  cursor: 'pointer',
@@ -8838,9 +9541,9 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8838
9541
  e.stopPropagation();
8839
9542
  goToNext();
8840
9543
  }, onMouseEnter: (e) => {
8841
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
9544
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
8842
9545
  }, onMouseLeave: (e) => {
8843
- e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
9546
+ e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
8844
9547
  } }, "\u203A"))),
8845
9548
  React.createElement("img", { src: allImages[lightboxIndex], alt: alt, style: {
8846
9549
  maxWidth: '90%',
@@ -8866,7 +9569,7 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8866
9569
  width: 60,
8867
9570
  height: 60,
8868
9571
  padding: 0,
8869
- border: i === lightboxIndex ? '3px solid #fff' : '2px solid rgba(255,255,255,0.3)',
9572
+ border: i === lightboxIndex ? 'var(--seekora-lightbox-thumb-border-active, 3px solid #fff)' : 'var(--seekora-lightbox-thumb-border, 2px solid rgba(255,255,255,0.3))',
8870
9573
  borderRadius: 4,
8871
9574
  overflow: 'hidden',
8872
9575
  cursor: 'pointer',
@@ -8882,10 +9585,10 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8882
9585
  } },
8883
9586
  React.createElement("img", { src: img, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover' } }))))),
8884
9587
  React.createElement("div", { style: {
8885
- color: 'rgba(255,255,255,0.9)',
9588
+ color: 'var(--seekora-lightbox-counter-text, rgba(255,255,255,0.9))',
8886
9589
  fontSize: '0.875rem',
8887
9590
  textAlign: 'center',
8888
- backgroundColor: 'rgba(0,0,0,0.5)',
9591
+ backgroundColor: 'var(--seekora-lightbox-counter-bg, rgba(0,0,0,0.5))',
8889
9592
  padding: '4px 12px',
8890
9593
  borderRadius: 12,
8891
9594
  } },
@@ -8897,10 +9600,10 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8897
9600
  top: 20,
8898
9601
  left: '50%',
8899
9602
  transform: 'translateX(-50%)',
8900
- color: 'rgba(255,255,255,0.7)',
9603
+ color: 'var(--seekora-lightbox-instructions-text, rgba(255,255,255,0.7))',
8901
9604
  fontSize: '0.875rem',
8902
9605
  textAlign: 'center',
8903
- backgroundColor: 'rgba(0,0,0,0.5)',
9606
+ backgroundColor: 'var(--seekora-lightbox-instructions-bg, rgba(0,0,0,0.5))',
8904
9607
  padding: '8px 16px',
8905
9608
  borderRadius: 12,
8906
9609
  } }, hasMultipleImages ? 'Use arrow keys or click thumbnails to navigate • ESC to close' : 'Click outside or press ESC to close')))));
@@ -8914,10 +9617,13 @@ function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, className, s
8914
9617
  */
8915
9618
  const imgBaseStyle = {
8916
9619
  width: '100%',
9620
+ height: 'auto',
8917
9621
  aspectRatio: '1',
8918
9622
  objectFit: 'cover',
8919
9623
  borderRadius: 4,
8920
9624
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
9625
+ display: 'block',
9626
+ overflow: 'hidden',
8921
9627
  };
8922
9628
  function ImageDisplay({ images, variant = 'single', alt = '', className, style, carouselAutoplay = false, carouselIntervalMs = 4000, enableZoom = false, zoomMode = 'both', zoomLevel = 2.5, showDots = true, }) {
8923
9629
  const [index, setIndex] = React.useState(0);
@@ -8960,8 +9666,8 @@ function ImageDisplay({ images, variant = 'single', alt = '', className, style,
8960
9666
  return (React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-carousel', className), style: { position: 'relative', ...style } },
8961
9667
  mainImage,
8962
9668
  safeImages.length > 1 && (React.createElement(React.Fragment, null,
8963
- React.createElement("button", { type: "button", "aria-label": "Previous", className: "seekora-img-carousel-prev", style: arrowStyle(true), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(-1); }, onClick: (e) => e.stopPropagation(), onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,1)'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.9)'; } }, "\u2039"),
8964
- React.createElement("button", { type: "button", "aria-label": "Next", className: "seekora-img-carousel-next", style: arrowStyle(false), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(1); }, onClick: (e) => e.stopPropagation(), onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,1)'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.9)'; } }, "\u203A"),
9669
+ React.createElement("button", { type: "button", "aria-label": "Previous", className: "seekora-img-carousel-prev", style: arrowStyle(true), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(-1); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg-hover, rgba(255,255,255,1))'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg, rgba(255,255,255,0.9))'; } }, "\u2039"),
9670
+ React.createElement("button", { type: "button", "aria-label": "Next", className: "seekora-img-carousel-next", style: arrowStyle(false), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(1); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg-hover, rgba(255,255,255,1))'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg, rgba(255,255,255,0.9))'; } }, "\u203A"),
8965
9671
  showDots && (React.createElement("div", { className: "seekora-img-carousel-dots", style: {
8966
9672
  position: 'absolute',
8967
9673
  bottom: 8,
@@ -8970,16 +9676,16 @@ function ImageDisplay({ images, variant = 'single', alt = '', className, style,
8970
9676
  display: 'flex',
8971
9677
  gap: 6,
8972
9678
  padding: '6px 12px',
8973
- backgroundColor: 'rgba(0,0,0,0.5)',
9679
+ backgroundColor: 'var(--seekora-carousel-dots-bg, rgba(0,0,0,0.5))',
8974
9680
  borderRadius: 12,
8975
9681
  zIndex: 10,
8976
- } }, safeImages.map((_, i) => (React.createElement("button", { key: i, type: "button", "aria-label": `Go to image ${i + 1}`, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); }, onClick: (e) => { e.stopPropagation(); setIndex(i); }, style: {
9682
+ } }, safeImages.map((_, i) => (React.createElement("button", { key: i, type: "button", "aria-label": `Go to image ${i + 1}`, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, style: {
8977
9683
  width: 8,
8978
9684
  height: 8,
8979
9685
  borderRadius: '50%',
8980
9686
  border: 'none',
8981
9687
  padding: 0,
8982
- backgroundColor: i === index ? '#fff' : 'rgba(255,255,255,0.5)',
9688
+ backgroundColor: i === index ? 'var(--seekora-carousel-dot-active, #fff)' : 'var(--seekora-carousel-dot, rgba(255,255,255,0.5))',
8983
9689
  cursor: 'pointer',
8984
9690
  transition: 'all 150ms ease',
8985
9691
  } })))))))));
@@ -8989,7 +9695,7 @@ function ImageDisplay({ images, variant = 'single', alt = '', className, style,
8989
9695
  const mainImage = enableZoom ? (React.createElement(ImageZoom, { src: current, alt: alt, mode: zoomMode, zoomLevel: zoomLevel, images: safeImages, currentIndex: index, className: "seekora-img-thumb-main", style: thumbMainStyle })) : (React.createElement("img", { src: current, alt: alt, className: "seekora-img-thumb-main", style: thumbMainStyle, loading: "lazy" }));
8990
9696
  return (React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-thumbstrip', className), style: { display: 'flex', flexDirection: 'column', gap: 8, ...style } },
8991
9697
  mainImage,
8992
- React.createElement("div", { className: "seekora-img-thumbs", style: { display: 'flex', gap: 4, overflowX: 'auto', paddingBottom: 4 } }, safeImages.map((src, i) => (React.createElement("button", { type: "button", key: i, className: clsx('seekora-img-thumb', i === index && 'seekora-img-thumb--active'), style: { flexShrink: 0, width: 48, height: 48, padding: 0, border: i === index ? '2px solid var(--seekora-primary)' : '1px solid transparent', borderRadius: 4, overflow: 'hidden', cursor: 'pointer', background: 'none' }, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, onClick: (e) => e.stopPropagation() },
9698
+ React.createElement("div", { className: "seekora-img-thumbs", style: { display: 'flex', gap: 4, overflowX: 'auto', paddingBottom: 4 } }, safeImages.map((src, i) => (React.createElement("button", { type: "button", key: i, className: clsx('seekora-img-thumb', i === index && 'seekora-img-thumb--active'), style: { flexShrink: 0, width: 48, height: 48, padding: 0, border: i === index ? '2px solid var(--seekora-primary)' : '1px solid transparent', borderRadius: 4, overflow: 'hidden', cursor: 'pointer', background: 'none' }, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); } },
8993
9699
  React.createElement("img", { src: src, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover' } })))))));
8994
9700
  }
8995
9701
  return React.createElement("img", { src: current, alt: alt, className: clsx('seekora-img-display', className), style: { ...imgBaseStyle, ...style }, loading: "lazy" });
@@ -9004,8 +9710,8 @@ function arrowStyle(left) {
9004
9710
  height: 32,
9005
9711
  borderRadius: '50%',
9006
9712
  border: 'none',
9007
- backgroundColor: 'rgba(255, 255, 255, 0.9)',
9008
- color: '#111',
9713
+ backgroundColor: 'var(--seekora-carousel-btn-bg, rgba(255, 255, 255, 0.9))',
9714
+ color: 'var(--seekora-carousel-btn-text, #111)',
9009
9715
  fontSize: '1.25rem',
9010
9716
  fontWeight: 'bold',
9011
9717
  cursor: 'pointer',
@@ -9024,6 +9730,14 @@ function arrowStyle(left) {
9024
9730
  * Renders a set of action buttons for product cards. Can be positioned absolutely
9025
9731
  * over the image (on hover) or inline below the card content.
9026
9732
  */
9733
+ const SPACING$2 = {
9734
+ sm: 8};
9735
+ const TRANSITIONS$2 = {
9736
+ fast: '150ms ease-in-out'};
9737
+ const BORDER_RADIUS$4 = {
9738
+ md: 6};
9739
+ const SHADOWS = {
9740
+ md: '0 2px 4px rgba(0,0,0,0.1)'};
9027
9741
  const DEFAULT_ICONS = {
9028
9742
  addToCart: '🛒',
9029
9743
  wishlist: '♡',
@@ -9039,8 +9753,8 @@ const DEFAULT_LABELS = {
9039
9753
  compare: 'Compare',
9040
9754
  };
9041
9755
  const BUTTON_SIZES = {
9042
- small: { width: 28, height: 28, fontSize: '0.75rem', iconSize: '1rem' },
9043
- medium: { width: 36, height: 36, fontSize: '0.875rem', iconSize: '1.25rem' },
9756
+ small: { width: 44, height: 44, fontSize: '0.75rem', iconSize: '1rem' },
9757
+ medium: { width: 44, height: 44, fontSize: '0.875rem', iconSize: '1.25rem' },
9044
9758
  large: { width: 44, height: 44, fontSize: '1rem', iconSize: '1.5rem' },
9045
9759
  };
9046
9760
  function ActionButtons({ buttons, layout = 'horizontal', position = 'inline', showLabels = false, size = 'medium', className, style, }) {
@@ -9049,11 +9763,11 @@ function ActionButtons({ buttons, layout = 'horizontal', position = 'inline', sh
9049
9763
  const containerStyle = {
9050
9764
  display: 'flex',
9051
9765
  flexDirection: layout === 'vertical' ? 'column' : 'row',
9052
- gap: 6,
9766
+ gap: SPACING$2.sm,
9053
9767
  ...(isOverlay ? {
9054
9768
  position: 'absolute',
9055
- ...(position === 'top-right' ? { top: 8, right: 8 } : {}),
9056
- ...(position === 'bottom-center' ? { bottom: 8, left: '50%', transform: 'translateX(-50%)' } : {}),
9769
+ ...(position === 'top-right' ? { top: SPACING$2.sm, right: SPACING$2.sm } : {}),
9770
+ ...(position === 'bottom-center' ? { bottom: SPACING$2.sm, left: '50%', transform: 'translateX(-50%)' } : {}),
9057
9771
  } : {}),
9058
9772
  ...style,
9059
9773
  };
@@ -9068,12 +9782,12 @@ function ActionButtons({ buttons, layout = 'horizontal', position = 'inline', sh
9068
9782
  fontSize: sizeConfig.fontSize,
9069
9783
  fontWeight: 500,
9070
9784
  border: 'none',
9071
- borderRadius: 6,
9072
- backgroundColor: 'var(--seekora-bg-surface, #fff)',
9073
- color: 'var(--seekora-text, #111827)',
9785
+ borderRadius: BORDER_RADIUS$4.md,
9786
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
9787
+ color: 'var(--seekora-text, inherit)',
9074
9788
  cursor: 'pointer',
9075
- transition: 'all 150ms ease',
9076
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
9789
+ transition: `all ${TRANSITIONS$2.fast}`,
9790
+ boxShadow: SHADOWS.md,
9077
9791
  };
9078
9792
  const handleClick = (btn, e) => {
9079
9793
  e.stopPropagation();
@@ -9102,6 +9816,11 @@ function ActionButtons({ buttons, layout = 'horizontal', position = 'inline', sh
9102
9816
  * optional description, image, url. Overridable via className/style. Use for
9103
9817
  * search results, section blocks, or any list; for e-commerce products use ProductCard.
9104
9818
  */
9819
+ const TRANSITIONS$1 = {
9820
+ fast: '150ms ease-in-out'};
9821
+ const BORDER_RADIUS$3 = {
9822
+ sm: 4,
9823
+ md: 6};
9105
9824
  const cardStyle$1 = {
9106
9825
  display: 'flex',
9107
9826
  flexDirection: 'column',
@@ -9109,19 +9828,21 @@ const cardStyle$1 = {
9109
9828
  padding: 8,
9110
9829
  cursor: 'pointer',
9111
9830
  border: 'none',
9112
- borderRadius: 'var(--seekora-border-radius, 6px)',
9831
+ borderRadius: `var(--seekora-border-radius, ${BORDER_RADIUS$3.md}px)`,
9113
9832
  backgroundColor: 'transparent',
9114
9833
  textAlign: 'left',
9115
9834
  fontSize: 'inherit',
9116
9835
  fontFamily: 'inherit',
9117
- transition: 'background-color 120ms ease',
9836
+ transition: `background-color ${TRANSITIONS$1.fast}`,
9118
9837
  };
9119
9838
  const imgStyle$1 = {
9120
9839
  width: '100%',
9121
- aspectRatio: '1',
9840
+ aspectRatio: 'var(--seekora-card-aspect-ratio, 1)',
9122
9841
  objectFit: 'cover',
9123
- borderRadius: 4,
9842
+ borderRadius: BORDER_RADIUS$3.sm,
9124
9843
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
9844
+ display: 'block',
9845
+ overflow: 'hidden',
9125
9846
  };
9126
9847
  function ItemCard({ item, position, onSelect, className, style, asLink = true, imageVariant = 'single', layout = 'vertical', actionButtons, actionButtonsPosition = 'overlay-top-right', showActionLabels = false, }) {
9127
9848
  const images = item.images?.length ? item.images : item.image ?? item.imageUrl ? [String(item.image ?? item.imageUrl)] : [];
@@ -9129,12 +9850,12 @@ function ItemCard({ item, position, onSelect, className, style, asLink = true, i
9129
9850
  const description = item.description ?? item.secondaryText;
9130
9851
  const href = item.url;
9131
9852
  const isHorizontal = layout === 'horizontal';
9132
- const imageBlock = images.length > 0 ? (React.createElement("div", { style: { position: 'relative', ...(isHorizontal ? { width: 80, flexShrink: 0 } : {}) } },
9853
+ const imageBlock = images.length > 0 ? (React.createElement("div", { style: { position: 'relative', overflow: 'hidden', borderRadius: 4, ...(isHorizontal ? { minWidth: 80, flexBasis: '20%', maxWidth: 120, flexShrink: 0 } : {}) } },
9133
9854
  React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: String(title), className: "seekora-item-card-image" }),
9134
- actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" })))) : (React.createElement("div", { className: "seekora-item-card-placeholder", style: { ...imgStyle$1, ...(isHorizontal ? { width: 80, height: 80, flexShrink: 0 } : {}) }, "aria-hidden": true }));
9855
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" })))) : (React.createElement("div", { className: "seekora-item-card-placeholder", style: { ...imgStyle$1, ...(isHorizontal ? { minWidth: 80, flexBasis: '20%', maxWidth: 120, height: 80, flexShrink: 0 } : {}) }, "aria-hidden": true }));
9135
9856
  const textBlock = (React.createElement("div", { style: isHorizontal ? { display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 0 } : undefined },
9136
- React.createElement("span", { className: "seekora-item-card-title", style: { fontSize: '0.875rem', fontWeight: 500 } }, String(title)),
9137
- description ? (React.createElement("span", { className: "seekora-item-card-description", style: { fontSize: '0.8125rem', color: 'var(--seekora-text-secondary, #6b7280)', lineHeight: 1.3 } }, String(description))) : null,
9857
+ React.createElement("span", { className: "seekora-item-card-title", style: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, String(title)),
9858
+ description ? (React.createElement("span", { className: "seekora-item-card-description", style: { fontSize: '0.8125rem', color: 'var(--seekora-text-secondary, #6b7280)', lineHeight: 1.3, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' } }, String(description))) : null,
9138
9859
  actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" }))));
9139
9860
  const content = isHorizontal ? (React.createElement("div", { style: { display: 'flex', gap: 12, alignItems: 'flex-start' } },
9140
9861
  imageBlock,
@@ -9165,11 +9886,12 @@ function ItemCard({ item, position, onSelect, className, style, asLink = true, i
9165
9886
  * or custom renderItem. Use for search hits, section blocks, docs, articles; for
9166
9887
  * product-only lists use ProductGrid.
9167
9888
  */
9889
+ const SPACING$1 = {
9890
+ md: 12};
9168
9891
  const defaultGridStyle = {
9169
9892
  display: 'grid',
9170
- gridTemplateColumns: 'repeat(var(--seekora-grid-cols, 4), minmax(0, 1fr))',
9171
- gap: 12,
9172
- padding: 12,
9893
+ gap: SPACING$1.md,
9894
+ padding: SPACING$1.md,
9173
9895
  };
9174
9896
  function toGenericItem(item, getItemId, getItemTitle, getItemImage, getItemDescription, getItemUrl) {
9175
9897
  return {
@@ -9766,19 +10488,24 @@ function PriceDisplay({ price, comparePrice, priceRange, currency = '$', currenc
9766
10488
  /**
9767
10489
  * BadgeList – renders product badges (sale, new, sold out, custom)
9768
10490
  */
10491
+ const SPACING = {
10492
+ xs: 4,
10493
+ sm: 8};
10494
+ const BORDER_RADIUS$2 = {
10495
+ sm: 4};
9769
10496
  const positionStyles = {
9770
- 'top-left': { position: 'absolute', top: 6, left: 6 },
9771
- 'top-right': { position: 'absolute', top: 6, right: 6 },
9772
- 'bottom-left': { position: 'absolute', bottom: 6, left: 6 },
9773
- 'bottom-right': { position: 'absolute', bottom: 6, right: 6 },
10497
+ 'top-left': { position: 'absolute', top: SPACING.sm, left: SPACING.sm },
10498
+ 'top-right': { position: 'absolute', top: SPACING.sm, right: SPACING.sm },
10499
+ 'bottom-left': { position: 'absolute', bottom: SPACING.sm, left: SPACING.sm },
10500
+ 'bottom-right': { position: 'absolute', bottom: SPACING.sm, right: SPACING.sm },
9774
10501
  inline: {},
9775
10502
  };
9776
10503
  const typeColors = {
9777
- sale: { bg: '#ef4444', text: '#fff' },
9778
- new: { bg: '#3b82f6', text: '#fff' },
9779
- soldOut: { bg: '#6b7280', text: '#fff' },
9780
- limited: { bg: '#f59e0b', text: '#fff' },
9781
- custom: { bg: '#111827', text: '#fff' },
10504
+ sale: { bg: 'var(--seekora-badge-sale-bg, #ef4444)', text: 'var(--seekora-badge-sale-text, #fff)' },
10505
+ new: { bg: 'var(--seekora-badge-new-bg, #3b82f6)', text: 'var(--seekora-badge-new-text, #fff)' },
10506
+ soldOut: { bg: 'var(--seekora-badge-soldout-bg, #6b7280)', text: 'var(--seekora-badge-soldout-text, #fff)' },
10507
+ limited: { bg: 'var(--seekora-badge-limited-bg, #f59e0b)', text: 'var(--seekora-badge-limited-text, #fff)' },
10508
+ custom: { bg: 'var(--seekora-badge-custom-bg, #111827)', text: 'var(--seekora-badge-custom-text, #fff)' },
9782
10509
  };
9783
10510
  function BadgeList({ badges, maxBadges, position = 'top-left', className, style, }) {
9784
10511
  if (!badges || badges.length === 0)
@@ -9787,8 +10514,8 @@ function BadgeList({ badges, maxBadges, position = 'top-left', className, style,
9787
10514
  return (React.createElement("div", { className: clsx('seekora-badge-list', className), style: {
9788
10515
  display: 'flex',
9789
10516
  flexWrap: 'wrap',
9790
- gap: 4,
9791
- zIndex: 1,
10517
+ gap: SPACING.xs,
10518
+ zIndex: 2,
9792
10519
  ...positionStyles[position],
9793
10520
  ...style,
9794
10521
  } }, visible.map((badge, i) => {
@@ -9796,10 +10523,10 @@ function BadgeList({ badges, maxBadges, position = 'top-left', className, style,
9796
10523
  return (React.createElement("span", { key: `${badge.text}-${i}`, className: clsx('seekora-badge', badge.type && `seekora-badge--${badge.type === 'soldOut' ? 'sold-out' : badge.type}`), style: {
9797
10524
  display: 'inline-block',
9798
10525
  padding: '2px 8px',
9799
- borderRadius: 4,
10526
+ borderRadius: BORDER_RADIUS$2.sm,
9800
10527
  fontSize: '0.6875rem',
9801
10528
  fontWeight: 600,
9802
- lineHeight: 1.4,
10529
+ lineHeight: 1.2,
9803
10530
  backgroundColor: badge.color ?? colors.bg,
9804
10531
  color: badge.textColor ?? colors.text,
9805
10532
  whiteSpace: 'nowrap',
@@ -10029,7 +10756,7 @@ function VariantSwatches({ options, visibleOptions, maxValues = 5, colorMap, sel
10029
10756
  outlineOffset: 2,
10030
10757
  cursor: onSwatchClick && isAvailable ? 'pointer' : 'not-allowed',
10031
10758
  flexShrink: 0,
10032
- boxShadow: isSelected ? '0 0 0 1px #fff' : 'none',
10759
+ boxShadow: isSelected ? 'var(--seekora-swatch-ring, 0 0 0 1px #fff)' : 'none',
10033
10760
  opacity: isAvailable ? 1 : 0.3,
10034
10761
  position: 'relative',
10035
10762
  }, onMouseEnter: () => isAvailable && onSwatchHover?.(option.name, value), onMouseDown: (e) => {
@@ -10046,7 +10773,7 @@ function VariantSwatches({ options, visibleOptions, maxValues = 5, colorMap, sel
10046
10773
  left: '-2px',
10047
10774
  right: '-2px',
10048
10775
  height: 1,
10049
- backgroundColor: '#ef4444',
10776
+ backgroundColor: 'var(--seekora-unavailable-line, #ef4444)',
10050
10777
  transform: 'translateY(-50%) rotate(-45deg)',
10051
10778
  } }))));
10052
10779
  }
@@ -10062,7 +10789,7 @@ function VariantSwatches({ options, visibleOptions, maxValues = 5, colorMap, sel
10062
10789
  ? 'var(--seekora-primary, #111827)'
10063
10790
  : 'transparent',
10064
10791
  color: isSelected
10065
- ? '#fff'
10792
+ ? 'var(--seekora-primary-text, #fff)'
10066
10793
  : 'var(--seekora-text-secondary, #6b7280)',
10067
10794
  cursor: onSwatchClick && isAvailable ? 'pointer' : 'not-allowed',
10068
10795
  whiteSpace: 'nowrap',
@@ -10098,17 +10825,21 @@ function VariantSwatches({ options, visibleOptions, maxValues = 5, colorMap, sel
10098
10825
  * Not exported from the package. Each layout renders the same product data
10099
10826
  * with different visual emphasis.
10100
10827
  */
10828
+ const BORDER_RADIUS$1 = {
10829
+ sm: 4};
10101
10830
  const imgPlaceholderStyle = {
10102
10831
  width: '100%',
10103
10832
  aspectRatio: '1',
10104
10833
  objectFit: 'cover',
10105
- borderRadius: 4,
10834
+ borderRadius: BORDER_RADIUS$1.sm,
10106
10835
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
10107
10836
  };
10108
10837
  function ImageBlock({ images, title, imageVariant, aspectRatio, enableZoom, zoomMode, zoomLevel }) {
10109
- const ar = aspectRatio ? aspectRatio.replace(':', '/') : '1';
10838
+ const ar = aspectRatio
10839
+ ? (aspectRatio.includes(':') ? aspectRatio.replace(':', '/') : aspectRatio)
10840
+ : '1';
10110
10841
  if (images.length > 0) {
10111
- return (React.createElement("div", { className: "seekora-product-card__image", style: { position: 'relative', overflow: 'hidden', borderRadius: 4 } },
10842
+ return (React.createElement("div", { className: "seekora-product-card__image", style: { position: 'relative', overflow: 'hidden', borderRadius: BORDER_RADIUS$1.sm } },
10112
10843
  React.createElement(ImageDisplay, { images: images, variant: images.length > 1 ? imageVariant : 'single', alt: title, className: "seekora-suggestions-product-card-image", style: { aspectRatio: ar }, enableZoom: enableZoom, zoomMode: zoomMode, zoomLevel: zoomLevel })));
10113
10844
  }
10114
10845
  return React.createElement("div", { className: "seekora-product-card__image seekora-suggestions-product-card-placeholder", style: { ...imgPlaceholderStyle, aspectRatio: ar }, "aria-hidden": true });
@@ -10117,7 +10848,7 @@ function ImageBlock({ images, title, imageVariant, aspectRatio, enableZoom, zoom
10117
10848
  function MinimalLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }) {
10118
10849
  return (React.createElement(React.Fragment, null,
10119
10850
  React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: displayConfig.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
10120
- React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
10851
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis' } }, title),
10121
10852
  price != null && !Number.isNaN(price) && (React.createElement("span", { className: "seekora-product-card__price seekora-suggestions-product-card-price", style: { fontSize: '0.875rem', color: 'var(--seekora-text-secondary, #6b7280)' } },
10122
10853
  product.currency ?? '$',
10123
10854
  price.toFixed(2)))));
@@ -10125,31 +10856,35 @@ function MinimalLayout({ images, title, price, product, imageVariant, displayCon
10125
10856
  /** standard: image, badges, brand, title, price + compare price, color swatches */
10126
10857
  function StandardLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
10127
10858
  const cfg = displayConfig;
10859
+ // Normalize position: 'overlay-*' positions render over image, everything else renders inline
10860
+ const isOverlayPosition = actionButtonsPosition?.startsWith('overlay');
10128
10861
  return (React.createElement(React.Fragment, null,
10129
10862
  React.createElement("div", { style: { position: 'relative' } },
10130
10863
  React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: cfg.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
10131
10864
  cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left", maxBadges: 2 })),
10132
- actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
10865
+ actionButtons && actionButtons.length > 0 && isOverlayPosition && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
10133
10866
  React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4 } },
10134
10867
  cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase', letterSpacing: '0.02em' } }, brand)),
10135
- React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
10868
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis' } }, title),
10136
10869
  React.createElement("div", { className: "seekora-product-card__price" },
10137
10870
  React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } })),
10138
10871
  cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
10139
- actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
10872
+ actionButtons && actionButtons.length > 0 && !isOverlayPosition && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
10140
10873
  }
10141
10874
  /** detailed: image, badges, brand, title, price + compare + discount, rating, all swatches, stock */
10142
10875
  function DetailedLayout({ images, title, price, comparePrice, brand, badges, priceRange, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
10143
10876
  const cfg = displayConfig;
10144
10877
  const available = product.available;
10878
+ // Normalize position: 'overlay-*' positions render over image, everything else renders inline
10879
+ const isOverlayPosition = actionButtonsPosition?.startsWith('overlay');
10145
10880
  return (React.createElement(React.Fragment, null,
10146
10881
  React.createElement("div", { style: { position: 'relative' } },
10147
10882
  React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: cfg.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
10148
10883
  cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left" })),
10149
- actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
10884
+ actionButtons && actionButtons.length > 0 && isOverlayPosition && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
10150
10885
  React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4 } },
10151
10886
  cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase', letterSpacing: '0.02em' } }, brand)),
10152
- React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
10887
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis' } }, title),
10153
10888
  cfg.showRating !== false && product.rating != null && (React.createElement(RatingDisplay, { rating: product.rating, reviewCount: product.reviewCount, variant: "compact", size: "small", showNumeric: false, showReviewCount: true, className: "seekora-product-card__rating" })),
10154
10889
  React.createElement("div", { className: "seekora-product-card__price" }, cfg.showPriceRange && priceRange ? (React.createElement(PriceDisplay, { priceRange: priceRange, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, style: { fontSize: '0.875rem' } })) : (React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } }))),
10155
10890
  cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
@@ -10157,7 +10892,7 @@ function DetailedLayout({ images, title, price, comparePrice, brand, badges, pri
10157
10892
  fontSize: '0.75rem',
10158
10893
  color: available ? 'var(--seekora-success, #22c55e)' : 'var(--seekora-error, #ef4444)',
10159
10894
  } }, available ? 'In Stock' : 'Out of Stock')),
10160
- actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
10895
+ actionButtons && actionButtons.length > 0 && !isOverlayPosition && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
10161
10896
  }
10162
10897
  /** compact: smaller image, 1-line title, price */
10163
10898
  function CompactLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }) {
@@ -10178,13 +10913,13 @@ function CompactLayout({ images, title, price, product, imageVariant, displayCon
10178
10913
  function HorizontalLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
10179
10914
  const cfg = displayConfig;
10180
10915
  return (React.createElement("div", { style: { display: 'flex', gap: 12, alignItems: 'flex-start' } },
10181
- React.createElement("div", { style: { position: 'relative', width: 80, flexShrink: 0 } },
10916
+ React.createElement("div", { style: { position: 'relative', minWidth: 80, flexBasis: '25%', maxWidth: 120, flexShrink: 0 } },
10182
10917
  React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: "1:1", enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
10183
10918
  cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left", maxBadges: 1 })),
10184
10919
  actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
10185
10920
  React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 0 } },
10186
10921
  cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase' } }, brand)),
10187
- React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
10922
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis' } }, title),
10188
10923
  React.createElement("div", { className: "seekora-product-card__price" },
10189
10924
  React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } })),
10190
10925
  cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues ?? 3, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
@@ -10197,6 +10932,11 @@ function HorizontalLayout({ images, title, price, comparePrice, brand, badges, o
10197
10932
  * Without displayConfig: renders the original minimal layout (image, title, price).
10198
10933
  * With displayConfig: renders layout variants (minimal, standard, detailed, compact, horizontal).
10199
10934
  */
10935
+ const TRANSITIONS = {
10936
+ fast: '150ms ease-in-out'};
10937
+ const BORDER_RADIUS = {
10938
+ sm: 4,
10939
+ md: 6};
10200
10940
  const cardStyle = {
10201
10941
  display: 'flex',
10202
10942
  flexDirection: 'column',
@@ -10204,19 +10944,19 @@ const cardStyle = {
10204
10944
  padding: 8,
10205
10945
  cursor: 'pointer',
10206
10946
  border: 'none',
10207
- borderRadius: 'var(--seekora-border-radius, 6px)',
10947
+ borderRadius: `var(--seekora-border-radius, ${BORDER_RADIUS.md}px)`,
10208
10948
  backgroundColor: 'transparent',
10209
10949
  textAlign: 'left',
10210
- transition: 'background-color 120ms ease',
10950
+ transition: `background-color ${TRANSITIONS.fast}`,
10211
10951
  };
10212
10952
  const imgStyle = {
10213
10953
  width: '100%',
10214
10954
  aspectRatio: '1',
10215
10955
  objectFit: 'cover',
10216
- borderRadius: 4,
10956
+ borderRadius: BORDER_RADIUS.sm,
10217
10957
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
10218
10958
  };
10219
- function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant = 'single', displayConfig, onVariantHover, onVariantClick, selectedVariants, asLink, actionButtons, actionButtonsPosition = 'overlay-top-right', showActionLabels = false, enableImageZoom = false, imageZoomMode = 'both', imageZoomLevel = 2.5, }) {
10959
+ function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant = 'single', displayConfig, onVariantHover, onVariantClick, selectedVariants, asLink, actionButtons, actionButtonsPosition = 'inline', showActionLabels = false, enableImageZoom = false, imageZoomMode = 'both', imageZoomLevel = 2.5, }) {
10220
10960
  // Find selected variant if selections are provided
10221
10961
  const selectedVariant = React.useMemo(() => {
10222
10962
  if (!selectedVariants || !product.options || !product.variants)
@@ -10261,9 +11001,11 @@ function ProductCard({ product, position, section, tabId, onSelect, className, s
10261
11001
  const price = effectivePrice;
10262
11002
  // If no displayConfig, render original minimal layout (backwards compat)
10263
11003
  if (!displayConfig) {
10264
- return (React.createElement("button", { type: "button", className: clsx('seekora-suggestions-product-card', className), style: { ...cardStyle, ...style }, onMouseDown: (e) => {
10265
- e.preventDefault();
10266
- onSelect();
11004
+ return (React.createElement("div", { role: "button", tabIndex: 0, className: clsx('seekora-suggestions-product-card', className), style: { ...cardStyle, ...style }, onClick: () => onSelect(), onKeyDown: (e) => {
11005
+ if (e.key === 'Enter' || e.key === ' ') {
11006
+ e.preventDefault();
11007
+ onSelect();
11008
+ }
10267
11009
  }, "data-position": position, "data-section": section, "data-tab-id": tabId },
10268
11010
  images.length > 0 ? (React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: title, className: "seekora-suggestions-product-card-image", enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel })) : (React.createElement("div", { className: "seekora-suggestions-product-card-placeholder", style: imgStyle, "aria-hidden": true })),
10269
11011
  React.createElement("span", { className: "seekora-suggestions-product-card-title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
@@ -10333,9 +11075,11 @@ function ProductCard({ product, position, section, tabId, onSelect, className, s
10333
11075
  }, "data-position": position, "data-section": section, "data-tab-id": tabId },
10334
11076
  React.createElement(LayoutComponent, { ...layoutProps })));
10335
11077
  }
10336
- return (React.createElement("button", { type: "button", className: rootClassName, style: rootStyle, onMouseDown: (e) => {
10337
- e.preventDefault();
10338
- onSelect();
11078
+ return (React.createElement("div", { role: "button", tabIndex: 0, className: rootClassName, style: rootStyle, onClick: () => onSelect(), onKeyDown: (e) => {
11079
+ if (e.key === 'Enter' || e.key === ' ') {
11080
+ e.preventDefault();
11081
+ onSelect();
11082
+ }
10339
11083
  }, "data-position": position, "data-section": section, "data-tab-id": tabId },
10340
11084
  React.createElement(LayoutComponent, { ...layoutProps })));
10341
11085
  }
@@ -10611,10 +11355,10 @@ function VariantSelector({ options, variants, selections, onSelectionChange, opt
10611
11355
  fontSize: '0.875rem',
10612
11356
  fontWeight: 600,
10613
11357
  marginBottom: 8,
10614
- color: 'var(--seekora-text-primary, #111827)',
11358
+ color: 'var(--seekora-text-primary, inherit)',
10615
11359
  } },
10616
11360
  option.name,
10617
- selected && (React.createElement("span", { style: { fontWeight: 400, marginLeft: 6, color: 'var(--seekora-text-secondary, #6b7280)' } }, selected))),
11361
+ selected && (React.createElement("span", { style: { fontWeight: 400, marginLeft: 6, color: 'var(--seekora-text-secondary, inherit)' } }, selected))),
10618
11362
  mode === 'dropdown' ? (React.createElement("select", { className: "seekora-variant-dropdown", value: selected ?? '', onChange: (e) => {
10619
11363
  e.stopPropagation();
10620
11364
  onSelectionChange(option.name, e.target.value);
@@ -10622,9 +11366,9 @@ function VariantSelector({ options, variants, selections, onSelectionChange, opt
10622
11366
  padding: '8px 12px',
10623
11367
  fontSize: '0.875rem',
10624
11368
  borderRadius: 6,
10625
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
10626
- backgroundColor: 'var(--seekora-bg-surface, #fff)',
10627
- color: 'var(--seekora-text-primary, #111827)',
11369
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
11370
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
11371
+ color: 'var(--seekora-text-primary, inherit)',
10628
11372
  cursor: 'pointer',
10629
11373
  minWidth: 120,
10630
11374
  } },
@@ -10658,7 +11402,7 @@ function VariantSelector({ options, variants, selections, onSelectionChange, opt
10658
11402
  backgroundColor: color,
10659
11403
  border: isActive
10660
11404
  ? '2px solid var(--seekora-primary, #111827)'
10661
- : '1px solid var(--seekora-border-color, #e5e7eb)',
11405
+ : '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
10662
11406
  outline: isActive ? '2px solid var(--seekora-primary, #111827)' : 'none',
10663
11407
  outlineOffset: 2,
10664
11408
  cursor: available ? 'pointer' : 'not-allowed',
@@ -10679,13 +11423,13 @@ function VariantSelector({ options, variants, selections, onSelectionChange, opt
10679
11423
  borderRadius: 6,
10680
11424
  border: isActive
10681
11425
  ? '2px solid var(--seekora-primary, #111827)'
10682
- : '1px solid var(--seekora-border-color, #e5e7eb)',
11426
+ : '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
10683
11427
  backgroundColor: isActive
10684
11428
  ? 'var(--seekora-primary, #111827)'
10685
- : 'var(--seekora-bg-surface, #fff)',
11429
+ : 'var(--seekora-bg-surface, transparent)',
10686
11430
  color: isActive
10687
- ? '#fff'
10688
- : 'var(--seekora-text-primary, #111827)',
11431
+ ? 'transparent'
11432
+ : 'var(--seekora-text-primary, inherit)',
10689
11433
  cursor: available ? 'pointer' : 'not-allowed',
10690
11434
  opacity: available ? 1 : 0.5,
10691
11435
  textDecoration: !available ? 'line-through' : 'none',
@@ -10904,7 +11648,7 @@ function extractTotal(response) {
10904
11648
  return Number(data.data.total_results);
10905
11649
  return 0;
10906
11650
  }
10907
- function SectionSearchProvider({ children, query, refinements = [], maxItems = 12, sortBy, enabled = true, sectionId, }) {
11651
+ function SectionSearchProvider({ children, query, refinements = [], maxItems = 12, sortBy, enabled = true, sectionId, searchOptions, }) {
10908
11652
  const { client } = useSearchContext();
10909
11653
  const [items, setItems] = React.useState([]);
10910
11654
  const [loading, setLoading] = React.useState(true);
@@ -10922,6 +11666,7 @@ function SectionSearchProvider({ children, query, refinements = [], maxItems = 1
10922
11666
  setLoading(true);
10923
11667
  setError(null);
10924
11668
  const options = {
11669
+ ...searchOptions,
10925
11670
  per_page: maxItems,
10926
11671
  page: 1,
10927
11672
  };
@@ -10949,7 +11694,7 @@ function SectionSearchProvider({ children, query, refinements = [], maxItems = 1
10949
11694
  return () => {
10950
11695
  cancelled = true;
10951
11696
  };
10952
- }, [client, enabled, query, maxItems, sortBy, refinements]);
11697
+ }, [client, enabled, query, maxItems, sortBy, refinements, searchOptions]);
10953
11698
  const trackClick = React.useCallback((item, position) => {
10954
11699
  if (!client?.trackEvent)
10955
11700
  return;
@@ -11014,9 +11759,9 @@ function SectionItemGrid({ columns = 4, maxItems = 12, className, style, showLoa
11014
11759
  * Uses ImageDisplay with configurable variant (carousel, thumbStrip, etc.).
11015
11760
  * For use on individual product page.
11016
11761
  */
11017
- function ProductGallery({ images, variant = 'thumbStrip', alt = 'Product', className, style, carouselAutoplay, carouselIntervalMs, }) {
11762
+ function ProductGallery({ images, variant = 'thumbStrip', alt = 'Product', className, style, carouselAutoplay, carouselIntervalMs, enableZoom, zoomMode, zoomLevel, }) {
11018
11763
  return (React.createElement("div", { className: clsx('seekora-product-gallery', className), style: style },
11019
- React.createElement(ImageDisplay, { images: images, variant: variant, alt: alt, carouselAutoplay: carouselAutoplay, carouselIntervalMs: carouselIntervalMs })));
11764
+ React.createElement(ImageDisplay, { images: images, variant: variant, alt: alt, carouselAutoplay: carouselAutoplay, carouselIntervalMs: carouselIntervalMs, enableZoom: enableZoom, zoomMode: zoomMode, zoomLevel: zoomLevel })));
11020
11765
  }
11021
11766
 
11022
11767
  /**
@@ -13320,8 +14065,8 @@ const createStyles$3 = (isMobile = false) => ({
13320
14065
  right: 0,
13321
14066
  bottom: isMobile ? 0 : 'auto',
13322
14067
  marginTop: isMobile ? 0 : '8px',
13323
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
13324
- color: 'var(--seekora-text-primary, #121212)',
14068
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
14069
+ color: 'var(--seekora-text-primary, inherit)',
13325
14070
  borderRadius: isMobile ? 0 : '16px',
13326
14071
  boxShadow: isMobile ? 'none' : '0 4px 30px rgba(0, 0, 0, 0.12)',
13327
14072
  overflow: 'hidden',
@@ -13339,14 +14084,14 @@ const createStyles$3 = (isMobile = false) => ({
13339
14084
  overflowY: 'auto',
13340
14085
  },
13341
14086
  leftPanel: {
13342
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
13343
- borderRight: isMobile ? 'none' : '1px solid var(--seekora-border-color, #e8e8e1)',
13344
- borderBottom: isMobile ? '1px solid var(--seekora-border-color, #e8e8e1)' : 'none',
14087
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
14088
+ borderRight: isMobile ? 'none' : '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
14089
+ borderBottom: isMobile ? '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))' : 'none',
13345
14090
  display: 'flex',
13346
14091
  flexDirection: 'column',
13347
14092
  },
13348
14093
  rightPanel: {
13349
- backgroundColor: 'var(--seekora-bg-secondary, #fafafa)',
14094
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
13350
14095
  padding: isMobile ? '16px' : '24px',
13351
14096
  display: 'flex',
13352
14097
  flexDirection: 'column',
@@ -13361,7 +14106,7 @@ const createStyles$3 = (isMobile = false) => ({
13361
14106
  display: 'flex',
13362
14107
  alignItems: 'center',
13363
14108
  justifyContent: 'space-between',
13364
- borderBottom: '1px solid var(--seekora-border-color, #e8e8e1)',
14109
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
13365
14110
  },
13366
14111
  sectionTitle: {
13367
14112
  fontSize: '11px',
@@ -13372,7 +14117,7 @@ const createStyles$3 = (isMobile = false) => ({
13372
14117
  },
13373
14118
  viewAllLink: {
13374
14119
  fontSize: '12px',
13375
- color: 'var(--seekora-text-primary, #121212)',
14120
+ color: 'var(--seekora-text-primary, inherit)',
13376
14121
  textDecoration: 'underline',
13377
14122
  cursor: 'pointer',
13378
14123
  },
@@ -13386,11 +14131,11 @@ const createStyles$3 = (isMobile = false) => ({
13386
14131
  minHeight: '48px',
13387
14132
  margin: '4px 8px',
13388
14133
  borderRadius: '10px',
13389
- color: 'var(--seekora-text-primary, #121212)',
14134
+ color: 'var(--seekora-text-primary, inherit)',
13390
14135
  },
13391
14136
  suggestionItemActive: {
13392
- backgroundColor: 'var(--seekora-bg-hover, #f5f5f5)',
13393
- color: 'var(--seekora-text-primary, #121212)',
14137
+ backgroundColor: 'var(--seekora-bg-hover, rgba(255, 255, 255, 0.1))',
14138
+ color: 'var(--seekora-text-primary, inherit)',
13394
14139
  },
13395
14140
  suggestionIcon: {
13396
14141
  display: 'flex',
@@ -13405,12 +14150,12 @@ const createStyles$3 = (isMobile = false) => ({
13405
14150
  },
13406
14151
  suggestionQuery: {
13407
14152
  fontSize: '14px',
13408
- color: 'var(--seekora-text-primary, #121212)',
14153
+ color: 'var(--seekora-text-primary, inherit)',
13409
14154
  fontWeight: 400,
13410
14155
  },
13411
14156
  suggestionMeta: {
13412
14157
  fontSize: '12px',
13413
- color: 'var(--seekora-text-secondary, #666)',
14158
+ color: 'var(--seekora-text-secondary, inherit)',
13414
14159
  marginTop: '2px',
13415
14160
  },
13416
14161
  suggestionArrow: {
@@ -13428,29 +14173,29 @@ const createStyles$3 = (isMobile = false) => ({
13428
14173
  display: 'grid',
13429
14174
  gridTemplateColumns: 'repeat(2, 1fr)',
13430
14175
  gap: '1px',
13431
- backgroundColor: 'var(--seekora-border-color, #e8e8e1)',
13432
- borderTop: '1px solid var(--seekora-border-color, #e8e8e1)',
14176
+ backgroundColor: 'var(--seekora-border-color, rgba(128,128,128,0.2))',
14177
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
13433
14178
  },
13434
14179
  collectionItem: {
13435
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
13436
- color: 'var(--seekora-text-primary, #121212)',
14180
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
14181
+ color: 'var(--seekora-text-primary, inherit)',
13437
14182
  padding: '16px 20px',
13438
14183
  cursor: 'pointer',
13439
14184
  transition: 'background-color 150ms',
13440
14185
  },
13441
14186
  collectionItemHover: {
13442
- backgroundColor: 'var(--seekora-bg-hover, #f0f0f0)',
13443
- color: 'var(--seekora-text-primary, #121212)',
14187
+ backgroundColor: 'var(--seekora-bg-hover, rgba(255, 255, 255, 0.1))',
14188
+ color: 'var(--seekora-text-primary, inherit)',
13444
14189
  },
13445
14190
  collectionName: {
13446
14191
  fontSize: '13px',
13447
14192
  fontWeight: 500,
13448
- color: 'var(--seekora-text-primary, #121212)',
14193
+ color: 'var(--seekora-text-primary, inherit)',
13449
14194
  marginBottom: '4px',
13450
14195
  },
13451
14196
  collectionCount: {
13452
14197
  fontSize: '11px',
13453
- color: 'var(--seekora-text-secondary, #666)',
14198
+ color: 'var(--seekora-text-secondary, inherit)',
13454
14199
  },
13455
14200
  heroProduct: {
13456
14201
  marginBottom: '24px',
@@ -13466,13 +14211,13 @@ const createStyles$3 = (isMobile = false) => ({
13466
14211
  heroTitle: {
13467
14212
  fontSize: '16px',
13468
14213
  fontWeight: 500,
13469
- color: 'var(--seekora-text-primary, #121212)',
14214
+ color: 'var(--seekora-text-primary, inherit)',
13470
14215
  marginBottom: '8px',
13471
14216
  lineHeight: 1.3,
13472
14217
  },
13473
14218
  heroBrand: {
13474
14219
  fontSize: '12px',
13475
- color: 'var(--seekora-text-secondary, #666)',
14220
+ color: 'var(--seekora-text-secondary, inherit)',
13476
14221
  marginBottom: '12px',
13477
14222
  textTransform: 'uppercase',
13478
14223
  letterSpacing: '0.05em',
@@ -13486,7 +14231,7 @@ const createStyles$3 = (isMobile = false) => ({
13486
14231
  heroPrice: {
13487
14232
  fontSize: '18px',
13488
14233
  fontWeight: 500,
13489
- color: 'var(--seekora-text-primary, #121212)',
14234
+ color: 'var(--seekora-text-primary, inherit)',
13490
14235
  },
13491
14236
  heroComparePrice: {
13492
14237
  fontSize: '14px',
@@ -13504,8 +14249,8 @@ const createStyles$3 = (isMobile = false) => ({
13504
14249
  heroButton: {
13505
14250
  width: '100%',
13506
14251
  padding: '14px 20px',
13507
- backgroundColor: 'var(--seekora-text-primary, #121212)',
13508
- color: 'var(--seekora-bg-surface, #ffffff)',
14252
+ backgroundColor: 'var(--seekora-text-primary, inherit)',
14253
+ color: 'var(--seekora-bg-surface, transparent)',
13509
14254
  border: 'none',
13510
14255
  borderRadius: '2px',
13511
14256
  fontSize: '13px',
@@ -13516,8 +14261,8 @@ const createStyles$3 = (isMobile = false) => ({
13516
14261
  transition: 'background-color 150ms',
13517
14262
  },
13518
14263
  heroButtonHover: {
13519
- backgroundColor: 'var(--seekora-text-secondary, #666666)',
13520
- color: 'var(--seekora-bg-surface, #ffffff)',
14264
+ backgroundColor: 'var(--seekora-text-secondary, inherit)',
14265
+ color: 'var(--seekora-bg-surface, transparent)',
13521
14266
  },
13522
14267
  productsScroll: {
13523
14268
  flex: 1,
@@ -13545,7 +14290,7 @@ const createStyles$3 = (isMobile = false) => ({
13545
14290
  },
13546
14291
  productTitle: {
13547
14292
  fontSize: '12px',
13548
- color: 'var(--seekora-text-primary, #121212)',
14293
+ color: 'var(--seekora-text-primary, inherit)',
13549
14294
  marginBottom: '4px',
13550
14295
  whiteSpace: 'nowrap',
13551
14296
  overflow: 'hidden',
@@ -13554,20 +14299,20 @@ const createStyles$3 = (isMobile = false) => ({
13554
14299
  productPrice: {
13555
14300
  fontSize: '12px',
13556
14301
  fontWeight: 500,
13557
- color: 'var(--seekora-text-primary, #121212)',
14302
+ color: 'var(--seekora-text-primary, inherit)',
13558
14303
  },
13559
14304
  footer: {
13560
14305
  padding: '12px 20px',
13561
- borderTop: '1px solid var(--seekora-border-color, #e8e8e1)',
13562
- backgroundColor: 'var(--seekora-bg-secondary, #fafafa)',
14306
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
14307
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
13563
14308
  display: 'flex',
13564
14309
  alignItems: 'center',
13565
14310
  justifyContent: 'space-between',
13566
14311
  fontSize: '11px',
13567
- color: 'var(--seekora-text-secondary, #666)',
14312
+ color: 'var(--seekora-text-secondary, inherit)',
13568
14313
  },
13569
14314
  footerLink: {
13570
- color: 'var(--seekora-text-primary, #121212)',
14315
+ color: 'var(--seekora-text-primary, inherit)',
13571
14316
  textDecoration: 'underline',
13572
14317
  cursor: 'pointer',
13573
14318
  },
@@ -13576,13 +14321,13 @@ const createStyles$3 = (isMobile = false) => ({
13576
14321
  alignItems: 'center',
13577
14322
  justifyContent: 'center',
13578
14323
  padding: '60px',
13579
- color: 'var(--seekora-text-secondary, #666)',
14324
+ color: 'var(--seekora-text-secondary, inherit)',
13580
14325
  },
13581
14326
  spinner: {
13582
14327
  width: '24px',
13583
14328
  height: '24px',
13584
- border: '2px solid var(--seekora-border-color, #e8e8e1)',
13585
- borderTopColor: 'var(--seekora-text-primary, #121212)',
14329
+ border: '2px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
14330
+ borderTopColor: 'var(--seekora-text-primary, inherit)',
13586
14331
  borderRadius: '50%',
13587
14332
  animation: 'seekora-spin 0.8s linear infinite',
13588
14333
  },
@@ -13773,7 +14518,7 @@ const createStyles$2 = () => ({
13773
14518
  left: 0,
13774
14519
  right: 0,
13775
14520
  bottom: 0,
13776
- backgroundColor: 'var(--seekora-bg-surface, #fff)',
14521
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
13777
14522
  borderRadius: '16px 16px 0 0',
13778
14523
  boxShadow: '0 -4px 20px rgba(0, 0, 0, 0.15)',
13779
14524
  fontFamily: 'var(--seekora-font-family, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif)',
@@ -13797,17 +14542,17 @@ const createStyles$2 = () => ({
13797
14542
  dragBar: {
13798
14543
  width: '36px',
13799
14544
  height: '5px',
13800
- backgroundColor: 'var(--seekora-border-color, #e0e0e0)',
14545
+ backgroundColor: 'var(--seekora-border-color, rgba(128,128,128,0.2))',
13801
14546
  borderRadius: '3px',
13802
14547
  },
13803
14548
  header: {
13804
14549
  padding: '0 16px 16px',
13805
- borderBottom: '1px solid var(--seekora-border-color, #f0f0f0)',
14550
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
13806
14551
  },
13807
14552
  searchContainer: {
13808
14553
  display: 'flex',
13809
14554
  alignItems: 'center',
13810
- backgroundColor: 'var(--seekora-bg-secondary, #f5f5f5)',
14555
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
13811
14556
  borderRadius: '12px',
13812
14557
  padding: '12px 16px',
13813
14558
  gap: '12px',
@@ -13823,7 +14568,7 @@ const createStyles$2 = () => ({
13823
14568
  border: 'none',
13824
14569
  background: 'transparent',
13825
14570
  fontSize: '17px',
13826
- color: 'var(--seekora-text-primary, #000)',
14571
+ color: 'var(--seekora-text-primary, inherit)',
13827
14572
  outline: 'none',
13828
14573
  },
13829
14574
  cancelBtn: {
@@ -13871,11 +14616,11 @@ const createStyles$2 = () => ({
13871
14616
  cursor: 'pointer',
13872
14617
  transition: 'background-color 100ms',
13873
14618
  minHeight: '56px', // Touch-friendly
13874
- color: 'var(--seekora-text-primary, #000)',
14619
+ color: 'var(--seekora-text-primary, inherit)',
13875
14620
  },
13876
14621
  itemActive: {
13877
- backgroundColor: 'var(--seekora-bg-hover, #f2f2f7)',
13878
- color: 'var(--seekora-text-primary, #000)',
14622
+ backgroundColor: 'var(--seekora-bg-hover, rgba(255, 255, 255, 0.1))',
14623
+ color: 'var(--seekora-text-primary, inherit)',
13879
14624
  },
13880
14625
  itemIcon: {
13881
14626
  width: '24px',
@@ -13897,14 +14642,14 @@ const createStyles$2 = () => ({
13897
14642
  },
13898
14643
  itemTitle: {
13899
14644
  fontSize: '17px',
13900
- color: 'var(--seekora-text-primary, #000)',
14645
+ color: 'var(--seekora-text-primary, inherit)',
13901
14646
  whiteSpace: 'nowrap',
13902
14647
  overflow: 'hidden',
13903
14648
  textOverflow: 'ellipsis',
13904
14649
  },
13905
14650
  itemSubtitle: {
13906
14651
  fontSize: '15px',
13907
- color: 'var(--seekora-text-secondary, #8e8e93)',
14652
+ color: 'var(--seekora-text-secondary, inherit)',
13908
14653
  marginTop: '2px',
13909
14654
  whiteSpace: 'nowrap',
13910
14655
  overflow: 'hidden',
@@ -13937,7 +14682,7 @@ const createStyles$2 = () => ({
13937
14682
  },
13938
14683
  productTitle: {
13939
14684
  fontSize: '15px',
13940
- color: 'var(--seekora-text-primary, #000)',
14685
+ color: 'var(--seekora-text-primary, inherit)',
13941
14686
  marginBottom: '4px',
13942
14687
  whiteSpace: 'nowrap',
13943
14688
  overflow: 'hidden',
@@ -13946,19 +14691,19 @@ const createStyles$2 = () => ({
13946
14691
  productPrice: {
13947
14692
  fontSize: '15px',
13948
14693
  fontWeight: 600,
13949
- color: 'var(--seekora-text-primary, #000)',
14694
+ color: 'var(--seekora-text-primary, inherit)',
13950
14695
  },
13951
14696
  footer: {
13952
14697
  padding: '12px 16px',
13953
14698
  paddingBottom: 'calc(12px + env(safe-area-inset-bottom, 0px))',
13954
- borderTop: '1px solid var(--seekora-border-color, #f0f0f0)',
13955
- backgroundColor: 'var(--seekora-bg-secondary, #f8f8f8)',
14699
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
14700
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
13956
14701
  },
13957
14702
  footerBtn: {
13958
14703
  width: '100%',
13959
14704
  padding: '16px',
13960
14705
  backgroundColor: 'var(--seekora-primary, #007aff)',
13961
- color: 'var(--seekora-text-inverse, #ffffff)',
14706
+ color: 'var(--seekora-text-inverse, transparent)',
13962
14707
  border: 'none',
13963
14708
  borderRadius: '12px',
13964
14709
  fontSize: '17px',
@@ -13970,12 +14715,12 @@ const createStyles$2 = () => ({
13970
14715
  alignItems: 'center',
13971
14716
  justifyContent: 'center',
13972
14717
  padding: '60px',
13973
- color: 'var(--seekora-text-secondary, #8e8e93)',
14718
+ color: 'var(--seekora-text-secondary, inherit)',
13974
14719
  },
13975
14720
  spinner: {
13976
14721
  width: '28px',
13977
14722
  height: '28px',
13978
- border: '3px solid var(--seekora-border-color, #e5e5ea)',
14723
+ border: '3px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
13979
14724
  borderTopColor: 'var(--seekora-primary, #007aff)',
13980
14725
  borderRadius: '50%',
13981
14726
  animation: 'seekora-spin 0.8s linear infinite',
@@ -13983,7 +14728,7 @@ const createStyles$2 = () => ({
13983
14728
  empty: {
13984
14729
  padding: '60px 20px',
13985
14730
  textAlign: 'center',
13986
- color: 'var(--seekora-text-secondary, #8e8e93)',
14731
+ color: 'var(--seekora-text-secondary, inherit)',
13987
14732
  fontSize: '17px',
13988
14733
  },
13989
14734
  emptyIcon: {
@@ -17448,6 +18193,7 @@ exports.CurrentRefinements = CurrentRefinements;
17448
18193
  exports.DocSearch = DocSearch;
17449
18194
  exports.DocSearchButton = DocSearchButton;
17450
18195
  exports.DropdownPanel = DropdownPanel;
18196
+ exports.FacetDropdown = FacetDropdown;
17451
18197
  exports.Facets = Facets;
17452
18198
  exports.FederatedDropdown = FederatedDropdown;
17453
18199
  exports.Fingerprint = Fingerprint;