@seekora-ai/ui-sdk-react 0.2.13 → 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 (117) hide show
  1. package/dist/components/CurrentRefinements.d.ts +22 -2
  2. package/dist/components/CurrentRefinements.d.ts.map +1 -1
  3. package/dist/components/CurrentRefinements.js +259 -47
  4. package/dist/components/FacetDropdown.d.ts +92 -0
  5. package/dist/components/FacetDropdown.d.ts.map +1 -0
  6. package/dist/components/FacetDropdown.js +374 -0
  7. package/dist/components/Facets.d.ts +56 -1
  8. package/dist/components/Facets.d.ts.map +1 -1
  9. package/dist/components/Facets.js +602 -41
  10. package/dist/components/FederatedDropdown.d.ts.map +1 -1
  11. package/dist/components/FederatedDropdown.js +45 -31
  12. package/dist/components/HierarchicalMenu.d.ts.map +1 -1
  13. package/dist/components/HierarchicalMenu.js +112 -4
  14. package/dist/components/Pagination.d.ts +47 -1
  15. package/dist/components/Pagination.d.ts.map +1 -1
  16. package/dist/components/Pagination.js +166 -28
  17. package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
  18. package/dist/components/QuerySuggestionsDropdown.js +32 -18
  19. package/dist/components/RangeInput.d.ts.map +1 -1
  20. package/dist/components/RangeInput.js +6 -6
  21. package/dist/components/RangeSlider.d.ts.map +1 -1
  22. package/dist/components/RangeSlider.js +101 -32
  23. package/dist/components/RichQuerySuggestions.d.ts +7 -0
  24. package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
  25. package/dist/components/RichQuerySuggestions.js +40 -26
  26. package/dist/components/SearchBar.d.ts +16 -0
  27. package/dist/components/SearchBar.d.ts.map +1 -1
  28. package/dist/components/SearchBar.js +139 -17
  29. package/dist/components/SearchBarWithSuggestions.js +3 -3
  30. package/dist/components/SearchLayout.d.ts.map +1 -1
  31. package/dist/components/SearchLayout.js +10 -1
  32. package/dist/components/SearchProvider.d.ts +8 -1
  33. package/dist/components/SearchProvider.d.ts.map +1 -1
  34. package/dist/components/SearchProvider.js +16 -4
  35. package/dist/components/SearchResults.d.ts +10 -0
  36. package/dist/components/SearchResults.d.ts.map +1 -1
  37. package/dist/components/SearchResults.js +46 -30
  38. package/dist/components/SortBy.d.ts +44 -4
  39. package/dist/components/SortBy.d.ts.map +1 -1
  40. package/dist/components/SortBy.js +154 -29
  41. package/dist/components/Stats.d.ts +14 -0
  42. package/dist/components/Stats.d.ts.map +1 -1
  43. package/dist/components/Stats.js +172 -23
  44. package/dist/components/primitives/ActionButtons.d.ts.map +1 -1
  45. package/dist/components/primitives/ActionButtons.js +34 -10
  46. package/dist/components/primitives/BadgeList.d.ts.map +1 -1
  47. package/dist/components/primitives/BadgeList.js +33 -13
  48. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -1
  49. package/dist/components/primitives/ImageDisplay.js +11 -8
  50. package/dist/components/primitives/ImageZoom.js +26 -26
  51. package/dist/components/primitives/VariantSelector.js +10 -10
  52. package/dist/components/primitives/VariantSwatches.js +3 -3
  53. package/dist/components/product-page/ProductGallery.d.ts +8 -1
  54. package/dist/components/product-page/ProductGallery.d.ts.map +1 -1
  55. package/dist/components/product-page/ProductGallery.js +2 -2
  56. package/dist/components/section-primitives/SectionSearchProvider.d.ts +3 -1
  57. package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -1
  58. package/dist/components/section-primitives/SectionSearchProvider.js +3 -2
  59. package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
  60. package/dist/components/suggestions/AmazonDropdown.js +2 -4
  61. package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
  62. package/dist/components/suggestions/GoogleDropdown.js +2 -6
  63. package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
  64. package/dist/components/suggestions/MinimalDropdown.js +2 -4
  65. package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
  66. package/dist/components/suggestions/MobileSheetDropdown.js +20 -22
  67. package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
  68. package/dist/components/suggestions/PinterestDropdown.js +2 -6
  69. package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
  70. package/dist/components/suggestions/ShopifyDropdown.js +39 -41
  71. package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
  72. package/dist/components/suggestions/SpotlightDropdown.js +2 -4
  73. package/dist/components/suggestions/utils.d.ts +10 -1
  74. package/dist/components/suggestions/utils.d.ts.map +1 -1
  75. package/dist/components/suggestions/utils.js +36 -0
  76. package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -1
  77. package/dist/components/suggestions-primitives/DropdownPanel.js +15 -2
  78. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -1
  79. package/dist/components/suggestions-primitives/ItemCard.js +21 -8
  80. package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -1
  81. package/dist/components/suggestions-primitives/ItemGrid.js +9 -3
  82. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -1
  83. package/dist/components/suggestions-primitives/ProductCard.js +25 -10
  84. package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -1
  85. package/dist/components/suggestions-primitives/ProductCardLayouts.js +24 -12
  86. package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -1
  87. package/dist/components/suggestions-primitives/SearchInput.js +28 -9
  88. package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -1
  89. package/dist/components/suggestions-primitives/SuggestionItem.js +3 -0
  90. package/dist/components/suggestions-primitives/highlightMarkup.d.ts +16 -4
  91. package/dist/components/suggestions-primitives/highlightMarkup.d.ts.map +1 -1
  92. package/dist/components/suggestions-primitives/highlightMarkup.js +42 -4
  93. package/dist/hooks/useClickTracking.d.ts +36 -0
  94. package/dist/hooks/useClickTracking.d.ts.map +1 -0
  95. package/dist/hooks/useClickTracking.js +96 -0
  96. package/dist/hooks/useExperiment.d.ts +25 -0
  97. package/dist/hooks/useExperiment.d.ts.map +1 -0
  98. package/dist/hooks/useExperiment.js +146 -0
  99. package/dist/hooks/useKeyboardNavigation.d.ts +51 -0
  100. package/dist/hooks/useKeyboardNavigation.d.ts.map +1 -0
  101. package/dist/hooks/useKeyboardNavigation.js +113 -0
  102. package/dist/hooks/useQuerySuggestions.d.ts.map +1 -1
  103. package/dist/hooks/useQuerySuggestions.js +19 -3
  104. package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -1
  105. package/dist/hooks/useQuerySuggestionsEnhanced.js +23 -6
  106. package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -1
  107. package/dist/hooks/useSuggestionsAnalytics.js +6 -1
  108. package/dist/index.d.ts +6 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +1 -0
  111. package/dist/index.umd.js +1 -1
  112. package/dist/src/index.d.ts +345 -19
  113. package/dist/src/index.esm.js +2869 -787
  114. package/dist/src/index.esm.js.map +1 -1
  115. package/dist/src/index.js +2868 -785
  116. package/dist/src/index.js.map +1 -1
  117. package/package.json +6 -6
