@seekora-ai/ui-sdk-react 0.2.11 → 0.2.13

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 (120) hide show
  1. package/dist/components/InfiniteHits.d.ts +2 -0
  2. package/dist/components/InfiniteHits.d.ts.map +1 -1
  3. package/dist/components/InfiniteHits.js +6 -3
  4. package/dist/components/QuerySuggestions.d.ts +2 -0
  5. package/dist/components/QuerySuggestions.d.ts.map +1 -1
  6. package/dist/components/QuerySuggestions.js +4 -3
  7. package/dist/components/QuerySuggestionsDropdown.d.ts +1 -1
  8. package/dist/components/QuerySuggestionsDropdown.d.ts.map +1 -1
  9. package/dist/components/QuerySuggestionsDropdown.js +4 -4
  10. package/dist/components/Recommendations.d.ts +6 -0
  11. package/dist/components/Recommendations.d.ts.map +1 -1
  12. package/dist/components/Recommendations.js +12 -6
  13. package/dist/components/RichQuerySuggestions.d.ts +4 -0
  14. package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
  15. package/dist/components/RichQuerySuggestions.js +2 -3
  16. package/dist/components/SearchBar.d.ts +2 -0
  17. package/dist/components/SearchBar.d.ts.map +1 -1
  18. package/dist/components/SearchBar.js +5 -9
  19. package/dist/components/SearchResults.d.ts +2 -0
  20. package/dist/components/SearchResults.d.ts.map +1 -1
  21. package/dist/components/SearchResults.js +4 -2
  22. package/dist/components/primitives/ActionButtons.d.ts +27 -0
  23. package/dist/components/primitives/ActionButtons.d.ts.map +1 -0
  24. package/dist/components/primitives/ActionButtons.js +78 -0
  25. package/dist/components/primitives/AnalyticsProvider.d.ts +22 -0
  26. package/dist/components/primitives/AnalyticsProvider.d.ts.map +1 -0
  27. package/dist/components/primitives/AnalyticsProvider.js +87 -0
  28. package/dist/components/primitives/BadgeList.d.ts +14 -0
  29. package/dist/components/primitives/BadgeList.d.ts.map +1 -0
  30. package/dist/components/primitives/BadgeList.js +45 -0
  31. package/dist/components/primitives/ImageDisplay.d.ts +10 -1
  32. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -1
  33. package/dist/components/primitives/ImageDisplay.js +49 -9
  34. package/dist/components/primitives/ImageZoom.d.ts +33 -0
  35. package/dist/components/primitives/ImageZoom.d.ts.map +1 -0
  36. package/dist/components/primitives/ImageZoom.js +357 -0
  37. package/dist/components/primitives/PriceDisplay.d.ts +21 -0
  38. package/dist/components/primitives/PriceDisplay.d.ts.map +1 -0
  39. package/dist/components/primitives/PriceDisplay.js +44 -0
  40. package/dist/components/primitives/RatingDisplay.d.ts +43 -0
  41. package/dist/components/primitives/RatingDisplay.d.ts.map +1 -0
  42. package/dist/components/primitives/RatingDisplay.js +114 -0
  43. package/dist/components/primitives/VariantSelector.d.ts +30 -0
  44. package/dist/components/primitives/VariantSelector.d.ts.map +1 -0
  45. package/dist/components/primitives/VariantSelector.js +162 -0
  46. package/dist/components/primitives/VariantSwatches.d.ts +28 -0
  47. package/dist/components/primitives/VariantSwatches.d.ts.map +1 -0
  48. package/dist/components/primitives/VariantSwatches.js +173 -0
  49. package/dist/components/primitives/index.d.ts +9 -0
  50. package/dist/components/primitives/index.d.ts.map +1 -1
  51. package/dist/components/primitives/index.js +9 -0
  52. package/dist/components/primitives/withAnalytics.d.ts +24 -0
  53. package/dist/components/primitives/withAnalytics.d.ts.map +1 -0
  54. package/dist/components/primitives/withAnalytics.js +73 -0
  55. package/dist/components/product-page/ProductInfo.d.ts +25 -2
  56. package/dist/components/product-page/ProductInfo.d.ts.map +1 -1
  57. package/dist/components/product-page/ProductInfo.js +20 -5
  58. package/dist/components/section-primitives/SectionItemGrid.d.ts +3 -1
  59. package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -1
  60. package/dist/components/section-primitives/SectionItemGrid.js +3 -2
  61. package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
  62. package/dist/components/suggestions/AmazonDropdown.js +2 -2
  63. package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
  64. package/dist/components/suggestions/GoogleDropdown.js +2 -2
  65. package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
  66. package/dist/components/suggestions/MinimalDropdown.js +2 -2
  67. package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
  68. package/dist/components/suggestions/MobileSheetDropdown.js +2 -2
  69. package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
  70. package/dist/components/suggestions/PinterestDropdown.js +2 -2
  71. package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
  72. package/dist/components/suggestions/ShopifyDropdown.js +2 -2
  73. package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
  74. package/dist/components/suggestions/SpotlightDropdown.js +2 -2
  75. package/dist/components/suggestions/SuggestionSearchBar.d.ts.map +1 -1
  76. package/dist/components/suggestions/SuggestionSearchBar.js +1 -0
  77. package/dist/components/suggestions/types.d.ts +26 -0
  78. package/dist/components/suggestions/types.d.ts.map +1 -1
  79. package/dist/components/suggestions/utils.d.ts +37 -0
  80. package/dist/components/suggestions/utils.d.ts.map +1 -1
  81. package/dist/components/suggestions/utils.js +118 -0
  82. package/dist/components/suggestions-primitives/ItemCard.d.ts +10 -1
  83. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -1
  84. package/dist/components/suggestions-primitives/ItemCard.js +20 -6
  85. package/dist/components/suggestions-primitives/ProductCard.d.ts +27 -3
  86. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -1
  87. package/dist/components/suggestions-primitives/ProductCard.js +124 -17
  88. package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts +44 -0
  89. package/dist/components/suggestions-primitives/ProductCardLayouts.d.ts.map +1 -0
  90. package/dist/components/suggestions-primitives/ProductCardLayouts.js +105 -0
  91. package/dist/components/suggestions-primitives/ProductGrid.d.ts +6 -1
  92. package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -1
  93. package/dist/components/suggestions-primitives/ProductGrid.js +2 -2
  94. package/dist/components/suggestions-primitives/SuggestionList.d.ts +8 -1
  95. package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -1
  96. package/dist/components/suggestions-primitives/SuggestionList.js +7 -4
  97. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts.map +1 -1
  98. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.js +0 -2
  99. package/dist/docsearch/components/Results.d.ts +3 -1
  100. package/dist/docsearch/components/Results.d.ts.map +1 -1
  101. package/dist/docsearch/components/Results.js +6 -2
  102. package/dist/hooks/useProductAnalytics.d.ts +49 -0
  103. package/dist/hooks/useProductAnalytics.d.ts.map +1 -0
  104. package/dist/hooks/useProductAnalytics.js +116 -0
  105. package/dist/hooks/useQuerySuggestionsEnhanced.js +2 -1
  106. package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -1
  107. package/dist/hooks/useSuggestionsAnalytics.js +6 -0
  108. package/dist/hooks/useVariantSelection.d.ts +28 -0
  109. package/dist/hooks/useVariantSelection.d.ts.map +1 -0
  110. package/dist/hooks/useVariantSelection.js +44 -0
  111. package/dist/index.d.ts +8 -3
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +5 -1
  114. package/dist/index.umd.js +1 -1
  115. package/dist/src/index.d.ts +1138 -681
  116. package/dist/src/index.esm.js +2407 -723
  117. package/dist/src/index.esm.js.map +1 -1
  118. package/dist/src/index.js +2423 -722
  119. package/dist/src/index.js.map +1 -1
  120. package/package.json +3 -3
