@seekora-ai/ui-sdk-react 0.2.12 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CurrentRefinements.d.ts +22 -2
- package/dist/components/CurrentRefinements.d.ts.map +1 -1
- package/dist/components/CurrentRefinements.js +199 -47
- package/dist/components/Facets.d.ts +30 -1
- package/dist/components/Facets.d.ts.map +1 -1
- package/dist/components/Facets.js +418 -46
- package/dist/components/HierarchicalMenu.d.ts.map +1 -1
- package/dist/components/HierarchicalMenu.js +112 -4
- package/dist/components/InfiniteHits.d.ts +2 -0
- package/dist/components/InfiniteHits.d.ts.map +1 -1
- package/dist/components/InfiniteHits.js +6 -3
- package/dist/components/Pagination.d.ts +47 -1
- package/dist/components/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination.js +166 -28
- package/dist/components/QuerySuggestions.d.ts +2 -0
- package/dist/components/QuerySuggestions.d.ts.map +1 -1
- package/dist/components/QuerySuggestions.js +4 -3
- package/dist/components/QuerySuggestionsDropdown.d.ts +1 -1
- package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
- package/dist/components/QuerySuggestionsDropdown.js +4 -4
- package/dist/components/RangeSlider.d.ts.map +1 -1
- package/dist/components/RangeSlider.js +49 -2
- package/dist/components/Recommendations.d.ts +6 -0
- package/dist/components/Recommendations.d.ts.map +1 -1
- package/dist/components/Recommendations.js +12 -6
- package/dist/components/RichQuerySuggestions.d.ts +11 -0
- package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
- package/dist/components/RichQuerySuggestions.js +2 -3
- package/dist/components/SearchBar.d.ts +18 -0
- package/dist/components/SearchBar.d.ts.map +1 -1
- package/dist/components/SearchBar.js +134 -24
- package/dist/components/SearchProvider.d.ts +8 -1
- package/dist/components/SearchProvider.d.ts.map +1 -1
- package/dist/components/SearchProvider.js +16 -4
- package/dist/components/SearchResults.d.ts +12 -0
- package/dist/components/SearchResults.d.ts.map +1 -1
- package/dist/components/SearchResults.js +11 -5
- package/dist/components/SortBy.d.ts +44 -4
- package/dist/components/SortBy.d.ts.map +1 -1
- package/dist/components/SortBy.js +154 -29
- package/dist/components/Stats.d.ts +14 -0
- package/dist/components/Stats.d.ts.map +1 -1
- package/dist/components/Stats.js +172 -23
- package/dist/components/section-primitives/SectionItemGrid.d.ts +3 -1
- package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -1
- package/dist/components/section-primitives/SectionItemGrid.js +3 -2
- package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/AmazonDropdown.js +4 -6
- package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/GoogleDropdown.js +4 -8
- package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MinimalDropdown.js +4 -6
- package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MobileSheetDropdown.js +4 -6
- package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/PinterestDropdown.js +4 -8
- package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/ShopifyDropdown.js +4 -6
- package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/SpotlightDropdown.js +4 -6
- package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -1
- package/dist/components/suggestions/SuggestionSearchBar.js +1 -0
- package/dist/components/suggestions/types.d.ts +2 -0
- package/dist/components/suggestions/types.d.ts.map +1 -1
- package/dist/components/suggestions/utils.d.ts +10 -1
- package/dist/components/suggestions/utils.d.ts.map +1 -1
- package/dist/components/suggestions/utils.js +36 -0
- package/dist/components/suggestions-primitives/SuggestionList.d.ts +8 -1
- package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SuggestionList.js +7 -4
- package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.js +0 -2
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts +16 -4
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/highlightMarkup.js +42 -4
- package/dist/docsearch/components/Results.d.ts +3 -1
- package/dist/docsearch/components/Results.d.ts.map +1 -1
- package/dist/docsearch/components/Results.js +6 -2
- package/dist/hooks/useClickTracking.d.ts +36 -0
- package/dist/hooks/useClickTracking.d.ts.map +1 -0
- package/dist/hooks/useClickTracking.js +96 -0
- package/dist/hooks/useExperiment.d.ts +25 -0
- package/dist/hooks/useExperiment.d.ts.map +1 -0
- package/dist/hooks/useExperiment.js +146 -0
- package/dist/hooks/useKeyboardNavigation.d.ts +51 -0
- package/dist/hooks/useKeyboardNavigation.d.ts.map +1 -0
- package/dist/hooks/useKeyboardNavigation.js +113 -0
- package/dist/hooks/useQuerySuggestions.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestions.js +19 -3
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestionsEnhanced.js +25 -7
- package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -1
- package/dist/hooks/useSuggestionsAnalytics.js +6 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +249 -19
- package/dist/src/index.esm.js +1659 -305
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +1658 -304
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/components/RangeSlider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAKjF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/components/RangeSlider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAKjF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAqUlD,CAAC"}
|
|
@@ -103,6 +103,53 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
|
|
|
103
103
|
const handleDragEnd = () => {
|
|
104
104
|
setIsDragging(false);
|
|
105
105
|
};
|
|
106
|
+
// Handle keyboard navigation for enhanced control (Shift+Arrow for 10x step, Home/End)
|
|
107
|
+
const handleMinKeyDown = (e) => {
|
|
108
|
+
let newValue = null;
|
|
109
|
+
if (e.key === 'Home') {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
newValue = min;
|
|
112
|
+
}
|
|
113
|
+
else if (e.key === 'End') {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
newValue = internalMax - step;
|
|
116
|
+
}
|
|
117
|
+
else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
newValue = Math.max(min, internalMin - step * 10);
|
|
120
|
+
}
|
|
121
|
+
else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
newValue = Math.min(internalMax - step, internalMin + step * 10);
|
|
124
|
+
}
|
|
125
|
+
if (newValue !== null) {
|
|
126
|
+
setInternalMin(newValue);
|
|
127
|
+
debouncedUpdate(newValue, internalMax);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const handleMaxKeyDown = (e) => {
|
|
131
|
+
let newValue = null;
|
|
132
|
+
if (e.key === 'Home') {
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
newValue = internalMin + step;
|
|
135
|
+
}
|
|
136
|
+
else if (e.key === 'End') {
|
|
137
|
+
e.preventDefault();
|
|
138
|
+
newValue = max;
|
|
139
|
+
}
|
|
140
|
+
else if (e.shiftKey && (e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
newValue = Math.max(internalMin + step, internalMax - step * 10);
|
|
143
|
+
}
|
|
144
|
+
else if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowUp')) {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
newValue = Math.min(max, internalMax + step * 10);
|
|
147
|
+
}
|
|
148
|
+
if (newValue !== null) {
|
|
149
|
+
setInternalMax(newValue);
|
|
150
|
+
debouncedUpdate(internalMin, newValue);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
106
153
|
// Calculate filled track position
|
|
107
154
|
const minPercent = ((internalMin - min) / (max - min)) * 100;
|
|
108
155
|
const maxPercent = ((internalMax - min) / (max - min)) * 100;
|
|
@@ -138,7 +185,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
|
|
|
138
185
|
backgroundColor: theme.colors.primary,
|
|
139
186
|
borderRadius: '2px',
|
|
140
187
|
} }),
|
|
141
|
-
React.createElement("input", { type: "range", min: min, max: max, step: step, value: internalMin, onChange: handleMinChange, onMouseUp: handleDragEnd, onTouchEnd: handleDragEnd, className: rangeSliderTheme.thumb, style: {
|
|
188
|
+
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: {
|
|
142
189
|
position: 'absolute',
|
|
143
190
|
width: '100%',
|
|
144
191
|
height: '4px',
|
|
@@ -148,7 +195,7 @@ export const RangeSlider = ({ field, label, min, max, step = 1, currentMin: curr
|
|
|
148
195
|
cursor: 'pointer',
|
|
149
196
|
pointerEvents: 'none',
|
|
150
197
|
}, "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: {
|
|
198
|
+
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: {
|
|
152
199
|
position: 'absolute',
|
|
153
200
|
width: '100%',
|
|
154
201
|
height: '4px',
|
|
@@ -51,6 +51,8 @@ export interface RelatedProductsProps extends BaseRecommendationProps {
|
|
|
51
51
|
items?: RecommendationItem[];
|
|
52
52
|
/** Loading state */
|
|
53
53
|
loading?: boolean;
|
|
54
|
+
/** Show loading state when fetching and no previous items (default false: show previous results until new render) */
|
|
55
|
+
showLoadingState?: boolean;
|
|
54
56
|
}
|
|
55
57
|
export declare const RelatedProducts: React.FC<RelatedProductsProps>;
|
|
56
58
|
export interface TrendingItemsProps extends BaseRecommendationProps {
|
|
@@ -58,6 +60,8 @@ export interface TrendingItemsProps extends BaseRecommendationProps {
|
|
|
58
60
|
items?: RecommendationItem[];
|
|
59
61
|
/** Loading state */
|
|
60
62
|
loading?: boolean;
|
|
63
|
+
/** Show loading state when fetching and no previous items (default false: show previous results until new render) */
|
|
64
|
+
showLoadingState?: boolean;
|
|
61
65
|
/** Facet name for trending (if using facet data) */
|
|
62
66
|
facetName?: string;
|
|
63
67
|
}
|
|
@@ -69,6 +73,8 @@ export interface FrequentlyBoughtTogetherProps extends BaseRecommendationProps {
|
|
|
69
73
|
items?: RecommendationItem[];
|
|
70
74
|
/** Loading state */
|
|
71
75
|
loading?: boolean;
|
|
76
|
+
/** Show loading state when fetching and no previous items (default false: show previous results until new render) */
|
|
77
|
+
showLoadingState?: boolean;
|
|
72
78
|
/** Show "Add all to cart" button */
|
|
73
79
|
showAddAllButton?: boolean;
|
|
74
80
|
/** Callback when "Add all" is clicked */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Recommendations.d.ts","sourceRoot":"","sources":["../../src/components/Recommendations.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAG5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E,oCAAoC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,kBAAkB;IAClB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD,MAAM,WAAW,oBAAqB,SAAQ,uBAAuB;IACnE,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Recommendations.d.ts","sourceRoot":"","sources":["../../src/components/Recommendations.tsx"],"names":[],"mappings":"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"}
|
|
@@ -10,36 +10,40 @@
|
|
|
10
10
|
import React, { useEffect, useState, useMemo } from 'react';
|
|
11
11
|
import { useSearchContext } from './SearchProvider';
|
|
12
12
|
import { clsx } from 'clsx';
|
|
13
|
-
export const RelatedProducts = ({ productId, items: itemsProp, loading: loadingProp = false, title = 'Related Products', maxItems = 6, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
13
|
+
export const RelatedProducts = ({ productId, items: itemsProp, loading: loadingProp = false, showLoadingState = false, title = 'Related Products', maxItems = 6, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
14
14
|
const { theme } = useSearchContext();
|
|
15
15
|
const recommendationTheme = customTheme || {};
|
|
16
16
|
// If items are provided, use them directly
|
|
17
17
|
const items = itemsProp?.slice(0, maxItems) || [];
|
|
18
18
|
const loading = loadingProp;
|
|
19
|
-
if (loading) {
|
|
19
|
+
if (loading && items.length === 0 && showLoadingState) {
|
|
20
20
|
return (React.createElement("div", { className: clsx(recommendationTheme.root, className), style: style },
|
|
21
21
|
React.createElement("div", { className: recommendationTheme.loading, style: getLoadingStyle(theme) }, "Loading related products...")));
|
|
22
22
|
}
|
|
23
|
+
if (loading && items.length === 0)
|
|
24
|
+
return null;
|
|
23
25
|
if (items.length === 0) {
|
|
24
26
|
return null;
|
|
25
27
|
}
|
|
26
28
|
return (React.createElement(RecommendationSection, { title: title, items: items, renderItem: renderItem, onItemClick: onItemClick, className: className, style: style, theme: customTheme, layout: layout, currencySymbol: currencySymbol }));
|
|
27
29
|
};
|
|
28
|
-
export const TrendingItems = ({ items: itemsProp, loading: loadingProp = false, title = 'Trending Now', maxItems = 8, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
30
|
+
export const TrendingItems = ({ items: itemsProp, loading: loadingProp = false, showLoadingState = false, title = 'Trending Now', maxItems = 8, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', }) => {
|
|
29
31
|
const { theme } = useSearchContext();
|
|
30
32
|
const recommendationTheme = customTheme || {};
|
|
31
33
|
const items = itemsProp?.slice(0, maxItems) || [];
|
|
32
34
|
const loading = loadingProp;
|
|
33
|
-
if (loading) {
|
|
35
|
+
if (loading && items.length === 0 && showLoadingState) {
|
|
34
36
|
return (React.createElement("div", { className: clsx(recommendationTheme.root, className), style: style },
|
|
35
37
|
React.createElement("div", { className: recommendationTheme.loading, style: getLoadingStyle(theme) }, "Loading trending items...")));
|
|
36
38
|
}
|
|
39
|
+
if (loading && items.length === 0)
|
|
40
|
+
return null;
|
|
37
41
|
if (items.length === 0) {
|
|
38
42
|
return null;
|
|
39
43
|
}
|
|
40
44
|
return (React.createElement(RecommendationSection, { title: title, items: items, renderItem: renderItem, onItemClick: onItemClick, className: className, style: style, theme: customTheme, layout: layout, currencySymbol: currencySymbol }));
|
|
41
45
|
};
|
|
42
|
-
export const FrequentlyBoughtTogether = ({ productId, items: itemsProp, loading: loadingProp = false, title = 'Frequently Bought Together', maxItems = 4, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', showAddAllButton = true, onAddAll, }) => {
|
|
46
|
+
export const FrequentlyBoughtTogether = ({ productId, items: itemsProp, loading: loadingProp = false, showLoadingState = false, title = 'Frequently Bought Together', maxItems = 4, renderItem, onItemClick, className, style, theme: customTheme, layout = 'horizontal', currencySymbol = '$', showAddAllButton = true, onAddAll, }) => {
|
|
43
47
|
const { theme } = useSearchContext();
|
|
44
48
|
const recommendationTheme = customTheme || {};
|
|
45
49
|
const items = itemsProp?.slice(0, maxItems) || [];
|
|
@@ -52,10 +56,12 @@ export const FrequentlyBoughtTogether = ({ productId, items: itemsProp, loading:
|
|
|
52
56
|
return sum + price;
|
|
53
57
|
}, 0);
|
|
54
58
|
}, [items]);
|
|
55
|
-
if (loading) {
|
|
59
|
+
if (loading && items.length === 0 && showLoadingState) {
|
|
56
60
|
return (React.createElement("div", { className: clsx(recommendationTheme.root, className), style: style },
|
|
57
61
|
React.createElement("div", { className: recommendationTheme.loading, style: getLoadingStyle(theme) }, "Loading recommendations...")));
|
|
58
62
|
}
|
|
63
|
+
if (loading && items.length === 0)
|
|
64
|
+
return null;
|
|
59
65
|
if (items.length === 0) {
|
|
60
66
|
return null;
|
|
61
67
|
}
|
|
@@ -57,6 +57,10 @@ export interface RichQuerySuggestionsProps extends QuerySuggestionsEventHandlers
|
|
|
57
57
|
header?: React.ReactNode;
|
|
58
58
|
/** Custom footer content */
|
|
59
59
|
footer?: React.ReactNode;
|
|
60
|
+
/** Show loading overlay when fetching (default false: show previous results until new results render) */
|
|
61
|
+
showLoadingOverlay?: boolean;
|
|
62
|
+
/** Custom render for loading overlay (only when showLoadingOverlay is true) */
|
|
63
|
+
renderLoading?: () => React.ReactNode;
|
|
60
64
|
/** Dropdown width */
|
|
61
65
|
width?: string | number;
|
|
62
66
|
/** Dropdown max height */
|
|
@@ -67,6 +71,13 @@ export interface RichQuerySuggestionsProps extends QuerySuggestionsEventHandlers
|
|
|
67
71
|
ariaLabel?: string;
|
|
68
72
|
/** Analytics tags */
|
|
69
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
|
+
};
|
|
70
81
|
}
|
|
71
82
|
export interface RichQuerySuggestionsRef {
|
|
72
83
|
getActiveIndex: () => number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichQuerySuggestions.d.ts","sourceRoot":"","sources":["../../src/components/RichQuerySuggestions.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAQN,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EAGd,kBAAkB,EAClB,0BAA0B,EAC1B,6BAA6B,EAE7B,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAMlC,MAAM,WAAW,yBAA0B,SAAQ,6BAA6B;IAC9E,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACnC,sCAAsC;IACtC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,2BAA2B;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,sEAAsE;IACtE,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,kEAAkE;IAClE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,wCAAwC;IACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2BAA2B;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,2BAA2B;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yBAAyB;IACzB,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACxC,wBAAwB;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mCAAmC;IACnC,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IACtF,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,KAAK,CAAC,SAAS,CAAC;IACnE,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9E,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;IAC3D,4BAA4B;IAC5B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"RichQuerySuggestions.d.ts","sourceRoot":"","sources":["../../src/components/RichQuerySuggestions.tsx"],"names":[],"mappings":"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"}
|
|
@@ -233,7 +233,7 @@ const CloseIcon = () => (React.createElement("svg", { viewBox: "0 0 20 20", fill
|
|
|
233
233
|
// Component
|
|
234
234
|
// ============================================================================
|
|
235
235
|
export const RichQuerySuggestions = forwardRef(function RichQuerySuggestions(props, ref) {
|
|
236
|
-
const { query, isOpen = true, sections = DEFAULT_SECTIONS, maxSuggestionsPerSection = 8, minQueryLength = 0, debounceMs = 200, includeDropdownRecommendations = true, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, maxCategories = 3, showCounts = true, showCategoryCounts = true, showSectionHeaders = true, classNames = {}, style, renderSuggestion, renderCategory, renderTrendingItem, renderRecentItem, header, footer, width = '100%', maxHeight = '480px', zIndex = 1000, ariaLabel = 'Search suggestions', analyticsTags, onSuggestionSelect, onCategoryClick, onRecentSearchClick, onRecentSearchRemove, onViewAllClick, onOpen, onClose, } = props;
|
|
236
|
+
const { query, isOpen = true, sections = DEFAULT_SECTIONS, maxSuggestionsPerSection = 8, minQueryLength = 0, debounceMs = 200, includeDropdownRecommendations = true, includeDropdownProductList = true, includeFilteredTabs = true, includeCategories = true, maxCategories = 3, showCounts = true, showCategoryCounts = true, showSectionHeaders = true, classNames = {}, style, renderSuggestion, renderCategory, renderTrendingItem, renderRecentItem, header, footer, width = '100%', maxHeight = '480px', zIndex = 1000, ariaLabel = 'Search suggestions', analyticsTags, onSuggestionSelect, onCategoryClick, onRecentSearchClick, onRecentSearchRemove, onViewAllClick, onOpen, onClose, showLoadingOverlay = false, renderLoading, } = props;
|
|
237
237
|
const { client } = useSearchContext();
|
|
238
238
|
const containerRef = useRef(null);
|
|
239
239
|
const [activeIndex, setActiveIndex] = useState(-1);
|
|
@@ -452,8 +452,7 @@ export const RichQuerySuggestions = forwardRef(function RichQuerySuggestions(pro
|
|
|
452
452
|
} },
|
|
453
453
|
header && React.createElement("div", { style: styles.header }, header),
|
|
454
454
|
React.createElement("div", { style: { ...styles.content, maxHeight } },
|
|
455
|
-
loading && (React.createElement("div", { style: styles.loadingOverlay },
|
|
456
|
-
React.createElement("span", null, "Loading..."))),
|
|
455
|
+
loading && showLoadingOverlay && (React.createElement("div", { style: styles.loadingOverlay }, renderLoading ? renderLoading() : React.createElement("span", null, "Loading..."))),
|
|
457
456
|
enabledSections.map((section, index) => {
|
|
458
457
|
let content = null;
|
|
459
458
|
switch (section.id) {
|
|
@@ -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;
|
|
@@ -33,8 +37,22 @@ export interface SearchBarProps {
|
|
|
33
37
|
className?: string;
|
|
34
38
|
style?: React.CSSProperties;
|
|
35
39
|
theme?: SearchBarTheme;
|
|
40
|
+
/** Show loading state when fetching and no previous suggestions (default false: show previous results until new render) */
|
|
41
|
+
showLoadingState?: boolean;
|
|
36
42
|
renderSuggestion?: (suggestion: string, index: number) => React.ReactNode;
|
|
37
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;
|
|
38
56
|
}
|
|
39
57
|
export declare const SearchBar: React.FC<SearchBarProps>;
|
|
40
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;
|
|
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,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,CA0b9C,CAAC"}
|
|
@@ -9,7 +9,42 @@ 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
|
-
|
|
12
|
+
const SIZE_CONFIG = {
|
|
13
|
+
small: {
|
|
14
|
+
padding: '0.375rem 0.5rem',
|
|
15
|
+
fontSize: '0.875rem',
|
|
16
|
+
iconSize: 14,
|
|
17
|
+
iconPaddingLeft: '1.75rem',
|
|
18
|
+
iconPaddingRight: '1.75rem',
|
|
19
|
+
iconLeft: '0.5rem',
|
|
20
|
+
iconRight: '0.5rem',
|
|
21
|
+
},
|
|
22
|
+
medium: {
|
|
23
|
+
padding: '0.625rem 1rem',
|
|
24
|
+
fontSize: '1rem',
|
|
25
|
+
iconSize: 18,
|
|
26
|
+
iconPaddingLeft: '2.25rem',
|
|
27
|
+
iconPaddingRight: '2.25rem',
|
|
28
|
+
iconLeft: '0.625rem',
|
|
29
|
+
iconRight: '0.625rem',
|
|
30
|
+
},
|
|
31
|
+
large: {
|
|
32
|
+
padding: '0.875rem 1.25rem',
|
|
33
|
+
fontSize: '1.25rem',
|
|
34
|
+
iconSize: 22,
|
|
35
|
+
iconPaddingLeft: '2.75rem',
|
|
36
|
+
iconPaddingRight: '2.75rem',
|
|
37
|
+
iconLeft: '0.75rem',
|
|
38
|
+
iconRight: '0.75rem',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
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" },
|
|
42
|
+
React.createElement("circle", { cx: "11", cy: "11", r: "8" }),
|
|
43
|
+
React.createElement("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })));
|
|
44
|
+
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" },
|
|
45
|
+
React.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
46
|
+
React.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })));
|
|
47
|
+
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
48
|
const { client, theme, enableAnalytics, autoTrackSearch } = useSearchContext();
|
|
14
49
|
const { query, setQuery, search: triggerSearch, results, loading: searchLoading, error: searchError } = useSearchState();
|
|
15
50
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -142,40 +177,115 @@ export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, d
|
|
|
142
177
|
const defaultRenderLoading = () => (React.createElement("div", { style: { padding: theme.spacing.medium, textAlign: 'center' } }, "Loading suggestions..."));
|
|
143
178
|
const searchBarTheme = customTheme || {};
|
|
144
179
|
const isLoading = suggestionsLoading || searchLoading;
|
|
145
|
-
//
|
|
146
|
-
// 1. Input is focused
|
|
147
|
-
// 2. Suggestions are enabled
|
|
148
|
-
// 3. Query is long enough
|
|
149
|
-
// 4. AND (we have suggestions to show OR we're currently loading suggestions)
|
|
180
|
+
// Show list when we have suggestions (including previous while loading) or when loading and showLoadingState
|
|
150
181
|
const hasSuggestions = displayedSuggestions.length > 0;
|
|
151
|
-
const showSuggestionsList = isFocused && showSuggestions && query.length >= minQueryLength && (hasSuggestions || isLoading);
|
|
182
|
+
const showSuggestionsList = isFocused && showSuggestions && query.length >= minQueryLength && (hasSuggestions || (isLoading && showLoadingState));
|
|
152
183
|
// Get processing time from results
|
|
153
184
|
const res = results;
|
|
154
185
|
const processingTime = res?.processingTimeMS
|
|
155
186
|
|| res?.data?.processingTimeMS
|
|
156
187
|
|| res?.data?.data?.processingTimeMS;
|
|
188
|
+
// Size-based configuration
|
|
189
|
+
const sizeConfig = SIZE_CONFIG[size];
|
|
190
|
+
// Determine whether the search icon is shown (always unless renderSearchIcon returns null explicitly — but
|
|
191
|
+
// we always show it; there is no prop to hide the search icon, only to customise it)
|
|
192
|
+
const hasSearchIcon = true;
|
|
193
|
+
const hasClearBtn = showClearButton && query.length > 0;
|
|
194
|
+
// Compute input padding accounting for icons
|
|
195
|
+
const inputPaddingLeft = hasSearchIcon ? sizeConfig.iconPaddingLeft : sizeConfig.padding.split(' ')[1] || sizeConfig.padding;
|
|
196
|
+
const inputPaddingRight = hasClearBtn ? sizeConfig.iconPaddingRight : sizeConfig.padding.split(' ')[1] || sizeConfig.padding;
|
|
197
|
+
const borderRadius = typeof theme.borderRadius === 'string' ? theme.borderRadius : theme.borderRadius.medium;
|
|
198
|
+
const focusBorderColor = isFocused ? theme.colors.focus : theme.colors.border;
|
|
199
|
+
const focusRingShadow = isFocused
|
|
200
|
+
? `0 0 0 3px ${theme.colors.focus}33`
|
|
201
|
+
: undefined;
|
|
202
|
+
const handleClear = useCallback(() => {
|
|
203
|
+
setQuery('', false);
|
|
204
|
+
setSelectedIndex(-1);
|
|
205
|
+
inputRef.current?.focus();
|
|
206
|
+
}, [setQuery]);
|
|
207
|
+
const handleSubmit = useCallback(() => {
|
|
208
|
+
const currentValue = inputRef.current?.value || query;
|
|
209
|
+
handleSearch(currentValue);
|
|
210
|
+
}, [query, handleSearch]);
|
|
157
211
|
return (React.createElement("div", { ref: containerRef, className: clsx(searchBarTheme.container, className), style: {
|
|
158
212
|
position: 'relative',
|
|
159
213
|
display: 'flex',
|
|
160
214
|
alignItems: 'center',
|
|
215
|
+
// CSS custom properties for external styling
|
|
216
|
+
'--seekora-searchbar-bg': theme.colors.background,
|
|
217
|
+
'--seekora-searchbar-border': theme.colors.border,
|
|
218
|
+
'--seekora-searchbar-focus-border': theme.colors.focus,
|
|
219
|
+
'--seekora-searchbar-radius': borderRadius,
|
|
220
|
+
'--seekora-searchbar-icon-color': theme.colors.textSecondary,
|
|
161
221
|
...style,
|
|
162
222
|
} },
|
|
163
|
-
React.createElement("
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
223
|
+
React.createElement("div", { style: { position: 'relative', flex: 1, display: 'flex', alignItems: 'center' } },
|
|
224
|
+
hasSearchIcon && (React.createElement("span", { className: searchBarTheme.searchIcon, "aria-hidden": "true", style: {
|
|
225
|
+
position: 'absolute',
|
|
226
|
+
left: sizeConfig.iconLeft,
|
|
227
|
+
top: '50%',
|
|
228
|
+
transform: 'translateY(-50%)',
|
|
229
|
+
display: 'flex',
|
|
230
|
+
alignItems: 'center',
|
|
231
|
+
justifyContent: 'center',
|
|
232
|
+
pointerEvents: 'none',
|
|
233
|
+
color: 'var(--seekora-searchbar-icon-color)',
|
|
234
|
+
zIndex: 1,
|
|
235
|
+
} }, renderSearchIcon ? renderSearchIcon() : React.createElement(DefaultSearchIcon, { size: sizeConfig.iconSize }))),
|
|
236
|
+
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: {
|
|
237
|
+
width: '100%',
|
|
238
|
+
paddingTop: sizeConfig.padding.split(' ')[0],
|
|
239
|
+
paddingBottom: sizeConfig.padding.split(' ')[0],
|
|
240
|
+
paddingLeft: inputPaddingLeft,
|
|
241
|
+
paddingRight: inputPaddingRight,
|
|
242
|
+
fontSize: sizeConfig.fontSize,
|
|
243
|
+
fontFamily: theme.typography.fontFamily,
|
|
244
|
+
backgroundColor: 'var(--seekora-searchbar-bg)',
|
|
245
|
+
color: theme.colors.text,
|
|
246
|
+
borderWidth: '1px',
|
|
247
|
+
borderStyle: 'solid',
|
|
248
|
+
borderColor: focusBorderColor,
|
|
249
|
+
borderRadius: 'var(--seekora-searchbar-radius)',
|
|
250
|
+
outline: 'none',
|
|
251
|
+
boxShadow: focusRingShadow,
|
|
252
|
+
transition: theme.transitions?.fast || '150ms ease-in-out',
|
|
253
|
+
boxSizing: 'border-box',
|
|
254
|
+
} }),
|
|
255
|
+
hasClearBtn && (React.createElement("button", { type: "button", onClick: handleClear, className: searchBarTheme.clearButton, "aria-label": "Clear search", style: {
|
|
256
|
+
position: 'absolute',
|
|
257
|
+
right: sizeConfig.iconRight,
|
|
258
|
+
top: '50%',
|
|
259
|
+
transform: 'translateY(-50%)',
|
|
260
|
+
display: 'flex',
|
|
261
|
+
alignItems: 'center',
|
|
262
|
+
justifyContent: 'center',
|
|
263
|
+
background: 'none',
|
|
264
|
+
border: 'none',
|
|
265
|
+
cursor: 'pointer',
|
|
266
|
+
padding: '2px',
|
|
267
|
+
borderRadius: '50%',
|
|
268
|
+
color: 'var(--seekora-searchbar-icon-color)',
|
|
269
|
+
transition: theme.transitions?.fast || '150ms ease-in-out',
|
|
270
|
+
zIndex: 1,
|
|
271
|
+
}, onMouseDown: (e) => {
|
|
272
|
+
// Prevent input blur so the clear action doesn't race with blur handler
|
|
273
|
+
e.preventDefault();
|
|
274
|
+
} }, renderClearIcon ? renderClearIcon() : React.createElement(DefaultClearIcon, { size: sizeConfig.iconSize - 4 })))),
|
|
275
|
+
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: {
|
|
276
|
+
marginLeft: theme.spacing.small,
|
|
277
|
+
padding: sizeConfig.padding,
|
|
278
|
+
fontSize: sizeConfig.fontSize,
|
|
167
279
|
fontFamily: theme.typography.fontFamily,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}),
|
|
178
|
-
} }),
|
|
280
|
+
fontWeight: theme.typography.fontWeight?.medium ?? 500,
|
|
281
|
+
backgroundColor: theme.colors.primary,
|
|
282
|
+
color: '#ffffff',
|
|
283
|
+
border: 'none',
|
|
284
|
+
borderRadius: 'var(--seekora-searchbar-radius)',
|
|
285
|
+
cursor: 'pointer',
|
|
286
|
+
whiteSpace: 'nowrap',
|
|
287
|
+
transition: theme.transitions?.fast || '150ms ease-in-out',
|
|
288
|
+
} }, "Search"))),
|
|
179
289
|
processingTime !== undefined && (React.createElement("span", { style: {
|
|
180
290
|
marginLeft: theme.spacing.small,
|
|
181
291
|
fontSize: theme.typography.fontSize.small,
|
|
@@ -199,8 +309,8 @@ export const SearchBar = ({ placeholder = 'Search...', showSuggestions = true, d
|
|
|
199
309
|
overflowY: 'auto',
|
|
200
310
|
zIndex: 1000,
|
|
201
311
|
} },
|
|
202
|
-
isLoading && (renderLoading ? renderLoading() : defaultRenderLoading()),
|
|
203
|
-
|
|
312
|
+
isLoading && displayedSuggestions.length === 0 && showLoadingState && (renderLoading ? renderLoading() : defaultRenderLoading()),
|
|
313
|
+
displayedSuggestions.length > 0 && (React.createElement(React.Fragment, null, displayedSuggestions.map((suggestion, index) => {
|
|
204
314
|
const isSelected = index === selectedIndex;
|
|
205
315
|
const renderFn = renderSuggestion || defaultRenderSuggestion;
|
|
206
316
|
return (React.createElement("div", { key: index, className: clsx(searchBarTheme.suggestionItem, isSelected && searchBarTheme.suggestionItemActive), onClick: () => handleSuggestionSelect(suggestion.query), onMouseEnter: () => setSelectedIndex(index), style: {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SearchProvider Component
|
|
3
3
|
*
|
|
4
|
-
* Provides Seekora client and context to child components
|
|
4
|
+
* Provides Seekora client and context to child components.
|
|
5
|
+
* Supports A/B testing via abTestId/abVariant props.
|
|
5
6
|
*/
|
|
6
7
|
import React, { ReactNode } from 'react';
|
|
7
8
|
import type { SeekoraClient } from '@seekora-ai/search-sdk';
|
|
@@ -21,6 +22,12 @@ export interface SearchProviderProps {
|
|
|
21
22
|
autoTrackSearch?: boolean;
|
|
22
23
|
stateManager?: SearchStateManagerConfig;
|
|
23
24
|
children: ReactNode;
|
|
25
|
+
/** A/B test experiment ID to include in all analytics events */
|
|
26
|
+
abTestId?: string;
|
|
27
|
+
/** A/B test variant to include in all analytics events */
|
|
28
|
+
abVariant?: string;
|
|
29
|
+
/** Auto-fetch experiment assignments on mount (default: false) */
|
|
30
|
+
experiments?: boolean;
|
|
24
31
|
}
|
|
25
32
|
export declare const SearchProvider: React.FC<SearchProviderProps>;
|
|
26
33
|
export declare const useSearchContext: () => SearchContextValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchProvider.d.ts","sourceRoot":"","sources":["../../src/components/SearchProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SearchProvider.d.ts","sourceRoot":"","sources":["../../src/components/SearchProvider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,EAA6B,SAAS,EAAsB,MAAM,OAAO,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAO,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI1D,UAAU,kBAAkB;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,kBAAkB,CAAC;CAClC;AAID,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAoDxD,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,kBAQnC,CAAC"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SearchProvider Component
|
|
3
3
|
*
|
|
4
|
-
* Provides Seekora client and context to child components
|
|
4
|
+
* Provides Seekora client and context to child components.
|
|
5
|
+
* Supports A/B testing via abTestId/abVariant props.
|
|
5
6
|
*/
|
|
6
|
-
import React, { createContext, useContext, useMemo } from 'react';
|
|
7
|
+
import React, { createContext, useContext, useMemo, useEffect } from 'react';
|
|
7
8
|
import { log, SearchStateManager } from '@seekora-ai/ui-sdk-core';
|
|
8
9
|
import { defaultTheme } from '../themes/default';
|
|
9
10
|
import { createTheme } from '../themes/createTheme';
|
|
10
11
|
const SearchContext = createContext(null);
|
|
11
|
-
export const SearchProvider = ({ client, theme: themeConfig, enableAnalytics = true, autoTrackSearch = true, stateManager: stateManagerConfig, children, }) => {
|
|
12
|
+
export const SearchProvider = ({ client, theme: themeConfig, enableAnalytics = true, autoTrackSearch = true, stateManager: stateManagerConfig, children, abTestId, abVariant, experiments: _experiments, }) => {
|
|
12
13
|
const theme = useMemo(() => {
|
|
13
14
|
return themeConfig ? createTheme(themeConfig) : defaultTheme;
|
|
14
15
|
}, [themeConfig]);
|
|
@@ -21,8 +22,19 @@ export const SearchProvider = ({ client, theme: themeConfig, enableAnalytics = t
|
|
|
21
22
|
itemsPerPage: 10,
|
|
22
23
|
defaultSearchOptions: { widget_mode: true },
|
|
23
24
|
...stateManagerConfig,
|
|
25
|
+
abTestId,
|
|
26
|
+
abVariant,
|
|
24
27
|
});
|
|
25
|
-
}, [client, stateManagerConfig]);
|
|
28
|
+
}, [client, stateManagerConfig, abTestId, abVariant]);
|
|
29
|
+
// Update A/B test fields on state manager and SDK client when props change
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (abTestId !== undefined || abVariant !== undefined) {
|
|
32
|
+
stateManager.setAbTest(abTestId, abVariant);
|
|
33
|
+
if (typeof client.setAbTest === 'function') {
|
|
34
|
+
client.setAbTest(abTestId, abVariant);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, [stateManager, client, abTestId, abVariant]);
|
|
26
38
|
const value = useMemo(() => ({
|
|
27
39
|
client,
|
|
28
40
|
theme,
|
|
@@ -21,6 +21,10 @@ export interface SearchResultsTheme {
|
|
|
21
21
|
loadingState?: string;
|
|
22
22
|
errorState?: string;
|
|
23
23
|
pagination?: string;
|
|
24
|
+
/** Custom min-height class override */
|
|
25
|
+
minHeight?: string;
|
|
26
|
+
/** Custom min-width class override */
|
|
27
|
+
minWidth?: string;
|
|
24
28
|
}
|
|
25
29
|
export interface SearchResultsProps {
|
|
26
30
|
results?: SearchResponse | null;
|
|
@@ -29,6 +33,8 @@ export interface SearchResultsProps {
|
|
|
29
33
|
onResultClick?: (result: ResultItem, index: number) => void;
|
|
30
34
|
renderResult?: (result: ResultItem, index: number, isActive?: boolean) => React.ReactNode;
|
|
31
35
|
renderEmpty?: () => React.ReactNode;
|
|
36
|
+
/** Show loading state when fetching and no previous results (default false: show previous results until new render) */
|
|
37
|
+
showLoadingState?: boolean;
|
|
32
38
|
renderLoading?: () => React.ReactNode;
|
|
33
39
|
renderError?: (error: Error) => React.ReactNode;
|
|
34
40
|
className?: string;
|
|
@@ -46,6 +52,12 @@ export interface SearchResultsProps {
|
|
|
46
52
|
enableKeyboardNavigation?: boolean;
|
|
47
53
|
/** Auto-focus the results container */
|
|
48
54
|
autoFocus?: boolean;
|
|
55
|
+
/** Minimum height to prevent container collapse when empty (default: '400px') */
|
|
56
|
+
minHeight?: string;
|
|
57
|
+
/** Minimum width to prevent container shrinking (default: '100%') */
|
|
58
|
+
minWidth?: string;
|
|
59
|
+
/** Opacity applied to results while loading new results (default: 0.7, set to 1 to disable) */
|
|
60
|
+
loadingOpacity?: number;
|
|
49
61
|
}
|
|
50
62
|
export declare const SearchResults: React.FC<SearchResultsProps>;
|
|
51
63
|
//# sourceMappingURL=SearchResults.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchResults.d.ts","sourceRoot":"","sources":["../../src/components/SearchResults.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnF,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SearchResults.d.ts","sourceRoot":"","sources":["../../src/components/SearchResults.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnF,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1F,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACpC,uHAAuH;IACvH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mEAAmE;IACnE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gFAAgF;IAChF,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;IAC1C,+DAA+D;IAC/D,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoBD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA6mBtD,CAAC"}
|