@@ -4,18 +4,29 @@
4
4
  * Visual slider for numeric range filtering
5
5
  * Alternative to RangeInput for a more interactive UX
6
6
  */
7
- import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react';
7
+ import React, { useState, useCallback, useEffect, useRef } from 'react';
8
8
  import { useSearchContext } from './SearchProvider';
9
9
  import { useSearchState } from '../hooks/useSearchState';
10
10
  import { clsx } from 'clsx';
11
+ const SHADOWS = {
12
+ sm: '0 1px 2px rgba(0,0,0,0.05)',
13
+ md: '0 2px 4px rgba(0,0,0,0.1)',
14
+ lg: '0 4px 6px rgba(0,0,0,0.1)',
15
+ xl: '0 10px 15px rgba(0,0,0,0.1)',
16
+ };
11
17
  export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: currentMinProp, currentMax: currentMaxProp, onRangeChange, formatValue = (v) => v.toString(), className, style, theme: customTheme, showValues = true, syncWithState = true, debounceMs = 300, }) => {
12
18
  const { theme } = useSearchContext();
13
19
  const { refinements, addRefinement, removeRefinement } = useSearchState();
14
20
  const rangeSliderTheme = customTheme || {};
21
+ const thumbClass = rangeSliderTheme.thumb || 'seekora-range-slider__thumb';
15
22
  // Parse current range from StateManager
16
- const stateRange = useMemo(() => {
17
- if (!syncWithState)
18
- return { min: undefined, max: undefined };
23
+ // NOTE: computed every render (no useMemo) because the state manager mutates
24
+ // the refinements array in place — the reference never changes.
25
+ let stateRange;
26
+ if (!syncWithState) {
27
+ stateRange = { min: undefined, max: undefined };
28
+ }
29
+ else {
19
30
  let minVal;
20
31
  let maxVal;
21
32
  refinements.forEach(r => {
@@ -28,15 +39,17 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
28
39
  maxVal = parseFloat(maxMatch[1]);
29
40
  }
30
41
  });
31
- return { min: minVal, max: maxVal };
32
- }, [syncWithState, refinements, field]);
42
+ stateRange = { min: minVal, max: maxVal };
43
+ }
33
44
  const [internalMin, setInternalMin] = useState(currentMinProp ?? stateRange.min ?? min);
34
45
  const [internalMax, setInternalMax] = useState(currentMaxProp ?? stateRange.max ?? max);
35
- const [isDragging, setIsDragging] = useState(false);
46
+ const isDraggingRef = useRef(false);
36
47
  const debounceRef = useRef(null);
