@seekora-ai/ui-sdk-react 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CurrentRefinements.d.ts +22 -2
- package/dist/components/CurrentRefinements.d.ts.map +1 -1
- package/dist/components/CurrentRefinements.js +199 -47
- package/dist/components/Facets.d.ts +30 -1
- package/dist/components/Facets.d.ts.map +1 -1
- package/dist/components/Facets.js +418 -46
- package/dist/components/HierarchicalMenu.d.ts.map +1 -1
- package/dist/components/HierarchicalMenu.js +112 -4
- package/dist/components/Pagination.d.ts +47 -1
- package/dist/components/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination.js +166 -28
- package/dist/components/RangeSlider.d.ts.map +1 -1
- package/dist/components/RangeSlider.js +49 -2
- package/dist/components/RichQuerySuggestions.d.ts +7 -0
- package/dist/components/RichQuerySuggestions.d.ts.map +1 -1
- package/dist/components/SearchBar.d.ts +16 -0
- package/dist/components/SearchBar.d.ts.map +1 -1
- package/dist/components/SearchBar.js +130 -16
- package/dist/components/SearchProvider.d.ts +8 -1
- package/dist/components/SearchProvider.d.ts.map +1 -1
- package/dist/components/SearchProvider.js +16 -4
- package/dist/components/SearchResults.d.ts +10 -0
- package/dist/components/SearchResults.d.ts.map +1 -1
- package/dist/components/SearchResults.js +9 -5
- package/dist/components/SortBy.d.ts +44 -4
- package/dist/components/SortBy.d.ts.map +1 -1
- package/dist/components/SortBy.js +154 -29
- package/dist/components/Stats.d.ts +14 -0
- package/dist/components/Stats.d.ts.map +1 -1
- package/dist/components/Stats.js +172 -23
- package/dist/components/suggestions/AmazonDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/AmazonDropdown.js +2 -4
- package/dist/components/suggestions/GoogleDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/GoogleDropdown.js +2 -6
- package/dist/components/suggestions/MinimalDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MinimalDropdown.js +2 -4
- package/dist/components/suggestions/MobileSheetDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/MobileSheetDropdown.js +2 -4
- package/dist/components/suggestions/PinterestDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/PinterestDropdown.js +2 -6
- package/dist/components/suggestions/ShopifyDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/ShopifyDropdown.js +2 -4
- package/dist/components/suggestions/SpotlightDropdown.d.ts.map +1 -1
- package/dist/components/suggestions/SpotlightDropdown.js +2 -4
- package/dist/components/suggestions/utils.d.ts +10 -1
- package/dist/components/suggestions/utils.d.ts.map +1 -1
- package/dist/components/suggestions/utils.js +36 -0
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts +16 -4
- package/dist/components/suggestions-primitives/highlightMarkup.d.ts.map +1 -1
- package/dist/components/suggestions-primitives/highlightMarkup.js +42 -4
- package/dist/hooks/useClickTracking.d.ts +36 -0
- package/dist/hooks/useClickTracking.d.ts.map +1 -0
- package/dist/hooks/useClickTracking.js +96 -0
- package/dist/hooks/useExperiment.d.ts +25 -0
- package/dist/hooks/useExperiment.d.ts.map +1 -0
- package/dist/hooks/useExperiment.js +146 -0
- package/dist/hooks/useKeyboardNavigation.d.ts +51 -0
- package/dist/hooks/useKeyboardNavigation.d.ts.map +1 -0
- package/dist/hooks/useKeyboardNavigation.js +113 -0
- package/dist/hooks/useQuerySuggestions.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestions.js +19 -3
- package/dist/hooks/useQuerySuggestionsEnhanced.d.ts.map +1 -1
- package/dist/hooks/useQuerySuggestionsEnhanced.js +23 -6
- package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -1
- package/dist/hooks/useSuggestionsAnalytics.js +6 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/src/index.d.ts +217 -16
- package/dist/src/index.esm.js +1586 -249
- package/dist/src/index.esm.js.map +1 -1
- package/dist/src/index.js +1585 -248
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CurrentRefinements Component
|
|
3
3
|
*
|
|
4
|
-
* Displays currently active filters/refinements with ability to clear them
|
|
4
|
+
* Displays currently active filters/refinements with ability to clear them.
|
|
5
|
+
* Supports StateManager auto-sync, display variants, layout modes, and animations.
|
|
5
6
|
*/
|
|
6
7
|
import React from 'react';
|
|
7
8
|
export interface Refinement {
|
|
@@ -18,9 +19,20 @@ export interface CurrentRefinementsTheme {
|
|
|
18
19
|
value?: string;
|
|
19
20
|
clearButton?: string;
|
|
20
21
|
clearAllButton?: string;
|
|
22
|
+
/** Variant-specific class slots */
|
|
23
|
+
chip?: string;
|
|
24
|
+
tag?: string;
|
|
25
|
+
pill?: string;
|
|
26
|
+
badge?: string;
|
|
27
|
+
group?: string;
|
|
28
|
+
groupLabel?: string;
|
|
21
29
|
}
|
|
30
|
+
/** Display variant for refinement items */
|
|
31
|
+
export type RefinementVariant = 'chips' | 'tags' | 'pills' | 'badges' | 'text-list';
|
|
32
|
+
/** Layout variant for the container */
|
|
33
|
+
export type RefinementLayout = 'horizontal' | 'vertical' | 'grouped';
|
|
22
34
|
export interface CurrentRefinementsProps {
|
|
23
|
-
/** Current refinements */
|
|
35
|
+
/** Current refinements (if not provided, auto-reads from StateManager) */
|
|
24
36
|
refinements?: Refinement[];
|
|
25
37
|
/** Callback when a refinement is cleared */
|
|
26
38
|
onRefinementClear?: (field: string, value: string) => void;
|
|
@@ -30,6 +42,14 @@ export interface CurrentRefinementsProps {
|
|
|
30
42
|
renderRefinement?: (refinement: Refinement, index: number) => React.ReactNode;
|
|
31
43
|
/** Show "Clear all" button */
|
|
32
44
|
showClearAll?: boolean;
|
|
45
|
+
/** Display variant (default: 'chips') */
|
|
46
|
+
variant?: RefinementVariant;
|
|
47
|
+
/** Layout mode (default: 'horizontal') */
|
|
48
|
+
layout?: RefinementLayout;
|
|
49
|
+
/** Per-field color mapping */
|
|
50
|
+
fieldColors?: Record<string, string>;
|
|
51
|
+
/** Custom close icon renderer */
|
|
52
|
+
renderCloseIcon?: () => React.ReactNode;
|
|
33
53
|
/** Custom className */
|
|
34
54
|
className?: string;
|
|
35
55
|
/** Custom styles */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrentRefinements.d.ts","sourceRoot":"","sources":["../../src/components/CurrentRefinements.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CurrentRefinements.d.ts","sourceRoot":"","sources":["../../src/components/CurrentRefinements.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAK3D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpF,uCAAuC;AACvC,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9E,8BAA8B;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACxC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC;AA0FD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA2OhE,CAAC"}
|
|
@@ -1,75 +1,226 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CurrentRefinements Component
|
|
3
3
|
*
|
|
4
|
-
* Displays currently active filters/refinements with ability to clear them
|
|
4
|
+
* Displays currently active filters/refinements with ability to clear them.
|
|
5
|
+
* Supports StateManager auto-sync, display variants, layout modes, and animations.
|
|
5
6
|
*/
|
|
6
|
-
import React from 'react';
|
|
7
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
7
8
|
import { useSearchContext } from './SearchProvider';
|
|
9
|
+
import { useSearchState } from '../hooks/useSearchState';
|
|
8
10
|
import { clsx } from 'clsx';
|
|
9
|
-
|
|
11
|
+
/** Get variant-specific styles */
|
|
12
|
+
const getVariantStyles = (variant, themeColors, themeSpacing, themeBorderRadius, fieldColor) => {
|
|
13
|
+
const baseBg = fieldColor || `var(--seekora-refinement-bg, ${themeColors.hover})`;
|
|
14
|
+
const baseColor = `var(--seekora-refinement-color, ${themeColors.text})`;
|
|
15
|
+
const baseBorder = `var(--seekora-refinement-border, ${themeColors.border})`;
|
|
16
|
+
switch (variant) {
|
|
17
|
+
case 'tags':
|
|
18
|
+
return {
|
|
19
|
+
display: 'inline-flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
padding: `2px ${themeSpacing.medium}`,
|
|
22
|
+
backgroundColor: baseBg,
|
|
23
|
+
border: `1px solid ${baseBorder}`,
|
|
24
|
+
borderRadius: `var(--seekora-refinement-radius, 4px)`,
|
|
25
|
+
fontSize: '12px',
|
|
26
|
+
color: baseColor,
|
|
27
|
+
fontWeight: 500,
|
|
28
|
+
};
|
|
29
|
+
case 'pills':
|
|
30
|
+
return {
|
|
31
|
+
display: 'inline-flex',
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
padding: `${themeSpacing.small} ${themeSpacing.medium}`,
|
|
34
|
+
backgroundColor: baseBg,
|
|
35
|
+
border: 'none',
|
|
36
|
+
borderRadius: `var(--seekora-refinement-radius, 9999px)`,
|
|
37
|
+
fontSize: '13px',
|
|
38
|
+
color: baseColor,
|
|
39
|
+
};
|
|
40
|
+
case 'badges':
|
|
41
|
+
return {
|
|
42
|
+
display: 'inline-flex',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
padding: `3px ${themeSpacing.small}`,
|
|
45
|
+
backgroundColor: themeColors.primary,
|
|
46
|
+
border: 'none',
|
|
47
|
+
borderRadius: `var(--seekora-refinement-radius, 4px)`,
|
|
48
|
+
fontSize: '11px',
|
|
49
|
+
color: '#fff',
|
|
50
|
+
fontWeight: 600,
|
|
51
|
+
textTransform: 'uppercase',
|
|
52
|
+
letterSpacing: '0.5px',
|
|
53
|
+
};
|
|
54
|
+
case 'text-list':
|
|
55
|
+
return {
|
|
56
|
+
display: 'flex',
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
padding: `${themeSpacing.small} 0`,
|
|
59
|
+
backgroundColor: 'transparent',
|
|
60
|
+
border: 'none',
|
|
61
|
+
borderBottom: `1px solid ${baseBorder}`,
|
|
62
|
+
borderRadius: '0',
|
|
63
|
+
fontSize: '14px',
|
|
64
|
+
color: baseColor,
|
|
65
|
+
};
|
|
66
|
+
case 'chips':
|
|
67
|
+
default:
|
|
68
|
+
return {
|
|
69
|
+
display: 'inline-flex',
|
|
70
|
+
alignItems: 'center',
|
|
71
|
+
padding: `${themeSpacing.small} ${themeSpacing.medium}`,
|
|
72
|
+
backgroundColor: baseBg,
|
|
73
|
+
border: `1px solid ${baseBorder}`,
|
|
74
|
+
borderRadius: `var(--seekora-refinement-radius, ${typeof themeBorderRadius === 'string' ? themeBorderRadius : themeBorderRadius.medium})`,
|
|
75
|
+
fontSize: '13px',
|
|
76
|
+
color: baseColor,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/** Get variant-specific class name from theme */
|
|
81
|
+
const getVariantClass = (variant, refinementsTheme) => {
|
|
82
|
+
switch (variant) {
|
|
83
|
+
case 'tags': return refinementsTheme.tag;
|
|
84
|
+
case 'pills': return refinementsTheme.pill;
|
|
85
|
+
case 'badges': return refinementsTheme.badge;
|
|
86
|
+
case 'chips': return refinementsTheme.chip;
|
|
87
|
+
default: return refinementsTheme.item;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
export const CurrentRefinements = ({ refinements: refinementsProp, onRefinementClear, onClearAll, renderRefinement, showClearAll = true, variant = 'chips', layout = 'horizontal', fieldColors, renderCloseIcon, className, style, theme: customTheme, }) => {
|
|
10
91
|
const { theme } = useSearchContext();
|
|
92
|
+
const { refinements: stateRefinements, removeRefinement, clearRefinements } = useSearchState();
|
|
11
93
|
const refinementsTheme = customTheme || {};
|
|
94
|
+
// Use props if provided, otherwise auto-read from StateManager
|
|
95
|
+
const refinements = refinementsProp !== undefined
|
|
96
|
+
? refinementsProp
|
|
97
|
+
: stateRefinements.map(r => ({ field: r.field, value: r.value }));
|
|
98
|
+
// Track items for entry/exit animations
|
|
99
|
+
const [visibleItems, setVisibleItems] = useState(new Set());
|
|
100
|
+
const [exitingItems, setExitingItems] = useState(new Set());
|
|
101
|
+
const prevRefinementsRef = useRef([]);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const currentKeys = new Set(refinements.map(r => `${r.field}:${r.value}`));
|
|
104
|
+
const prevKeys = new Set(prevRefinementsRef.current.map(r => `${r.field}:${r.value}`));
|
|
105
|
+
// Detect removed items for exit animation
|
|
106
|
+
const removed = new Set();
|
|
107
|
+
prevKeys.forEach(key => {
|
|
108
|
+
if (!currentKeys.has(key))
|
|
109
|
+
removed.add(key);
|
|
110
|
+
});
|
|
111
|
+
if (removed.size > 0) {
|
|
112
|
+
setExitingItems(removed);
|
|
113
|
+
// Remove after animation completes
|
|
114
|
+
setTimeout(() => setExitingItems(new Set()), 200);
|
|
115
|
+
}
|
|
116
|
+
// Mark new items for entry animation
|
|
117
|
+
setVisibleItems(currentKeys);
|
|
118
|
+
prevRefinementsRef.current = [...refinements];
|
|
119
|
+
}, [refinements]);
|
|
12
120
|
const handleClear = (field, value) => {
|
|
121
|
+
// If synced with StateManager and no prop provided, auto-clear via StateManager
|
|
122
|
+
if (refinementsProp === undefined) {
|
|
123
|
+
removeRefinement(field, value);
|
|
124
|
+
}
|
|
13
125
|
if (onRefinementClear) {
|
|
14
126
|
onRefinementClear(field, value);
|
|
15
127
|
}
|
|
16
128
|
};
|
|
17
129
|
const handleClearAll = () => {
|
|
130
|
+
// If synced with StateManager, auto-clear all via StateManager
|
|
131
|
+
if (refinementsProp === undefined) {
|
|
132
|
+
clearRefinements();
|
|
133
|
+
}
|
|
18
134
|
if (onClearAll) {
|
|
19
135
|
onClearAll();
|
|
20
136
|
}
|
|
21
137
|
};
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
138
|
+
const defaultCloseIcon = () => (React.createElement("span", { "aria-hidden": "true", style: { lineHeight: 1 } }, "\u00D7"));
|
|
139
|
+
const defaultRenderRefinement = (refinement, index) => {
|
|
140
|
+
const key = `${refinement.field}:${refinement.value}`;
|
|
141
|
+
const fieldColor = fieldColors?.[refinement.field];
|
|
142
|
+
const isEntering = visibleItems.has(key) && !prevRefinementsRef.current.some(r => `${r.field}:${r.value}` === key);
|
|
143
|
+
const variantStyles = getVariantStyles(variant, theme.colors, theme.spacing, theme.borderRadius, fieldColor);
|
|
144
|
+
const variantClass = getVariantClass(variant, refinementsTheme);
|
|
145
|
+
return (React.createElement("div", { key: `${key}-${index}`, className: clsx(refinementsTheme.item, variantClass), role: "listitem", style: {
|
|
146
|
+
...variantStyles,
|
|
147
|
+
margin: layout === 'vertical'
|
|
148
|
+
? `0 0 ${theme.spacing.small} 0`
|
|
149
|
+
: `0 ${theme.spacing.small} ${theme.spacing.small} 0`,
|
|
150
|
+
transition: 'all 200ms ease-in-out',
|
|
151
|
+
opacity: exitingItems.has(key) ? 0 : 1,
|
|
152
|
+
transform: exitingItems.has(key) ? 'scale(0.8)' : 'scale(1)',
|
|
153
|
+
animation: isEntering ? 'seekoraChipIn 200ms ease-out' : undefined,
|
|
36
154
|
} },
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
155
|
+
variant !== 'badges' && (React.createElement("span", { className: refinementsTheme.label, style: {
|
|
156
|
+
marginRight: theme.spacing.small,
|
|
157
|
+
fontWeight: '500',
|
|
158
|
+
opacity: 0.7,
|
|
159
|
+
} },
|
|
160
|
+
refinement.label || refinement.field,
|
|
161
|
+
":")),
|
|
162
|
+
React.createElement("span", { className: refinementsTheme.value }, refinement.displayValue || refinement.value),
|
|
163
|
+
React.createElement("button", { type: "button", onClick: () => handleClear(refinement.field, refinement.value), className: refinementsTheme.clearButton, style: {
|
|
164
|
+
border: 'none',
|
|
165
|
+
backgroundColor: 'transparent',
|
|
166
|
+
color: 'inherit',
|
|
167
|
+
cursor: 'pointer',
|
|
168
|
+
fontSize: '14px',
|
|
169
|
+
padding: '0 0 0 6px',
|
|
170
|
+
display: 'flex',
|
|
171
|
+
alignItems: 'center',
|
|
172
|
+
justifyContent: 'center',
|
|
173
|
+
borderRadius: '50%',
|
|
174
|
+
transition: 'opacity 150ms ease-in-out',
|
|
175
|
+
opacity: 0.6,
|
|
176
|
+
}, "aria-label": `Clear ${refinement.label || refinement.field}: ${refinement.value}`, onMouseEnter: e => (e.currentTarget.style.opacity = '1'), onMouseLeave: e => (e.currentTarget.style.opacity = '0.6') }, renderCloseIcon ? renderCloseIcon() : defaultCloseIcon())));
|
|
177
|
+
};
|
|
59
178
|
if (refinements.length === 0) {
|
|
60
179
|
return null;
|
|
61
180
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
181
|
+
// Group refinements by field for grouped layout
|
|
182
|
+
const groupedRefinements = layout === 'grouped'
|
|
183
|
+
? refinements.reduce((acc, r) => {
|
|
184
|
+
if (!acc[r.field])
|
|
185
|
+
acc[r.field] = [];
|
|
186
|
+
acc[r.field].push(r);
|
|
187
|
+
return acc;
|
|
188
|
+
}, {})
|
|
189
|
+
: null;
|
|
190
|
+
const containerStyles = {
|
|
191
|
+
...style,
|
|
192
|
+
};
|
|
193
|
+
const listStyles = {
|
|
194
|
+
display: 'flex',
|
|
195
|
+
flexWrap: layout === 'vertical' ? 'nowrap' : 'wrap',
|
|
196
|
+
flexDirection: layout === 'vertical' ? 'column' : 'row',
|
|
197
|
+
alignItems: layout === 'vertical' ? 'flex-start' : 'center',
|
|
198
|
+
marginBottom: showClearAll ? theme.spacing.medium : 0,
|
|
199
|
+
};
|
|
200
|
+
return (React.createElement("div", { className: clsx(refinementsTheme.container, className), style: containerStyles },
|
|
201
|
+
React.createElement("style", null, `
|
|
202
|
+
@keyframes seekoraChipIn {
|
|
203
|
+
from { opacity: 0; transform: scale(0.8); }
|
|
204
|
+
to { opacity: 1; transform: scale(1); }
|
|
205
|
+
}
|
|
206
|
+
`),
|
|
207
|
+
layout === 'grouped' && groupedRefinements ? (Object.entries(groupedRefinements).map(([field, items]) => (React.createElement("div", { key: field, className: refinementsTheme.group, style: { marginBottom: theme.spacing.medium } },
|
|
208
|
+
React.createElement("div", { className: refinementsTheme.groupLabel, style: {
|
|
209
|
+
fontSize: theme.typography.fontSize.small,
|
|
210
|
+
fontWeight: 600,
|
|
211
|
+
color: theme.colors.text,
|
|
212
|
+
marginBottom: theme.spacing.small,
|
|
213
|
+
textTransform: 'capitalize',
|
|
214
|
+
} }, items[0]?.label || field),
|
|
215
|
+
React.createElement("div", { role: "list", style: listStyles }, items.map((refinement, index) => {
|
|
216
|
+
return renderRefinement
|
|
217
|
+
? renderRefinement(refinement, index)
|
|
218
|
+
: defaultRenderRefinement(refinement, index);
|
|
219
|
+
})))))) : (React.createElement("div", { role: "list", className: refinementsTheme.list, style: listStyles }, refinements.map((refinement, index) => {
|
|
69
220
|
return renderRefinement
|
|
70
221
|
? renderRefinement(refinement, index)
|
|
71
222
|
: defaultRenderRefinement(refinement, index);
|
|
72
|
-
})),
|
|
223
|
+
}))),
|
|
73
224
|
showClearAll && refinements.length > 1 && (React.createElement("button", { type: "button", onClick: handleClearAll, className: refinementsTheme.clearAllButton, style: {
|
|
74
225
|
padding: `${theme.spacing.small} ${theme.spacing.medium}`,
|
|
75
226
|
border: `1px solid ${theme.colors.border}`,
|
|
@@ -79,5 +230,6 @@ export const CurrentRefinements = ({ refinements = [], onRefinementClear, onClea
|
|
|
79
230
|
cursor: 'pointer',
|
|
80
231
|
fontSize: theme.typography.fontSize.small,
|
|
81
232
|
textDecoration: 'underline',
|
|
233
|
+
transition: 'background-color 150ms ease-in-out',
|
|
82
234
|
} }, "Clear all filters"))));
|
|
83
235
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Facets Component
|
|
3
3
|
*
|
|
4
|
-
* Displays facet filters for search results
|
|
4
|
+
* Displays facet filters for search results with multiple display variants,
|
|
5
|
+
* client-side search, count badges, and color swatch support.
|
|
5
6
|
*/
|
|
6
7
|
import React from 'react';
|
|
7
8
|
import type { SearchResponse } from '@seekora-ai/search-sdk';
|
|
@@ -26,7 +27,23 @@ export interface FacetsTheme {
|
|
|
26
27
|
facetItemCount?: string;
|
|
27
28
|
facetItemLabel?: string;
|
|
28
29
|
checkbox?: string;
|
|
30
|
+
/** Color swatch circle/square */
|
|
31
|
+
colorSwatch?: string;
|
|
32
|
+
/** Color swatch when selected */
|
|
33
|
+
colorSwatchSelected?: string;
|
|
34
|
+
/** Inner element of color swatch (for checkmark overlay) */
|
|
35
|
+
colorSwatchInner?: string;
|
|
36
|
+
/** Search input within a facet group */
|
|
37
|
+
searchInput?: string;
|
|
38
|
+
/** Collapsible header row */
|
|
39
|
+
collapsibleHeader?: string;
|
|
40
|
+
/** Chevron/expand icon in collapsible header */
|
|
41
|
+
collapsibleIcon?: string;
|
|
42
|
+
/** Count badge pill */
|
|
43
|
+
countBadge?: string;
|
|
29
44
|
}
|
|
45
|
+
export type FacetVariant = 'checkbox' | 'color-swatch' | 'collapsible';
|
|
46
|
+
export type FacetSize = 'small' | 'medium' | 'large';
|
|
30
47
|
export interface FacetsProps {
|
|
31
48
|
/** Search results response */
|
|
32
49
|
results?: SearchResponse | null;
|
|
@@ -48,6 +65,18 @@ export interface FacetsProps {
|
|
|
48
65
|
style?: React.CSSProperties;
|
|
49
66
|
/** Custom theme */
|
|
50
67
|
theme?: FacetsTheme;
|
|
68
|
+
/** Display variant: checkbox (default), color-swatch, or collapsible */
|
|
69
|
+
variant?: FacetVariant;
|
|
70
|
+
/** When true, show a search input at the top of each facet group */
|
|
71
|
+
searchable?: boolean;
|
|
72
|
+
/** Show count badges (default: true) */
|
|
73
|
+
showCounts?: boolean;
|
|
74
|
+
/** Maps facet values to CSS colors (used by color-swatch variant) */
|
|
75
|
+
colorMap?: Record<string, string>;
|
|
76
|
+
/** For collapsible variant, whether facets start collapsed (default: false) */
|
|
77
|
+
defaultCollapsed?: boolean;
|
|
78
|
+
/** Size preset: small, medium (default), or large */
|
|
79
|
+
size?: FacetSize;
|
|
51
80
|
}
|
|
52
81
|
export declare const Facets: React.FC<FacetsProps>;
|
|
53
82
|
//# sourceMappingURL=Facets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Facets.d.ts","sourceRoot":"","sources":["../../src/components/Facets.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"Facets.d.ts","sourceRoot":"","sources":["../../src/components/Facets.tsx"],"names":[],"mappings":"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"}
|