@seekora-ai/ui-sdk-react 0.2.5 → 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 (102) hide show
  1. package/dist/components/SearchBarWithSuggestions.d.ts +2 -0
  2. package/dist/components/SearchBarWithSuggestions.d.ts.map +1 -1
  3. package/dist/components/SearchBarWithSuggestions.js +2 -2
  4. package/dist/components/primitives/ImageDisplay.d.ts +19 -0
  5. package/dist/components/primitives/ImageDisplay.d.ts.map +1 -0
  6. package/dist/components/primitives/ImageDisplay.js +74 -0
  7. package/dist/components/primitives/index.d.ts +2 -0
  8. package/dist/components/primitives/index.d.ts.map +1 -0
  9. package/dist/components/primitives/index.js +1 -0
  10. package/dist/components/product-page/ProductGallery.d.ts +19 -0
  11. package/dist/components/product-page/ProductGallery.d.ts.map +1 -0
  12. package/dist/components/product-page/ProductGallery.js +13 -0
  13. package/dist/components/product-page/ProductInfo.d.ts +21 -0
  14. package/dist/components/product-page/ProductInfo.d.ts.map +1 -0
  15. package/dist/components/product-page/ProductInfo.js +19 -0
  16. package/dist/components/product-page/ProductRecommendations.d.ts +21 -0
  17. package/dist/components/product-page/ProductRecommendations.d.ts.map +1 -0
  18. package/dist/components/product-page/ProductRecommendations.js +17 -0
  19. package/dist/components/product-page/index.d.ts +4 -0
  20. package/dist/components/product-page/index.d.ts.map +1 -0
  21. package/dist/components/product-page/index.js +3 -0
  22. package/dist/components/section-primitives/SectionError.d.ts +11 -0
  23. package/dist/components/section-primitives/SectionError.d.ts.map +1 -0
  24. package/dist/components/section-primitives/SectionError.js +13 -0
  25. package/dist/components/section-primitives/SectionItemGrid.d.ts +18 -0
  26. package/dist/components/section-primitives/SectionItemGrid.d.ts.map +1 -0
  27. package/dist/components/section-primitives/SectionItemGrid.js +16 -0
  28. package/dist/components/section-primitives/SectionLoading.d.ts +11 -0
  29. package/dist/components/section-primitives/SectionLoading.d.ts.map +1 -0
  30. package/dist/components/section-primitives/SectionLoading.js +11 -0
  31. package/dist/components/section-primitives/SectionSearchContext.d.ts +17 -0
  32. package/dist/components/section-primitives/SectionSearchContext.d.ts.map +1 -0
  33. package/dist/components/section-primitives/SectionSearchContext.js +17 -0
  34. package/dist/components/section-primitives/SectionSearchProvider.d.ts +23 -0
  35. package/dist/components/section-primitives/SectionSearchProvider.d.ts.map +1 -0
  36. package/dist/components/section-primitives/SectionSearchProvider.js +105 -0
  37. package/dist/components/section-primitives/index.d.ts +6 -0
  38. package/dist/components/section-primitives/index.d.ts.map +1 -0
  39. package/dist/components/section-primitives/index.js +5 -0
  40. package/dist/components/suggestions-primitives/CategoriesTabs.d.ts +13 -0
  41. package/dist/components/suggestions-primitives/CategoriesTabs.d.ts.map +1 -0
  42. package/dist/components/suggestions-primitives/CategoriesTabs.js +35 -0
  43. package/dist/components/suggestions-primitives/DropdownPanel.d.ts +24 -0
  44. package/dist/components/suggestions-primitives/DropdownPanel.d.ts.map +1 -0
  45. package/dist/components/suggestions-primitives/DropdownPanel.js +54 -0
  46. package/dist/components/suggestions-primitives/ItemCard.d.ts +39 -0
  47. package/dist/components/suggestions-primitives/ItemCard.d.ts.map +1 -0
  48. package/dist/components/suggestions-primitives/ItemCard.js +52 -0
  49. package/dist/components/suggestions-primitives/ItemGrid.d.ts +28 -0
  50. package/dist/components/suggestions-primitives/ItemGrid.d.ts.map +1 -0
  51. package/dist/components/suggestions-primitives/ItemGrid.js +42 -0
  52. package/dist/components/suggestions-primitives/ProductCard.d.ts +21 -0
  53. package/dist/components/suggestions-primitives/ProductCard.d.ts.map +1 -0
  54. package/dist/components/suggestions-primitives/ProductCard.js +46 -0
  55. package/dist/components/suggestions-primitives/ProductGrid.d.ts +17 -0
  56. package/dist/components/suggestions-primitives/ProductGrid.d.ts.map +1 -0
  57. package/dist/components/suggestions-primitives/ProductGrid.js +36 -0
  58. package/dist/components/suggestions-primitives/RecentSearchesList.d.ts +17 -0
  59. package/dist/components/suggestions-primitives/RecentSearchesList.d.ts.map +1 -0
  60. package/dist/components/suggestions-primitives/RecentSearchesList.js +39 -0
  61. package/dist/components/suggestions-primitives/SearchInput.d.ts +19 -0
  62. package/dist/components/suggestions-primitives/SearchInput.d.ts.map +1 -0
  63. package/dist/components/suggestions-primitives/SearchInput.js +92 -0
  64. package/dist/components/suggestions-primitives/SuggestionItem.d.ts +18 -0
  65. package/dist/components/suggestions-primitives/SuggestionItem.d.ts.map +1 -0
  66. package/dist/components/suggestions-primitives/SuggestionItem.js +34 -0
  67. package/dist/components/suggestions-primitives/SuggestionList.d.ts +15 -0
  68. package/dist/components/suggestions-primitives/SuggestionList.d.ts.map +1 -0
  69. package/dist/components/suggestions-primitives/SuggestionList.js +36 -0
  70. package/dist/components/suggestions-primitives/SuggestionsContext.d.ts +41 -0
  71. package/dist/components/suggestions-primitives/SuggestionsContext.d.ts.map +1 -0
  72. package/dist/components/suggestions-primitives/SuggestionsContext.js +18 -0
  73. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts +24 -0
  74. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.d.ts.map +1 -0
  75. package/dist/components/suggestions-primitives/SuggestionsDropdownComposition.js +32 -0
  76. package/dist/components/suggestions-primitives/SuggestionsError.d.ts +11 -0
  77. package/dist/components/suggestions-primitives/SuggestionsError.d.ts.map +1 -0
  78. package/dist/components/suggestions-primitives/SuggestionsError.js +19 -0
  79. package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts +11 -0
  80. package/dist/components/suggestions-primitives/SuggestionsLoading.d.ts.map +1 -0
  81. package/dist/components/suggestions-primitives/SuggestionsLoading.js +17 -0
  82. package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts +38 -0
  83. package/dist/components/suggestions-primitives/SuggestionsProvider.d.ts.map +1 -0
  84. package/dist/components/suggestions-primitives/SuggestionsProvider.js +222 -0
  85. package/dist/components/suggestions-primitives/TrendingList.d.ts +17 -0
  86. package/dist/components/suggestions-primitives/TrendingList.d.ts.map +1 -0
  87. package/dist/components/suggestions-primitives/TrendingList.js +41 -0
  88. package/dist/components/suggestions-primitives/index.d.ts +39 -0
  89. package/dist/components/suggestions-primitives/index.d.ts.map +1 -0
  90. package/dist/components/suggestions-primitives/index.js +24 -0
  91. package/dist/hooks/useSuggestionsAnalytics.d.ts +6 -6
  92. package/dist/hooks/useSuggestionsAnalytics.js +6 -6
  93. package/dist/index.d.ts +9 -1
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +7 -0
  96. package/dist/index.umd.js +1 -1
  97. package/dist/src/index.d.ts +626 -130
  98. package/dist/src/index.esm.js +1077 -35
  99. package/dist/src/index.esm.js.map +1 -1
  100. package/dist/src/index.js +1101 -34
  101. package/dist/src/index.js.map +1 -1
  102. package/package.json +3 -3