37
- // Sync with StateManager changes
48
+ const pendingMinRef = useRef(internalMin);
49
+ const pendingMaxRef = useRef(internalMax);
50
+ // Sync with StateManager changes (only when stateRange actually changes, not on drag)
38
51
  useEffect(() => {
39
- if (syncWithState && !isDragging) {
52
+ if (syncWithState && !isDraggingRef.current) {
40
53
  if (stateRange.min !== undefined)
41
54
  setInternalMin(stateRange.min);
42
55
  else
@@ -46,7 +59,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
46
59
  else
47
60
  setInternalMax(max);
48
61
  }
49
- }, [syncWithState, stateRange.min, stateRange.max, isDragging, min, max]);
62
+ }, [syncWithState, stateRange.min, stateRange.max, min, max]);
50
63
  // Update StateManager with range refinements
51
64
  const updateStateManager = useCallback((minVal, maxVal) => {
52
65
  if (!syncWithState)
@@ -57,24 +70,24 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
57
70
  removeRefinement(field, r.value, false);
58
71
  }
59
72
  });
60
- // Add new range refinements
61
- if (minVal > min) {
73
+ // Add new range refinements — trigger search on the last one added
74
+ const setMin = minVal > min;
75
+ const setMax = maxVal < max;
76
+ if (setMin && setMax) {
62
77
  addRefinement(field, `>=${minVal}`, false);
78
+ addRefinement(field, `<=${maxVal}`, true);
63
79
  }
64
- if (maxVal < max) {
65
- addRefinement(field, `<=${maxVal}`, minVal <= min); // Trigger search if only max is set
66
- }
67
- if (minVal > min && maxVal >= max) {
68
- // Trigger search after setting min
80
+ else if (setMin) {
69
81
  addRefinement(field, `>=${minVal}`, true);
70
82
  }
71
- else if (minVal > min || maxVal < max) {
72
- // If both are set, we need to trigger search
73
- // already triggered above
83
+ else if (setMax) {
84
+ addRefinement(field, `<=${maxVal}`, true);
74
85
  }
75
86
  }, [syncWithState, field, refinements, addRefinement, removeRefinement, min, max]);
76
- // Debounced update
87
+ // Debounced update (during drag only)
77
88
  const debouncedUpdate = useCallback((minVal, maxVal) => {
89
+ pendingMinRef.current = minVal;
90
+ pendingMaxRef.current = maxVal;
78
91
  if (debounceRef.current) {
79
92
  clearTimeout(debounceRef.current);
80
93
  }
@@ -89,19 +102,75 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
89
102
  const handleMinChange = (e) => {
90
103
  const value = Math.min(Number(e.target.value), internalMax - step);
91
104
  setInternalMin(value);
92
- setIsDragging(true);
105
+ isDraggingRef.current = true;
93
106
  debouncedUpdate(value, internalMax);
94
107
  };
95
108
  // Handle max slider change
96
109
  const handleMaxChange = (e) => {
97
110
  const value = Math.max(Number(e.target.value), internalMin + step);
98
111
  setInternalMax(value);
99
- setIsDragging(true);
112
+ isDraggingRef.current = true;
100
113
  debouncedUpdate(internalMin, value);
101
114
  };
102
- // Handle drag end
115
+ // Handle drag end — flush pending update immediately
103
116
  const handleDragEnd = () => {
104
- setIsDragging(false);
117
+ isDraggingRef.current = false;
118
+ // Cancel the debounce and commit immediately
119
+ if (debounceRef.current) {
120
+ clearTimeout(debounceRef.current);
121
+ debounceRef.current = null;
122
+ }
123
+ updateStateManager(pendingMinRef.current, pendingMaxRef.current);
124
+ if (onRangeChange) {
125
+ onRangeChange(pendingMinRef.current, pendingMaxRef.current);
126
+ }
127
+ };
128
+ // Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
129
+ const handleMinKeyDown = (e) => {
130
+ let newValue = null;
131
+ if (e.key === 'Home') {
132
+ e.preventDefault();
133
+ newValue = min;
134
+ }
135
+ else if (e.key === 'End') {
136
+ e.preventDefault();
137
+ newValue = internalMax - step;
138
+ }
139
+ else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
140
+ e.preventDefault();
141
+ newValue = Math.max(min, internalMin - step * 10);
142
+ }
143
+ else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
144
+ e.preventDefault();
145
+ newValue = Math.min(internalMax - step, internalMin + step * 10);
146
+ }
147
+ if (newValue !== null) {
148
+ setInternalMin(newValue);
149
+ debouncedUpdate(newValue, internalMax);
150
+ }
151
+ };
152
+ const handleMaxKeyDown = (e) => {
153
+ let newValue = null;
154
+ if (e.key === 'Home') {
155
+ e.preventDefault();
156
+ newValue = internalMin + step;
157
+ }
158
+ else if (e.key === 'End') {
159
+ e.preventDefault();
160
+ newValue = max;
161
+ }
162
+ else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
163
+ e.preventDefault();
164
+ newValue = Math.max(internalMin + step, internalMax - step * 10);
165
+ }
166
+ else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
167
+ e.preventDefault();
168
+ newValue = Math.min(max, internalMax + step * 10);
169
+ }
170
+ if (newValue !== null) {
171
+ setInternalMax(newValue);
172
+ debouncedUpdate(internalMin, newValue);
173
+ }
105
174
  };
