@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.
Files changed (143) hide show
  1. package/dist/components/CurrentRefinements.d.ts.map +1 -1
  2. package/dist/components/CurrentRefinements.js +69 -9
  3. package/dist/components/FacetDropdown.d.ts +94 -0
  4. package/dist/components/FacetDropdown.d.ts.map +1 -0
  5. package/dist/components/FacetDropdown.js +396 -0
  6. package/dist/components/Facets.d.ts +30 -0
  7. package/dist/components/Facets.d.ts.map +1 -1
  8. package/dist/components/Facets.js +215 -7
  9. package/dist/components/FederatedDropdown.d.ts.map +1 -1
  10. package/dist/components/FederatedDropdown.js +45 -31
  11. package/dist/components/InfiniteHits.d.ts +0 -7
  12. package/dist/components/InfiniteHits.d.ts.map +1 -1
  13. package/dist/components/InfiniteHits.js +2 -13
  14. package/dist/components/Pagination.d.ts.map +1 -1
  15. package/dist/components/Pagination.js +27 -9
  16. package/dist/components/QuerySuggestions.d.ts +0 -4
  17. package/dist/components/QuerySuggestions.d.ts.map +1 -1
  18. package/dist/components/QuerySuggestions.js +1 -17
  19. package/dist/components/QuerySuggestionsDropdown.d.ts +0 -4
  20. package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
  21. package/dist/components/QuerySuggestionsDropdown.js +32 -33
  22. package/dist/components/RangeInput.d.ts.map +1 -1
  23. package/dist/components/RangeInput.js +6 -6
  24. package/dist/components/RangeSlider.d.ts.map +1 -1
  25. package/dist/components/RangeSlider.js +54 -32
  26. package/dist/components/Recommendations.d.ts +0 -7
  27. package/dist/components/Recommendations.d.ts.map +1 -1
  28. package/dist/components/Recommendations.js +3 -23
  29. package/dist/components/RichQuerySuggestions.d.ts +0 -4
  30. package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
  31. package/dist/components/RichQuerySuggestions.js +40 -35
  32. package/dist/components/SearchBar.d.ts +0 -4
  33. package/dist/components/SearchBar.d.ts.map +1 -1
  34. package/dist/components/SearchBar.js +17 -11
  35. package/dist/components/SearchBarWithSuggestions.js +4 -4
  36. package/dist/components/SearchLayout.d.ts.map +1 -1
  37. package/dist/components/SearchLayout.js +22 -17
  38. package/dist/components/SearchProvider.d.ts.map +1 -1
  39. package/dist/components/SearchProvider.js +1 -3
  40. package/dist/components/SearchResults.d.ts +0 -6
  41. package/dist/components/SearchResults.d.ts.map +1 -1
  42. package/dist/components/SearchResults.js +38 -39
  43. package/dist/components/primitives/ActionButtons.d.ts.map +1 -1
  44. package/dist/components/primitives/ActionButtons.js +34 -10
  45. package/dist/components/primitives/BadgeList.d.ts.map +1 -1
  46. package/dist/components/primitives/BadgeList.js +33 -13
  47. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -1
  48. package/dist/components/primitives/ImageDisplay.js +32 -19
  49. package/dist/components/primitives/ImageZoom.d.ts.map +1 -1
  50. package/dist/components/primitives/ImageZoom.js +85 -30
  51. package/dist/components/primitives/VariantSelector.js +10 -10
  52. package/dist/components/primitives/VariantSwatches.d.ts.map +1 -1
  53. package/dist/components/primitives/VariantSwatches.js +28 -13
  54. package/dist/components/product-page/ProductGallery.d.ts +8 -1
  55. package/dist/components/product-page/ProductGallery.d.ts.map +1 -1
  56. package/dist/components/product-page/ProductGallery.js +2 -2
  57. package/dist/components/section-primitives/SectionItemGrid.d.ts +1 -3
  58. package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -1
  59. package/dist/components/section-primitives/SectionItemGrid.js +1 -4
  60. package/dist/components/section-primitives/SectionSearchProvider.d.ts +3 -1
  61. package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -1
  62. package/dist/components/section-primitives/SectionSearchProvider.js +3 -2
  63. package/dist/components/section-primitives/index.d.ts +0 -1
  64. package/dist/components/section-primitives/index.d.ts.map +1 -1
  65. package/dist/components/section-primitives/index.js +0 -1
  66. package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
  67. package/dist/components/suggestions/AmazonDropdown.js +3 -21
  68. package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
  69. package/dist/components/suggestions/GoogleDropdown.js +3 -20
  70. package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
  71. package/dist/components/suggestions/MinimalDropdown.js +2 -2
  72. package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
  73. package/dist/components/suggestions/MobileSheetDropdown.js +78 -78
  74. package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
  75. package/dist/components/suggestions/PinterestDropdown.js +41 -41
  76. package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
  77. package/dist/components/suggestions/ShopifyDropdown.js +40 -41
  78. package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
  79. package/dist/components/suggestions/SpotlightDropdown.js +2 -3
  80. package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -1
  81. package/dist/components/suggestions/SuggestionSearchBar.js +2 -15
  82. package/dist/components/suggestions/types.d.ts +0 -6
  83. package/dist/components/suggestions/types.d.ts.map +1 -1
  84. package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -1
  85. package/dist/components/suggestions-primitives/DropdownPanel.js +15 -2
  86. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -1
  87. package/dist/components/suggestions-primitives/ItemCard.js +48 -11
  88. package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -1
  89. package/dist/components/suggestions-primitives/ItemGrid.js +18 -5
  90. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -1
  91. package/dist/components/suggestions-primitives/ProductCard.js +36 -12
  92. package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -1
  93. package/dist/components/suggestions-primitives/ProductCardLayouts.js +52 -20
  94. package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -1
  95. package/dist/components/suggestions-primitives/ProductGrid.js +8 -3
  96. package/dist/components/suggestions-primitives/RecentSearchesList.d.ts.map +1 -1
  97. package/dist/components/suggestions-primitives/RecentSearchesList.js +12 -5
  98. package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -1
  99. package/dist/components/suggestions-primitives/SearchInput.js +29 -10
  100. package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -1
  101. package/dist/components/suggestions-primitives/SuggestionItem.js +8 -3
  102. package/dist/components/suggestions-primitives/SuggestionList.d.ts +1 -8
  103. package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -1
  104. package/dist/components/suggestions-primitives/SuggestionList.js +1 -7
  105. package/dist/components/suggestions-primitives/TrendingList.d.ts.map +1 -1
  106. package/dist/components/suggestions-primitives/TrendingList.js +14 -7
  107. package/dist/components/suggestions-primitives/index.d.ts +1 -3
  108. package/dist/components/suggestions-primitives/index.d.ts.map +1 -1
  109. package/dist/components/suggestions-primitives/index.js +1 -2
  110. package/dist/docsearch/components/DocSearch.d.ts.map +1 -1
  111. package/dist/docsearch/components/DocSearch.js +1 -1
  112. package/dist/docsearch/components/Results.d.ts +1 -3
  113. package/dist/docsearch/components/Results.d.ts.map +1 -1
  114. package/dist/docsearch/components/Results.js +1 -9
  115. package/dist/docsearch/components/SearchBox.d.ts +1 -2
  116. package/dist/docsearch/components/SearchBox.d.ts.map +1 -1
  117. package/dist/docsearch/components/SearchBox.js +4 -6
  118. package/dist/docsearch/hooks/useSeekoraSearch.d.ts.map +1 -1
  119. package/dist/docsearch/hooks/useSeekoraSearch.js +6 -0
  120. package/dist/docsearch/types.d.ts +0 -1
  121. package/dist/docsearch/types.d.ts.map +1 -1
  122. package/dist/docsearch.css +2 -5
  123. package/dist/hooks/useClickTracking.d.ts.map +1 -1
  124. package/dist/hooks/useClickTracking.js +4 -11
  125. package/dist/hooks/useExperiment.d.ts.map +1 -1
  126. package/dist/hooks/useExperiment.js +10 -33
  127. package/dist/hooks/useFilters.d.ts +27 -0
  128. package/dist/hooks/useFilters.d.ts.map +1 -0
  129. package/dist/hooks/useFilters.js +66 -0
  130. package/dist/index.d.ts +10 -5
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +4 -2
  133. package/dist/index.umd.js +1 -1
  134. package/dist/src/index.d.ts +166 -81
  135. package/dist/src/index.esm.js +2141 -1048
  136. package/dist/src/index.esm.js.map +1 -1
  137. package/dist/src/index.js +2142 -1049
  138. package/dist/src/index.js.map +1 -1
  139. package/dist/utils/responsive.d.ts +130 -0
  140. package/dist/utils/responsive.d.ts.map +1 -0
  141. package/dist/utils/responsive.js +231 -0
  142. package/package.json +7 -7
  143. 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, showLoadingState = false, renderLoading, renderError, className, style, theme: customTheme, itemsPerPage = 20, showPagination = false, viewMode = 'list', fieldMapping, extractResults, enableKeyboardNavigation = true, autoFocus = false, minHeight = '400px', minWidth = '100%', loadingOpacity = 0.7, }) => {
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;AAG1B,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"}
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: 28, height: 28, fontSize: '0.75rem', iconSize: '1rem' },
25
- medium: { width: 36, height: 36, fontSize: '0.875rem', iconSize: '1.25rem' },
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: 6,
58
+ gap: SPACING.sm,
35
59
  ...(isOverlay ? {
36
60
  position: 'absolute',
37
- ...(position === 'top-right' ? { top: 8, right: 8 } : {}),
38
- ...(position === 'bottom-center' ? { bottom: 8, left: '50%', transform: 'translateX(-50%)' } : {}),
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: 6,
54
- backgroundColor: 'var(--seekora-bg-surface, #fff)',
55
- color: 'var(--seekora-text, #111827)',
77
+ borderRadius: BORDER_RADIUS.md,
78
+ backgroundColor: 'var(--seekora-bg-surface, transparent)',
79
+ color: 'var(--seekora-text, inherit)',
56
80
  cursor: 'pointer',
57
- transition: 'all 150ms ease',
58
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
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;AAE7D,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"}
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: 6, left: 6 },
8
- 'top-right': { position: 'absolute', top: 6, right: 6 },
9
- 'bottom-left': { position: 'absolute', bottom: 6, left: 6 },
10
- 'bottom-right': { position: 'absolute', bottom: 6, right: 6 },
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: 4,
28
- zIndex: 1,
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: 4,
56
+ borderRadius: BORDER_RADIUS.sm,
37
57
  fontSize: '0.6875rem',
38
58
  fontWeight: 600,
39
- lineHeight: 1.4,
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;AAEjD,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;AAUD,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,qBAsNnB"}
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: 8, ...style } },
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: 48, height: 48, padding: 0, border: i === index ? '2px solid var(--seekora-primary)' : '1px solid transparent', borderRadius: 4, overflow: 'hidden', cursor: 'pointer', background: 'none' }, onMouseDown: (e) => { e.stopPropagation(); e.preventDefault(); setIndex(i); }, onClick: (e) => e.stopPropagation() },
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: 32,
99
- height: 32,
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,qBAgehB"}
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', // Changed from absolute to fixed for better positioning
119
- top: rect.top,
120
- left: rect.right + 16, // 16px gap from the image
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')))));