@@ -0,0 +1,34 @@
1
+ /**
2
+ * SuggestionItem – single text suggestion row (primitive)
3
+ *
4
+ * Highlights when isActive; onClick calls context selectSuggestion. Overridable via className/style.
5
+ */
6
+ import React from 'react';
7
+ import { clsx } from 'clsx';
8
+ const defaultItemStyle = {
9
+ padding: '10px 12px',
10
+ cursor: 'pointer',
11
+ listStyle: 'none',
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 SuggestionItem({ suggestion, index, isActive, onSelect, className, style, renderHighlight, }) {
22
+ const displayText = suggestion.highlightedQuery ?? suggestion.query;
23
+ const content = renderHighlight ? renderHighlight(displayText) : displayText;
24
+ return (React.createElement("li", { role: "option", "aria-selected": isActive, id: `seekora-suggestion-${index}`, className: clsx('seekora-suggestions-item', isActive && 'seekora-suggestions-item--active', className), style: {
25
+ ...defaultItemStyle,
26
+ ...(isActive ? { backgroundColor: 'var(--seekora-bg-hover, #f3f4f6)' } : {}),
27
+ ...style,
28
+ }, onMouseDown: (e) => {
29
+ e.preventDefault();
30
+ onSelect();
31
+ } },
32
+ content,
33
+ suggestion.count != null ? (React.createElement("span", { className: "seekora-suggestions-item-count", style: { marginLeft: 8, color: 'var(--seekora-text-secondary, #6b7280)', fontSize: '0.875em' } }, suggestion.count)) : null));
34
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * SuggestionList – container for text suggestions (primitive)
3
+ *
4
+ * Renders list of SuggestionItem from context; uses activeIndex for highlight. Optional renderItem.
5
+ */
6
+ import React from 'react';
7
+ export interface SuggestionListProps {
8
+ maxItems?: number;
9
+ className?: string;
10
+ style?: React.CSSProperties;
11
+ listClassName?: string;
12
+ renderItem?: (suggestion: import('@seekora-ai/ui-sdk-types').SuggestionItem, index: number, isActive: boolean, onSelect: () => void) => React.ReactNode;
13
+ }
14
+ export declare function SuggestionList({ maxItems, className, style, listClassName, renderItem, }: SuggestionListProps): React.JSX.Element | null;
15
+ //# sourceMappingURL=SuggestionList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuggestionList.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionList.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,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,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,UAAU,GACX,EAAE,mBAAmB,4BA+CrB"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * SuggestionList – container for text suggestions (primitive)
3
+ *
4
+ * Renders list of SuggestionItem from context; uses activeIndex for highlight. Optional renderItem.
5
+ */
6
+ import React from 'react';
7
+ import { useSuggestionsContext } from './SuggestionsContext';
8
+ import { SuggestionItem } from './SuggestionItem';
9
+ import { SuggestionsLoading } from './SuggestionsLoading';
10
+ import { clsx } from 'clsx';
11
+ const listStyle = {
12
+ margin: 0,
13
+ padding: '4px 0',
14
+ };
15
+ export function SuggestionList({ maxItems = 10, className, style, listClassName, renderItem, }) {
16
+ const { suggestions, activeIndex, loading, selectSuggestion, getAllNavigableItems, } = useSuggestionsContext();
17
+ const items = suggestions.slice(0, maxItems);
18
+ const navigableItems = getAllNavigableItems();
19
+ const suggestionStartIndex = navigableItems.findIndex((n) => n.type === 'suggestion');
20
+ const activeIsInSuggestions = suggestionStartIndex >= 0 && activeIndex >= suggestionStartIndex && activeIndex < suggestionStartIndex + items.length;
21
+ if (loading) {
22
+ return React.createElement(SuggestionsLoading, { className: className, style: style });
23
+ }
24
+ if (items.length === 0)
25
+ return null;
26
+ return (React.createElement("div", { className: clsx('seekora-suggestions-list', className), style: style },
27
+ React.createElement("ul", { className: clsx('seekora-suggestions-list-ul', listClassName), style: listStyle, role: "listbox" }, items.map((suggestion, i) => {
28
+ const globalIndex = suggestionStartIndex >= 0 ? suggestionStartIndex + i : i;
29
+ const isActive = activeIsInSuggestions && activeIndex === globalIndex;
30
+ const onSelect = () => selectSuggestion(suggestion, globalIndex);
31
+ if (renderItem) {
32
+ return (React.createElement("li", { key: suggestion.objectID ?? suggestion.query ?? i, role: "option" }, renderItem(suggestion, globalIndex, isActive, onSelect)));
33
+ }
34
+ return (React.createElement(SuggestionItem, { key: suggestion.objectID ?? suggestion.query ?? i, suggestion: suggestion, index: globalIndex, isActive: isActive, onSelect: onSelect }));
35
+ }))));
36
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Suggestions Context
3
+ *
4
+ * Type definitions and React context for composable suggestions primitives.
5
+ * Consuming components use useSuggestionsContext() for state and actions.
6
+ */
7
+ import React from 'react';
8
+ import type { SuggestionItem, ProductItem, RecentSearch, TrendingSearch, FilteredTab } from '@seekora-ai/ui-sdk-types';
9
+ import type { NavigableItem } from '../../hooks/useQuerySuggestionsEnhanced';
10
+ export interface SuggestionsContextValue {
11
+ query: string;
12
+ setQuery: (query: string) => void;
13
+ isOpen: boolean;
14
+ setIsOpen: (open: boolean) => void;
15
+ activeIndex: number;
16
+ setActiveIndex: (index: number) => void;
17
+ suggestions: SuggestionItem[];
18
+ recentSearches: RecentSearch[];
19
+ trendingSearches: TrendingSearch[];
20
+ trendingProducts: ProductItem[];
21
+ filteredTabs: FilteredTab[];
22
+ activeTabId: string;
23
+ setActiveTabId: (id: string) => void;
24
+ loading: boolean;
25
+ error: Error | null;
26
+ hasContent: boolean;
27
+ getAllNavigableItems: () => NavigableItem[];
28
+ selectSuggestion: (suggestion: SuggestionItem, position: number) => void;
29
+ selectProduct: (product: ProductItem, position: number, section?: string, tabId?: string) => void;
30
+ selectRecentSearch: (search: RecentSearch) => void;
31
+ selectTrendingSearch: (trending: TrendingSearch, position: number) => void;
32
+ setActiveTab: (tab: FilteredTab) => void;
33
+ submitSearch: (query: string, fromSuggestion?: boolean, suggestion?: SuggestionItem) => void;
34
+ close: () => void;
35
+ navigateNext: () => void;
36
+ navigatePrev: () => void;
37
+ selectActive: () => void;
38
+ }
39
+ export declare const SuggestionsContext: React.Context<SuggestionsContextValue | null>;
40
+ export declare function useSuggestionsContext(): SuggestionsContextValue;
41
+ //# sourceMappingURL=SuggestionsContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuggestionsContext.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,cAAc,EACd,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,WAAW,uBAAuB;IAEtC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,gBAAgB,EAAE,cAAc,EAAE,CAAC;IACnC,gBAAgB,EAAE,WAAW,EAAE,CAAC;IAChC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,MAAM,aAAa,EAAE,CAAC;IAG5C,gBAAgB,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAClG,kBAAkB,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,YAAY,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7F,KAAK,EAAE,MAAM,IAAI,CAAC;IAGlB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,kBAAkB,+CAAsD,CAAC;AAEtF,wBAAgB,qBAAqB,IAAI,uBAAuB,CAQ/D"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Suggestions Context
3
+ *
4
+ * Type definitions and React context for composable suggestions primitives.
5
+ * Consuming components use useSuggestionsContext() for state and actions.
6
+ */
7
+ import { createContext, useContext } from 'react';
8
+ import { log } from '@seekora-ai/ui-sdk-core';
9
+ export const SuggestionsContext = createContext(null);
10
+ export function useSuggestionsContext() {
11
+ const context = useContext(SuggestionsContext);
12
+ if (!context) {
13
+ const error = new Error('useSuggestionsContext must be used within a SuggestionsProvider');
14
+ log.error('SuggestionsContext: not available', { error: error.message });
15
+ throw error;
16
+ }
17
+ return context;
18
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SuggestionsDropdownComposition – reference composition
3
+ *
4
+ * Example layout built from primitives: SearchInput + DropdownPanel containing
5
+ * RecentSearchesList (when query empty), SuggestionList, CategoriesTabs, ProductGrid, TrendingList.
6
+ * Wrap with SearchProvider and SuggestionsProvider. Use as reference or replace
7
+ * with your own arrangement of the same primitives.
8
+ */
9
+ import React from 'react';
10
+ import type { SuggestionsProviderProps } from './SuggestionsProvider';
11
+ export interface SuggestionsDropdownCompositionProps extends Omit<SuggestionsProviderProps, 'children'> {
12
+ /** Show recent searches when query is empty */
13
+ showRecentSearches?: boolean;
14
+ /** Show trending list */
15
+ showTrending?: boolean;
16
+ /** Show categories/filtered tabs */
17
+ showTabs?: boolean;
18
+ /** Show product grid */
19
+ showProducts?: boolean;
20
+ /** SearchInput placeholder */
21
+ placeholder?: string;
22
+ }
23
+ export declare function SuggestionsDropdownComposition({ showRecentSearches, showTrending, showTabs, showProducts, placeholder, ...providerProps }: SuggestionsDropdownCompositionProps): React.JSX.Element;
24
+ //# sourceMappingURL=SuggestionsDropdownComposition.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * SuggestionsDropdownComposition – reference composition
3
+ *
4
+ * Example layout built from primitives: SearchInput + DropdownPanel containing
5
+ * RecentSearchesList (when query empty), SuggestionList, CategoriesTabs, ProductGrid, TrendingList.
6
+ * Wrap with SearchProvider and SuggestionsProvider. Use as reference or replace
7
+ * with your own arrangement of the same primitives.
8
+ */
9
+ import React from 'react';
10
+ import { SuggestionsProvider } from './SuggestionsProvider';
11
+ import { SearchInput } from './SearchInput';
12
+ import { DropdownPanel } from './DropdownPanel';
13
+ import { RecentSearchesList } from './RecentSearchesList';
14
+ import { SuggestionList } from './SuggestionList';
15
+ import { CategoriesTabs } from './CategoriesTabs';
16
+ import { ProductGrid } from './ProductGrid';
17
+ import { TrendingList } from './TrendingList';
18
+ import { SuggestionsLoading } from './SuggestionsLoading';
19
+ import { SuggestionsError } from './SuggestionsError';
20
+ export function SuggestionsDropdownComposition({ showRecentSearches = true, showTrending = true, showTabs = true, showProducts = true, placeholder, ...providerProps }) {
21
+ return (React.createElement(SuggestionsProvider, { ...providerProps },
22
+ React.createElement("div", { className: "seekora-suggestions-dropdown-composition", style: { position: 'relative', width: '100%' } },
23
+ React.createElement(SearchInput, { placeholder: placeholder }),
24
+ React.createElement(DropdownPanel, null,
25
+ React.createElement(SuggestionsError, null),
26
+ React.createElement(SuggestionsLoading, null),
27
+ showRecentSearches ? React.createElement(RecentSearchesList, null) : null,
28
+ React.createElement(SuggestionList, null),
29
+ showTabs ? React.createElement(CategoriesTabs, null) : null,
30
+ showProducts ? React.createElement(ProductGrid, null) : null,
31
+ showTrending ? React.createElement(TrendingList, null) : null))));
32
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SuggestionsError – error message (primitive)
3
+ */
4
+ import React from 'react';
5
+ export interface SuggestionsErrorProps {
6
+ className?: string;
7
+ style?: React.CSSProperties;
8
+ render?: (error: Error) => React.ReactNode;
9
+ }
10
+ export declare function SuggestionsError({ className, style, render }: SuggestionsErrorProps): React.JSX.Element | null;
11
+ //# sourceMappingURL=SuggestionsError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuggestionsError.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsError.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAC;CAC5C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,qBAAqB,4BAmBnF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * SuggestionsError – error message (primitive)
3
+ */
4
+ import React from 'react';
5
+ import { useSuggestionsContext } from './SuggestionsContext';
6
+ import { clsx } from 'clsx';
7
+ export function SuggestionsError({ className, style, render }) {
8
+ const { error } = useSuggestionsContext();
9
+ if (!error)
10
+ return null;
11
+ if (render)
12
+ return React.createElement(React.Fragment, null, render(error));
13
+ return (React.createElement("div", { className: clsx('seekora-suggestions-error', className), style: {
14
+ padding: 16,
15
+ color: 'var(--seekora-error, #dc2626)',
16
+ fontSize: '0.875rem',
17
+ ...style,
18
+ } }, error.message));
19
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SuggestionsLoading – loading indicator (primitive)
3
+ */
4
+ import React from 'react';
5
+ export interface SuggestionsLoadingProps {
6
+ className?: string;
7
+ style?: React.CSSProperties;
8
+ text?: string;
9
+ }
10
+ export declare function SuggestionsLoading({ className, style, text }: SuggestionsLoadingProps): React.JSX.Element | null;
11
+ //# sourceMappingURL=SuggestionsLoading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuggestionsLoading.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsLoading.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAmB,EAAE,EAAE,uBAAuB,4BAiBpG"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * SuggestionsLoading – loading indicator (primitive)
3
+ */
4
+ import React from 'react';
5
+ import { useSuggestionsContext } from './SuggestionsContext';
6
+ import { clsx } from 'clsx';
7
+ export function SuggestionsLoading({ className, style, text = 'Loading...' }) {
8
+ const { loading } = useSuggestionsContext();
9
+ if (!loading)
10
+ return null;
11
+ return (React.createElement("div", { className: clsx('seekora-suggestions-loading', className), style: {
12
+ padding: 16,
13
+ color: 'var(--seekora-text-secondary, #6b7280)',
14
+ fontSize: '0.875rem',
15
+ ...style,
16
+ } }, text));
17
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * SuggestionsProvider
3
+ *
4
+ * Provides suggestions state (query, suggestions, products, recent, trending, tabs),
5
+ * actions (selectSuggestion, selectProduct, submitSearch, etc.), and keyboard navigation.
6
+ * Uses useQuerySuggestionsEnhanced and useSuggestionsAnalytics; must be inside SearchProvider.
7
+ */
8
+ import React from 'react';
9
+ import type { SuggestionItem, ProductItem } from '@seekora-ai/ui-sdk-types';
10
+ export interface SuggestionsProviderProps {
11
+ children: React.ReactNode;
12
+ /** Min query length to fetch suggestions */
13
+ minQueryLength?: number;
14
+ /** Debounce ms for suggestion fetch */
15
+ debounceMs?: number;
16
+ /** Max suggestions */
17
+ maxSuggestions?: number;
18
+ /** Include dropdown recommendations (trending, products, etc.) */
19
+ includeDropdownRecommendations?: boolean;
20
+ /** Filtered tabs config */
21
+ filteredTabs?: Array<{
22
+ id?: string;
23
+ label: string;
24
+ filter: string;
25
+ }>;
26
+ /** Enable analytics (V3) */
27
+ enableAnalytics?: boolean;
28
+ /** Analytics tags */
29
+ analyticsTags?: string[];
30
+ /** Callback when user submits search (e.g. navigate to results page) */
31
+ onSearch?: (query: string) => void;
32
+ /** Callback when user selects a suggestion */
33
+ onSuggestionSelect?: (suggestion: SuggestionItem) => void;
34
+ /** Callback when user clicks a product */
35
+ onProductClick?: (product: ProductItem) => void;
36
+ }
37
+ export declare function SuggestionsProvider({ children, minQueryLength, debounceMs, maxSuggestions, includeDropdownRecommendations, filteredTabs, enableAnalytics, analyticsTags, onSearch, onSuggestionSelect, onProductClick, }: SuggestionsProviderProps): React.JSX.Element;
38
+ //# sourceMappingURL=SuggestionsProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuggestionsProvider.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/SuggestionsProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAMN,MAAM,OAAO,CAAC;AAKf,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAA6C,MAAM,0BAA0B,CAAC;AAGvH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,2BAA2B;IAC3B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,4BAA4B;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qBAAqB;IACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1D,0CAA0C;IAC1C,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,cAAkB,EAClB,UAAgB,EAChB,cAAmB,EACnB,8BAAqC,EACrC,YAAY,EACZ,eAAsB,EACtB,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,cAAc,GACf,EAAE,wBAAwB,qBA8O1B"}
@@ -0,0 +1,222 @@
1
+ /**
2
+ * SuggestionsProvider
3
+ *
4
+ * Provides suggestions state (query, suggestions, products, recent, trending, tabs),
5
+ * actions (selectSuggestion, selectProduct, submitSearch, etc.), and keyboard navigation.
6
+ * Uses useQuerySuggestionsEnhanced and useSuggestionsAnalytics; must be inside SearchProvider.
7
+ */
8
+ import React, { useState, useCallback, useMemo, useEffect, useRef, } from 'react';
9
+ import { useSearchContext } from '../SearchProvider';
10
+ import { useQuerySuggestionsEnhanced } from '../../hooks/useQuerySuggestionsEnhanced';
11
+ import { useSuggestionsAnalytics } from '../../hooks/useSuggestionsAnalytics';
12
+ import { SuggestionsContext } from './SuggestionsContext';
13
+ export function SuggestionsProvider({ children, minQueryLength = 1, debounceMs = 200, maxSuggestions = 10, includeDropdownRecommendations = true, filteredTabs, enableAnalytics = true, analyticsTags, onSearch, onSuggestionSelect, onProductClick, }) {
14
+ const { client } = useSearchContext();
15
+ const [query, setQueryState] = useState('');
16
+ const [isOpen, setIsOpenState] = useState(false);
17
+ const [activeIndex, setActiveIndex] = useState(-1);
18
+ const [activeTabId, setActiveTabId] = useState('');
19
+ const suggestionsData = useQuerySuggestionsEnhanced({
20
+ client,
21
+ query,
22
+ enabled: isOpen,
23
+ minQueryLength,
24
+ debounceMs,
25
+ maxSuggestions,
26
+ includeDropdownRecommendations,
27
+ filteredTabs,
28
+ includeCategories: true,
29
+ enableRecentSearches: true,
30
+ maxRecentSearches: 8,
31
+ analyticsTags,
32
+ });
33
+ const analytics = useSuggestionsAnalytics({
34
+ client,
35
+ enabled: enableAnalytics,
36
+ analyticsTags,
37
+ trackClicks: true,
38
+ trackImpressions: true,
39
+ });
40
+ const { suggestions, recentSearches, trendingSearches, trendingProducts, filteredTabs: filteredTabsData, loading, error, hasContent, getAllNavigableItems, addRecentSearch, } = suggestionsData;
41
+ const onSearchRef = useRef(onSearch);
42
+ const onSuggestionSelectRef = useRef(onSuggestionSelect);
43
+ const onProductClickRef = useRef(onProductClick);
44
+ onSearchRef.current = onSearch;
45
+ onSuggestionSelectRef.current = onSuggestionSelect;
46
+ onProductClickRef.current = onProductClick;
47
+ const setQuery = useCallback((q) => {
48
+ setQueryState(q);
49
+ setActiveIndex(-1);
50
+ }, []);
51
+ const close = useCallback(() => {
52
+ analytics.trackDropdownClose(query);
53
+ setIsOpenState(false);
54
+ setActiveIndex(-1);
55
+ }, [analytics, query]);
56
+ const setIsOpen = useCallback((open) => {
57
+ if (open) {
58
+ setIsOpenState(true);
59
+ analytics.trackDropdownOpen(query);
60
+ }
61
+ else {
62
+ close();
63
+ }
64
+ }, [analytics, query, close]);
65
+ const selectSuggestion = useCallback((suggestion, position) => {
66
+ analytics.trackSuggestionClick({
67
+ suggestion,
68
+ position,
69
+ query,
70
+ totalSuggestions: suggestions.length,
71
+ });
72
+ setQuery(suggestion.query);
73
+ onSuggestionSelectRef.current?.(suggestion);
74
+ analytics.trackSearchSubmit(suggestion.query, true, suggestion);
75
+ addRecentSearch(suggestion.query);
76
+ close();
77
+ onSearchRef.current?.(suggestion.query);
78
+ }, [analytics, query, suggestions.length, addRecentSearch, close]);
79
+ const selectProduct = useCallback((product, position, section, tabId) => {
80
+ analytics.trackProductClick({
81
+ product,
82
+ position,
83
+ section: section ?? 'products',
84
+ tabId,
85
+ query,
86
+ });
87
+ close();
88
+ onProductClickRef.current?.(product);
89
+ }, [analytics, query, close]);
90
+ const selectRecentSearch = useCallback((search) => {
91
+ analytics.trackRecentSearchClick(search);
92
+ setQuery(search.query);
93
+ close();
94
+ onSearchRef.current?.(search.query);
95
+ analytics.trackSearchSubmit(search.query, false);
96
+ }, [analytics, close]);
97
+ const selectTrendingSearch = useCallback((trending, position) => {
98
+ analytics.trackTrendingClick(trending, position);
99
+ setQuery(trending.query);
100
+ close();
101
+ onSearchRef.current?.(trending.query);
102
+ analytics.trackSearchSubmit(trending.query, false);
103
+ }, [analytics, close]);
104
+ const setActiveTab = useCallback((tab) => {
105
+ setActiveTabId(tab.id);
106
+ analytics.trackTabSelect(tab, query);
107
+ }, [analytics, query]);
108
+ const submitSearch = useCallback((q, fromSuggestion, suggestion) => {
109
+ const trimmed = q.trim();
110
+ if (!trimmed)
111
+ return;
112
+ analytics.trackSearchSubmit(trimmed, !!fromSuggestion, suggestion);
113
+ addRecentSearch(trimmed);
114
+ close();
115
+ onSearchRef.current?.(trimmed);
116
+ }, [analytics, addRecentSearch, close]);
117
+ const navigateNext = useCallback(() => {
118
+ const items = getAllNavigableItems();
119
+ if (items.length === 0)
120
+ return;
121
+ setActiveIndex((i) => (i < items.length - 1 ? i + 1 : 0));
122
+ }, [getAllNavigableItems]);
123
+ const navigatePrev = useCallback(() => {
124
+ const items = getAllNavigableItems();
125
+ if (items.length === 0)
126
+ return;
127
+ setActiveIndex((i) => (i <= 0 ? items.length - 1 : i - 1));
128
+ }, [getAllNavigableItems]);
129
+ const selectActive = useCallback(() => {
130
+ const items = getAllNavigableItems();
131
+ if (activeIndex < 0 || activeIndex >= items.length) {
132
+ submitSearch(query);
133
+ return;
134
+ }
135
+ const item = items[activeIndex];
136
+ switch (item.type) {
137
+ case 'suggestion':
138
+ selectSuggestion(item.data, item.index);
139
+ break;
140
+ case 'product':
141
+ selectProduct(item.data, item.index, 'products');
142
+ break;
143
+ case 'recent':
144
+ selectRecentSearch(item.data);
145
+ break;
146
+ case 'trending':
147
+ selectTrendingSearch(item.data, item.index);
148
+ break;
149
+ default:
150
+ submitSearch(query);
151
+ }
152
+ }, [activeIndex, getAllNavigableItems, query, submitSearch, selectSuggestion, selectProduct, selectRecentSearch, selectTrendingSearch]);
153
+ // Impression when open and content changes
154
+ useEffect(() => {
155
+ if (!isOpen || !hasContent || !query)
156
+ return;
157
+ analytics.trackImpression({
158
+ suggestions,
159
+ products: trendingProducts,
160
+ query,
161
+ timestamp: Date.now(),
162
+ });
163
+ }, [isOpen, hasContent, query, suggestions, trendingProducts, analytics]);
164
+ const value = useMemo(() => ({
165
+ query,
166
+ setQuery,
167
+ isOpen,
168
+ setIsOpen,
169
+ activeIndex,
170
+ setActiveIndex,
171
+ suggestions,
172
+ recentSearches,
173
+ trendingSearches,
174
+ trendingProducts,
175
+ filteredTabs: filteredTabsData,
176
+ activeTabId,
177
+ setActiveTabId,
178
+ loading,
179
+ error,
180
+ hasContent,
181
+ getAllNavigableItems,
182
+ selectSuggestion,
183
+ selectProduct,
184
+ selectRecentSearch,
185
+ selectTrendingSearch,
186
+ setActiveTab,
187
+ submitSearch,
188
+ close,
189
+ navigateNext,
190
+ navigatePrev,
191
+ selectActive,
192
+ }), [
193
+ query,
194
+ setQuery,
195
+ isOpen,
196
+ setIsOpen,
197
+ activeIndex,
198
+ setActiveIndex,
199
+ suggestions,
200
+ recentSearches,
201
+ trendingSearches,
202
+ trendingProducts,
203
+ filteredTabsData,
204
+ activeTabId,
205
+ setActiveTabId,
206
+ loading,
207
+ error,
208
+ hasContent,
209
+ getAllNavigableItems,
210
+ selectSuggestion,
211
+ selectProduct,
212
+ selectRecentSearch,
213
+ selectTrendingSearch,
214
+ setActiveTab,
215
+ submitSearch,
216
+ close,
217
+ navigateNext,
218
+ navigatePrev,
219
+ selectActive,
220
+ ]);
221
+ return (React.createElement(SuggestionsContext.Provider, { value: value }, children));
222
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * TrendingList – list of trending searches (primitive)
3
+ *
4
+ * Reads trendingSearches from context; each click calls selectTrendingSearch. Optional title/render.
5
+ */
6
+ import React from 'react';
7
+ import type { TrendingSearch } from '@seekora-ai/ui-sdk-types';
8
+ export interface TrendingListProps {
9
+ title?: string;
10
+ maxItems?: number;
11
+ className?: string;
12
+ style?: React.CSSProperties;
13
+ listClassName?: string;
14
+ renderItem?: (trending: TrendingSearch, index: number, onSelect: () => void) => React.ReactNode;
15
+ }
16
+ export declare function TrendingList({ title, maxItems, className, style, listClassName, renderItem, }: TrendingListProps): React.JSX.Element | null;
17
+ //# sourceMappingURL=TrendingList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrendingList.d.ts","sourceRoot":"","sources":["../../../src/components/suggestions-primitives/TrendingList.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IAChC,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,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;CACjG;AAeD,wBAAgB,YAAY,CAAC,EAC3B,KAAkB,EAClB,QAAY,EACZ,SAAS,EACT,KAAK,EACL,aAAa,EACb,UAAU,GACX,EAAE,iBAAiB,4BA4CnB"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * TrendingList – list of trending searches (primitive)
3
+ *
4
+ * Reads trendingSearches from context; each click calls selectTrendingSearch. 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 TrendingList({ title = 'Trending', maxItems = 8, className, style, listClassName, renderItem, }) {
22
+ const { trendingSearches, selectTrendingSearch } = useSuggestionsContext();
23
+ const items = trendingSearches.slice(0, maxItems);
24
+ if (items.length === 0)
25
+ return null;
26
+ return (React.createElement("div", { className: clsx('seekora-suggestions-trending-list', className), style: style },
27
+ title ? (React.createElement("div", { className: "seekora-suggestions-trending-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-trending-ul', listClassName), style: { margin: 0, padding: 0, listStyle: 'none' } }, items.map((trending, i) => {
29
+ const onSelect = () => selectTrendingSearch(trending, i);
30
+ if (renderItem) {
31
+ return React.createElement("li", { key: `${trending.query}-${i}` }, renderItem(trending, i, onSelect));
32
+ }
33
+ return (React.createElement("li", { key: `${trending.query}-${i}` },
34
+ React.createElement("button", { type: "button", className: "seekora-suggestions-trending-item", style: itemStyle, onMouseDown: (e) => {
35
+ e.preventDefault();
36
+ onSelect();
37
+ } },
38
+ trending.query,
39
+ trending.count != null ? (React.createElement("span", { style: { marginLeft: 8, color: 'var(--seekora-text-secondary, #6b7280)', fontSize: '0.875em' } }, trending.count)) : null)));
40
+ }))));
41
+ }