106
175
  // Calculate filled track position
107
176
  const minPercent = ((internalMin - min) / (max - min)) * 100;
@@ -119,7 +188,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
119
188
  } }, label)),
120
189
  React.createElement("div", { className: rangeSliderTheme.slider, style: {
121
190
  position: 'relative',
122
- height: '40px',
191
+ minHeight: '40px',
123
192
  display: 'flex',
124
193
  alignItems: 'center',
125
194
  } },
@@ -138,7 +207,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
138
207
  backgroundColor: theme.colors.primary,
139
208
  borderRadius: '2px',
140
209
  } }),
141
- React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, className: rangeSliderTheme.thumb, style: {
210
+ React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMinKeyDown, tabIndex: 0, "aria-valuenow": internalMin, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
142
211
  position: 'absolute',
143
212
  width: '100%',
144
213
  height: '4px',
@@ -148,7 +217,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
148
217
  cursor: 'pointer',
149
218
  pointerEvents: 'none',
150
219
  }, "aria-label": `Minimum ${label || field}` }),
151
- React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, className: rangeSliderTheme.thumb, style: {
220
+ React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMax, onChange: handleMaxChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, onKeyDown: handleMaxKeyDown, tabIndex: 0, "aria-valuenow": internalMax, "aria-valuemin": min, "aria-valuemax": max, className: thumbClass, style: {
152
221
  position: 'absolute',
153
222
  width: '100%',
154
223
  height: '4px',
@@ -168,7 +237,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
168
237
  React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMin)),
169
238
  React.createElement("span", { className: rangeSliderTheme.value }, formatValue(internalMax)))),
170
239
  React.createElement("style", null, `
171
- .${rangeSliderTheme.thumb || 'seekora-range-slider__thumb'}::-webkit-slider-thumb {
240
+ .${thumbClass}::-webkit-slider-thumb {
172
241
  -webkit-appearance: none;
173
242
  appearance: none;
174
243
  width: 20px;
@@ -177,9 +246,9 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
177
246
  border-radius: 50%;
178
247
  cursor: pointer;
179
248
  pointer-events: all;
180
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
249
+ box-shadow: ${SHADOWS.md};
181
250
  }
182
- .${rangeSliderTheme.thumb || 'seekora-range-slider__thumb'}::-moz-range-thumb {
251
+ .${thumbClass}::-moz-range-thumb {
183
252
  width: 20px;
184
253
  height: 20px;
185
254
  background: ${theme.colors.primary};
@@ -187,7 +256,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
187
256
  cursor: pointer;
188
257
  pointer-events: all;
189
258
  border: none;
190
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
259
+ box-shadow: ${SHADOWS.md};
191
260
  }
192
261
  `)));
193
262
  };
@@ -71,6 +71,13 @@ export interface RichQuerySuggestionsProps extends QuerySuggestionsEventHandlers
71
71
  ariaLabel?: string;
72
72
  /** Analytics tags */
73
73
  analyticsTags?: string[];
74
+ /** Highlight options for query suggestions (passed to highlight rendering) */
75
+ highlightOptions?: {
76
+ highlightColor?: string;
77
+ highlightTextColor?: string;
78
+ highlightFontWeight?: string | number;
79
+ highlightStyle?: 'background' | 'underline' | 'bold' | 'color-only';
80
+ };
74
81
  }