@@ -8,6 +8,7 @@
8
8
  import React from 'react';
9
9
  import { clsx } from 'clsx';
10
10
  import { ImageDisplay } from '../primitives/ImageDisplay';
11
+ import { ActionButtons } from '../primitives/ActionButtons';
11
12
  const cardStyle = {
12
13
  display: 'flex',
13
14
  flexDirection: 'column',
@@ -29,18 +30,31 @@ const imgStyle = {
29
30
  borderRadius: 4,
30
31
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
31
32
  };
32
- export function ItemCard({ item, position, onSelect, className, style, asLink = true, imageVariant = 'single', }) {
33
+ export function ItemCard({ item, position, onSelect, className, style, asLink = true, imageVariant = 'single', layout = 'vertical', actionButtons, actionButtonsPosition = 'overlay-top-right', showActionLabels = false, }) {
33
34
  const images = item.images?.length ? item.images : item.image ?? item.imageUrl ? [String(item.image ?? item.imageUrl)] : [];
34
35
  const title = item.title ?? item.primaryText ?? '';
35
36
  const description = item.description ?? item.secondaryText;
36
37
  const href = item.url;
37
- const content = (React.createElement(React.Fragment, null,
38
- images.length > 0 ? (React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: String(title), className: "seekora-item-card-image" })) : (React.createElement("div", { className: "seekora-item-card-placeholder", style: imgStyle, "aria-hidden": true })),
38
+ const isHorizontal = layout === 'horizontal';
39
+ const imageBlock = images.length > 0 ? (React.createElement("div", { style: { position: 'relative', ...(isHorizontal ? { width: 80, flexShrink: 0 } : {}) } },
40
+ React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: String(title), className: "seekora-item-card-image" }),
41
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" })))) : (React.createElement("div", { className: "seekora-item-card-placeholder", style: { ...imgStyle, ...(isHorizontal ? { width: 80, height: 80, flexShrink: 0 } : {}) }, "aria-hidden": true }));
42
+ const textBlock = (React.createElement("div", { style: isHorizontal ? { display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 0 } : undefined },
39
43
  React.createElement("span", { className: "seekora-item-card-title", style: { fontSize: '0.875rem', fontWeight: 500 } }, String(title)),
40
- description ? (React.createElement("span", { className: "seekora-item-card-description", style: { fontSize: '0.8125rem', color: 'var(--seekora-text-secondary, #6b7280)', lineHeight: 1.3 } }, String(description))) : null));
44
+ description ? (React.createElement("span", { className: "seekora-item-card-description", style: { fontSize: '0.8125rem', color: 'var(--seekora-text-secondary, #6b7280)', lineHeight: 1.3 } }, String(description))) : null,
45
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" }))));
46
+ const content = isHorizontal ? (React.createElement("div", { style: { display: 'flex', gap: 12, alignItems: 'flex-start' } },
47
+ imageBlock,
48
+ textBlock)) : (React.createElement(React.Fragment, null,
49
+ imageBlock,
50
+ textBlock));
41
51
  const commonProps = {
42
- className: clsx('seekora-item-card', className),
43
- style: { ...cardStyle, ...style },
52
+ className: clsx('seekora-item-card', isHorizontal && 'seekora-item-card--horizontal', className),
53
+ style: {
54
+ ...cardStyle,
55
+ ...(isHorizontal ? { flexDirection: 'row' } : {}),
56
+ ...style,
57
+ },
44
58
  'data-position': position,
45
59
  onClick: onSelect,
46
60
  onMouseDown: onSelect ? (e) => { e.preventDefault(); onSelect(); } : undefined,
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * ProductCard – one product tile (primitive)
3
3
  *
4
- * Minimal layout: image (via ImageDisplay when imageVariant set), title, price.
5
- * onClick calls context selectProduct. Overridable via className/style.
4
+ * Without displayConfig: renders the original minimal layout (image, title, price).
5
+ * With displayConfig: renders layout variants (minimal, standard, detailed, compact, horizontal).
6
6
  */
7
7
  import React from 'react';
8
+ import type { ActionButton } from '../primitives/ActionButtons';
8
9
  import type { ProductItem } from '@seekora-ai/ui-sdk-types';
10
+ import type { ProductDisplayConfig } from '../suggestions/types';
9
11
  export type ProductCardImageVariant = 'single' | 'carousel' | 'hover' | 'thumbStrip' | 'thumbList';
10
12
  export interface ProductCardProps {
11
13
  product: ProductItem;
@@ -16,6 +18,28 @@ export interface ProductCardProps {
16
18
  className?: string;
17
19
  style?: React.CSSProperties;
18
20
  imageVariant?: ProductCardImageVariant;
21
+ /** Product display configuration for layout variants */
22
+ displayConfig?: ProductDisplayConfig;
23
+ /** Callback when a variant swatch is hovered (e.g., to swap card image) */
24
+ onVariantHover?: (optionName: string, value: string) => void;
25
+ /** Callback when a variant swatch is clicked (e.g., to swap card image permanently) */
26
+ onVariantClick?: (optionName: string, value: string) => void;
27
+ /** Currently selected variant values (e.g., { Color: 'Black', Size: 'M' }) */
28
+ selectedVariants?: Record<string, string>;
29
+ /** Render as link when true and product.url exists */
30
+ asLink?: boolean;
31
+ /** Action buttons (add to cart, wishlist, etc.) */
32
+ actionButtons?: ActionButton[];
33
+ /** Action buttons position */
34
+ actionButtonsPosition?: 'overlay-top-right' | 'overlay-bottom' | 'inline';
35
+ /** Show action button labels */
36
+ showActionLabels?: boolean;
37
+ /** Enable image zoom functionality */
38
+ enableImageZoom?: boolean;
39
+ /** Image zoom mode: 'hover' (Amazon-style), 'lens', 'click' (lightbox), 'both' (hover + click) */
40
+ imageZoomMode?: 'hover' | 'lens' | 'click' | 'both';
41
+ /** Image zoom magnification level (2 = 200%, 3 = 300%) */
42
+ imageZoomLevel?: number;
19
43
  }
20
- export declare function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant, }: ProductCardProps): React.JSX.Element;
44
+ export declare function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, asLink, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }: ProductCardProps): React.JSX.Element;
21
45
  //# sourceMappingURL=ProductCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductCard.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ProductCard.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAsBD,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,EACT,KAAK,EACL,YAAuB,GACxB,EAAE,gBAAgB,qBAqClB"}
1
+ {"version":3,"file":"ProductCard.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ProductCard.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAA2C,MAAM,0BAA0B,CAAC;AACrG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAWjE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,YAAY,CAAC,EAAE,uBAAuB,CAAC;IACvC,wDAAwD;IACxD,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,2EAA2E;IAC3E,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,8BAA8B;IAC9B,qBAAqB,CAAC,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,QAAQ,CAAC;IAC1E,gCAAgC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sCAAsC;IACtC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kGAAkG;IAClG,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACpD,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAsBD,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,EACT,KAAK,EACL,YAAuB,EACvB,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,MAAM,EACN,aAAa,EACb,qBAA2C,EAC3C,gBAAwB,EACxB,eAAuB,EACvB,aAAsB,EACtB,cAAoB,GACrB,EAAE,gBAAgB,qBAuLlB"}
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * ProductCard – one product tile (primitive)
3
3
  *
4
- * Minimal layout: image (via ImageDisplay when imageVariant set), title, price.
5
- * onClick calls context selectProduct. Overridable via className/style.
4
+ * Without displayConfig: renders the original minimal layout (image, title, price).
5
+ * With displayConfig: renders layout variants (minimal, standard, detailed, compact, horizontal).
6
6
  */
7
- import React from 'react';
7
+ import React, { useMemo } from 'react';
8
8
  import { clsx } from 'clsx';
9
9
  import { ImageDisplay } from '../primitives/ImageDisplay';
10
+ import { extractBadges, getPriceRange, findVariantBySelections } from '../suggestions/utils';
11
+ import { MinimalLayout, StandardLayout, DetailedLayout, CompactLayout, HorizontalLayout, } from './ProductCardLayouts';
10
12
  const cardStyle = {
11
13
  display: 'flex',
12
14
  flexDirection: 'column',
@@ -26,21 +28,126 @@ const imgStyle = {
26
28
  borderRadius: 4,
27
29
  backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
28
30
  };
29
- export function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant = 'single', }) {
30
- const images = product.images?.length
31
- ? product.images
32
- : product.image ?? product.imageUrl
33
- ? [String(product.image ?? product.imageUrl)]
34
- : [];
35
- const title = product.title ?? product.name ?? '';
36
- const price = product.price != null ? (typeof product.price === 'number' ? product.price : Number(product.price)) : null;
37
- return (React.createElement("button", { type: "button", className: clsx('seekora-suggestions-product-card', className), style: { ...cardStyle, ...style }, onMouseDown: (e) => {
31
+ export function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant = 'single', displayConfig, onVariantHover, onVariantClick, selectedVariants, asLink, actionButtons, actionButtonsPosition = 'overlay-top-right', showActionLabels = false, enableImageZoom = false, imageZoomMode = 'both', imageZoomLevel = 2.5, }) {
32
+ // Find selected variant if selections are provided
33
+ const selectedVariant = useMemo(() => {
34
+ if (!selectedVariants || !product.options || !product.variants)
35
+ return null;
36
+ return findVariantBySelections(product.options, product.variants, selectedVariants);
37
+ }, [selectedVariants, product.options, product.variants]);
38
+ // Compute effective display data (use selected variant if available, otherwise product defaults)
39
+ const effectiveImages = useMemo(() => {
40
+ // Priority: selected variant image > product images > product image
41
+ if (selectedVariant?.image)
42
+ return [selectedVariant.image];
43
+ if (product.images?.length)
44
+ return product.images;
45
+ if (product.image ?? product.imageUrl)
46
+ return [String(product.image ?? product.imageUrl)];
47
+ return [];
48
+ }, [selectedVariant, product]);
49
+ const effectiveTitle = useMemo(() => {
50
+ // Show variant title if available (e.g., "T-Shirt - Black / M")
51
+ if (selectedVariant?.title && selectedVariant.title !== product.title) {
52
+ return `${product.title ?? product.name ?? ''} - ${selectedVariant.title}`;
53
+ }
54
+ return product.title ?? product.name ?? '';
55
+ }, [selectedVariant, product]);
56
+ const effectivePrice = useMemo(() => {
57
+ const variantPrice = selectedVariant?.price;
58
+ if (variantPrice != null)
59
+ return typeof variantPrice === 'number' ? variantPrice : Number(variantPrice);
60
+ const productPrice = product.price;
61
+ return productPrice != null ? (typeof productPrice === 'number' ? productPrice : Number(productPrice)) : null;
62
+ }, [selectedVariant, product.price]);
63
+ const effectiveComparePrice = useMemo(() => {
64
+ const variantCompare = selectedVariant?.comparePrice;
65
+ if (variantCompare != null)
66
+ return typeof variantCompare === 'number' ? variantCompare : Number(variantCompare);
67
+ const productCompare = product.original_price ?? product.compare_at_price;
68
+ return productCompare != null ? (typeof productCompare === 'number' ? productCompare : Number(productCompare)) : null;
69
+ }, [selectedVariant, product]);
70
+ // Legacy vars for backwards compat
71
+ const images = effectiveImages;
72
+ const title = effectiveTitle;
73
+ const price = effectivePrice;
74
+ // If no displayConfig, render original minimal layout (backwards compat)
75
+ if (!displayConfig) {
76
+ return (React.createElement("button", { type: "button", className: clsx('seekora-suggestions-product-card', className), style: { ...cardStyle, ...style }, onMouseDown: (e) => {
77
+ e.preventDefault();
78
+ onSelect();
79
+ }, "data-position": position, "data-section": section, "data-tab-id": tabId },
80
+ images.length > 0 ? (React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: title, className: "seekora-suggestions-product-card-image", enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel })) : (React.createElement("div", { className: "seekora-suggestions-product-card-placeholder", style: imgStyle, "aria-hidden": true })),
81
+ React.createElement("span", { className: "seekora-suggestions-product-card-title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
82
+ price != null && !Number.isNaN(price) ? (React.createElement("span", { className: "seekora-suggestions-product-card-price", style: { fontSize: '0.875rem', color: 'var(--seekora-text-secondary, #6b7280)' } },
83
+ product.currency ?? '$',
84
+ price.toFixed(2))) : null));
85
+ }
86
+ // Enhanced layout with displayConfig
87
+ const layoutStyle = displayConfig.style ?? 'minimal';
88
+ const comparePrice = effectiveComparePrice;
89
+ const brand = product.brand ?? null;
90
+ const options = product.options ?? [];
91
+ const variants = product.variants ?? [];
92
+ const badges = useMemo(() => {
93
+ if (displayConfig.showBadges === false)
94
+ return [];
95
+ if (displayConfig.badgeExtractor)
96
+ return displayConfig.badgeExtractor(product.tags, product);
97
+ return extractBadges(product.tags, product);
98
+ }, [displayConfig, product]);
99
+ const priceRange = useMemo(() => {
100
+ if (!displayConfig.showPriceRange)
101
+ return null;
102
+ return getPriceRange(product.variants);
103
+ }, [displayConfig.showPriceRange, product.variants]);
104
+ const layoutProps = {
105
+ product,
106
+ images,
107
+ title,
108
+ price,
109
+ comparePrice,
110
+ brand,
111
+ badges,
112
+ priceRange,
113
+ options,
114
+ variants,
115
+ displayConfig,
116
+ imageVariant,
117
+ onVariantHover,
118
+ onVariantClick,
119
+ selectedVariants,
120
+ actionButtons,
121
+ actionButtonsPosition,
122
+ showActionLabels,
123
+ enableImageZoom,
124
+ imageZoomMode,
125
+ imageZoomLevel,
126
+ };
127
+ const layoutMap = {
128
+ minimal: MinimalLayout,
129
+ standard: StandardLayout,
130
+ detailed: DetailedLayout,
131
+ compact: CompactLayout,
132
+ horizontal: HorizontalLayout,
133
+ };
134
+ const LayoutComponent = layoutMap[layoutStyle] ?? MinimalLayout;
135
+ const rootClassName = clsx('seekora-product-card', `seekora-product-card--${layoutStyle}`, 'seekora-suggestions-product-card', className);
136
+ const rootStyle = {
137
+ ...cardStyle,
138
+ ...(layoutStyle === 'horizontal' ? { flexDirection: 'row' } : {}),
139
+ ...style,
140
+ };
141
+ if (asLink && product.url) {
142
+ return (React.createElement("a", { href: product.url, className: rootClassName, style: { ...rootStyle, textDecoration: 'none', color: 'inherit' }, onClick: (e) => {
143
+ e.preventDefault();
144
+ onSelect();
145
+ }, "data-position": position, "data-section": section, "data-tab-id": tabId },
146
+ React.createElement(LayoutComponent, { ...layoutProps })));
147
+ }
148
+ return (React.createElement("button", { type: "button", className: rootClassName, style: rootStyle, onMouseDown: (e) => {
38
149
  e.preventDefault();
39
150
  onSelect();
40
151
  }, "data-position": position, "data-section": section, "data-tab-id": tabId },
41
- images.length > 0 ? (React.createElement(ImageDisplay, { images: images, variant: imageVariant, alt: title, className: "seekora-suggestions-product-card-image" })) : (React.createElement("div", { className: "seekora-suggestions-product-card-placeholder", style: imgStyle, "aria-hidden": true })),
42
- React.createElement("span", { className: "seekora-suggestions-product-card-title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
43
- price != null && !Number.isNaN(price) ? (React.createElement("span", { className: "seekora-suggestions-product-card-price", style: { fontSize: '0.875rem', color: 'var(--seekora-text-secondary, #6b7280)' } },
44
- product.currency ?? '$',
45
- price.toFixed(2))) : null));
152
+ React.createElement(LayoutComponent, { ...layoutProps })));
46
153
  }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ProductCardLayouts – internal layout sub-components for ProductCard
3
+ *
4
+ * Not exported from the package. Each layout renders the same product data
5
+ * with different visual emphasis.
6
+ */
7
+ import React from 'react';
8
+ import type { ActionButton } from '../primitives/ActionButtons';
9
+ import type { ProductItem, ProductBadge, PriceRange, ProductOption, ProductVariant } from '@seekora-ai/ui-sdk-types';
10
+ import type { ProductDisplayConfig } from '../suggestions/types';
11
+ export interface LayoutProps {
12
+ product: ProductItem;
13
+ images: string[];
14
+ title: string;
15
+ price: number | null;
16
+ comparePrice: number | null;
17
+ brand: string | null;
18
+ badges: ProductBadge[];
19
+ priceRange: PriceRange | null;
20
+ options: ProductOption[];
21
+ variants: ProductVariant[];
22
+ displayConfig: ProductDisplayConfig;
23
+ imageVariant: 'single' | 'carousel' | 'hover' | 'thumbStrip' | 'thumbList';
24
+ onVariantHover?: (optionName: string, value: string) => void;
25
+ onVariantClick?: (optionName: string, value: string) => void;
26
+ selectedVariants?: Record<string, string>;
27
+ actionButtons?: ActionButton[];
28
+ actionButtonsPosition?: 'overlay-top-right' | 'overlay-bottom' | 'inline';
29
+ showActionLabels?: boolean;
30
+ enableImageZoom?: boolean;
31
+ imageZoomMode?: 'hover' | 'lens' | 'click' | 'both';
32
+ imageZoomLevel?: number;
33
+ }
34
+ /** minimal: image, title, price (current default behavior) */
35
+ export declare function MinimalLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }: LayoutProps): React.JSX.Element;
36
+ /** standard: image, badges, brand, title, price + compare price, color swatches */
37
+ export declare function StandardLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }: LayoutProps): React.JSX.Element;
38
+ /** detailed: image, badges, brand, title, price + compare + discount, rating, all swatches, stock */
39
+ export declare function DetailedLayout({ images, title, price, comparePrice, brand, badges, priceRange, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }: LayoutProps): React.JSX.Element;
40
+ /** compact: smaller image, 1-line title, price */
41
+ export declare function CompactLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }: LayoutProps): React.JSX.Element;
42
+ /** horizontal: image left + content right (title, brand, price, swatches) */
43
+ export declare function HorizontalLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }: LayoutProps): React.JSX.Element;
44
+ //# sourceMappingURL=ProductCardLayouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductCardLayouts.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ProductCardLayouts.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACrH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,aAAa,EAAE,oBAAoB,CAAC;IACpC,YAAY,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;IAC3E,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,qBAAqB,CAAC,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,QAAQ,CAAC;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAwCD,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,EAAE,WAAW,qBAsBxJ;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EACtF,aAAa,EAAE,qBAAqB,EAAE,gBAAgB,EACtD,eAAe,EAAE,aAAa,EAAE,cAAc,GAC/C,EAAE,WAAW,qBAqEb;AAED,qGAAqG;AACrG,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAChF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EACtF,aAAa,EAAE,qBAAqB,EAAE,gBAAgB,EACtD,eAAe,EAAE,aAAa,EAAE,cAAc,GAC/C,EAAE,WAAW,qBAuGb;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,EAAE,WAAW,qBA+BxJ;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EACtF,aAAa,EAAE,qBAAqB,EAAE,gBAAgB,EACtD,eAAe,EAAE,aAAa,EAAE,cAAc,GAC/C,EAAE,WAAW,qBAqEb"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ProductCardLayouts – internal layout sub-components for ProductCard
3
+ *
4
+ * Not exported from the package. Each layout renders the same product data
5
+ * with different visual emphasis.
6
+ */
7
+ import React from 'react';
8
+ import { ImageDisplay } from '../primitives/ImageDisplay';
9
+ import { PriceDisplay } from '../primitives/PriceDisplay';
10
+ import { BadgeList } from '../primitives/BadgeList';
11
+ import { RatingDisplay } from '../primitives/RatingDisplay';
12
+ import { VariantSwatches } from '../primitives/VariantSwatches';
13
+ import { ActionButtons } from '../primitives/ActionButtons';
14
+ const imgPlaceholderStyle = {
15
+ width: '100%',
16
+ aspectRatio: '1',
17
+ objectFit: 'cover',
18
+ borderRadius: 4,
19
+ backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
20
+ };
21
+ function ImageBlock({ images, title, imageVariant, aspectRatio, enableZoom, zoomMode, zoomLevel }) {
22
+ const ar = aspectRatio ? aspectRatio.replace(':', '/') : '1';
23
+ if (images.length > 0) {
24
+ return (React.createElement("div", { className: "seekora-product-card__image", style: { position: 'relative', overflow: 'hidden', borderRadius: 4 } },
25
+ React.createElement(ImageDisplay, { images: images, variant: images.length > 1 ? imageVariant : 'single', alt: title, className: "seekora-suggestions-product-card-image", style: { aspectRatio: ar }, enableZoom: enableZoom, zoomMode: zoomMode, zoomLevel: zoomLevel })));
26
+ }
27
+ return React.createElement("div", { className: "seekora-product-card__image seekora-suggestions-product-card-placeholder", style: { ...imgPlaceholderStyle, aspectRatio: ar }, "aria-hidden": true });
28
+ }
29
+ /** minimal: image, title, price (current default behavior) */
30
+ export function MinimalLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }) {
31
+ return (React.createElement(React.Fragment, null,
32
+ React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: displayConfig.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
33
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
34
+ price != null && !Number.isNaN(price) && (React.createElement("span", { className: "seekora-product-card__price seekora-suggestions-product-card-price", style: { fontSize: '0.875rem', color: 'var(--seekora-text-secondary, #6b7280)' } },
35
+ product.currency ?? '$',
36
+ price.toFixed(2)))));
37
+ }
38
+ /** standard: image, badges, brand, title, price + compare price, color swatches */
39
+ export function StandardLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
40
+ const cfg = displayConfig;
41
+ return (React.createElement(React.Fragment, null,
42
+ React.createElement("div", { style: { position: 'relative' } },
43
+ React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: cfg.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
44
+ cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left", maxBadges: 2 })),
45
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
46
+ React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4 } },
47
+ cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase', letterSpacing: '0.02em' } }, brand)),
48
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
49
+ React.createElement("div", { className: "seekora-product-card__price" },
50
+ React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } })),
51
+ cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
52
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
53
+ }
54
+ /** detailed: image, badges, brand, title, price + compare + discount, rating, all swatches, stock */
55
+ export function DetailedLayout({ images, title, price, comparePrice, brand, badges, priceRange, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
56
+ const cfg = displayConfig;
57
+ const available = product.available;
58
+ return (React.createElement(React.Fragment, null,
59
+ React.createElement("div", { style: { position: 'relative' } },
60
+ React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: cfg.imageAspectRatio, enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
61
+ cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left" })),
62
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
63
+ React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4 } },
64
+ cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase', letterSpacing: '0.02em' } }, brand)),
65
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
66
+ cfg.showRating !== false && product.rating != null && (React.createElement(RatingDisplay, { rating: product.rating, reviewCount: product.reviewCount, variant: "compact", size: "small", showNumeric: false, showReviewCount: true, className: "seekora-product-card__rating" })),
67
+ React.createElement("div", { className: "seekora-product-card__price" }, cfg.showPriceRange && priceRange ? (React.createElement(PriceDisplay, { priceRange: priceRange, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, style: { fontSize: '0.875rem' } })) : (React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } }))),
68
+ cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
69
+ cfg.showStock !== false && available != null && (React.createElement("span", { className: "seekora-product-card__stock", style: {
70
+ fontSize: '0.75rem',
71
+ color: available ? 'var(--seekora-success, #22c55e)' : 'var(--seekora-error, #ef4444)',
72
+ } }, available ? 'In Stock' : 'Out of Stock')),
73
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
74
+ }
75
+ /** compact: smaller image, 1-line title, price */
76
+ export function CompactLayout({ images, title, price, product, imageVariant, displayConfig, enableImageZoom, imageZoomMode, imageZoomLevel }) {
77
+ return (React.createElement(React.Fragment, null,
78
+ React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: displayConfig.imageAspectRatio ?? '1:1', enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
79
+ React.createElement("span", { className: "seekora-product-card__title", style: {
80
+ fontSize: '0.8125rem',
81
+ fontWeight: 500,
82
+ overflow: 'hidden',
83
+ textOverflow: 'ellipsis',
84
+ whiteSpace: 'nowrap',
85
+ } }, title),
86
+ price != null && !Number.isNaN(price) && (React.createElement("span", { className: "seekora-product-card__price", style: { fontSize: '0.8125rem', color: 'var(--seekora-text-secondary, #6b7280)' } },
87
+ product.currency ?? '$',
88
+ price.toFixed(2)))));
89
+ }
90
+ /** horizontal: image left + content right (title, brand, price, swatches) */
91
+ export function HorizontalLayout({ images, title, price, comparePrice, brand, badges, options, variants, product, imageVariant, displayConfig, onVariantHover, onVariantClick, selectedVariants, actionButtons, actionButtonsPosition, showActionLabels, enableImageZoom, imageZoomMode, imageZoomLevel, }) {
92
+ const cfg = displayConfig;
93
+ return (React.createElement("div", { style: { display: 'flex', gap: 12, alignItems: 'flex-start' } },
94
+ React.createElement("div", { style: { position: 'relative', width: 80, flexShrink: 0 } },
95
+ React.createElement(ImageBlock, { images: images, title: title, imageVariant: imageVariant, aspectRatio: "1:1", enableZoom: enableImageZoom, zoomMode: imageZoomMode, zoomLevel: imageZoomLevel }),
96
+ cfg.showBadges !== false && badges.length > 0 && (React.createElement(BadgeList, { badges: badges, position: "top-left", maxBadges: 1 })),
97
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition?.startsWith('overlay') && (React.createElement(ActionButtons, { buttons: actionButtons, position: actionButtonsPosition === 'overlay-top-right' ? 'top-right' : 'bottom-center', showLabels: showActionLabels, size: "small" }))),
98
+ React.createElement("div", { className: "seekora-product-card__body", style: { display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 0 } },
99
+ cfg.showBrand !== false && brand && (React.createElement("span", { className: "seekora-product-card__brand", style: { fontSize: '0.75rem', color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase' } }, brand)),
100
+ React.createElement("span", { className: "seekora-product-card__title", style: { fontSize: '0.875rem', fontWeight: 500 } }, title),
101
+ React.createElement("div", { className: "seekora-product-card__price" },
102
+ React.createElement(PriceDisplay, { price: price ?? undefined, comparePrice: comparePrice ?? undefined, currency: cfg.currency ?? product.currency, currencyPosition: cfg.currencyPosition, priceDecimals: cfg.priceDecimals, showDiscount: cfg.showDiscount, style: { fontSize: '0.875rem' } })),
103
+ cfg.showVariants !== false && options.length > 0 && (React.createElement(VariantSwatches, { options: options, visibleOptions: cfg.variantOptionsToShow, maxValues: cfg.maxVariantValues ?? 3, selectedValues: selectedVariants, variants: variants, onSwatchHover: onVariantHover, onSwatchClick: onVariantClick })),
104
+ actionButtons && actionButtons.length > 0 && actionButtonsPosition === 'inline' && (React.createElement(ActionButtons, { buttons: actionButtons, position: "inline", showLabels: showActionLabels, size: "small", layout: "horizontal" })))));
105
+ }
@@ -4,6 +4,7 @@
4
4
  * Uses trendingProducts or active tab products; each click calls context selectProduct.
5
5
  */
6
6
  import React from 'react';
7
+ import type { ProductDisplayConfig } from '../suggestions/types';
7
8
  export interface ProductGridProps {
8
9
  maxItems?: number;
9
10
  /** 'trending' | tab id for filtered tab products */
@@ -12,6 +13,10 @@ export interface ProductGridProps {
12
13
  className?: string;
13
14
  style?: React.CSSProperties;
14
15
  gridClassName?: string;
16
+ /** Product display configuration passed through to each ProductCard */
17
+ displayConfig?: ProductDisplayConfig;
18
+ /** Callback when a variant swatch is hovered on a card */
19
+ onVariantHover?: (optionName: string, value: string) => void;
15
20
  }
16
- export declare function ProductGrid({ maxItems, source, columns, className, style, gridClassName, }: ProductGridProps): React.JSX.Element | null;
21
+ export declare function ProductGrid({ maxItems, source, columns, className, style, gridClassName, displayConfig, onVariantHover, }: ProductGridProps): React.JSX.Element | null;
17
22
  //# sourceMappingURL=ProductGrid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductGrid.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ProductGrid.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAY,EACZ,MAAmB,EACnB,OAAW,EACX,SAAS,EACT,KAAK,EACL,aAAa,GACd,EAAE,gBAAgB,4BAiDlB"}
1
+ {"version":3,"file":"ProductGrid.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ProductGrid.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAKvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAY,EACZ,MAAmB,EACnB,OAAW,EACX,SAAS,EACT,KAAK,EACL,aAAa,EACb,aAAa,EACb,cAAc,GACf,EAAE,gBAAgB,4BAmDlB"}
@@ -7,7 +7,7 @@ import React, { useMemo } from 'react';
7
7
  import { useSuggestionsContext } from './SuggestionsContext';
8
8
  import { ProductCard } from './ProductCard';
9
9
  import { clsx } from 'clsx';
10
- export function ProductGrid({ maxItems = 8, source = 'trending', columns = 4, className, style, gridClassName, }) {
10
+ export function ProductGrid({ maxItems = 8, source = 'trending', columns = 4, className, style, gridClassName, displayConfig, onVariantHover, }) {
11
11
  const { trendingProducts, filteredTabs, activeTabId, selectProduct, getAllNavigableItems, } = useSuggestionsContext();
12
12
  const products = useMemo(() => {
13
13
  if (source === 'trending')
@@ -31,6 +31,6 @@ export function ProductGrid({ maxItems = 8, source = 'trending', columns = 4, cl
31
31
  const globalIndex = productStartIndex >= 0 ? productStartIndex + i : i;
32
32
  const section = source === 'trending' ? 'products' : 'filtered_tab';
33
33
  const tabId = source !== 'trending' ? (source === 'tab' ? activeTabId : source) : undefined;
34
- return (React.createElement(ProductCard, { key: product.id ?? product.objectID ?? i, product: product, position: globalIndex, section: section, tabId: tabId, onSelect: () => selectProduct(product, globalIndex, section, tabId) }));
34
+ return (React.createElement(ProductCard, { key: product.id ?? product.objectID ?? i, product: product, position: globalIndex, section: section, tabId: tabId, onSelect: () => selectProduct(product, globalIndex, section, tabId), displayConfig: displayConfig, onVariantHover: onVariantHover }));
35
35
  }))));
36
36
  }
@@ -12,6 +12,13 @@ export interface SuggestionListProps {
12
12
  className?: string;
13
13
  style?: React.CSSProperties;
14
14
  listClassName?: string;
15
+ /**
16
+ * When true, show a loading state when fetching and no previous suggestions exist.
17
+ * When false (default), show previous results until new results render; no loading screen.
18
+ */
19
+ showLoadingState?: boolean;
20
+ /** Custom render for loading state (only when showLoadingState is true and loading with no items). */
21
+ renderLoading?: () => React.ReactNode;
15
22
  /**
16
23
  * When true (default), suggestion text with <mark>...</mark> is rendered
17
24
  * with those segments highlighted. When false, plain text is shown.
@@ -22,5 +29,5 @@ export interface SuggestionListProps {
22
29
  highlightMarkupOptions?: HighlightMarkupOptions;
23
30
  renderItem?: (suggestion: import('@seekora-ai/ui-sdk-types').SuggestionItem, index: number, isActive: boolean, onSelect: () => void) => React.ReactNode;
24
31
  }
25
- export declare function SuggestionList({ maxItems, className, style, listClassName, enableHighlightMarkup, highlightMarkupOptions, renderItem, }: SuggestionListProps): React.JSX.Element | null;
32
+ export declare function SuggestionList({ maxItems, className, style, listClassName, showLoadingState, renderLoading, enableHighlightMarkup, highlightMarkupOptions, renderItem, }: SuggestionListProps): React.JSX.Element | null;
26
33
  //# sourceMappingURL=SuggestionList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SuggestionList.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionList.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mGAAmG;IACnG,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,UAAU,CAAC,EAAE,CACX,UAAU,EAAE,OAAO,0BAA0B,EAAE,cAAc,EAC7D,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,IAAI,KACjB,KAAK,CAAC,SAAS,CAAC;CACtB;AAOD,wBAAgB,cAAc,CAAC,EAC7B,QAAa,EACb,SAAS,EACT,KAAK,EACL,aAAa,EACb,qBAA4B,EAC5B,sBAAsB,EACtB,UAAU,GACX,EAAE,mBAAmB,4BAiDrB"}
1
+ {"version":3,"file":"SuggestionList.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionList.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sGAAsG;IACtG,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mGAAmG;IACnG,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,UAAU,CAAC,EAAE,CACX,UAAU,EAAE,OAAO,0BAA0B,EAAE,cAAc,EAC7D,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,IAAI,KACjB,KAAK,CAAC,SAAS,CAAC;CACtB;AAOD,wBAAgB,cAAc,CAAC,EAC7B,QAAa,EACb,SAAS,EACT,KAAK,EACL,aAAa,EACb,gBAAwB,EACxB,aAAa,EACb,qBAA4B,EAC5B,sBAAsB,EACtB,UAAU,GACX,EAAE,mBAAmB,4BAwDrB"}
@@ -8,21 +8,24 @@
8
8
  import React from 'react';
9
9
  import { useSuggestionsContext } from './SuggestionsContext';
10
10
  import { SuggestionItem } from './SuggestionItem';
11
- import { SuggestionsLoading } from './SuggestionsLoading';
12
11
  import { clsx } from 'clsx';
13
12
  const listStyle = {
14
13
  margin: 0,
15
14
  padding: '4px 0',
16
15
  };
17
- export function SuggestionList({ maxItems = 10, className, style, listClassName, enableHighlightMarkup = true, highlightMarkupOptions, renderItem, }) {
16
+ export function SuggestionList({ maxItems = 10, className, style, listClassName, showLoadingState = false, renderLoading, enableHighlightMarkup = true, highlightMarkupOptions, renderItem, }) {
18
17
  const { suggestions, activeIndex, loading, selectSuggestion, getAllNavigableItems, } = useSuggestionsContext();
19
18
  const items = suggestions.slice(0, maxItems);
20
19
  const navigableItems = getAllNavigableItems();
21
20
  const suggestionStartIndex = navigableItems.findIndex((n) => n.type === 'suggestion');
22
21
  const activeIsInSuggestions = suggestionStartIndex >= 0 && activeIndex >= suggestionStartIndex && activeIndex < suggestionStartIndex + items.length;
23
- if (loading) {
24
- return React.createElement(SuggestionsLoading, { className: className, style: style });
22
+ // When loading with no previous results, show loading only if showLoadingState (default: don't show loading screen)
23
+ if (loading && items.length === 0 && showLoadingState) {
24
+ if (renderLoading)
25
+ return React.createElement(React.Fragment, null, renderLoading());
26
+ return (React.createElement("div", { className: clsx('seekora-suggestions-loading', className), style: { padding: 16, color: 'var(--seekora-text-secondary, #6b7280)', fontSize: '0.875rem', ...style } }, "Loading..."));
25
27
  }
28
+ // When loading with previous results, show previous results (no loading UI)
26
29
  if (items.length === 0)
27
30
  return null;
28
31
  return (React.createElement("div", { className: clsx('seekora-suggestions-list', className), style: style },
@@ -1 +1 @@
1
- {"version":3,"file":"SuggestionsDropdownComposition.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsDropdownComposition.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAW1B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,mCAAoC,SAAQ,IAAI,CAAC,wBAAwB,EAAE,UAAU,CAAC;IACrG,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yBAAyB;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wBAAwB;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,kBAAyB,EACzB,YAAmB,EACnB,QAAe,EACf,YAAmB,EACnB,WAAW,EACX,GAAG,aAAa,EACjB,EAAE,mCAAmC,qBAiBrC"}
1
+ {"version":3,"file":"SuggestionsDropdownComposition.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsDropdownComposition.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,mCAAoC,SAAQ,IAAI,CAAC,wBAAwB,EAAE,UAAU,CAAC;IACrG,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yBAAyB;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wBAAwB;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,kBAAyB,EACzB,YAAmB,EACnB,QAAe,EACf,YAAmB,EACnB,WAAW,EACX,GAAG,aAAa,EACjB,EAAE,mCAAmC,qBAgBrC"}
@@ -15,7 +15,6 @@ import { SuggestionList } from './SuggestionList';
15
15
  import { CategoriesTabs } from './CategoriesTabs';
16
16
  import { ProductGrid } from './ProductGrid';
17
17
  import { TrendingList } from './TrendingList';
18
- import { SuggestionsLoading } from './SuggestionsLoading';
19
18
  import { SuggestionsError } from './SuggestionsError';
20
19
  export function SuggestionsDropdownComposition({ showRecentSearches = true, showTrending = true, showTabs = true, showProducts = true, placeholder, ...providerProps }) {
21
20
  return (React.createElement(SuggestionsProvider, { ...providerProps },
@@ -23,7 +22,6 @@ export function SuggestionsDropdownComposition({ showRecentSearches = true, show
23
22
  React.createElement(SearchInput, { placeholder: placeholder }),
24
23
  React.createElement(DropdownPanel, null,
25
24
  React.createElement(SuggestionsError, null),
26
- React.createElement(SuggestionsLoading, null),
27
25
  showRecentSearches ? React.createElement(RecentSearchesList, null) : null,
28
26
  React.createElement(SuggestionList, null),
29
27
  showTabs ? React.createElement(CategoriesTabs, null) : null,
@@ -14,10 +14,12 @@ interface ResultsProps {
14
14
  scrollSelectionIntoViewRef?: React.MutableRefObject<boolean>;
15
15
  query: string;
16
16
  isLoading: boolean;
17
+ /** Show loading state when fetching and no previous hits (default false: show previous results until new render) */
18
+ showLoadingState?: boolean;
17
19
  error: string | null;
18
20
  translations?: DocSearchTranslations;
19
21
  sources?: SearchSource[];
20
22
  }
21
- export declare function Results({ hits, groupedHits, selectedIndex, onSelect, onHover, scrollSelectionIntoViewRef, query, isLoading, error, translations, sources: _sources, }: ResultsProps): React.JSX.Element;
23
+ export declare function Results({ hits, groupedHits, selectedIndex, onSelect, onHover, scrollSelectionIntoViewRef, query, isLoading, showLoadingState, error, translations, sources: _sources, }: ResultsProps): React.JSX.Element;
22
24
  export {};
23
25
  //# sourceMappingURL=Results.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Results.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Results.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvG,UAAU,WAAW;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,CAAC,YAAY,GAAG,mBAAmB,CAAC,EAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,4GAA4G;IAC5G,0BAA0B,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAuGD,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,0BAA0B,EAC1B,KAAK,EACL,SAAS,EACT,KAAK,EACL,YAAiB,EACjB,OAAO,EAAE,QAAa,GACvB,EAAE,YAAY,qBAsGd"}
1
+ {"version":3,"file":"Results.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Results.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvG,UAAU,WAAW;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,CAAC,YAAY,GAAG,mBAAmB,CAAC,EAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,4GAA4G;IAC5G,0BAA0B,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,oHAAoH;IACpH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAuGD,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,0BAA0B,EAC1B,KAAK,EACL,SAAS,EACT,gBAAwB,EACxB,KAAK,EACL,YAAiB,EACjB,OAAO,EAAE,QAAa,GACvB,EAAE,YAAY,qBA0Gd"}