@seekora-ai/ui-sdk-react 0.2.4 → 0.2.7

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 (121) hide show
  1. package/dist/components/FederatedDropdown.d.ts +6 -0
  2. package/dist/components/FederatedDropdown.d.ts.map +1 -1
  3. package/dist/components/FederatedDropdown.js +4 -2
  4. package/dist/components/SearchBarWithSuggestions.d.ts +6 -0
  5. package/dist/components/SearchBarWithSuggestions.d.ts.map +1 -1
  6. package/dist/components/SearchBarWithSuggestions.js +2 -2
  7. package/dist/components/primitives/ImageDisplay.d.ts +19 -0
  8. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -0
  9. package/dist/components/primitives/ImageDisplay.js +74 -0
  10. package/dist/components/primitives/index.d.ts +2 -0
  11. package/dist/components/primitives/index.d.ts.map +1 -0
  12. package/dist/components/primitives/index.js +1 -0
  13. package/dist/components/product-page/ProductGallery.d.ts +19 -0
  14. package/dist/components/product-page/ProductGallery.d.ts.map +1 -0
  15. package/dist/components/product-page/ProductGallery.js +13 -0
  16. package/dist/components/product-page/ProductInfo.d.ts +21 -0
  17. package/dist/components/product-page/ProductInfo.d.ts.map +1 -0
  18. package/dist/components/product-page/ProductInfo.js +19 -0
  19. package/dist/components/product-page/ProductRecommendations.d.ts +21 -0
  20. package/dist/components/product-page/ProductRecommendations.d.ts.map +1 -0
  21. package/dist/components/product-page/ProductRecommendations.js +17 -0
  22. package/dist/components/product-page/index.d.ts +4 -0
  23. package/dist/components/product-page/index.d.ts.map +1 -0
  24. package/dist/components/product-page/index.js +3 -0
  25. package/dist/components/section-primitives/SectionError.d.ts +11 -0
  26. package/dist/components/section-primitives/SectionError.d.ts.map +1 -0
  27. package/dist/components/section-primitives/SectionError.js +13 -0
  28. package/dist/components/section-primitives/SectionItemGrid.d.ts +18 -0
  29. package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -0
  30. package/dist/components/section-primitives/SectionItemGrid.js +16 -0
  31. package/dist/components/section-primitives/SectionLoading.d.ts +11 -0
  32. package/dist/components/section-primitives/SectionLoading.d.ts.map +1 -0
  33. package/dist/components/section-primitives/SectionLoading.js +11 -0
  34. package/dist/components/section-primitives/SectionSearchContext.d.ts +17 -0
  35. package/dist/components/section-primitives/SectionSearchContext.d.ts.map +1 -0
  36. package/dist/components/section-primitives/SectionSearchContext.js +17 -0
  37. package/dist/components/section-primitives/SectionSearchProvider.d.ts +23 -0
  38. package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -0
  39. package/dist/components/section-primitives/SectionSearchProvider.js +105 -0
  40. package/dist/components/section-primitives/index.d.ts +6 -0
  41. package/dist/components/section-primitives/index.d.ts.map +1 -0
  42. package/dist/components/section-primitives/index.js +5 -0
  43. package/dist/components/suggestions-primitives/CategoriesTabs.d.ts +13 -0
  44. package/dist/components/suggestions-primitives/CategoriesTabs.d.ts.map +1 -0
  45. package/dist/components/suggestions-primitives/CategoriesTabs.js +35 -0
  46. package/dist/components/suggestions-primitives/DropdownPanel.d.ts +24 -0
  47. package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -0
  48. package/dist/components/suggestions-primitives/DropdownPanel.js +54 -0
  49. package/dist/components/suggestions-primitives/ItemCard.d.ts +39 -0
  50. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -0
  51. package/dist/components/suggestions-primitives/ItemCard.js +52 -0
  52. package/dist/components/suggestions-primitives/ItemGrid.d.ts +28 -0
  53. package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -0
  54. package/dist/components/suggestions-primitives/ItemGrid.js +42 -0
  55. package/dist/components/suggestions-primitives/ProductCard.d.ts +21 -0
  56. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -0
  57. package/dist/components/suggestions-primitives/ProductCard.js +46 -0
  58. package/dist/components/suggestions-primitives/ProductGrid.d.ts +17 -0
  59. package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -0
  60. package/dist/components/suggestions-primitives/ProductGrid.js +36 -0
  61. package/dist/components/suggestions-primitives/RecentSearchesList.d.ts +17 -0
  62. package/dist/components/suggestions-primitives/RecentSearchesList.d.ts.map +1 -0
  63. package/dist/components/suggestions-primitives/RecentSearchesList.js +39 -0
  64. package/dist/components/suggestions-primitives/SearchInput.d.ts +19 -0
  65. package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -0
  66. package/dist/components/suggestions-primitives/SearchInput.js +92 -0
  67. package/dist/components/suggestions-primitives/SuggestionItem.d.ts +18 -0
  68. package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -0
  69. package/dist/components/suggestions-primitives/SuggestionItem.js +34 -0
  70. package/dist/components/suggestions-primitives/SuggestionList.d.ts +15 -0
  71. package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -0
  72. package/dist/components/suggestions-primitives/SuggestionList.js +36 -0
  73. package/dist/components/suggestions-primitives/SuggestionsContext.d.ts +41 -0
  74. package/dist/components/suggestions-primitives/SuggestionsContext.d.ts.map +1 -0
  75. package/dist/components/suggestions-primitives/SuggestionsContext.js +18 -0
  76. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts +24 -0
  77. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts.map +1 -0
  78. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.js +32 -0
  79. package/dist/components/suggestions-primitives/SuggestionsError.d.ts +11 -0
  80. package/dist/components/suggestions-primitives/SuggestionsError.d.ts.map +1 -0
  81. package/dist/components/suggestions-primitives/SuggestionsError.js +19 -0
  82. package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts +11 -0
  83. package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts.map +1 -0
  84. package/dist/components/suggestions-primitives/SuggestionsLoading.js +17 -0
  85. package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts +38 -0
  86. package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts.map +1 -0
  87. package/dist/components/suggestions-primitives/SuggestionsProvider.js +222 -0
  88. package/dist/components/suggestions-primitives/TrendingList.d.ts +17 -0
  89. package/dist/components/suggestions-primitives/TrendingList.d.ts.map +1 -0
  90. package/dist/components/suggestions-primitives/TrendingList.js +41 -0
  91. package/dist/components/suggestions-primitives/index.d.ts +39 -0
  92. package/dist/components/suggestions-primitives/index.d.ts.map +1 -0
  93. package/dist/components/suggestions-primitives/index.js +24 -0
  94. package/dist/docsearch/components/DocSearch.d.ts +1 -1
  95. package/dist/docsearch/components/DocSearch.d.ts.map +1 -1
  96. package/dist/docsearch/components/DocSearch.js +15 -5
  97. package/dist/docsearch/components/Results.d.ts +3 -1
  98. package/dist/docsearch/components/Results.d.ts.map +1 -1
  99. package/dist/docsearch/components/Results.js +66 -12
  100. package/dist/docsearch/hooks/useDocSearch.d.ts +1 -0
  101. package/dist/docsearch/hooks/useDocSearch.d.ts.map +1 -1
  102. package/dist/docsearch/hooks/useDocSearch.js +6 -3
  103. package/dist/docsearch/hooks/useSeekoraSearch.d.ts.map +1 -1
  104. package/dist/docsearch/hooks/useSeekoraSearch.js +46 -26
  105. package/dist/docsearch/types.d.ts +2 -0
  106. package/dist/docsearch/types.d.ts.map +1 -1
  107. package/dist/docsearch.css +1 -1
  108. package/dist/hooks/useQuerySuggestionsEnhanced.js +1 -1
  109. package/dist/hooks/useSuggestionsAnalytics.d.ts +6 -6
  110. package/dist/hooks/useSuggestionsAnalytics.js +6 -6
  111. package/dist/index.d.ts +9 -1
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +7 -0
  114. package/dist/index.umd.js +1 -1
  115. package/dist/src/index.d.ts +640 -131
  116. package/dist/src/index.esm.js +1215 -84
  117. package/dist/src/index.esm.js.map +1 -1
  118. package/dist/src/index.js +1239 -83
  119. package/dist/src/index.js.map +1 -1
  120. package/package.json +5 -4
  121. package/src/docsearch/docsearch.css +237 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * SectionSearchProvider – preset query + filter section