75
82
  export interface RichQuerySuggestionsRef {
76
83
  getActiveIndex: () => number;
@@ -1 +1 @@
1
- {"version":3,"file":"RichQuerySuggestions.d.ts","sourceRoot":"","sources":["../../src/components/RichQuerySuggestions.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RichQuerySuggestions.d.ts","sourceRoot":"","sources":["../../src/components/RichQuerySuggestions.tsx"],"names":[],"mappings":"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"}
@@ -14,6 +14,20 @@ import React, { useState, useRef, useCallback, useMemo, forwardRef, useImperativ
14
14
  import { useSearchContext } from './SearchProvider';
15
15
  import { useQuerySuggestionsEnhanced } from '../hooks/useQuerySuggestionsEnhanced';
16
16
  import { clsx } from 'clsx';
17
+ // ============================================================================
18
+ // Constants
19
+ // ============================================================================
20
+ const TRANSITIONS = {
21
+ fast: '150ms ease-in-out',
22
+ normal: '200ms ease-in-out',
23
+ slow: '300ms ease-in-out',
24
+ };
25
+ const BORDER_RADIUS = {
26
+ sm: 4,
27
+ md: 6,
28
+ lg: 8,
29
+ full: 9999,
30
+ };
17
31
  // Default section order
18
32
  const DEFAULT_SECTIONS = [
19
33
  { id: 'recent', title: 'Recent Searches', maxItems: 5, enabled: true, order: 1 },
@@ -26,16 +40,16 @@ const DEFAULT_SECTIONS = [
26
40
  // ============================================================================
27
41
  const styles = {
28
42
  container: {
29
- backgroundColor: 'var(--seekora-bg-surface, #ffffff)',
30
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
31
- borderRadius: 'var(--seekora-border-radius-lg, 12px)',
43
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
44
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
45
+ borderRadius: `var(--seekora-border-radius-lg, ${BORDER_RADIUS.lg * 1.5}px)`,
32
46
  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))',
33
47
  overflow: 'hidden',
34
48
  },
35
49
  header: {
36
50
  padding: '12px 16px',
37
- borderBottom: '1px solid var(--seekora-border-color, #e5e7eb)',
38
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
51
+ borderBottom: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
52
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
39
53
  },
40
54
  content: {
41
55
  overflowY: 'auto',
@@ -70,7 +84,7 @@ const styles = {
70
84
  alignItems: 'flex-start',
71
85
  padding: '10px 16px',
72
86
  cursor: 'pointer',
73
- transition: 'background-color 100ms ease',
87
+ transition: `background-color ${TRANSITIONS.fast}`,
74
88
  gap: '12px',
75
89
  },
76
90
  itemActive: {
@@ -89,7 +103,7 @@ const styles = {
89
103
  },
90
104
  itemQuery: {
91
105
  fontSize: '14px',
92
- color: 'var(--seekora-text-primary, #111827)',
106
+ color: 'var(--seekora-text-primary, inherit)',
93
107
  fontWeight: 500,
94
108
  margin: 0,
95
109
  overflow: 'hidden',
@@ -98,7 +112,7 @@ const styles = {
98
112
  },
99
113
  itemMeta: {
100
114
  fontSize: '12px',
101
- color: 'var(--seekora-text-secondary, #6b7280)',
115
+ color: 'var(--seekora-text-secondary, inherit)',
102
116
  marginTop: '2px',
103
117
  },
104
118
  itemCount: {
@@ -119,11 +133,11 @@ const styles = {
119
133
  padding: '3px 8px',
120
134
  fontSize: '11px',
121
135
  fontWeight: 500,
122
- color: 'var(--seekora-text-secondary, #6b7280)',
123
- backgroundColor: 'var(--seekora-bg-tertiary, #f3f4f6)',
124
- borderRadius: '12px',
136
+ color: 'var(--seekora-text-secondary, inherit)',
137
+ backgroundColor: 'var(--seekora-bg-tertiary, rgba(255, 255, 255, 0.1))',
138
+ borderRadius: `${BORDER_RADIUS.lg * 1.5}px`,
125
139
  cursor: 'pointer',
126
- transition: 'all 100ms ease',
140
+ transition: `all ${TRANSITIONS.fast}`,
127
141
  },
128
142
  categoryPillHover: {
129
143
  backgroundColor: 'var(--seekora-primary-light, #dbeafe)',
@@ -145,12 +159,12 @@ const styles = {
145
159
  padding: '6px 12px',
146
160
  fontSize: '13px',
147
161
  fontWeight: 500,
148
- color: 'var(--seekora-text-primary, #374151)',
149
- backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
150
- border: '1px solid var(--seekora-border-color, #e5e7eb)',
151
- borderRadius: '20px',
162
+ color: 'var(--seekora-text-primary, inherit)',
163
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
164
+ border: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
165
+ borderRadius: `${BORDER_RADIUS.full}px`,
152
166
  cursor: 'pointer',
153
- transition: 'all 150ms ease',
167
+ transition: `all ${TRANSITIONS.fast}`,
154
168
  },
155
169
  trendingChipHover: {
156
170
  borderColor: 'var(--seekora-primary, #3b82f6)',
@@ -164,7 +178,7 @@ const styles = {
164
178
  trendingRank: {
165
179
  width: '18px',
166
180
  height: '18px',
167
- borderRadius: '50%',
181
+ borderRadius: `${BORDER_RADIUS.full}px`,
168
182
  backgroundColor: 'var(--seekora-primary, #3b82f6)',
169
183
  color: 'white',
170
184
  fontSize: '10px',
@@ -176,25 +190,25 @@ const styles = {
176
190
  removeButton: {
177
191
  padding: '4px',
178
192
  marginLeft: 'auto',
179
- borderRadius: '4px',
193
+ borderRadius: `${BORDER_RADIUS.sm}px`,
180
194
  border: 'none',
181
195
  background: 'transparent',
182
196
  cursor: 'pointer',
183
197
  color: 'var(--seekora-text-tertiary, #9ca3af)',
184
198
  opacity: 0,
185
- transition: 'opacity 100ms ease',
199
+ transition: `opacity ${TRANSITIONS.fast}`,
186
200
  },
187
201
  divider: {
188
202
  height: '1px',
189
- backgroundColor: 'var(--seekora-border-color, #e5e7eb)',
203
+ backgroundColor: 'var(--seekora-border-color, rgba(128,128,128,0.2))',
190
204
  margin: '4px 16px',
191
205
  },
192
206
  footer: {
193
207
  padding: '12px 16px',
194
- borderTop: '1px solid var(--seekora-border-color, #e5e7eb)',
195
- backgroundColor: 'var(--seekora-bg-secondary, #f9fafb)',
208
+ borderTop: '1px solid var(--seekora-border-color, rgba(128,128,128,0.2))',
209
+ backgroundColor: 'var(--seekora-bg-secondary, rgba(255, 255, 255, 0.1))',
196
210
  fontSize: '12px',
197
- color: 'var(--seekora-text-secondary, #6b7280)',
211
+ color: 'var(--seekora-text-secondary, inherit)',
198
212
  },
199
213
  loadingOverlay: {
200
214
  position: 'absolute',
@@ -202,12 +216,12 @@ const styles = {
202
216
  display: 'flex',
203
217
  alignItems: 'center',
204
218
  justifyContent: 'center',
205
- backgroundColor: 'rgba(255, 255, 255, 0.8)',
219
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
206
220
  },
207
221
  emptyState: {
208
222
  padding: '32px 16px',
209
223
  textAlign: 'center',
210
- color: 'var(--seekora-text-secondary, #6b7280)',
224
+ color: 'var(--seekora-text-secondary, inherit)',
211
225
  },
212
226
  highlight: {
213
227
  backgroundColor: 'var(--seekora-highlight-bg, #fef9c3)',
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import React from 'react';
7
7
  import type { SearchOptions } from '@seekora-ai/search-sdk';
8
+ export type SearchBarSize = 'small' | 'medium' | 'large';
8
9
  export interface SearchBarTheme {
9
10
  container?: string;
10
11
  input?: string;
@@ -14,6 +15,9 @@ export interface SearchBarTheme {
14
15
  suggestionItemHover?: string;
15
16
  suggestionItemActive?: string;
16
17
  loadingIndicator?: string;
18
+ searchIcon?: string;
19
+ clearButton?: string;
20
+ submitButton?: string;
17
21
  }
18
22
  export interface SearchBarProps {
19
23
  placeholder?: string;
@@ -37,6 +41,18 @@ export interface SearchBarProps {
37
41
  showLoadingState?: boolean;
38
42
  renderSuggestion?: (suggestion: string, index: number) => React.ReactNode;
39
43
  renderLoading?: () => React.ReactNode;
44
+ /** Custom render for the search icon. If not provided, a default magnifying glass SVG is rendered. */
45
+ renderSearchIcon?: () => React.ReactNode;
46
+ /** Whether to show a clear button when the query is non-empty (default: true) */
47
+ showClearButton?: boolean;
48
+ /** Custom render for the clear icon */
49
+ renderClearIcon?: () => React.ReactNode;
50
+ /** Whether to show a submit button to the right of the input (default: false) */
51
+ showSubmitButton?: boolean;
52
+ /** Custom render for the submit button */
53
+ renderSubmitButton?: () => React.ReactNode;
54
+ /** Size variant controlling padding and font size (default: 'medium') */
55
+ size?: SearchBarSize;
40
56
  }
41
57
  export declare const SearchBar: React.FC<SearchBarProps>;
42
58
  //# sourceMappingURL=SearchBar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBar.d.ts","sourceRoot":"","sources":["../../src/components/SearchBar.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAMxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/F,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,2HAA2H;IAC3H,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACvC;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAoT9C,CAAC"}
1
+ {"version":3,"file":"SearchBar.d.ts","sourceRoot":"","sources":["../../src/components/SearchBar.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAMxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAU5D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/F,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,2HAA2H;IAC3H,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC,sGAAsG;IACtG,gBAAgB,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACzC,iFAAiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACxC,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0CAA0C;IAC1C,kBAAkB,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IAC3C,yEAAyE;IACzE,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAgED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA2b9C,CAAC"}
@@ -9,7 +9,49 @@ import { useSearchState } from '../hooks/useSearchState';
9
9
  import { useQuerySuggestions } from '../hooks/useQuerySuggestions';
10
10
  import { log } from '@seekora-ai/ui-sdk-core';
11
11
  import { clsx } from 'clsx';
12
- export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounceMs = 300, minQueryLength = 2, maxSuggestions = 10, onSearch, onQueryChange, onSuggestionSelect, onSearchStateChange, searchOptions, className, style, theme: customTheme, showLoadingState = false, renderSuggestion, renderLoading, }) => {
12
+ // Z-index scale for consistent layering
13
+ const Z_INDEX = {
14
+ dropdown: 100,
15
+ modal: 200,
16
+ overlay: 300,
17
+ tooltip: 50,
18
+ };
19
+ const SIZE_CONFIG = {
20
+ small: {
21
+ padding: '0.375rem 0.5rem',
22
+ fontSize: '0.875rem',
23
+ iconSize: 14,
24
+ iconPaddingLeft: '1.75rem',
25
+ iconPaddingRight: '1.75rem',
26
+ iconLeft: '0.5rem',
27
+ iconRight: '0.5rem',
28
+ },
29
+ medium: {
30
+ padding: '0.625rem 1rem',
31
+ fontSize: '1rem',
32
+ iconSize: 18,
33
+ iconPaddingLeft: '2.25rem',
34
+ iconPaddingRight: '2.25rem',
35
+ iconLeft: '0.625rem',
36
+ iconRight: '0.625rem',
37
+ },
38
+ large: {
39
+ padding: '0.875rem 1.25rem',
40
+ fontSize: '1.25rem',
41
+ iconSize: 22,
42
+ iconPaddingLeft: '2.75rem',
43
+ iconPaddingRight: '2.75rem',
44
+ iconLeft: '0.75rem',
45
+ iconRight: '0.75rem',
46
+ },
47
+ };
48
+ const DefaultSearchIcon = ({ size = 18 }) => (React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
49
+ React.createElement("circle", { cx: "11", cy: "11", r: "8" }),
50
+ React.createElement("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })));
51
+ const DefaultClearIcon = ({ size = 14 }) => (React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
52
+ React.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
53
+ React.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })));
54
+ export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, debounceMs = 300, minQueryLength = 2, maxSuggestions = 10, onSearch, onQueryChange, onSuggestionSelect, onSearchStateChange, searchOptions, className, style, theme: customTheme, showLoadingState = false, renderSuggestion, renderLoading, renderSearchIcon, showClearButton = true, renderClearIcon, showSubmitButton = false, renderSubmitButton, size = 'medium', }) => {
13
55
  const { client, theme, enableAnalytics, autoTrackSearch } = useSearchContext();
14
56
  const { query, setQuery, search: triggerSearch, results, loading: searchLoading, error: searchError } = useSearchState();
15
57
  const [isFocused, setIsFocused] = useState(false);
@@ -150,28 +192,107 @@ export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, d
150
192
  const processingTime = res?.processingTimeMS
151
193
  || res?.data?.processingTimeMS
152
194
  || res?.data?.data?.processingTimeMS;
195
+ // Size-based configuration
196
+ const sizeConfig = SIZE_CONFIG[size];
197
+ // Determine whether the search icon is shown (always unless renderSearchIcon returns null explicitly — but
198
+ // we always show it; there is no prop to hide the search icon, only to customise it)
199
+ const hasSearchIcon = true;
200
+ const hasClearBtn = showClearButton && query.length > 0;
201
+ // Compute input padding accounting for icons
202
+ const inputPaddingLeft = hasSearchIcon ? sizeConfig.iconPaddingLeft : sizeConfig.padding.split(' ')[1] || sizeConfig.padding;
203
+ const inputPaddingRight = hasClearBtn ? sizeConfig.iconPaddingRight : sizeConfig.padding.split(' ')[1] || sizeConfig.padding;
204
+ const borderRadius = typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium;
205
+ const focusBorderColor = isFocused ? `var(--seekora-border-focus, ${theme.colors.focus})` : `var(--seekora-border, ${theme.colors.border})`;
206
+ const focusRingShadow = isFocused
207
+ ? `0 0 0 3px var(--seekora-border-focus-alpha, ${theme.colors.focus}33)`
208
+ : undefined;
209
+ const handleClear = useCallback(() => {
210
+ setQuery('', false);
211
+ setSelectedIndex(-1);
212
+ inputRef.current?.focus();
213
+ }, [setQuery]);
214
+ const handleSubmit = useCallback(() => {
215
+ const currentValue = inputRef.current?.value || query;
216
+ handleSearch(currentValue);
217
+ }, [query, handleSearch]);
153
218
  return (React.createElement("div", { ref: containerRef, className: clsx(searchBarTheme.container, className), style: {
154
219
  position: 'relative',
155
220
  display: 'flex',
156
221
  alignItems: 'center',
222
+ // CSS custom properties for external styling
223
+ '--seekora-searchbar-bg': theme.colors.background,
224
+ '--seekora-searchbar-border': theme.colors.border,
225
+ '--seekora-searchbar-focus-border': theme.colors.focus,
226
+ '--seekora-searchbar-radius': borderRadius,
227
+ '--seekora-searchbar-icon-color': theme.colors.textSecondary,
157
228
  ...style,
158
229
  } },
159
- 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: {
160
- flex: 1,
161
- padding: theme.spacing.medium,
162
- fontSize: theme.typography.fontSize.medium,
230
+ React.createElement("div", { style: { position: 'relative', flex: 1, display: 'flex', alignItems: 'center' } },
231
+ hasSearchIcon && (React.createElement("span", { className: searchBarTheme.searchIcon, "aria-hidden": "true", style: {
232
+ position: 'absolute',
233
+ left: sizeConfig.iconLeft,
234
+ top: '50%',
235
+ transform: 'translateY(-50%)',
236
+ display: 'flex',
237
+ alignItems: 'center',
238
+ justifyContent: 'center',
239
+ pointerEvents: 'none',
240
+ color: 'var(--seekora-searchbar-icon-color)',
241
+ zIndex: 2,
242
+ } }, renderSearchIcon ? renderSearchIcon() : React.createElement(DefaultSearchIcon, { size: sizeConfig.iconSize }))),
243
+ 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: {
244
+ width: '100%',
245
+ paddingTop: sizeConfig.padding.split(' ')[0],
246
+ paddingBottom: sizeConfig.padding.split(' ')[0],
247
+ paddingLeft: inputPaddingLeft,
248
+ paddingRight: inputPaddingRight,
249
+ fontSize: sizeConfig.fontSize,
250
+ fontFamily: theme.typography.fontFamily,
251
+ backgroundColor: 'var(--seekora-searchbar-bg)',
252
+ color: theme.colors.text,
253
+ borderWidth: '1px',
254
+ borderStyle: 'solid',
255
+ borderColor: focusBorderColor,
256
+ borderRadius: 'var(--seekora-searchbar-radius)',
257
+ outline: 'none',
258
+ boxShadow: focusRingShadow,
259
+ transition: theme.transitions?.fast || '150ms ease-in-out',
260
+ boxSizing: 'border-box',
261
+ } }),
262
+ hasClearBtn && (React.createElement("button", { type: "button", onClick: handleClear, className: searchBarTheme.clearButton, "aria-label": "Clear search", style: {
263
+ position: 'absolute',
264
+ right: sizeConfig.iconRight,
265
+ top: '50%',
266
+ transform: 'translateY(-50%)',
267
+ display: 'flex',
268
+ alignItems: 'center',
269
+ justifyContent: 'center',
270
+ background: 'none',
271
+ border: 'none',
272
+ cursor: 'pointer',
273
+ padding: '2px',
274
+ borderRadius: '50%',
275
+ color: 'var(--seekora-searchbar-icon-color)',
276
+ transition: theme.transitions?.fast || '150ms ease-in-out',
277
+ zIndex: 2,
278
+ }, onMouseDown: (e) => {
279
+ // Prevent input blur so the clear action doesn't race with blur handler
280
+ e.preventDefault();
281
+ } }, renderClearIcon ? renderClearIcon() : React.createElement(DefaultClearIcon, { size: sizeConfig.iconSize - 4 })))),
282
+ showSubmitButton && (renderSubmitButton ? (React.createElement("div", { onClick: handleSubmit, style: { marginLeft: theme.spacing.small, cursor: 'pointer' } }, renderSubmitButton())) : (React.createElement("button", { type: "button", onClick: handleSubmit, className: searchBarTheme.submitButton, style: {
283
+ marginLeft: theme.spacing.small,
284
+ padding: sizeConfig.padding,
285
+ fontSize: sizeConfig.fontSize,
163
286
  fontFamily: theme.typography.fontFamily,
164
- backgroundColor: theme.colors.background,
165
- color: theme.colors.text,
166
- borderWidth: '1px',
167
- borderStyle: 'solid',
168
- borderColor: isFocused ? theme.colors.focus : theme.colors.border,
169
- borderRadius: typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium,
170
- outline: 'none',
171
- ...(isFocused && {
172
- boxShadow: theme.shadows.small,
173
- }),
174
- } }),
287
+ fontWeight: theme.typography.fontWeight?.medium ?? 500,
288
+ backgroundColor: `var(--seekora-primary, ${theme.colors.primary})`,
289
+ color: 'var(--seekora-primary-text, #ffffff)',
290
+ border: 'none',
291
+ borderRadius: 'var(--seekora-searchbar-radius)',
292
+ cursor: 'pointer',
293
+ whiteSpace: 'nowrap',
294
+ transition: theme.transitions?.fast || '150ms ease-in-out',
295
+ } }, "Search"))),
175
296
  processingTime !== undefined && (React.createElement("span", { style: {
176
297
  marginLeft: theme.spacing.small,
177
298
  fontSize: theme.typography.fontSize.small,
@@ -193,7 +314,8 @@ export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, d
193
314
  boxShadow: theme.shadows.medium,
194
315
  maxHeight: '400px',
195
316
  overflowY: 'auto',
196
- zIndex: 1000,
317
+ zIndex: Z_INDEX.dropdown,
318
+ boxSizing: 'border-box',
197
319
  } },
198
320
  isLoading && displayedSuggestions.length === 0 && showLoadingState && (renderLoading ? renderLoading() : defaultRenderLoading()),
199
321
  displayedSuggestions.length > 0 && (React.createElement(React.Fragment, null, displayedSuggestions.map((suggestion, index) => {