@seekora-ai/ui-sdk-react 0.2.14 → 0.2.16
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.map +1 -1
- package/dist/components/CurrentRefinements.js +69 -9
- package/dist/components/FacetDropdown.d.ts +94 -0
- package/dist/components/FacetDropdown.d.ts.map +1 -0
- package/dist/components/FacetDropdown.js +396 -0
- package/dist/components/Facets.d.ts +30 -0
- package/dist/components/Facets.d.ts.map +1 -1
- package/dist/components/Facets.js +215 -7
- package/dist/components/FederatedDropdown.d.ts.map +1 -1
- package/dist/components/FederatedDropdown.js +45 -31
- package/dist/components/InfiniteHits.d.ts +0 -7
- package/dist/components/InfiniteHits.d.ts.map +1 -1
- package/dist/components/InfiniteHits.js +2 -13
- package/dist/components/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination.js +27 -9
- package/dist/components/QuerySuggestions.d.ts +0 -4
- package/dist/components/QuerySuggestions.d.ts.map +1 -1
- package/dist/components/QuerySuggestions.js +1 -17
- package/dist/components/QuerySuggestionsDropdown.d.ts +0 -4
- package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
- package/dist/components/QuerySuggestionsDropdown.js +32 -33
- package/dist/components/RangeInput.d.ts.map +1 -1
- package/dist/components/RangeInput.js +6 -6
- package/dist/components/RangeSlider.d.ts.map +1 -1
- package/dist/components/RangeSlider.js +54 -32
- package/dist/components/Recommendations.d.ts +0 -7
- package/dist/components/Recommendations.d.ts.map +1 -1
- package/dist/components/Recommendations.js +3 -23
- package/dist/components/RichQuerySuggestions.d.ts +0 -4
- package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
- package/dist/components/RichQuerySuggestions.js +40 -35
- package/dist/components/SearchBar.d.ts +0 -4
- package/dist/components/SearchBar.d.ts.map +1 -1
- package/dist/components/SearchBar.js +17 -11
- package/dist/components/SearchBarWithSuggestions.js +4 -4
- package/dist/components/SearchLayout.d.ts.map +1 -1
- package/dist/components/SearchLayout.js +22 -17
- package/dist/components/SearchProvider.d.ts.map +1 -1
- package/dist/components/SearchProvider.js +1 -3
- package/dist/components/SearchResults.d.ts +0 -6
- package/dist/components/SearchResults.d.ts.map +1 -1
- package/dist/components/SearchResults.js +38 -39
- package/dist/components/primitives/ActionButtons.d.ts.map +1 -1
- package/dist/components/primitives/ActionButtons.js +34 -10
- package/dist/components/primitives/BadgeList.d.ts.map +1 -1
- package/dist/components/primitives/BadgeList.js +33 -13
- package/dist/components/primitives/ImageDisplay.d.ts.map +1 -1
- package/dist/components/primitives/ImageDisplay.js +32 -19
- package/dist/components/primitives/ImageZoom.d.ts.map +1 -1
- package/dist/components/primitives/ImageZoom.js +85 -30
- package/dist/components/primitives/VariantSelector.js +10 -10
- package/dist/components/primitives/VariantSwatches.d.ts.map +1 -1
- package/dist/components/primitives/VariantSwatches.js +28 -13
- package/dist/components/product-page/ProductGallery.d.ts +8 -1
- package/dist/components/product-page/ProductGallery.d.ts.map +1 -1
- package/dist/components/product-page/ProductGallery.js +2 -2
- package/dist/components/section-primitives/SectionItemGrid.d.ts +1 -3
- package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -1
- package/dist/components/section-primitives/SectionItemGrid.js +1 -4
- package/dist/components/section-primitives/SectionSearchProvider.d.ts +3 -1
- package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -1
- package/dist/components/section-primitives/SectionSearchProvider.js +3 -2
- package/dist/components/section-primitives/index.d.ts +0 -1
- package/dist/components/section-primitives/index.d.ts.map +1 -1
- package/dist/components/section-primitives/index.js +0 -1
- package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/AmazonDropdown.js +3 -21
- package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/GoogleDropdown.js +3 -20
- package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MinimalDropdown.js +2 -2
- package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MobileSheetDropdown.js +78 -78
- package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/PinterestDropdown.js +41 -41
- package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/ShopifyDropdown.js +40 -41
- package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/SpotlightDropdown.js +2 -3
- package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -1
- package/dist/components/suggestions/SuggestionSearchBar.js +2 -15
- package/dist/components/suggestions/types.d.ts +0 -6
- package/dist/components/suggestions/types.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/DropdownPanel.js +15 -2
- package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/ItemCard.js +48 -11
- package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/ItemGrid.js +18 -5
- package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/ProductCard.js +36 -12
- package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/ProductCardLayouts.js +52 -20
- package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/ProductGrid.js +8 -3
- package/dist/components/suggestions-primitives/RecentSearchesList.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/RecentSearchesList.js +12 -5
- package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SearchInput.js +29 -10
- package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SuggestionItem.js +8 -3
- package/dist/components/suggestions-primitives/SuggestionList.d.ts +1 -8
- package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/SuggestionList.js +1 -7
- package/dist/components/suggestions-primitives/TrendingList.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/TrendingList.js +14 -7
- package/dist/components/suggestions-primitives/index.d.ts +1 -3
- package/dist/components/suggestions-primitives/index.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/index.js +1 -2
- package/dist/docsearch/components/DocSearch.d.ts.map +1 -1
- package/dist/docsearch/components/DocSearch.js +1 -1
- package/dist/docsearch/components/Results.d.ts +1 -3
- package/dist/docsearch/components/Results.d.ts.map +1 -1
- package/dist/docsearch/components/Results.js +1 -9
- package/dist/docsearch/components/SearchBox.d.ts +1 -2
- package/dist/docsearch/components/SearchBox.d.ts.map +1 -1
- package/dist/docsearch/components/SearchBox.js +4 -6
- package/dist/docsearch/hooks/useSeekoraSearch.d.ts.map +1 -1
- package/dist/docsearch/hooks/useSeekoraSearch.js +6 -0
- package/dist/docsearch/types.d.ts +0 -1
- package/dist/docsearch/types.d.ts.map +1 -1
- package/dist/docsearch.css +2 -5
- package/dist/hooks/useClickTracking.d.ts.map +1 -1
- package/dist/hooks/useClickTracking.js +4 -11
- package/dist/hooks/useExperiment.d.ts.map +1 -1
- package/dist/hooks/useExperiment.js +10 -33
- package/dist/hooks/useFilters.d.ts +27 -0
- package/dist/hooks/useFilters.d.ts.map +1 -0
- package/dist/hooks/useFilters.js +66 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +166 -81
- package/dist/src/index.esm.js +2141 -1048
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +2142 -1049
- package/dist/src/index.js.map +1 -1
- package/dist/utils/responsive.d.ts +130 -0
- package/dist/utils/responsive.d.ts.map +1 -0
- package/dist/utils/responsive.js +231 -0
- package/package.json +7 -7
- package/src/docsearch/docsearch.css +2 -5
|
@@ -29,7 +29,7 @@ const formatPrice = (value, currency = '₹') => {
|
|
|
29
29
|
}
|
|
30
30
|
return String(value);
|
|
31
31
|
};
|
|
32
|
-
export const SearchResults = ({ results: resultsProp, loading: loadingProp, error: errorProp, onResultClick, renderResult, renderEmpty,
|
|
32
|
+
export const SearchResults = ({ results: resultsProp, loading: loadingProp, error: errorProp, onResultClick, renderResult, renderEmpty, renderError, className, style, theme: customTheme, itemsPerPage = 20, showPagination = false, viewMode = 'list', fieldMapping, extractResults, enableKeyboardNavigation = true, autoFocus = false, minHeight = '400px', minWidth = '100%', }) => {
|
|
33
33
|
const { theme, client, enableAnalytics } = useSearchContext();
|
|
34
34
|
const { results: stateResults, loading: stateLoading, error: stateError, currentPage, itemsPerPage: stateItemsPerPage } = useSearchState();
|
|
35
35
|
const searchResultsTheme = customTheme || {};
|
|
@@ -53,6 +53,43 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}, [activeIndex, enableKeyboardNavigation]);
|
|
56
|
+
// Global keyboard listener for seamless navigation from search box to results
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!enableKeyboardNavigation)
|
|
59
|
+
return;
|
|
60
|
+
const handleGlobalKeyDown = (e) => {
|
|
61
|
+
// Only handle if we have results and the container exists
|
|
62
|
+
if (!containerRef.current)
|
|
63
|
+
return;
|
|
64
|
+
const resultElements = containerRef.current.querySelectorAll('[data-result-index]');
|
|
65
|
+
const maxIndex = resultElements.length - 1;
|
|
66
|
+
if (maxIndex < 0)
|
|
67
|
+
return;
|
|
68
|
+
// Check if focus is on an input/textarea (search box)
|
|
69
|
+
const activeElement = document.activeElement;
|
|
70
|
+
const isInputFocused = activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA';
|
|
71
|
+
if (e.key === 'ArrowDown') {
|
|
72
|
+
// If in search box or no result selected, select first result
|
|
73
|
+
if (isInputFocused || activeIndex === -1) {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
setActiveIndex(0);
|
|
76
|
+
containerRef.current?.focus();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (e.key === 'ArrowUp') {
|
|
80
|
+
// If first result is selected, go back to search box
|
|
81
|
+
if (activeIndex === 0) {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
setActiveIndex(-1);
|
|
84
|
+
// Find and focus the search input
|
|
85
|
+
const searchInput = document.querySelector('input[type="text"], input[type="search"]');
|
|
86
|
+
searchInput?.focus();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
document.addEventListener('keydown', handleGlobalKeyDown);
|
|
91
|
+
return () => document.removeEventListener('keydown', handleGlobalKeyDown);
|
|
92
|
+
}, [enableKeyboardNavigation, activeIndex]);
|
|
56
93
|
// Keyboard navigation handler
|
|
57
94
|
const handleKeyDown = useCallback((e) => {
|
|
58
95
|
if (!enableKeyboardNavigation)
|
|
@@ -262,11 +299,6 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
|
|
|
262
299
|
textAlign: 'center',
|
|
263
300
|
color: theme.colors.text,
|
|
264
301
|
} }, "No results found"));
|
|
265
|
-
const defaultRenderLoading = () => (React.createElement("div", { className: searchResultsTheme.loadingState, style: {
|
|
266
|
-
padding: theme.spacing.large,
|
|
267
|
-
textAlign: 'center',
|
|
268
|
-
color: theme.colors.text,
|
|
269
|
-
} }, "Loading results..."));
|
|
270
302
|
const defaultRenderError = (err) => (React.createElement("div", { className: searchResultsTheme.errorState, style: {
|
|
271
303
|
padding: theme.spacing.large,
|
|
272
304
|
textAlign: 'center',
|
|
@@ -375,8 +407,6 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
|
|
|
375
407
|
const containerStyle = {
|
|
376
408
|
minHeight: `var(--seekora-results-min-height, ${minHeight})`,
|
|
377
409
|
minWidth: `var(--seekora-results-min-width, ${minWidth})`,
|
|
378
|
-
transition: 'opacity 200ms ease-in-out',
|
|
379
|
-
opacity: loading && resultItems.length > 0 ? loadingOpacity : 1,
|
|
380
410
|
...style,
|
|
381
411
|
};
|
|
382
412
|
// Determine results list style based on view mode
|
|
@@ -400,12 +430,6 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
|
|
|
400
430
|
hasError: !!error,
|
|
401
431
|
isLoading: loading,
|
|
402
432
|
});
|
|
403
|
-
// When loading with no previous results, show loading only if showLoadingState (default: show previous results, no loading screen)
|
|
404
|
-
if (loading && resultItems.length === 0 && showLoadingState) {
|
|
405
|
-
log.verbose('SearchResults: Rendering loading state');
|
|
406
|
-
return (React.createElement("div", { className: clsx(searchResultsTheme.container, className), style: containerStyle }, renderLoading ? renderLoading() : defaultRenderLoading()));
|
|
407
|
-
}
|
|
408
|
-
// When loading with previous results, fall through and render them (with opacity transition)
|
|
409
433
|
if (error) {
|
|
410
434
|
log.error('SearchResults: Rendering error state', {
|
|
411
435
|
error: error.message,
|
|
@@ -428,30 +452,5 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
|
|
|
428
452
|
results?.totalResults || results?.data?.total_results || 0,
|
|
429
453
|
" result",
|
|
430
454
|
(results?.totalResults || results?.data?.total_results || 0) !== 1 ? 's' : '')),
|
|
431
|
-
enableKeyboardNavigation && resultItems.length > 0 && (React.createElement("div", { style: {
|
|
432
|
-
fontSize: '12px',
|
|
433
|
-
color: theme.colors.text,
|
|
434
|
-
opacity: 0.6,
|
|
435
|
-
marginBottom: theme.spacing.small,
|
|
436
|
-
display: 'flex',
|
|
437
|
-
gap: '8px',
|
|
438
|
-
alignItems: 'center',
|
|
439
|
-
} },
|
|
440
|
-
React.createElement("span", { style: {
|
|
441
|
-
display: 'inline-flex',
|
|
442
|
-
gap: '4px',
|
|
443
|
-
padding: '2px 6px',
|
|
444
|
-
backgroundColor: theme.colors.hover,
|
|
445
|
-
borderRadius: '4px',
|
|
446
|
-
fontSize: '11px',
|
|
447
|
-
} }, "\u2191\u2193 navigate"),
|
|
448
|
-
React.createElement("span", { style: {
|
|
449
|
-
display: 'inline-flex',
|
|
450
|
-
gap: '4px',
|
|
451
|
-
padding: '2px 6px',
|
|
452
|
-
backgroundColor: theme.colors.hover,
|
|
453
|
-
borderRadius: '4px',
|
|
454
|
-
fontSize: '11px',
|
|
455
|
-
} }, "\u21B5 select"))),
|
|
456
455
|
React.createElement("div", { className: searchResultsTheme.resultsList, style: resultsListStyle }, resultItems.map((result, index) => renderFn(result, index, index === activeIndex)))));
|
|
457
456
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionButtons.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ActionButtons.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ActionButtons.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ActionButtons.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AA+B1B,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAE7F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,EAAE,WAAW,GAAG,eAAe,GAAG,QAAQ,CAAC;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAwBD,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,MAAqB,EACrB,QAAmB,EACnB,UAAkB,EAClB,IAAe,EACf,SAAS,EACT,KAAK,GACN,EAAE,kBAAkB,qBAqFpB"}
|
|
@@ -6,6 +6,30 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
|
+
const SPACING = {
|
|
10
|
+
xs: 4,
|
|
11
|
+
sm: 8,
|
|
12
|
+
md: 12,
|
|
13
|
+
lg: 16,
|
|
14
|
+
xl: 24,
|
|
15
|
+
};
|
|
16
|
+
const TRANSITIONS = {
|
|
17
|
+
fast: '150ms ease-in-out',
|
|
18
|
+
normal: '200ms ease-in-out',
|
|
19
|
+
slow: '300ms ease-in-out',
|
|
20
|
+
};
|
|
21
|
+
const BORDER_RADIUS = {
|
|
22
|
+
sm: 4,
|
|
23
|
+
md: 6,
|
|
24
|
+
lg: 8,
|
|
25
|
+
full: 9999,
|
|
26
|
+
};
|
|
27
|
+
const SHADOWS = {
|
|
28
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
29
|
+
md: '0 2px 4px rgba(0,0,0,0.1)',
|
|
30
|
+
lg: '0 4px 6px rgba(0,0,0,0.1)',
|
|
31
|
+
xl: '0 10px 15px rgba(0,0,0,0.1)',
|
|
32
|
+
};
|
|
9
33
|
const DEFAULT_ICONS = {
|
|
10
34
|
addToCart: '🛒',
|
|
11
35
|
wishlist: '♡',
|
|
@@ -21,8 +45,8 @@ const DEFAULT_LABELS = {
|
|
|
21
45
|
compare: 'Compare',
|
|
22
46
|
};
|
|
23
47
|
const BUTTON_SIZES = {
|
|
24
|
-
small: { width:
|
|
25
|
-
medium: { width:
|
|
48
|
+
small: { width: 44, height: 44, fontSize: '0.75rem', iconSize: '1rem' },
|
|
49
|
+
medium: { width: 44, height: 44, fontSize: '0.875rem', iconSize: '1.25rem' },
|
|
26
50
|
large: { width: 44, height: 44, fontSize: '1rem', iconSize: '1.5rem' },
|
|
27
51
|
};
|
|
28
52
|
export function ActionButtons({ buttons, layout = 'horizontal', position = 'inline', showLabels = false, size = 'medium', className, style, }) {
|
|
@@ -31,11 +55,11 @@ export function ActionButtons({ buttons, layout = 'horizontal', position = 'inli
|
|
|
31
55
|
const containerStyle = {
|
|
32
56
|
display: 'flex',
|
|
33
57
|
flexDirection: layout === 'vertical' ? 'column' : 'row',
|
|
34
|
-
gap:
|
|
58
|
+
gap: SPACING.sm,
|
|
35
59
|
...(isOverlay ? {
|
|
36
60
|
position: 'absolute',
|
|
37
|
-
...(position === 'top-right' ? { top:
|
|
38
|
-
...(position === 'bottom-center' ? { bottom:
|
|
61
|
+
...(position === 'top-right' ? { top: SPACING.sm, right: SPACING.sm } : {}),
|
|
62
|
+
...(position === 'bottom-center' ? { bottom: SPACING.sm, left: '50%', transform: 'translateX(-50%)' } : {}),
|
|
39
63
|
} : {}),
|
|
40
64
|
...style,
|
|
41
65
|
};
|
|
@@ -50,12 +74,12 @@ export function ActionButtons({ buttons, layout = 'horizontal', position = 'inli
|
|
|
50
74
|
fontSize: sizeConfig.fontSize,
|
|
51
75
|
fontWeight: 500,
|
|
52
76
|
border: 'none',
|
|
53
|
-
borderRadius:
|
|
54
|
-
backgroundColor: 'var(--seekora-bg-surface,
|
|
55
|
-
color: 'var(--seekora-text,
|
|
77
|
+
borderRadius: BORDER_RADIUS.md,
|
|
78
|
+
backgroundColor: 'var(--seekora-bg-surface, transparent)',
|
|
79
|
+
color: 'var(--seekora-text, inherit)',
|
|
56
80
|
cursor: 'pointer',
|
|
57
|
-
transition:
|
|
58
|
-
boxShadow:
|
|
81
|
+
transition: `all ${TRANSITIONS.fast}`,
|
|
82
|
+
boxShadow: SHADOWS.md,
|
|
59
83
|
};
|
|
60
84
|
const handleClick = (btn, e) => {
|
|
61
85
|
e.stopPropagation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BadgeList.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/BadgeList.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"BadgeList.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/BadgeList.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAyB7D,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,QAAQ,CAAC;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAkBD,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,SAAS,EACT,QAAqB,EACrB,SAAS,EACT,KAAK,GACN,EAAE,cAAc,4BA4ChB"}
|
|
@@ -3,19 +3,39 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
|
+
const SPACING = {
|
|
7
|
+
xs: 4,
|
|
8
|
+
sm: 8,
|
|
9
|
+
md: 12,
|
|
10
|
+
lg: 16,
|
|
11
|
+
xl: 24,
|
|
12
|
+
};
|
|
13
|
+
const BORDER_RADIUS = {
|
|
14
|
+
sm: 4,
|
|
15
|
+
md: 6,
|
|
16
|
+
lg: 8,
|
|
17
|
+
full: 9999,
|
|
18
|
+
};
|
|
19
|
+
// Z-index scale for consistent layering
|
|
20
|
+
const Z_INDEX = {
|
|
21
|
+
dropdown: 100,
|
|
22
|
+
modal: 200,
|
|
23
|
+
overlay: 300,
|
|
24
|
+
tooltip: 50,
|
|
25
|
+
};
|
|
6
26
|
const positionStyles = {
|
|
7
|
-
'top-left': { position: 'absolute', top:
|
|
8
|
-
'top-right': { position: 'absolute', top:
|
|
9
|
-
'bottom-left': { position: 'absolute', bottom:
|
|
10
|
-
'bottom-right': { position: 'absolute', bottom:
|
|
27
|
+
'top-left': { position: 'absolute', top: SPACING.sm, left: SPACING.sm },
|
|
28
|
+
'top-right': { position: 'absolute', top: SPACING.sm, right: SPACING.sm },
|
|
29
|
+
'bottom-left': { position: 'absolute', bottom: SPACING.sm, left: SPACING.sm },
|
|
30
|
+
'bottom-right': { position: 'absolute', bottom: SPACING.sm, right: SPACING.sm },
|
|
11
31
|
inline: {},
|
|
12
32
|
};
|
|
13
33
|
const typeColors = {
|
|
14
|
-
sale: { bg: '#ef4444', text: '#fff' },
|
|
15
|
-
new: { bg: '#3b82f6', text: '#fff' },
|
|
16
|
-
soldOut: { bg: '#6b7280', text: '#fff' },
|
|
17
|
-
limited: { bg: '#f59e0b', text: '#fff' },
|
|
18
|
-
custom: { bg: '#111827', text: '#fff' },
|
|
34
|
+
sale: { bg: 'var(--seekora-badge-sale-bg, #ef4444)', text: 'var(--seekora-badge-sale-text, #fff)' },
|
|
35
|
+
new: { bg: 'var(--seekora-badge-new-bg, #3b82f6)', text: 'var(--seekora-badge-new-text, #fff)' },
|
|
36
|
+
soldOut: { bg: 'var(--seekora-badge-soldout-bg, #6b7280)', text: 'var(--seekora-badge-soldout-text, #fff)' },
|
|
37
|
+
limited: { bg: 'var(--seekora-badge-limited-bg, #f59e0b)', text: 'var(--seekora-badge-limited-text, #fff)' },
|
|
38
|
+
custom: { bg: 'var(--seekora-badge-custom-bg, #111827)', text: 'var(--seekora-badge-custom-text, #fff)' },
|
|
19
39
|
};
|
|
20
40
|
export function BadgeList({ badges, maxBadges, position = 'top-left', className, style, }) {
|
|
21
41
|
if (!badges || badges.length === 0)
|
|
@@ -24,8 +44,8 @@ export function BadgeList({ badges, maxBadges, position = 'top-left', className,
|
|
|
24
44
|
return (React.createElement("div", { className: clsx('seekora-badge-list', className), style: {
|
|
25
45
|
display: 'flex',
|
|
26
46
|
flexWrap: 'wrap',
|
|
27
|
-
gap:
|
|
28
|
-
zIndex:
|
|
47
|
+
gap: SPACING.xs,
|
|
48
|
+
zIndex: 2,
|
|
29
49
|
...positionStyles[position],
|
|
30
50
|
...style,
|
|
31
51
|
} }, visible.map((badge, i) => {
|
|
@@ -33,10 +53,10 @@ export function BadgeList({ badges, maxBadges, position = 'top-left', className,
|
|
|
33
53
|
return (React.createElement("span", { key: `${badge.text}-${i}`, className: clsx('seekora-badge', badge.type && `seekora-badge--${badge.type === 'soldOut' ? 'sold-out' : badge.type}`), style: {
|
|
34
54
|
display: 'inline-block',
|
|
35
55
|
padding: '2px 8px',
|
|
36
|
-
borderRadius:
|
|
56
|
+
borderRadius: BORDER_RADIUS.sm,
|
|
37
57
|
fontSize: '0.6875rem',
|
|
38
58
|
fontWeight: 600,
|
|
39
|
-
lineHeight: 1.
|
|
59
|
+
lineHeight: 1.2,
|
|
40
60
|
backgroundColor: badge.color ?? colors.bg,
|
|
41
61
|
color: badge.textColor ?? colors.text,
|
|
42
62
|
whiteSpace: 'nowrap',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageDisplay.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ImageDisplay.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAgC,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ImageDisplay.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ImageDisplay.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAgC,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAE/F,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gCAAgC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAaD,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,OAAkB,EAClB,GAAQ,EACR,SAAS,EACT,KAAK,EACL,gBAAwB,EACxB,kBAAyB,EACzB,UAAkB,EAClB,QAAiB,EACjB,SAAe,EACf,QAAe,GAChB,EAAE,iBAAiB,qBA8NnB"}
|
|
@@ -7,18 +7,27 @@
|
|
|
7
7
|
import React, { useState } from 'react';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
9
|
import { ImageZoom } from './ImageZoom';
|
|
10
|
+
import { useIsMobile, useTouchTargetSize, useResponsiveGap } from '../../utils/responsive';
|
|
10
11
|
const imgBaseStyle = {
|
|
11
12
|
width: '100%',
|
|
13
|
+
height: 'auto',
|
|
12
14
|
aspectRatio: '1',
|
|
13
15
|
objectFit: 'cover',
|
|
14
16
|
borderRadius: 4,
|
|
15
17
|
backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
|
|
18
|
+
display: 'block',
|
|
19
|
+
overflow: 'hidden',
|
|
16
20
|
};
|
|
17
21
|
export function ImageDisplay({ images, variant = 'single', alt = '', className, style, carouselAutoplay = false, carouselIntervalMs = 4000, enableZoom = false, zoomMode = 'both', zoomLevel = 2.5, showDots = true, }) {
|
|
18
22
|
const [index, setIndex] = useState(0);
|
|
19
23
|
const [hovering, setHovering] = useState(false);
|
|
20
24
|
const safeImages = Array.isArray(images) ? images.filter(Boolean) : [];
|
|
21
25
|
const current = safeImages[index] ?? safeImages[0];
|
|
26
|
+
// Responsive values
|
|
27
|
+
const isMobile = useIsMobile();
|
|
28
|
+
const arrowSize = useTouchTargetSize(32); // 44px on mobile, 32px on desktop
|
|
29
|
+
const thumbSize = isMobile ? 56 : 48; // Larger thumbnails on mobile
|
|
30
|
+
const responsiveGap = useResponsiveGap(8);
|
|
22
31
|
if (safeImages.length === 0) {
|
|
23
32
|
return React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-placeholder', className), style: { ...imgBaseStyle, ...style }, "aria-hidden": true });
|
|
24
33
|
}
|
|
@@ -55,26 +64,28 @@ export function ImageDisplay({ images, variant = 'single', alt = '', className,
|
|
|
55
64
|
return (React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-carousel', className), style: { position: 'relative', ...style } },
|
|
56
65
|
mainImage,
|
|
57
66
|
safeImages.length > 1 && (React.createElement(React.Fragment, null,
|
|
58
|
-
React.createElement("button", { type: "button", "aria-label": "Previous", className: "seekora-img-carousel-prev", style: arrowStyle(true), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(-1); }, onClick: (e) => e.stopPropagation(), onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,1)'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.9)'; } }, "\u2039"),
|
|
59
|
-
React.createElement("button", { type: "button", "aria-label": "Next", className: "seekora-img-carousel-next", style: arrowStyle(false), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(1); }, onClick: (e) => e.stopPropagation(), onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,1)'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.9)'; } }, "\u203A"),
|
|
67
|
+
React.createElement("button", { type: "button", "aria-label": "Previous", className: "seekora-img-carousel-prev", style: arrowStyle(true, arrowSize), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(-1); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg-hover, rgba(255,255,255,1))'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg, rgba(255,255,255,0.9))'; } }, "\u2039"),
|
|
68
|
+
React.createElement("button", { type: "button", "aria-label": "Next", className: "seekora-img-carousel-next", style: arrowStyle(false, arrowSize), onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); go(1); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg-hover, rgba(255,255,255,1))'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = 'var(--seekora-carousel-btn-bg, rgba(255,255,255,0.9))'; } }, "\u203A"),
|
|
60
69
|
showDots && (React.createElement("div", { className: "seekora-img-carousel-dots", style: {
|
|
61
70
|
position: 'absolute',
|
|
62
|
-
bottom: 8,
|
|
71
|
+
bottom: isMobile ? 12 : 8,
|
|
63
72
|
left: '50%',
|
|
64
73
|
transform: 'translateX(-50%)',
|
|
65
74
|
display: 'flex',
|
|
66
|
-
gap: 6,
|
|
67
|
-
padding: '6px 12px',
|
|
68
|
-
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
75
|
+
gap: isMobile ? 8 : 6,
|
|
76
|
+
padding: isMobile ? '8px 16px' : '6px 12px',
|
|
77
|
+
backgroundColor: 'var(--seekora-carousel-dots-bg, rgba(0,0,0,0.5))',
|
|
69
78
|
borderRadius: 12,
|
|
70
79
|
zIndex: 10,
|
|
71
|
-
} }, safeImages.map((_, i) => (React.createElement("button", { key: i, type: "button", "aria-label": `Go to image ${i + 1}`, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); }, onClick: (e) => { e.stopPropagation(); setIndex(i); }, style: {
|
|
72
|
-
width: 8,
|
|
73
|
-
height: 8,
|
|
80
|
+
} }, safeImages.map((_, i) => (React.createElement("button", { key: i, type: "button", "aria-label": `Go to image ${i + 1}`, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, style: {
|
|
81
|
+
width: isMobile ? 10 : 8,
|
|
82
|
+
height: isMobile ? 10 : 8,
|
|
83
|
+
minWidth: isMobile ? 44 : 32, // Ensure touch target
|
|
84
|
+
minHeight: isMobile ? 44 : 32,
|
|
74
85
|
borderRadius: '50%',
|
|
75
86
|
border: 'none',
|
|
76
87
|
padding: 0,
|
|
77
|
-
backgroundColor: i === index ? '#fff' : 'rgba(255,255,255,0.5)',
|
|
88
|
+
backgroundColor: i === index ? 'var(--seekora-carousel-dot-active, #fff)' : 'var(--seekora-carousel-dot, rgba(255,255,255,0.5))',
|
|
78
89
|
cursor: 'pointer',
|
|
79
90
|
transition: 'all 150ms ease',
|
|
80
91
|
} })))))))));
|
|
@@ -82,26 +93,28 @@ export function ImageDisplay({ images, variant = 'single', alt = '', className,
|
|
|
82
93
|
if (variant === 'thumbStrip' || variant === 'thumbList') {
|
|
83
94
|
const thumbMainStyle = style?.aspectRatio ? { ...imgBaseStyle, aspectRatio: style.aspectRatio } : imgBaseStyle;
|
|
84
95
|
const mainImage = enableZoom ? (React.createElement(ImageZoom, { src: current, alt: alt, mode: zoomMode, zoomLevel: zoomLevel, images: safeImages, currentIndex: index, className: "seekora-img-thumb-main", style: thumbMainStyle })) : (React.createElement("img", { src: current, alt: alt, className: "seekora-img-thumb-main", style: thumbMainStyle, loading: "lazy" }));
|
|
85
|
-
return (React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-thumbstrip', className), style: { display: 'flex', flexDirection: 'column', gap:
|
|
96
|
+
return (React.createElement("div", { className: clsx('seekora-img-display', 'seekora-img-thumbstrip', className), style: { display: 'flex', flexDirection: 'column', gap: responsiveGap, ...style } },
|
|
86
97
|
mainImage,
|
|
87
|
-
React.createElement("div", { className: "seekora-img-thumbs", style: { display: 'flex', gap: 4, overflowX: 'auto', paddingBottom: 4 } }, safeImages.map((src, i) => (React.createElement("button", { type: "button", key: i, className: clsx('seekora-img-thumb', i === index && 'seekora-img-thumb--active'), style: { flexShrink: 0, width:
|
|
98
|
+
React.createElement("div", { className: "seekora-img-thumbs", style: { display: 'flex', gap: isMobile ? 6 : 4, overflowX: 'auto', paddingBottom: isMobile ? 6 : 4 } }, safeImages.map((src, i) => (React.createElement("button", { type: "button", key: i, className: clsx('seekora-img-thumb', i === index && 'seekora-img-thumb--active'), style: { flexShrink: 0, width: thumbSize, height: thumbSize, minWidth: thumbSize, minHeight: thumbSize, padding: 0, border: i === index ? '2px solid var(--seekora-primary)' : '1px solid transparent', borderRadius: 4, overflow: 'hidden', cursor: 'pointer', background: 'none' }, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, onClick: (e) => { e.stopPropagation(); e.preventDefault(); } },
|
|
88
99
|
React.createElement("img", { src: src, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover' } })))))));
|
|
89
100
|
}
|
|
90
101
|
return React.createElement("img", { src: current, alt: alt, className: clsx('seekora-img-display', className), style: { ...imgBaseStyle, ...style }, loading: "lazy" });
|
|
91
102
|
}
|
|
92
|
-
function arrowStyle(left) {
|
|
103
|
+
function arrowStyle(left, size = 32) {
|
|
93
104
|
return {
|
|
94
105
|
position: 'absolute',
|
|
95
106
|
top: '50%',
|
|
96
|
-
[left ? 'left' : 'right']: 8,
|
|
107
|
+
[left ? 'left' : 'right']: size >= 44 ? 4 : 8, // Less offset on mobile for larger buttons
|
|
97
108
|
transform: 'translateY(-50%)',
|
|
98
|
-
width:
|
|
99
|
-
height:
|
|
109
|
+
width: size,
|
|
110
|
+
height: size,
|
|
111
|
+
minWidth: size,
|
|
112
|
+
minHeight: size,
|
|
100
113
|
borderRadius: '50%',
|
|
101
114
|
border: 'none',
|
|
102
|
-
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
|
103
|
-
color: '#111',
|
|
104
|
-
fontSize: '1.25rem',
|
|
115
|
+
backgroundColor: 'var(--seekora-carousel-btn-bg, rgba(255, 255, 255, 0.9))',
|
|
116
|
+
color: 'var(--seekora-carousel-btn-text, #111)',
|
|
117
|
+
fontSize: size >= 44 ? '1.5rem' : '1.25rem', // Larger font on mobile
|
|
105
118
|
fontWeight: 'bold',
|
|
106
119
|
cursor: 'pointer',
|
|
107
120
|
display: 'flex',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageZoom.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ImageZoom.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EACxB,GAAG,EACH,GAAQ,EACR,IAAa,EACb,SAAe,EACf,SAAS,EACT,KAAK,EACL,iBAAwB,EACxB,QAAc,EACd,aAA2C,EAC3C,MAAM,EACN,YAAgB,GACjB,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ImageZoom.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/ImageZoom.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EACxB,GAAG,EACH,GAAQ,EACR,IAAa,EACb,SAAe,EACf,SAAS,EACT,KAAK,EACL,iBAAwB,EACxB,QAAc,EACd,aAA2C,EAC3C,MAAM,EACN,YAAgB,GACjB,EAAE,cAAc,qBAiiBhB"}
|
|
@@ -114,10 +114,66 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
114
114
|
const rect = containerRef.current.getBoundingClientRect();
|
|
115
115
|
const bgPosX = (cursorPos.x / rect.width) * 100;
|
|
116
116
|
const bgPosY = (cursorPos.y / rect.height) * 100;
|
|
117
|
+
// Calculate available space in all directions
|
|
118
|
+
const viewportWidth = window.innerWidth;
|
|
119
|
+
const viewportHeight = window.innerHeight;
|
|
120
|
+
const gap = 16;
|
|
121
|
+
const mouseBuffer = 50; // Minimum distance from mouse cursor
|
|
122
|
+
// Calculate mouse position in viewport
|
|
123
|
+
const mouseX = rect.left + cursorPos.x;
|
|
124
|
+
const mouseY = rect.top + cursorPos.y;
|
|
125
|
+
// Calculate space available in each direction
|
|
126
|
+
const spaceRight = viewportWidth - rect.right - gap;
|
|
127
|
+
const spaceLeft = rect.left - gap;
|
|
128
|
+
// Determine optimal horizontal position
|
|
129
|
+
let left;
|
|
130
|
+
let top = rect.top;
|
|
131
|
+
// Try right side first (default Amazon-style)
|
|
132
|
+
if (spaceRight >= zoomPanelSize.width) {
|
|
133
|
+
left = rect.right + gap;
|
|
134
|
+
}
|
|
135
|
+
// Try left side
|
|
136
|
+
else if (spaceLeft >= zoomPanelSize.width) {
|
|
137
|
+
left = rect.left - zoomPanelSize.width - gap;
|
|
138
|
+
}
|
|
139
|
+
// Not enough space on either side - center on the side with more space
|
|
140
|
+
else if (spaceRight > spaceLeft) {
|
|
141
|
+
left = rect.right + gap;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
left = Math.max(gap, rect.left - zoomPanelSize.width - gap);
|
|
145
|
+
}
|
|
146
|
+
// Adjust vertical position to keep within viewport
|
|
147
|
+
// Try to align with image top by default
|
|
148
|
+
if (rect.top + zoomPanelSize.height > viewportHeight - gap) {
|
|
149
|
+
// Panel would overflow bottom - adjust upward
|
|
150
|
+
top = Math.max(gap, viewportHeight - zoomPanelSize.height - gap);
|
|
151
|
+
}
|
|
152
|
+
// Ensure panel doesn't overlap with mouse cursor
|
|
153
|
+
const panelRight = left + zoomPanelSize.width;
|
|
154
|
+
const panelBottom = top + zoomPanelSize.height;
|
|
155
|
+
// Check if mouse is inside the panel area
|
|
156
|
+
if (mouseX >= left - mouseBuffer &&
|
|
157
|
+
mouseX <= panelRight + mouseBuffer &&
|
|
158
|
+
mouseY >= top - mouseBuffer &&
|
|
159
|
+
mouseY <= panelBottom + mouseBuffer) {
|
|
160
|
+
// Mouse is too close - try to reposition
|
|
161
|
+
// If on right side and there's space on left, flip to left
|
|
162
|
+
if (left > rect.right && spaceLeft >= zoomPanelSize.width) {
|
|
163
|
+
left = rect.left - zoomPanelSize.width - gap;
|
|
164
|
+
}
|
|
165
|
+
// If on left side and there's space on right, flip to right
|
|
166
|
+
else if (left < rect.left && spaceRight >= zoomPanelSize.width) {
|
|
167
|
+
left = rect.right + gap;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Clamp to viewport boundaries
|
|
171
|
+
left = Math.max(gap, Math.min(left, viewportWidth - zoomPanelSize.width - gap));
|
|
172
|
+
top = Math.max(gap, Math.min(top, viewportHeight - zoomPanelSize.height - gap));
|
|
117
173
|
return {
|
|
118
|
-
position: 'fixed',
|
|
119
|
-
top
|
|
120
|
-
left
|
|
174
|
+
position: 'fixed',
|
|
175
|
+
top,
|
|
176
|
+
left,
|
|
121
177
|
width: zoomPanelSize.width,
|
|
122
178
|
height: zoomPanelSize.height,
|
|
123
179
|
backgroundImage: `url(${src})`,
|
|
@@ -126,8 +182,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
126
182
|
backgroundRepeat: 'no-repeat',
|
|
127
183
|
border: '2px solid var(--seekora-border-color, #e5e7eb)',
|
|
128
184
|
borderRadius: 8,
|
|
129
|
-
boxShadow: '0 8px 24px rgba(0,0,0,0.2)',
|
|
130
|
-
backgroundColor: '#fff',
|
|
185
|
+
boxShadow: 'var(--seekora-zoom-panel-shadow, 0 8px 24px rgba(0,0,0,0.2))',
|
|
186
|
+
backgroundColor: 'var(--seekora-zoom-panel-bg, #fff)',
|
|
131
187
|
pointerEvents: 'none',
|
|
132
188
|
zIndex: 9998,
|
|
133
189
|
};
|
|
@@ -142,9 +198,9 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
142
198
|
height: lensSize,
|
|
143
199
|
left: cursorPos.x - lensSize / 2,
|
|
144
200
|
top: cursorPos.y - lensSize / 2,
|
|
145
|
-
border: '2px solid rgba(255,255,255,0.8)',
|
|
201
|
+
border: 'var(--seekora-lens-border, 2px solid rgba(255,255,255,0.8))',
|
|
146
202
|
borderRadius: '50%',
|
|
147
|
-
boxShadow: '0 0 0 1px rgba(0,0,0,0.3), inset 0 0 0 1px rgba(0,0,0,0.3)',
|
|
203
|
+
boxShadow: 'var(--seekora-lens-shadow, 0 0 0 1px rgba(0,0,0,0.3), inset 0 0 0 1px rgba(0,0,0,0.3))',
|
|
148
204
|
pointerEvents: 'none',
|
|
149
205
|
overflow: 'hidden',
|
|
150
206
|
zIndex: 100,
|
|
@@ -154,7 +210,6 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
154
210
|
if (!containerRef.current || !imageRef.current)
|
|
155
211
|
return {};
|
|
156
212
|
const rect = containerRef.current.getBoundingClientRect();
|
|
157
|
-
const imgRect = imageRef.current.getBoundingClientRect();
|
|
158
213
|
return {
|
|
159
214
|
position: 'absolute',
|
|
160
215
|
width: rect.width * zoomLevel,
|
|
@@ -174,8 +229,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
174
229
|
width: 32,
|
|
175
230
|
height: 32,
|
|
176
231
|
borderRadius: '50%',
|
|
177
|
-
backgroundColor: 'rgba(0,0,0,0.6)',
|
|
178
|
-
color: '#fff',
|
|
232
|
+
backgroundColor: 'var(--seekora-zoom-indicator-bg, rgba(0,0,0,0.6))',
|
|
233
|
+
color: 'var(--seekora-zoom-indicator-text, #fff)',
|
|
179
234
|
display: 'flex',
|
|
180
235
|
alignItems: 'center',
|
|
181
236
|
justifyContent: 'center',
|
|
@@ -192,8 +247,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
192
247
|
top: cursorPos.y - 75,
|
|
193
248
|
width: 150,
|
|
194
249
|
height: 150,
|
|
195
|
-
border: '2px solid rgba(0,0,0,0.3)',
|
|
196
|
-
backgroundColor: 'rgba(255,255,255,0.1)',
|
|
250
|
+
border: 'var(--seekora-hover-area-border, 2px solid rgba(0,0,0,0.3))',
|
|
251
|
+
backgroundColor: 'var(--seekora-hover-area-bg, rgba(255,255,255,0.1))',
|
|
197
252
|
pointerEvents: 'none',
|
|
198
253
|
zIndex: 50,
|
|
199
254
|
} })),
|
|
@@ -204,7 +259,7 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
204
259
|
left: 0,
|
|
205
260
|
right: 0,
|
|
206
261
|
bottom: 0,
|
|
207
|
-
backgroundColor: 'rgba(0,0,0,0.95)',
|
|
262
|
+
backgroundColor: 'var(--seekora-lightbox-bg, rgba(0,0,0,0.95))',
|
|
208
263
|
zIndex: 9999,
|
|
209
264
|
display: 'flex',
|
|
210
265
|
alignItems: 'center',
|
|
@@ -220,8 +275,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
220
275
|
height: 44,
|
|
221
276
|
borderRadius: '50%',
|
|
222
277
|
border: 'none',
|
|
223
|
-
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
224
|
-
color: '#fff',
|
|
278
|
+
backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
|
|
279
|
+
color: 'var(--seekora-lightbox-btn-text, #fff)',
|
|
225
280
|
fontSize: '1.5rem',
|
|
226
281
|
cursor: 'pointer',
|
|
227
282
|
display: 'flex',
|
|
@@ -233,9 +288,9 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
233
288
|
e.stopPropagation();
|
|
234
289
|
closeLightbox();
|
|
235
290
|
}, onMouseEnter: (e) => {
|
|
236
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
|
|
291
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
|
|
237
292
|
}, onMouseLeave: (e) => {
|
|
238
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
|
|
293
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
|
|
239
294
|
} }, "\u2715"),
|
|
240
295
|
hasMultipleImages && (React.createElement(React.Fragment, null,
|
|
241
296
|
React.createElement("button", { type: "button", "aria-label": "Previous image", style: {
|
|
@@ -247,8 +302,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
247
302
|
height: 56,
|
|
248
303
|
borderRadius: '50%',
|
|
249
304
|
border: 'none',
|
|
250
|
-
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
251
|
-
color: '#fff',
|
|
305
|
+
backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
|
|
306
|
+
color: 'var(--seekora-lightbox-btn-text, #fff)',
|
|
252
307
|
fontSize: '2rem',
|
|
253
308
|
fontWeight: 'bold',
|
|
254
309
|
cursor: 'pointer',
|
|
@@ -261,9 +316,9 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
261
316
|
e.stopPropagation();
|
|
262
317
|
goToPrev();
|
|
263
318
|
}, onMouseEnter: (e) => {
|
|
264
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
|
|
319
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
|
|
265
320
|
}, onMouseLeave: (e) => {
|
|
266
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
|
|
321
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
|
|
267
322
|
} }, "\u2039"),
|
|
268
323
|
React.createElement("button", { type: "button", "aria-label": "Next image", style: {
|
|
269
324
|
position: 'absolute',
|
|
@@ -274,8 +329,8 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
274
329
|
height: 56,
|
|
275
330
|
borderRadius: '50%',
|
|
276
331
|
border: 'none',
|
|
277
|
-
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
278
|
-
color: '#fff',
|
|
332
|
+
backgroundColor: 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))',
|
|
333
|
+
color: 'var(--seekora-lightbox-btn-text, #fff)',
|
|
279
334
|
fontSize: '2rem',
|
|
280
335
|
fontWeight: 'bold',
|
|
281
336
|
cursor: 'pointer',
|
|
@@ -288,9 +343,9 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
288
343
|
e.stopPropagation();
|
|
289
344
|
goToNext();
|
|
290
345
|
}, onMouseEnter: (e) => {
|
|
291
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.3)';
|
|
346
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg-hover, rgba(255,255,255,0.3))';
|
|
292
347
|
}, onMouseLeave: (e) => {
|
|
293
|
-
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.2)';
|
|
348
|
+
e.currentTarget.style.backgroundColor = 'var(--seekora-lightbox-btn-bg, rgba(255,255,255,0.2))';
|
|
294
349
|
} }, "\u203A"))),
|
|
295
350
|
React.createElement("img", { src: allImages[lightboxIndex], alt: alt, style: {
|
|
296
351
|
maxWidth: '90%',
|
|
@@ -316,7 +371,7 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
316
371
|
width: 60,
|
|
317
372
|
height: 60,
|
|
318
373
|
padding: 0,
|
|
319
|
-
border: i === lightboxIndex ? '3px solid #fff' : '2px solid rgba(255,255,255,0.3)',
|
|
374
|
+
border: i === lightboxIndex ? 'var(--seekora-lightbox-thumb-border-active, 3px solid #fff)' : 'var(--seekora-lightbox-thumb-border, 2px solid rgba(255,255,255,0.3))',
|
|
320
375
|
borderRadius: 4,
|
|
321
376
|
overflow: 'hidden',
|
|
322
377
|
cursor: 'pointer',
|
|
@@ -332,10 +387,10 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
332
387
|
} },
|
|
333
388
|
React.createElement("img", { src: img, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover' } }))))),
|
|
334
389
|
React.createElement("div", { style: {
|
|
335
|
-
color: 'rgba(255,255,255,0.9)',
|
|
390
|
+
color: 'var(--seekora-lightbox-counter-text, rgba(255,255,255,0.9))',
|
|
336
391
|
fontSize: '0.875rem',
|
|
337
392
|
textAlign: 'center',
|
|
338
|
-
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
393
|
+
backgroundColor: 'var(--seekora-lightbox-counter-bg, rgba(0,0,0,0.5))',
|
|
339
394
|
padding: '4px 12px',
|
|
340
395
|
borderRadius: 12,
|
|
341
396
|
} },
|
|
@@ -347,10 +402,10 @@ export function ImageZoom({ src, alt = '', mode = 'both', zoomLevel = 2.5, class
|
|
|
347
402
|
top: 20,
|
|
348
403
|
left: '50%',
|
|
349
404
|
transform: 'translateX(-50%)',
|
|
350
|
-
color: 'rgba(255,255,255,0.7)',
|
|
405
|
+
color: 'var(--seekora-lightbox-instructions-text, rgba(255,255,255,0.7))',
|
|
351
406
|
fontSize: '0.875rem',
|
|
352
407
|
textAlign: 'center',
|
|
353
|
-
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
408
|
+
backgroundColor: 'var(--seekora-lightbox-instructions-bg, rgba(0,0,0,0.5))',
|
|
354
409
|
padding: '8px 16px',
|
|
355
410
|
borderRadius: 12,
|
|
356
411
|
} }, hasMultipleImages ? 'Use arrow keys or click thumbnails to navigate • ESC to close' : 'Click outside or press ESC to close')))));
|