3
+ *
4
+ * Runs client.search(query, { refinements, hitsPerPage, sortBy }) on mount and when
5
+ * query/filters change. Does not use global SearchStateManager. Use for menus,
6
+ * sidebar, front-page blocks (e.g. "New arrivals", "On sale").
7
+ */
8
+ import React, { useState, useEffect, useCallback, useMemo } from 'react';
9
+ import { useSearchContext } from '../SearchProvider';
10
+ import { SectionSearchContext } from './SectionSearchContext';
11
+ function extractItems(response) {
12
+ if (!response)
13
+ return [];
14
+ if (Array.isArray(response.results))
15
+ return response.results;
16
+ if (Array.isArray(response.hits))
17
+ return response.hits;
18
+ const data = response.data;
19
+ if (data && Array.isArray(data.results))
20
+ return data.results;
21
+ if (data && Array.isArray(data.data))
22
+ return data.data;
23
+ return [];
24
+ }
25
+ function extractTotal(response) {
26
+ if (!response)
27
+ return 0;
28
+ const n = response.totalResults ?? response.total ?? response.total_results;
29
+ if (typeof n === 'number')
30
+ return n;
31
+ const data = response.data;
32
+ if (data?.total_results != null)
33
+ return Number(data.total_results);
34
+ if (data?.data?.total_results != null)
35
+ return Number(data.data.total_results);
36
+ return 0;
37
+ }
38
+ export function SectionSearchProvider({ children, query, refinements = [], maxItems = 12, sortBy, enabled = true, sectionId, }) {
39
+ const { client } = useSearchContext();
40
+ const [items, setItems] = useState([]);
41
+ const [loading, setLoading] = useState(true);
42
+ const [error, setError] = useState(null);
43
+ const [totalCount, setTotalCount] = useState(0);
44
+ useEffect(() => {
45
+ if (!enabled || !client?.search) {
46
+ setItems([]);
47
+ setLoading(false);
48
+ setError(null);
49
+ setTotalCount(0);
50
+ return;
51
+ }
52
+ let cancelled = false;
53
+ setLoading(true);
54
+ setError(null);
55
+ const options = {
56
+ per_page: maxItems,
57
+ page: 1,
58
+ };
59
+ if (sortBy)
60
+ options.sort_by = sortBy;
61
+ if (refinements.length > 0) {
62
+ options.filter_by = refinements.map((r) => `${r.field}:${r.value}`).join(',');
63
+ }
64
+ client
65
+ .search(query, options)
66
+ .then((response) => {
67
+ if (cancelled)
68
+ return;
69
+ setItems(extractItems(response));
70
+ setTotalCount(extractTotal(response));
71
+ setLoading(false);
72
+ })
73
+ .catch((err) => {
74
+ if (cancelled)
75
+ return;
76
+ setError(err instanceof Error ? err : new Error(String(err)));
77
+ setItems([]);
78
+ setLoading(false);
79
+ });
80
+ return () => {
81
+ cancelled = true;
82
+ };
83
+ }, [client, enabled, query, maxItems, sortBy, refinements]);
84
+ const trackClick = useCallback((item, position) => {
85
+ if (!client?.trackEvent)
86
+ return;
87
+ const id = item?.id ?? item?.objectID;
88
+ client.trackEvent({
89
+ event_name: 'section_result_click',
90
+ clicked_item_id: id,
91
+ position,
92
+ section: sectionId,
93
+ metadata: { section_id: sectionId },
94
+ }, undefined);
95
+ }, [client, sectionId]);
96
+ const value = useMemo(() => ({
97
+ items,
98
+ loading,
99
+ error,
100
+ totalCount,
101
+ sectionId,
102
+ trackClick,
103
+ }), [items, loading, error, totalCount, sectionId, trackClick]);
104
+ return React.createElement(SectionSearchContext.Provider, { value: value }, children);
105
+ }
@@ -0,0 +1,6 @@
1
+ export { SectionSearchProvider, type RefinementInput, type SectionSearchProviderProps } from './SectionSearchProvider';
2
+ export { SectionSearchContext, useSectionSearchContext, type SectionSearchContextValue } from './SectionSearchContext';
3
+ export { SectionItemGrid, type SectionItemGridProps } from './SectionItemGrid';
4
+ export { SectionLoading, type SectionLoadingProps } from './SectionLoading';
5
+ export { SectionError, type SectionErrorProps } from './SectionError';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/section-primitives/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACvH,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACvH,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { SectionSearchProvider } from './SectionSearchProvider';
2
+ export { SectionSearchContext, useSectionSearchContext } from './SectionSearchContext';
3
+ export { SectionItemGrid } from './SectionItemGrid';
4
+ export { SectionLoading } from './SectionLoading';
5
+ export { SectionError } from './SectionError';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * CategoriesTabs – horizontal tabs (e.g. filtered tabs) (primitive)
3
+ *
4
+ * Active tab from context; on select updates context and tracks analytics.
5
+ */
6
+ import React from 'react';
7
+ export interface CategoriesTabsProps {
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ tabClassName?: string;
11
+ }
12
+ export declare function CategoriesTabs({ className, style, tabClassName }: CategoriesTabsProps): React.JSX.Element | null;
13
+ //# sourceMappingURL=CategoriesTabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoriesTabs.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/CategoriesTabs.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,mBAAmB,4BA+CrF"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CategoriesTabs – horizontal tabs (e.g. filtered tabs) (primitive)
3
+ *
4
+ * Active tab from context; on select updates context and tracks analytics.
5
+ */
6
+ import React from 'react';
7
+ import { useSuggestionsContext } from './SuggestionsContext';
8
+ import { clsx } from 'clsx';
9
+ export function CategoriesTabs({ className, style, tabClassName }) {
10
+ const { filteredTabs, activeTabId, setActiveTab } = useSuggestionsContext();
11
+ if (filteredTabs.length === 0)
12
+ return null;
13
+ return (React.createElement("div", { className: clsx('seekora-suggestions-categories-tabs', className), style: {
14
+ display: 'flex',
15
+ gap: 4,
16
+ padding: '8px 12px',
17
+ borderBottom: '1px solid var(--seekora-border-color, #e5e7eb)',
18
+ overflowX: 'auto',
19
+ ...style,
20
+ }, role: "tablist" }, filteredTabs.map((tab) => {
21
+ const isActive = activeTabId === tab.id;
22
+ return (React.createElement("button", { key: tab.id, type: "button", role: "tab", "aria-selected": isActive, className: clsx('seekora-suggestions-tab', isActive && 'seekora-suggestions-tab--active', tabClassName), style: {
23
+ padding: '8px 12px',
24
+ border: 'none',
25
+ borderRadius: 'var(--seekora-border-radius, 6px)',
26
+ backgroundColor: isActive ? 'var(--seekora-primary-light, rgba(59, 130, 246, 0.1))' : 'transparent',
27
+ color: isActive ? 'var(--seekora-primary, #3b82f6)' : 'var(--seekora-text-primary, #111827)',
28
+ cursor: 'pointer',
29
+ fontSize: '0.875rem',
30
+ fontWeight: isActive ? 600 : 400,
31
+ whiteSpace: 'nowrap',
32
+ transition: 'background-color 120ms ease',
33
+ }, onClick: () => setActiveTab(tab) }, tab.label));
34
+ })));
35
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * DropdownPanel – floating panel for suggestions (primitive)
3
+ *
4
+ * Shows when isOpen; handles click-outside and Escape to close. Children = any composition
5
+ * of SuggestionList, ProductGrid, etc. Position and z-index configurable.
6
+ */
7
+ import React from 'react';
8
+ export interface DropdownPanelProps {
9
+ children: React.ReactNode;
10
+ position?: 'absolute' | 'fixed';
11
+ /** CSS top offset (e.g. '100%', '4px') */
12
+ top?: string | number;
13
+ left?: string | number;
14
+ right?: string | number;
15
+ width?: string | number;
16
+ maxHeight?: string | number;
17
+ zIndex?: number;
18
+ className?: string;
19
+ style?: React.CSSProperties;
20
+ closeOnClickOutside?: boolean;
21
+ closeOnEscape?: boolean;
22
+ }
23
+ export declare function DropdownPanel({ children, position, top, left, right, width, maxHeight, zIndex, className, style, closeOnClickOutside, closeOnEscape, }: DropdownPanelProps): React.JSX.Element | null;
24
+ //# sourceMappingURL=DropdownPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropdownPanel.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/DropdownPanel.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAI9D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAChC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,QAAqB,EACrB,GAAY,EACZ,IAAQ,EACR,KAAK,EACL,KAAc,EACd,SAAkB,EAClB,MAAa,EACb,SAAS,EACT,KAAK,EACL,mBAA0B,EAC1B,aAAoB,GACrB,EAAE,kBAAkB,4BAqDpB"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * DropdownPanel – floating panel for suggestions (primitive)
3
+ *
4
+ * Shows when isOpen; handles click-outside and Escape to close. Children = any composition
5
+ * of SuggestionList, ProductGrid, etc. Position and z-index configurable.
6
+ */
7
+ import React, { useRef, useEffect, useCallback } from 'react';
8
+ import { useSuggestionsContext } from './SuggestionsContext';
9
+ import { clsx } from 'clsx';
10
+ export function DropdownPanel({ children, position = 'absolute', top = '100%', left = 0, right, width = '100%', maxHeight = '80vh', zIndex = 1000, className, style, closeOnClickOutside = true, closeOnEscape = true, }) {
11
+ const { isOpen, close } = useSuggestionsContext();
12
+ const panelRef = useRef(null);
13
+ useEffect(() => {
14
+ if (!closeOnEscape || !isOpen)
15
+ return;
16
+ const handleKeyDown = (e) => {
17
+ if (e.key === 'Escape')
18
+ close();
19
+ };
20
+ window.addEventListener('keydown', handleKeyDown);
21
+ return () => window.removeEventListener('keydown', handleKeyDown);
22
+ }, [closeOnEscape, isOpen, close]);
23
+ const handleClickOutside = useCallback((e) => {
24
+ if (!closeOnClickOutside || !panelRef.current)
25
+ return;
26
+ const target = e.target;
27
+ if (!panelRef.current.contains(target))
28
+ close();
29
+ }, [closeOnClickOutside, close]);
30
+ useEffect(() => {
31
+ if (!isOpen)
32
+ return;
33
+ document.addEventListener('mousedown', handleClickOutside);
34
+ return () => document.removeEventListener('mousedown', handleClickOutside);
35
+ }, [isOpen, handleClickOutside]);
36
+ if (!isOpen)
37
+ return null;
38
+ const panelStyle = {
39
+ position,
40
+ top,
41
+ left,
42
+ right,
43
+ width,
44
+ maxHeight,
45
+ zIndex,
46
+ overflow: 'auto',
47
+ backgroundColor: 'var(--seekora-bg-surface, #fff)',
48
+ border: '1px solid var(--seekora-border-color, #e5e7eb)',
49
+ borderRadius: 'var(--seekora-border-radius, 6px)',
50
+ boxShadow: 'var(--seekora-shadow-lg, 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05))',
51
+ marginTop: 4,
52
+ };
53
+ return (React.createElement("div", { ref: panelRef, role: "listbox", className: clsx('seekora-suggestions-dropdown-panel', className), style: { ...panelStyle, ...style } }, children));
54
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * ItemCard – generic item tile (primitive)
3
+ *
4
+ * Domain-agnostic: works for docs, articles, products, or any hit with id, title,
5
+ * optional description, image, url. Overridable via className/style. Use for
6
+ * search results, section blocks, or any list; for e-commerce products use ProductCard.
7
+ */
8
+ import React from 'react';
9
+ /** Generic item shape for ItemCard – compatible with ResultItem and most hit types */
10
+ export interface GenericItem {
11
+ id: string;
12
+ title: string;
13
+ description?: string;
14
+ image?: string;
15
+ /** Multiple images for carousel/hover/thumbStrip */
16
+ images?: string[];
17
+ url?: string;
18
+ /** Widget/display fields */
19
+ primaryText?: string;
20
+ secondaryText?: string;
21
+ tertiaryText?: string;
22
+ imageUrl?: string;
23
+ [key: string]: unknown;
24
+ }
25
+ export type ImageDisplayVariant = 'single' | 'carousel' | 'hover' | 'thumbStrip' | 'thumbList';
26
+ export interface ItemCardProps {
27
+ item: GenericItem;
28
+ /** Position in list (for analytics) */
29
+ position?: number;
30
+ onSelect?: () => void;
31
+ className?: string;
32
+ style?: React.CSSProperties;
33
+ /** Render as link (anchor) when item.url is set; otherwise button */
34
+ asLink?: boolean;
35
+ /** When multiple images, use ImageDisplay with this variant */
36
+ imageVariant?: ImageDisplayVariant;
37
+ }
38
+ export declare function ItemCard({ item, position, onSelect, className, style, asLink, imageVariant, }: ItemCardProps): React.JSX.Element;
39
+ //# sourceMappingURL=ItemCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemCard.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ItemCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAE/F,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,qEAAqE;IACrE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,EACL,MAAa,EACb,YAAuB,GACxB,EAAE,aAAa,qBA6Cf"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ItemCard – generic item tile (primitive)
3
+ *
4
+ * Domain-agnostic: works for docs, articles, products, or any hit with id, title,
5
+ * optional description, image, url. Overridable via className/style. Use for
6
+ * search results, section blocks, or any list; for e-commerce products use ProductCard.
7
+ */
8
+ import React from 'react';
9
+ import { clsx } from 'clsx';
10
+ import { ImageDisplay } from '../primitives/ImageDisplay';
11
+ const cardStyle = {
12
+ display: 'flex',
13
+ flexDirection: 'column',
14
+ gap: 8,
15
+ padding: 8,
16
+ cursor: 'pointer',
17
+ border: 'none',
18
+ borderRadius: 'var(--seekora-border-radius, 6px)',
19
+ backgroundColor: 'transparent',
20
+ textAlign: 'left',
21
+ fontSize: 'inherit',
22
+ fontFamily: 'inherit',
23
+ transition: 'background-color 120ms ease',
24
+ };
25
+ const imgStyle = {
26
+ width: '100%',
27
+ aspectRatio: '1',
28
+ objectFit: 'cover',
29
+ borderRadius: 4,
30
+ backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
31
+ };
32
+ export function ItemCard({ item, position, onSelect, className, style, asLink = true, imageVariant = 'single', }) {
33
+ const images = item.images?.length ? item.images : item.image ?? item.imageUrl ? [String(item.image ?? item.imageUrl)] : [];
34
+ const title = item.title ?? item.primaryText ?? '';
35
+ const description = item.description ?? item.secondaryText;
36
+ 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 })),
39
+ 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));
41
+ const commonProps = {
42
+ className: clsx('seekora-item-card', className),
43
+ style: { ...cardStyle, ...style },
44
+ 'data-position': position,
45
+ onClick: onSelect,
46
+ onMouseDown: onSelect ? (e) => { e.preventDefault(); onSelect(); } : undefined,
47
+ };
48
+ if (asLink && href) {
49
+ return (React.createElement("a", { href: href, ...commonProps, "data-item-id": item.id }, content));
50
+ }
51
+ return (React.createElement("button", { type: "button", ...commonProps, "data-item-id": item.id }, content));
52
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ItemGrid – generic grid of items (primitive)
3
+ *
4
+ * Domain-agnostic: accepts any items[] and onItemClick. Renders ItemCard by default
5
+ * or custom renderItem. Use for search hits, section blocks, docs, articles; for
6
+ * product-only lists use ProductGrid.
7
+ */
8
+ import React from 'react';
9
+ import { type GenericItem } from './ItemCard';
10
+ export interface ItemGridProps<T = GenericItem> {
11
+ items: T[];
12
+ onItemClick?: (item: T, index: number) => void;
13
+ /** Map item to GenericItem for default ItemCard rendering */
14
+ getItemId?: (item: T) => string;
15
+ getItemTitle?: (item: T) => string;
16
+ getItemImage?: (item: T) => string | undefined;
17
+ getItemDescription?: (item: T) => string | undefined;
18
+ getItemUrl?: (item: T) => string | undefined;
19
+ /** Custom render for each item; overrides default ItemCard */
20
+ renderItem?: (item: T, index: number) => React.ReactNode;
21
+ maxItems?: number;
22
+ columns?: number;
23
+ className?: string;
24
+ style?: React.CSSProperties;
25
+ gridClassName?: string;
26
+ }
27
+ export declare function ItemGrid<T = GenericItem>({ items, onItemClick, getItemId, getItemTitle, getItemImage, getItemDescription, getItemUrl, renderItem, maxItems, columns, className, style, gridClassName, }: ItemGridProps<T>): React.JSX.Element | null;
28
+ //# sourceMappingURL=ItemGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemGrid.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/ItemGrid.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,WAAW;IAC5C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,6DAA6D;IAC7D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IAC7C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,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;AA2BD,wBAAgB,QAAQ,CAAC,CAAC,GAAG,WAAW,EAAE,EACxC,KAAK,EACL,WAAW,EACX,SAA2C,EAC3C,YAAiD,EACjD,YAAiD,EACjD,kBAA6D,EAC7D,UAA6C,EAC7C,UAAU,EACV,QAAa,EACb,OAAW,EACX,SAAS,EACT,KAAK,EACL,aAAa,GACd,EAAE,aAAa,CAAC,CAAC,CAAC,4BA2BlB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ItemGrid – generic grid of items (primitive)
3
+ *
4
+ * Domain-agnostic: accepts any items[] and onItemClick. Renders ItemCard by default
5
+ * or custom renderItem. Use for search hits, section blocks, docs, articles; for
6
+ * product-only lists use ProductGrid.
7
+ */
8
+ import React from 'react';
9
+ import { clsx } from 'clsx';
10
+ import { ItemCard } from './ItemCard';
11
+ const defaultGridStyle = {
12
+ display: 'grid',
13
+ gridTemplateColumns: 'repeat(var(--seekora-grid-cols, 4), minmax(0, 1fr))',
14
+ gap: 12,
15
+ padding: 12,
16
+ };
17
+ function toGenericItem(item, getItemId, getItemTitle, getItemImage, getItemDescription, getItemUrl) {
18
+ return {
19
+ id: getItemId(item),
20
+ title: getItemTitle(item),
21
+ image: getItemImage?.(item),
22
+ description: getItemDescription?.(item),
23
+ url: getItemUrl?.(item),
24
+ ...(typeof item === 'object' && item !== null ? item : {}),
25
+ };
26
+ }
27
+ export function ItemGrid({ items, onItemClick, getItemId = (i) => i.id, getItemTitle = (i) => i.title, getItemImage = (i) => i.image, getItemDescription = (i) => i.description, getItemUrl = (i) => i.url, renderItem, maxItems = 24, columns = 4, className, style, gridClassName, }) {
28
+ const slice = items.slice(0, maxItems);
29
+ if (slice.length === 0)
30
+ return null;
31
+ const gridStyle = {
32
+ ...defaultGridStyle,
33
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
34
+ };
35
+ return (React.createElement("div", { className: clsx('seekora-item-grid', className), style: style },
36
+ React.createElement("div", { className: clsx('seekora-item-grid-inner', gridClassName), style: gridStyle }, slice.map((item, i) => {
37
+ if (renderItem)
38
+ return React.createElement(React.Fragment, { key: getItemId(item) }, renderItem(item, i));
39
+ const generic = toGenericItem(item, getItemId, getItemTitle, getItemImage, getItemDescription, getItemUrl);
40
+ return (React.createElement(ItemCard, { key: generic.id, item: generic, position: i, onSelect: onItemClick ? () => onItemClick(item, i) : undefined }));
41
+ }))));
42
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ProductCard – one product tile (primitive)
3
+ *
4
+ * Minimal layout: image (via ImageDisplay when imageVariant set), title, price.
5
+ * onClick calls context selectProduct. Overridable via className/style.
6
+ */
7
+ import React from 'react';
8
+ import type { ProductItem } from '@seekora-ai/ui-sdk-types';
9
+ export type ProductCardImageVariant = 'single' | 'carousel' | 'hover' | 'thumbStrip' | 'thumbList';
10
+ export interface ProductCardProps {
11
+ product: ProductItem;
12
+ position: number;
13
+ section?: string;
14
+ tabId?: string;
15
+ onSelect: () => void;
16
+ className?: string;
17
+ style?: React.CSSProperties;
18
+ imageVariant?: ProductCardImageVariant;
19
+ }
20
+ export declare function ProductCard({ product, position, section, tabId, onSelect, className, style, imageVariant, }: ProductCardProps): React.JSX.Element;
21
+ //# sourceMappingURL=ProductCard.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ProductCard – one product tile (primitive)
3
+ *
4
+ * Minimal layout: image (via ImageDisplay when imageVariant set), title, price.
5
+ * onClick calls context selectProduct. Overridable via className/style.
6
+ */
7
+ import React from 'react';
8
+ import { clsx } from 'clsx';
9
+ import { ImageDisplay } from '../primitives/ImageDisplay';
10
+ const cardStyle = {
11
+ display: 'flex',
12
+ flexDirection: 'column',
13
+ gap: 8,
14
+ padding: 8,
15
+ cursor: 'pointer',
16
+ border: 'none',
17
+ borderRadius: 'var(--seekora-border-radius, 6px)',
18
+ backgroundColor: 'transparent',
19
+ textAlign: 'left',
20
+ transition: 'background-color 120ms ease',
21
+ };
22
+ const imgStyle = {
23
+ width: '100%',
24
+ aspectRatio: '1',
25
+ objectFit: 'cover',
26
+ borderRadius: 4,
27
+ backgroundColor: 'var(--seekora-bg-secondary, #f3f4f6)',
28
+ };
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) => {
38
+ e.preventDefault();
39
+ onSelect();
40
+ }, "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));
46
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ProductGrid – grid of product cards from context (primitive)
3
+ *
4
+ * Uses trendingProducts or active tab products; each click calls context selectProduct.
5
+ */
6
+ import React from 'react';
7
+ export interface ProductGridProps {
8
+ maxItems?: number;
9
+ /** 'trending' | tab id for filtered tab products */
10
+ source?: 'trending' | string;
11
+ columns?: number;
12
+ className?: string;
13
+ style?: React.CSSProperties;
14
+ gridClassName?: string;
15
+ }
16
+ export declare function ProductGrid({ maxItems, source, columns, className, style, gridClassName, }: ProductGridProps): React.JSX.Element | null;
17
+ //# sourceMappingURL=ProductGrid.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * ProductGrid – grid of product cards from context (primitive)
3
+ *
4
+ * Uses trendingProducts or active tab products; each click calls context selectProduct.
5
+ */
6
+ import React, { useMemo } from 'react';
7
+ import { useSuggestionsContext } from './SuggestionsContext';
8
+ import { ProductCard } from './ProductCard';
9
+ import { clsx } from 'clsx';
10
+ export function ProductGrid({ maxItems = 8, source = 'trending', columns = 4, className, style, gridClassName, }) {
11
+ const { trendingProducts, filteredTabs, activeTabId, selectProduct, getAllNavigableItems, } = useSuggestionsContext();
12
+ const products = useMemo(() => {
13
+ if (source === 'trending')
14
+ return trendingProducts;
15
+ const tab = filteredTabs.find((t) => t.id === (source === 'tab' ? activeTabId : source));
16
+ return tab?.products ?? [];
17
+ }, [source, activeTabId, trendingProducts, filteredTabs]);
18
+ const items = products.slice(0, maxItems);
19
+ const navigableItems = getAllNavigableItems();
20
+ const productStartIndex = navigableItems.findIndex((n) => n.type === 'product');
21
+ if (items.length === 0)
22
+ return null;
23
+ const gridStyle = {
24
+ display: 'grid',
25
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
26
+ gap: 12,
27
+ padding: 12,
28
+ };
29
+ return (React.createElement("div", { className: clsx('seekora-suggestions-product-grid', className), style: style },
30
+ React.createElement("div", { className: clsx('seekora-suggestions-product-grid-inner', gridClassName), style: gridStyle }, items.map((product, i) => {
31
+ const globalIndex = productStartIndex >= 0 ? productStartIndex + i : i;
32
+ const section = source === 'trending' ? 'products' : 'filtered_tab';
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) }));
35
+ }))));
36
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * RecentSearchesList – list of recent queries (primitive)
3
+ *
4
+ * Reads recentSearches from context; each click calls selectRecentSearch. Optional title/render.
5
+ */
6
+ import React from 'react';
7
+ import type { RecentSearch } from '@seekora-ai/ui-sdk-types';
8
+ export interface RecentSearchesListProps {
9
+ title?: string;
10
+ maxItems?: number;
11
+ className?: string;
12
+ style?: React.CSSProperties;
13
+ listClassName?: string;
14
+ renderItem?: (search: RecentSearch, index: number, onSelect: () => void) => React.ReactNode;
15
+ }
16
+ export declare function RecentSearchesList({ title, maxItems, className, style, listClassName, renderItem, }: RecentSearchesListProps): React.JSX.Element | null;
17
+ //# sourceMappingURL=RecentSearchesList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecentSearchesList.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/RecentSearchesList.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,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,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;CAC7F;AAeD,wBAAgB,kBAAkB,CAAC,EACjC,KAAgB,EAChB,QAAY,EACZ,SAAS,EACT,KAAK,EACL,aAAa,EACb,UAAU,GACX,EAAE,uBAAuB,4BAyCzB"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * RecentSearchesList – list of recent queries (primitive)
3
+ *
4
+ * Reads recentSearches from context; each click calls selectRecentSearch. Optional title/render.
5
+ */
6
+ import React from 'react';
7
+ import { useSuggestionsContext } from './SuggestionsContext';
8
+ import { clsx } from 'clsx';
9
+ const itemStyle = {
10
+ padding: '10px 12px',
11
+ cursor: 'pointer',
12
+ border: 'none',
13
+ width: '100%',
14
+ textAlign: 'left',
15
+ fontSize: 'inherit',
16
+ fontFamily: 'inherit',
17
+ backgroundColor: 'transparent',
18
+ color: 'var(--seekora-text-primary, #111827)',
19
+ transition: 'background-color 120ms ease',
20
+ };
21
+ export function RecentSearchesList({ title = 'Recent', maxItems = 8, className, style, listClassName, renderItem, }) {
22
+ const { recentSearches, query, selectRecentSearch } = useSuggestionsContext();
23
+ const items = recentSearches.slice(0, maxItems);
24
+ if (items.length === 0)
25
+ return null;
26
+ return (React.createElement("div", { className: clsx('seekora-suggestions-recent-list', className), style: style },
27
+ title ? (React.createElement("div", { className: "seekora-suggestions-recent-title", style: { padding: '8px 12px', fontSize: '0.75rem', fontWeight: 600, color: 'var(--seekora-text-secondary, #6b7280)', textTransform: 'uppercase' } }, title)) : null,
28
+ React.createElement("ul", { className: clsx('seekora-suggestions-recent-ul', listClassName), style: { margin: 0, padding: 0, listStyle: 'none' } }, items.map((search, i) => {
29
+ const onSelect = () => selectRecentSearch(search);
30
+ if (renderItem) {
31
+ return React.createElement("li", { key: `${search.query}-${search.timestamp}` }, renderItem(search, i, onSelect));
32
+ }
33
+ return (React.createElement("li", { key: `${search.query}-${search.timestamp}` },
34
+ React.createElement("button", { type: "button", className: "seekora-suggestions-recent-item", style: itemStyle, onMouseDown: (e) => {
35
+ e.preventDefault();
36
+ onSelect();
37
+ } }, search.query)));
38
+ }))));
39
+ }